From c545b546272b28e437010fea0680d738a8f7934b Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 10 May 2023 15:43:53 -0400 Subject: [PATCH 001/121] Use EXT_mesh_features to indicate feature IDs --- .../src/BatchTableToGltfFeatureMetadata.cpp | 40 +++++----- .../test/TestPntsToGltfConverter.cpp | 68 ++++++++--------- ...tUpgradeBatchTableToExtFeatureMetadata.cpp | 74 +++++++++---------- 3 files changed, 89 insertions(+), 93 deletions(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.cpp index a8c6ea77d..656f4bb2f 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.cpp @@ -3,6 +3,7 @@ #include "BatchTableHierarchyPropertyValues.h" #include "Cesium3DTilesSelection/spdlog-cesium.h" +#include #include #include #include @@ -1535,13 +1536,17 @@ ErrorList BatchTableToGltfFeatureMetadata::convertFromB3dm( primitive.attributes["_FEATURE_ID_0"] = batchIDIt->second; primitive.attributes.erase("_BATCHID"); - // Create a feature extension - ExtensionMeshPrimitiveExtFeatureMetadata& extension = - primitive.addExtension(); - FeatureIDAttribute& attribute = - extension.featureIdAttributes.emplace_back(); - attribute.featureTable = "default"; - attribute.featureIds.attribute = "_FEATURE_ID_0"; + // Create an EXT_mesh_features extension with a feature ID attribute. + ExtensionExtMeshFeatures& extension = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureId& featureID = + extension.featureIds.emplace_back(); + // No fast way to count the unique feature IDs in this primitive, so + // subtitute the batch table length. + featureID.featureCount = batchLength; + featureID.attribute = 0; + featureID.propertyTable = 0; } } @@ -1599,29 +1604,28 @@ ErrorList BatchTableToGltfFeatureMetadata::convertFromPnts( featureCount, result); - // Create the EXT_feature_metadata extension for the single mesh primitive. + // Create the EXT_mesh_features extension for the single mesh primitive. assert(gltf.meshes.size() == 1); Mesh& mesh = gltf.meshes[0]; assert(mesh.primitives.size() == 1); MeshPrimitive& primitive = mesh.primitives[0]; - ExtensionMeshPrimitiveExtFeatureMetadata& extension = - primitive.addExtension(); - FeatureIDAttribute& attribute = extension.featureIdAttributes.emplace_back(); - attribute.featureTable = "default"; + ExtensionExtMeshFeatures& extension = + primitive.addExtension(); + ExtensionExtMeshFeaturesFeatureId& featureID = + extension.featureIds.emplace_back(); + + // Setting the feature count is sufficient for implicit feature IDs. + featureID.featureCount = featureCount; + featureID.propertyTable = 0; auto primitiveBatchIdIt = primitive.attributes.find("_BATCHID"); if (primitiveBatchIdIt != primitive.attributes.end()) { // If _BATCHID is present, rename the _BATCHID attribute to _FEATURE_ID_0 primitive.attributes["_FEATURE_ID_0"] = primitiveBatchIdIt->second; primitive.attributes.erase("_BATCHID"); - attribute.featureIds.attribute = "_FEATURE_ID_0"; - } else { - // Otherwise, use implicit feature IDs to indicate the metadata is stored in - // per-point properties. - attribute.featureIds.constant = 0; - attribute.featureIds.divisor = 1; + featureID.attribute = 0; } return result; diff --git a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp index 543397b89..8aeafa635 100644 --- a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp +++ b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp @@ -3,8 +3,8 @@ #include #include #include +#include #include -#include #include #include @@ -675,13 +675,13 @@ TEST_CASE( MeshPrimitive& primitive = mesh.primitives[0]; CHECK(primitive.mode == MeshPrimitive::Mode::POINTS); - auto primitiveExtension = - primitive.getExtension(); + auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); - REQUIRE(primitiveExtension->featureIdAttributes.size() == 1); - FeatureIDAttribute& attribute = primitiveExtension->featureIdAttributes[0]; - CHECK(attribute.featureTable == "default"); - CHECK(attribute.featureIds.attribute == "_FEATURE_ID_0"); + REQUIRE(primitiveExtension->featureIds.size() == 1); + ExtensionExtMeshFeaturesFeatureId& featureId = + primitiveExtension->featureIds[0]; + CHECK(featureId.featureCount == 8); + CHECK(featureId.attribute == 0); CHECK(gltf.materials.size() == 1); @@ -754,16 +754,14 @@ TEST_CASE("Converts point cloud with per-point properties to glTF with " MeshPrimitive& primitive = mesh.primitives[0]; CHECK(primitive.mode == MeshPrimitive::Mode::POINTS); - auto primitiveExtension = - primitive.getExtension(); + auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); - REQUIRE(primitiveExtension->featureIdAttributes.size() == 1); - FeatureIDAttribute& attribute = primitiveExtension->featureIdAttributes[0]; - CHECK(attribute.featureTable == "default"); + REQUIRE(primitiveExtension->featureIds.size() == 1); + ExtensionExtMeshFeaturesFeatureId& featureId = + primitiveExtension->featureIds[0]; // Check for implicit feature IDs - CHECK(!attribute.featureIds.attribute); - CHECK(attribute.featureIds.constant == 0); - CHECK(attribute.featureIds.divisor == 1); + CHECK(featureId.featureCount == pointsLength); + CHECK(!featureId.attribute); CHECK(gltf.materials.size() == 1); @@ -815,16 +813,14 @@ TEST_CASE("Converts point cloud with Draco compression to glTF") { MeshPrimitive& primitive = mesh.primitives[0]; CHECK(primitive.mode == MeshPrimitive::Mode::POINTS); - auto primitiveExtension = - primitive.getExtension(); + auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); - REQUIRE(primitiveExtension->featureIdAttributes.size() == 1); - FeatureIDAttribute& attribute = primitiveExtension->featureIdAttributes[0]; - CHECK(attribute.featureTable == "default"); + REQUIRE(primitiveExtension->featureIds.size() == 1); + ExtensionExtMeshFeaturesFeatureId& featureId = + primitiveExtension->featureIds[0]; // Check for implicit feature IDs - CHECK(!attribute.featureIds.attribute); - CHECK(attribute.featureIds.constant == 0); - CHECK(attribute.featureIds.divisor == 1); + CHECK(featureId.featureCount == pointsLength); + CHECK(!featureId.attribute); REQUIRE(gltf.materials.size() == 1); Material& material = gltf.materials[0]; @@ -961,16 +957,14 @@ TEST_CASE("Converts point cloud with partial Draco compression to glTF") { MeshPrimitive& primitive = mesh.primitives[0]; CHECK(primitive.mode == MeshPrimitive::Mode::POINTS); - auto primitiveExtension = - primitive.getExtension(); + auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); - REQUIRE(primitiveExtension->featureIdAttributes.size() == 1); - FeatureIDAttribute& attribute = primitiveExtension->featureIdAttributes[0]; - CHECK(attribute.featureTable == "default"); + REQUIRE(primitiveExtension->featureIds.size() == 1); + ExtensionExtMeshFeaturesFeatureId& featureId = + primitiveExtension->featureIds[0]; // Check for implicit feature IDs - CHECK(!attribute.featureIds.attribute); - CHECK(attribute.featureIds.constant == 0); - CHECK(attribute.featureIds.divisor == 1); + CHECK(featureId.featureCount == pointsLength); + CHECK(!featureId.attribute); REQUIRE(gltf.materials.size() == 1); Material& material = gltf.materials[0]; @@ -1102,13 +1096,13 @@ TEST_CASE("Converts batched point cloud with Draco compression to glTF") { MeshPrimitive& primitive = mesh.primitives[0]; CHECK(primitive.mode == MeshPrimitive::Mode::POINTS); - auto primitiveExtension = - primitive.getExtension(); + auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); - REQUIRE(primitiveExtension->featureIdAttributes.size() == 1); - FeatureIDAttribute& attribute = primitiveExtension->featureIdAttributes[0]; - CHECK(attribute.featureTable == "default"); - CHECK(attribute.featureIds.attribute == "_FEATURE_ID_0"); + REQUIRE(primitiveExtension->featureIds.size() == 1); + ExtensionExtMeshFeaturesFeatureId& featureId = + primitiveExtension->featureIds[0]; + CHECK(featureId.featureCount == 8); + CHECK(featureId.attribute == 0); CHECK(gltf.materials.size() == 1); diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp index 3c2e62584..6e20c2a3d 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -360,15 +360,15 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { primitive.attributes.find("_FEATURE_ID_1") == primitive.attributes.end()); - ExtensionMeshPrimitiveExtFeatureMetadata* pPrimitiveExtension = - primitive.getExtension(); + ExtensionExtMeshFeatures* pPrimitiveExtension = + primitive.getExtension(); REQUIRE(pPrimitiveExtension); - REQUIRE(pPrimitiveExtension->featureIdAttributes.size() == 1); - - FeatureIDAttribute& attribute = - pPrimitiveExtension->featureIdAttributes[0]; - CHECK(attribute.featureIds.attribute == "_FEATURE_ID_0"); - CHECK(attribute.featureTable == "default"); + REQUIRE(pPrimitiveExtension->featureIds.size() == 1); + ExtensionExtMeshFeaturesFeatureId& featureId = + pPrimitiveExtension->featureIds[0]; + CHECK(featureId.featureCount == 10); + CHECK(featureId.attribute == 0); + CHECK(featureId.propertyTable == 0); } } @@ -677,14 +677,15 @@ TEST_CASE("Converts batched PNTS batch table to EXT_feature_metadata") { CHECK( primitive.attributes.find("_FEATURE_ID_0") != primitive.attributes.end()); - ExtensionMeshPrimitiveExtFeatureMetadata* pPrimitiveExtension = - primitive.getExtension(); + ExtensionExtMeshFeatures* pPrimitiveExtension = + primitive.getExtension(); REQUIRE(pPrimitiveExtension); - REQUIRE(pPrimitiveExtension->featureIdAttributes.size() == 1); - - FeatureIDAttribute& attribute = pPrimitiveExtension->featureIdAttributes[0]; - CHECK(attribute.featureTable == "default"); - CHECK(attribute.featureIds.attribute == "_FEATURE_ID_0"); + REQUIRE(pPrimitiveExtension->featureIds.size() == 1); + ExtensionExtMeshFeaturesFeatureId& featureId = + pPrimitiveExtension->featureIds[0]; + CHECK(featureId.featureCount ==8); + CHECK(featureId.attribute == 0); + CHECK(featureId.propertyTable == 0); // Check metadata values { @@ -824,17 +825,15 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_feature_metadata") { CHECK( primitive.attributes.find("_FEATURE_ID_0") == primitive.attributes.end()); - ExtensionMeshPrimitiveExtFeatureMetadata* pPrimitiveExtension = - primitive.getExtension(); + ExtensionExtMeshFeatures* pPrimitiveExtension = + primitive.getExtension(); REQUIRE(pPrimitiveExtension); - REQUIRE(pPrimitiveExtension->featureIdAttributes.size() == 1); - - FeatureIDAttribute& attribute = pPrimitiveExtension->featureIdAttributes[0]; - CHECK(attribute.featureTable == "default"); - // Check for implicit feature IDs - CHECK(!attribute.featureIds.attribute); - CHECK(attribute.featureIds.constant == 0); - CHECK(attribute.featureIds.divisor == 1); + REQUIRE(pPrimitiveExtension->featureIds.size() == 1); + ExtensionExtMeshFeaturesFeatureId& featureId = + pPrimitiveExtension->featureIds[0]; + CHECK(featureId.featureCount == 8); + CHECK(!featureId.attribute); + CHECK(featureId.propertyTable == 0); // Check metadata values { @@ -974,17 +973,16 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " CHECK( primitive.attributes.find("_FEATURE_ID_0") == primitive.attributes.end()); - ExtensionMeshPrimitiveExtFeatureMetadata* pPrimitiveExtension = - primitive.getExtension(); - REQUIRE(pPrimitiveExtension); - REQUIRE(pPrimitiveExtension->featureIdAttributes.size() == 1); - FeatureIDAttribute& attribute = pPrimitiveExtension->featureIdAttributes[0]; - CHECK(attribute.featureTable == "default"); - // Check for implicit feature IDs - CHECK(!attribute.featureIds.attribute); - CHECK(attribute.featureIds.constant == 0); - CHECK(attribute.featureIds.divisor == 1); + ExtensionExtMeshFeatures* pPrimitiveExtension = + primitive.getExtension(); + REQUIRE(pPrimitiveExtension); + REQUIRE(pPrimitiveExtension->featureIds.size() == 1); + ExtensionExtMeshFeaturesFeatureId& featureId = + pPrimitiveExtension->featureIds[0]; + CHECK(featureId.featureCount == 8); + CHECK(!featureId.attribute); + CHECK(featureId.propertyTable == 0); // Check metadata values { @@ -1248,7 +1246,7 @@ TEST_CASE("Upgrade fixed json number array") { {1244, 12200000, 1222, 544662}, {123, 10, 122, 334}, {13, 45, 122, 94}, - {11, 22, 3, 4294967295}}; + {11, 22, 3, (uint32_t)4294967295}}; // clang-format on std::string expectedComponentType = "UINT32"; @@ -1408,7 +1406,7 @@ TEST_CASE("Upgrade dynamic json number array") { {1244, 12200000, 1222, 544662}, {123, 10}, {13, 45, 122, 94, 333, 212, 534, 1122}, - {11, 22, 3, 4294967295}}; + {11, 22, 3, (uint32_t)4294967295}}; // clang-format on std::string expectedComponentType = "UINT32"; From c1e852fb7a25652e3c34a321498f2b7a6156664d Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 10 May 2023 15:58:28 -0400 Subject: [PATCH 002/121] Rename file --- .../src/B3dmToGltfConverter.cpp | 4 ++-- ...=> BatchTableToGltfStructuralMetadata.cpp} | 15 ++++++------- ...h => BatchTableToGltfStructuralMetadata.h} | 2 +- .../src/PntsToGltfConverter.cpp | 10 ++++----- .../test/TestPntsToGltfConverter.cpp | 2 +- ...tUpgradeBatchTableToExtFeatureMetadata.cpp | 21 +++++++++---------- 6 files changed, 27 insertions(+), 27 deletions(-) rename Cesium3DTilesSelection/src/{BatchTableToGltfFeatureMetadata.cpp => BatchTableToGltfStructuralMetadata.cpp} (99%) rename Cesium3DTilesSelection/src/{BatchTableToGltfFeatureMetadata.h => BatchTableToGltfStructuralMetadata.h} (94%) diff --git a/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp b/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp index 6ee772ca5..dc2689d38 100644 --- a/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp +++ b/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp @@ -1,6 +1,6 @@ #include "B3dmToGltfConverter.h" -#include "BatchTableToGltfFeatureMetadata.h" +#include "BatchTableToGltfStructuralMetadata.h" #include "BinaryToGltfConverter.h" #include @@ -220,7 +220,7 @@ void convertB3dmMetadataToGltfFeatureMetadata( } // upgrade batch table to glTF feature metadata and append the result - result.errors.merge(BatchTableToGltfFeatureMetadata::convertFromB3dm( + result.errors.merge(BatchTableToGltfStructuralMetadata::convertFromB3dm( featureTableJson, batchTableJson, batchTableBinaryData, diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp similarity index 99% rename from Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.cpp rename to Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 656f4bb2f..98ca77a24 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -1,10 +1,9 @@ -#include "BatchTableToGltfFeatureMetadata.h" +#include "BatchTableToGltfStructuralMetadata.h" #include "BatchTableHierarchyPropertyValues.h" #include "Cesium3DTilesSelection/spdlog-cesium.h" #include -#include #include #include #include @@ -1383,7 +1382,7 @@ void updateExtensionWithBatchTableHierarchy( } } -void convertBatchTableToGltfFeatureMetadataExtension( +void convertBatchTableToGltfStructuralMetadataExtension( const rapidjson::Document& batchTableJson, const gsl::span& batchTableBinaryData, CesiumGltf::Model& gltf, @@ -1486,7 +1485,7 @@ void convertBatchTableToGltfFeatureMetadataExtension( } // namespace -ErrorList BatchTableToGltfFeatureMetadata::convertFromB3dm( +ErrorList BatchTableToGltfStructuralMetadata::convertFromB3dm( const rapidjson::Document& featureTableJson, const rapidjson::Document& batchTableJson, const gsl::span& batchTableBinaryData, @@ -1515,7 +1514,7 @@ ErrorList BatchTableToGltfFeatureMetadata::convertFromB3dm( const int64_t batchLength = batchLengthIt->value.GetInt64(); - convertBatchTableToGltfFeatureMetadataExtension( + convertBatchTableToGltfStructuralMetadataExtension( batchTableJson, batchTableBinaryData, gltf, @@ -1546,6 +1545,7 @@ ErrorList BatchTableToGltfFeatureMetadata::convertFromB3dm( // subtitute the batch table length. featureID.featureCount = batchLength; featureID.attribute = 0; + featureID.label = "_FEATURE_ID_0"; featureID.propertyTable = 0; } } @@ -1553,7 +1553,7 @@ ErrorList BatchTableToGltfFeatureMetadata::convertFromB3dm( return result; } -ErrorList BatchTableToGltfFeatureMetadata::convertFromPnts( +ErrorList BatchTableToGltfStructuralMetadata::convertFromPnts( const rapidjson::Document& featureTableJson, const rapidjson::Document& batchTableJson, const gsl::span& batchTableBinaryData, @@ -1597,7 +1597,7 @@ ErrorList BatchTableToGltfFeatureMetadata::convertFromPnts( featureCount = pointsLengthIt->value.GetInt64(); } - convertBatchTableToGltfFeatureMetadataExtension( + convertBatchTableToGltfStructuralMetadataExtension( batchTableJson, batchTableBinaryData, gltf, @@ -1626,6 +1626,7 @@ ErrorList BatchTableToGltfFeatureMetadata::convertFromPnts( primitive.attributes["_FEATURE_ID_0"] = primitiveBatchIdIt->second; primitive.attributes.erase("_BATCHID"); featureID.attribute = 0; + featureID.label = "_FEATURE_ID_0"; } return result; diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.h b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.h similarity index 94% rename from Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.h rename to Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.h index 65008f913..05517786b 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfFeatureMetadata.h +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.h @@ -9,7 +9,7 @@ #include namespace Cesium3DTilesSelection { -struct BatchTableToGltfFeatureMetadata { +struct BatchTableToGltfStructuralMetadata { static ErrorList convertFromB3dm( const rapidjson::Document& featureTableJson, const rapidjson::Document& batchTableJson, diff --git a/Cesium3DTilesSelection/src/PntsToGltfConverter.cpp b/Cesium3DTilesSelection/src/PntsToGltfConverter.cpp index debda368f..ca49693b2 100644 --- a/Cesium3DTilesSelection/src/PntsToGltfConverter.cpp +++ b/Cesium3DTilesSelection/src/PntsToGltfConverter.cpp @@ -1,6 +1,6 @@ #include "PntsToGltfConverter.h" -#include "BatchTableToGltfFeatureMetadata.h" +#include "BatchTableToGltfStructuralMetadata.h" #include #include @@ -701,7 +701,7 @@ void parseDracoExtensionFromBatchTableJson( const std::string name = dracoPropertyIt->name.GetString(); // If there are issues with the extension, skip parsing metadata altogether. - // Otherwise, BatchTableToGltfFeatureMetadata will still try to parse the + // Otherwise, BatchTableToGltfStructuralMetadata will still try to parse the // invalid Draco-compressed properties. auto batchTablePropertyIt = batchTableJson.FindMember(name.c_str()); if (batchTablePropertyIt == batchTableJson.MemberEnd() || @@ -723,7 +723,7 @@ void parseDracoExtensionFromBatchTableJson( } // If the batch table binary property is invalid, it will also be ignored by - // BatchTableToGltfFeatureMetadata, so it's fine to continue parsing the + // BatchTableToGltfStructuralMetadata, so it's fine to continue parsing the // other properties. const rapidjson::Value& batchTableProperty = batchTablePropertyIt->value; auto byteOffsetIt = batchTableProperty.FindMember("byteOffset"); @@ -1464,7 +1464,7 @@ void addBatchIdsToGltf(PntsContent& parsedContent, CesiumGltf::Model& gltf) { Accessor::Type::SCALAR); MeshPrimitive& primitive = gltf.meshes[0].primitives[0]; - // This will be renamed by BatchTableToGltfFeatureMetadata. + // This will be renamed by BatchTableToGltfStructuralMetadata. primitive.attributes.emplace("_BATCHID", accessorId); } } @@ -1610,7 +1610,7 @@ void convertPntsContentToGltf( gsl::span(parsedContent.dracoBatchTableBinary); } - result.errors.merge(BatchTableToGltfFeatureMetadata::convertFromPnts( + result.errors.merge(BatchTableToGltfStructuralMetadata::convertFromPnts( featureTableJson, batchTableJson, batchTableBinaryData, diff --git a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp index 8aeafa635..41da45719 100644 --- a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp +++ b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp @@ -1096,7 +1096,7 @@ TEST_CASE("Converts batched point cloud with Draco compression to glTF") { MeshPrimitive& primitive = mesh.primitives[0]; CHECK(primitive.mode == MeshPrimitive::Mode::POINTS); - auto primitiveExtension = primitive.getExtension(); + auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); REQUIRE(primitiveExtension->featureIds.size() == 1); ExtensionExtMeshFeaturesFeatureId& featureId = diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp index 6e20c2a3d..34dfc9267 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp @@ -1,4 +1,4 @@ -#include "BatchTableToGltfFeatureMetadata.h" +#include "BatchTableToGltfStructuralMetadata.h" #include "ConvertTileToGltf.h" #include @@ -136,7 +136,7 @@ static void createTestForScalarJson( scalarProperty, batchTableJson.GetAllocator()); - auto errors = BatchTableToGltfFeatureMetadata::convertFromB3dm( + auto errors = BatchTableToGltfStructuralMetadata::convertFromB3dm( featureTableJson, batchTableJson, gsl::span(), @@ -212,7 +212,7 @@ static void createTestForArrayJson( fixedArrayProperties, batchTableJson.GetAllocator()); - auto errors = BatchTableToGltfFeatureMetadata::convertFromB3dm( + auto errors = BatchTableToGltfStructuralMetadata::convertFromB3dm( featureTableJson, batchTableJson, gsl::span(), @@ -683,7 +683,7 @@ TEST_CASE("Converts batched PNTS batch table to EXT_feature_metadata") { REQUIRE(pPrimitiveExtension->featureIds.size() == 1); ExtensionExtMeshFeaturesFeatureId& featureId = pPrimitiveExtension->featureIds[0]; - CHECK(featureId.featureCount ==8); + CHECK(featureId.featureCount == 8); CHECK(featureId.attribute == 0); CHECK(featureId.propertyTable == 0); @@ -973,8 +973,7 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " CHECK( primitive.attributes.find("_FEATURE_ID_0") == primitive.attributes.end()); - - ExtensionExtMeshFeatures* pPrimitiveExtension = + ExtensionExtMeshFeatures* pPrimitiveExtension = primitive.getExtension(); REQUIRE(pPrimitiveExtension); REQUIRE(pPrimitiveExtension->featureIds.size() == 1); @@ -1133,7 +1132,7 @@ TEST_CASE("Upgrade bool json to boolean binary") { boolProperties, batchTableJson.GetAllocator()); - auto errors = BatchTableToGltfFeatureMetadata::convertFromB3dm( + auto errors = BatchTableToGltfStructuralMetadata::convertFromB3dm( featureTableJson, batchTableJson, gsl::span(), @@ -1675,7 +1674,7 @@ TEST_CASE("Converts Feature Classes 3DTILES_batch_table_hierarchy example to " rapidjson::Document batchTableParsed; batchTableParsed.Parse(batchTableJson.data(), batchTableJson.size()); - auto errors = BatchTableToGltfFeatureMetadata::convertFromB3dm( + auto errors = BatchTableToGltfStructuralMetadata::convertFromB3dm( featureTableParsed, batchTableParsed, gsl::span(), @@ -1805,7 +1804,7 @@ TEST_CASE("Converts Feature Hierarchy 3DTILES_batch_table_hierarchy example to " rapidjson::Document batchTableParsed; batchTableParsed.Parse(batchTableJson.data(), batchTableJson.size()); - BatchTableToGltfFeatureMetadata::convertFromB3dm( + BatchTableToGltfStructuralMetadata::convertFromB3dm( featureTableParsed, batchTableParsed, gsl::span(), @@ -1999,7 +1998,7 @@ TEST_CASE( auto pLog = std::make_shared(3); spdlog::default_logger()->sinks().emplace_back(pLog); - BatchTableToGltfFeatureMetadata::convertFromB3dm( + BatchTableToGltfStructuralMetadata::convertFromB3dm( featureTableParsed, batchTableParsed, gsl::span(), @@ -2091,7 +2090,7 @@ TEST_CASE( auto pLog = std::make_shared(3); spdlog::default_logger()->sinks().emplace_back(pLog); - auto errors = BatchTableToGltfFeatureMetadata::convertFromB3dm( + auto errors = BatchTableToGltfStructuralMetadata::convertFromB3dm( featureTableParsed, batchTableParsed, gsl::span(), From 14997fb03170fc8960125345c4fc4aaf044b9cd7 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 15 May 2023 16:58:17 -0400 Subject: [PATCH 003/121] Add property types for structural metadata --- .../StructuralMetadataPropertyType.h | 57 ++++ .../src/StructuralMetadataPropertyType.cpp | 214 +++++++++++++++ .../TestStructuralMetadataPropertyType.cpp | 253 ++++++++++++++++++ 3 files changed, 524 insertions(+) create mode 100644 CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h create mode 100644 CesiumGltf/src/StructuralMetadataPropertyType.cpp create mode 100644 CesiumGltf/test/TestStructuralMetadataPropertyType.cpp diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h new file mode 100644 index 000000000..67d92d232 --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +namespace CesiumGltf { +namespace StructuralMetadata { + +enum class PropertyType { + Invalid, + Scalar, + Vec2, + Vec3, + Vec4, + Mat2, + Mat3, + Mat4, + String, + Boolean, + Enum +}; + +enum class PropertyComponentType { + None, + Int8, + Uint8, + Int16, + Uint16, + Int32, + Uint32, + Int64, + Uint64, + Float32, + Float64, +}; + +std::string +convertPropertyTypeToString(CesiumGltf::StructuralMetadata::PropertyType type); + +CesiumGltf::StructuralMetadata::PropertyType +convertStringToPropertyType(const std::string& str); + +std::string convertPropertyComponentTypeToString( + CesiumGltf::StructuralMetadata::PropertyComponentType componentType); + +CesiumGltf::StructuralMetadata::PropertyComponentType +convertStringToPropertyComponentType(const std::string& str); + +CesiumGltf::StructuralMetadata::PropertyComponentType +convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str); + +CesiumGltf::StructuralMetadata::PropertyComponentType +convertStringOffsetTypeStringToPropertyComponentType(const std::string& str); + +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/src/StructuralMetadataPropertyType.cpp b/CesiumGltf/src/StructuralMetadataPropertyType.cpp new file mode 100644 index 000000000..56a8262b1 --- /dev/null +++ b/CesiumGltf/src/StructuralMetadataPropertyType.cpp @@ -0,0 +1,214 @@ +#include "CesiumGltf/StructuralMetadataPropertyType.h" + +#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" +#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTable.h" + +namespace CesiumGltf { +namespace StructuralMetadata { + +std::string convertPropertyTypeToString(StructuralMetadata::PropertyType type) { + switch (type) { + case PropertyType::Scalar: + return ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + case PropertyType::Vec2: + return ExtensionExtStructuralMetadataClassProperty::Type::VEC2; + case PropertyType::Vec3: + return ExtensionExtStructuralMetadataClassProperty::Type::VEC3; + case PropertyType::Vec4: + return ExtensionExtStructuralMetadataClassProperty::Type::VEC4; + case PropertyType::Mat2: + return ExtensionExtStructuralMetadataClassProperty::Type::MAT2; + case PropertyType::Mat3: + return ExtensionExtStructuralMetadataClassProperty::Type::MAT3; + case PropertyType::Mat4: + return ExtensionExtStructuralMetadataClassProperty::Type::MAT4; + case PropertyType::Boolean: + return ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + case PropertyType::Enum: + return ExtensionExtStructuralMetadataClassProperty::Type::ENUM; + case PropertyType::String: + return ExtensionExtStructuralMetadataClassProperty::Type::STRING; + default: + return "INVALID"; + } +} + +PropertyType convertStringToPropertyType(const std::string& str) { + if (str == ExtensionExtStructuralMetadataClassProperty::Type::SCALAR) { + return PropertyType::Scalar; + } + + if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC2) { + return StructuralMetadata::PropertyType::Vec2; + } + + if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC3) { + return StructuralMetadata::PropertyType::Vec3; + } + + if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC4) { + return StructuralMetadata::PropertyType::Vec4; + } + + if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT2) { + return StructuralMetadata::PropertyType::Mat2; + } + + if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT3) { + return StructuralMetadata::PropertyType::Mat3; + } + + if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT4) { + return StructuralMetadata::PropertyType::Mat4; + } + + if (str == ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN) { + return StructuralMetadata::PropertyType::Boolean; + } + + if (str == ExtensionExtStructuralMetadataClassProperty::Type::STRING) { + return StructuralMetadata::PropertyType::String; + } + + if (str == ExtensionExtStructuralMetadataClassProperty::Type::ENUM) { + return StructuralMetadata::PropertyType::Enum; + } + + return PropertyType::Invalid; +} + +std::string convertPropertyComponentTypeToString(PropertyComponentType type) { + switch (type) { + case PropertyComponentType::None: + return "NONE"; + case PropertyComponentType::Uint8: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + case PropertyComponentType::Int8: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8; + case PropertyComponentType::Uint16: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16; + case PropertyComponentType::Int16: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16; + case PropertyComponentType::Uint32: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + case PropertyComponentType::Int32: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + case PropertyComponentType::Uint64: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64; + case PropertyComponentType::Int64: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64; + case PropertyComponentType::Float32: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32; + case PropertyComponentType::Float64: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64; + default: + return "NONE"; + } +} + +StructuralMetadata::PropertyComponentType +convertStringToPropertyComponentType(const std::string& str) { + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8) { + return PropertyComponentType::Uint8; + } + + if (str == ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8) { + return PropertyComponentType::Int8; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16) { + return PropertyComponentType::Uint16; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16) { + return PropertyComponentType::Int16; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32) { + return PropertyComponentType::Uint32; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32) { + return PropertyComponentType::Int32; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64) { + return PropertyComponentType::Uint64; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64) { + return PropertyComponentType::Int64; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32) { + return PropertyComponentType::Float32; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64) { + return PropertyComponentType::Float64; + } + + return PropertyComponentType::None; +} + +StructuralMetadata::PropertyComponentType +convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str) { + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT8) { + return PropertyComponentType::Uint8; + } + + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT16) { + return PropertyComponentType::Uint16; + } + + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT32) { + return PropertyComponentType::Uint32; + } + + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT64) { + return PropertyComponentType::Uint64; + } + + return PropertyComponentType::None; +} + +StructuralMetadata::PropertyComponentType +convertStringOffsetTypeStringToPropertyComponentType(const std::string& str) { + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT8) { + return PropertyComponentType::Uint8; + } + + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT16) { + return PropertyComponentType::Uint16; + } + + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT32) { + return PropertyComponentType::Uint32; + } + + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT64) { + return PropertyComponentType::Uint64; + } + + return PropertyComponentType::None; +} + +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyType.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyType.cpp new file mode 100644 index 000000000..759a485ec --- /dev/null +++ b/CesiumGltf/test/TestStructuralMetadataPropertyType.cpp @@ -0,0 +1,253 @@ +#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" +#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTableProperty.h" +#include "CesiumGltf/StructuralMetadataPropertyType.h" + +#include + +using namespace CesiumGltf; +using namespace StructuralMetadata; + +TEST_CASE("Test StructuralMetadata PropertyType utilities function") { + SECTION("Convert string to PropertyType") { + REQUIRE( + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR) == + PropertyType::Scalar); + + REQUIRE( + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::VEC2) == + PropertyType::Vec2); + + REQUIRE( + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::VEC3) == + PropertyType::Vec3); + + REQUIRE( + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::VEC4) == + PropertyType::Vec4); + + REQUIRE( + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::MAT2) == + PropertyType::Mat2); + + REQUIRE( + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::MAT3) == + PropertyType::Mat3); + + REQUIRE( + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::MAT4) == + PropertyType::Mat4); + + REQUIRE( + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN) == + PropertyType::Boolean); + + REQUIRE( + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::STRING) == + PropertyType::String); + + REQUIRE( + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::ENUM) == + PropertyType::Enum); + + REQUIRE(convertStringToPropertyType("invalid") == PropertyType::Invalid); + } + + SECTION("Convert string to PropertyComponentType") { + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + UINT8) == PropertyComponentType::Uint8); + + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8) == + PropertyComponentType::Int8); + + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + UINT16) == PropertyComponentType::Uint16); + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + INT16) == PropertyComponentType::Int16); + + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + UINT32) == PropertyComponentType::Uint32); + + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + INT32) == PropertyComponentType::Int32); + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + UINT64) == PropertyComponentType::Uint64); + + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + INT64) == PropertyComponentType::Int64); + + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + FLOAT32) == PropertyComponentType::Float32); + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + FLOAT64) == PropertyComponentType::Float64); + + REQUIRE( + convertStringToPropertyComponentType("invalid") == + PropertyComponentType::None); + } + + SECTION("Convert PropertyType to string") { + REQUIRE( + convertPropertyTypeToString(PropertyType::Scalar) == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Vec2) == + ExtensionExtStructuralMetadataClassProperty::Type::VEC2); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Vec3) == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Vec4) == + ExtensionExtStructuralMetadataClassProperty::Type::VEC4); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Mat2) == + ExtensionExtStructuralMetadataClassProperty::Type::MAT2); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Mat3) == + ExtensionExtStructuralMetadataClassProperty::Type::MAT3); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Mat4) == + ExtensionExtStructuralMetadataClassProperty::Type::MAT4); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Boolean) == + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + + REQUIRE( + convertPropertyTypeToString(PropertyType::String) == + ExtensionExtStructuralMetadataClassProperty::Type::STRING); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Enum) == + ExtensionExtStructuralMetadataClassProperty::Type::ENUM); + } + + SECTION("Convert PropertyComponentType to string") { + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint8) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int8) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint16) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int16) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint32) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int32) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint64) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int64) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Float32) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Float64) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); + } + + SECTION("Convert array offset type string to PropertyComponentType") { + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT8) == PropertyComponentType::Uint8); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT16) == PropertyComponentType::Uint16); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT32) == PropertyComponentType::Uint32); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT64) == PropertyComponentType::Uint64); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType("invalid") == + PropertyComponentType::None); + } + + SECTION("Convert string offset type string to PropertyComponentType") { + REQUIRE( + convertStringOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT8) == PropertyComponentType::Uint8); + + REQUIRE( + convertStringOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT16) == PropertyComponentType::Uint16); + + REQUIRE( + convertStringOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT32) == PropertyComponentType::Uint32); + + REQUIRE( + convertStringOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT64) == PropertyComponentType::Uint64); + + REQUIRE( + convertStringOffsetTypeStringToPropertyComponentType("invalid") == + PropertyComponentType::None); + } +} From 1433243c3d159aceb5033ab3ee6410d5455c1821 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 15 May 2023 18:13:47 -0400 Subject: [PATCH 004/121] Add StructuralMetadataPropertyTypeTraits --- .../CesiumGltf/StructuralMetadataArrayView.h | 145 ++++ .../StructuralMetadataPropertyTypeTraits.h | 658 ++++++++++++++++++ ...stStructuralMetadataPropertyTypeTraits.cpp | 524 ++++++++++++++ 3 files changed, 1327 insertions(+) create mode 100644 CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h create mode 100644 CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h create mode 100644 CesiumGltf/test/TestStructuralMetadataPropertyTypeTraits.cpp diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h new file mode 100644 index 000000000..c76abfcca --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h @@ -0,0 +1,145 @@ +#pragma once + +#include "CesiumGltf/StructuralMetadataPropertyType.h" + +#include + +#include + +#include +#include + +/** + * @brief A view on an array element of a + * ExtensionExtStructuralMetadataPropertyTableProperty. + * + * Provides utility to retrieve the data stored in the array of + * elements via the array index operator. + */ +namespace CesiumGltf { +namespace StructuralMetadata { + +template class MetadataArrayView { +public: + MetadataArrayView() : _values{} {} + + MetadataArrayView(const gsl::span& buffer) noexcept + : _values{ + CesiumUtility::reintepretCastSpan(buffer)} {} + + const ElementType& operator[](int64_t index) const noexcept { + return _values[index]; + } + + int64_t size() const noexcept { + return static_cast(_values.size()); + } + +private: + gsl::span _values; +}; + +template <> class MetadataArrayView { +public: + MetadataArrayView() + : _values{}, _bitOffset{0}, _instanceCount{0} {} + + MetadataArrayView( + const gsl::span& buffer, + int64_t bitOffset, + int64_t instanceCount) noexcept + : _values{buffer}, + _bitOffset{bitOffset}, + _instanceCount{instanceCount} {} + + bool operator[](int64_t index) const noexcept { + index += _bitOffset; + const int64_t byteIndex = index / 8; + const int64_t bitIndex = index % 8; + const int bitValue = + static_cast(_values[byteIndex] >> bitIndex) & 1; + return bitValue == 1; + } + + int64_t size() const noexcept { return _instanceCount; } + +private: + gsl::span _values; + int64_t _bitOffset; + int64_t _instanceCount; +}; + +template <> class MetadataArrayView { +public: + MetadataArrayView() + : _values{}, _stringOffsets{}, _stringOffsetType{}, _size{0} {} + + MetadataArrayView( + const gsl::span& values, + const gsl::span& stringOffsets, + StructuralMetadata::PropertyComponentType stringOffsetType, + int64_t size) noexcept + : _values{values}, + _stringOffsets{stringOffsets}, + _stringOffsetType{stringOffsetType}, + _size{size} {} + + std::string_view operator[](int64_t index) const noexcept { + const size_t currentOffset = getOffsetFromStringOffsetsBuffer( + index, + _stringOffsets, + _stringOffsetType); + const size_t nextOffset = getOffsetFromStringOffsetsBuffer( + index + 1, + _stringOffsets, + _stringOffsetType); + return std::string_view( + reinterpret_cast(_values.data() + currentOffset), + (nextOffset - currentOffset)); + } + + int64_t size() const noexcept { return _size; } + +private: + static size_t getOffsetFromStringOffsetsBuffer( + size_t instance, + const gsl::span& stringOffsetBuffer, + StructuralMetadata::PropertyComponentType offsetType) noexcept { + switch (offsetType) { + case StructuralMetadata::PropertyComponentType::Uint8: { + assert(instance < stringOffsetBuffer.size() / sizeof(uint8_t)); + const uint8_t offset = *reinterpret_cast( + stringOffsetBuffer.data() + instance * sizeof(uint8_t)); + return static_cast(offset); + } + case StructuralMetadata::PropertyComponentType::Uint16: { + assert(instance < stringOffsetBuffer.size() / sizeof(uint16_t)); + const uint16_t offset = *reinterpret_cast( + stringOffsetBuffer.data() + instance * sizeof(uint16_t)); + return static_cast(offset); + } + case StructuralMetadata::PropertyComponentType::Uint32: { + assert(instance < stringOffsetBuffer.size() / sizeof(uint32_t)); + const uint32_t offset = *reinterpret_cast( + stringOffsetBuffer.data() + instance * sizeof(uint32_t)); + return static_cast(offset); + } + case StructuralMetadata::PropertyComponentType::Uint64: { + assert(instance < stringOffsetBuffer.size() / sizeof(uint64_t)); + const uint64_t offset = *reinterpret_cast( + stringOffsetBuffer.data() + instance * sizeof(uint64_t)); + return static_cast(offset); + } + default: + assert(false && "Offset type has unknown type"); + return 0; + } + } + gsl::span _values; + gsl::span _stringOffsets; + StructuralMetadata::PropertyComponentType _stringOffsetType; + int64_t _size; +}; + +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h new file mode 100644 index 000000000..0998c3302 --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h @@ -0,0 +1,658 @@ +#pragma once + +#include "CesiumGltf/StructuralMetadataArrayView.h" +#include "CesiumGltf/StructuralMetadataPropertyType.h" + +#include + +#include +#include + +namespace CesiumGltf { +namespace StructuralMetadata { + +/** + * @brief Check if a C++ type can be represented as a scalar property type + */ +template struct IsMetadataScalar; +template struct IsMetadataScalar : std::false_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; + +/** + * @brief Check if a C++ type can be represented as an integer property type + */ +template struct IsMetadataInteger; +template struct IsMetadataInteger : std::false_type {}; +template <> struct IsMetadataInteger : std::true_type {}; +template <> struct IsMetadataInteger : std::true_type {}; +template <> struct IsMetadataInteger : std::true_type {}; +template <> struct IsMetadataInteger : std::true_type {}; +template <> struct IsMetadataInteger : std::true_type {}; +template <> struct IsMetadataInteger : std::true_type {}; +template <> struct IsMetadataInteger : std::true_type {}; +template <> struct IsMetadataInteger : std::true_type {}; + +/** + * @brief Check if a C++ type can be represented as a floating-point property + * type. + */ +template struct IsMetadataFloating; +template struct IsMetadataFloating : std::false_type {}; +template <> struct IsMetadataFloating : std::true_type {}; +template <> struct IsMetadataFloating : std::true_type {}; + +/** + * @brief Check if a C++ type can be represented as a vecN type. + */ +template struct IsMetadataVecN; +template struct IsMetadataVecN : std::false_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; +template <> struct IsMetadataVecN : std::true_type {}; + +/** + * @brief Check if a C++ type can be represented as a matN type. + */ +template struct IsMetadataMatN; +template struct IsMetadataMatN : std::false_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; +template <> struct IsMetadataMatN : std::true_type {}; + +/** + * @brief Check if a C++ type can be represented as a numeric property, i.e. + * a scalar / vecN / matN type. + */ +template struct IsMetadataNumeric; +template struct IsMetadataNumeric { + static constexpr bool value = IsMetadataScalar::value || + IsMetadataVecN::value || + IsMetadataMatN::value; +}; + +/** + * @brief Check if a C++ type can be represented as a boolean property type + */ +template struct IsMetadataBoolean; +template struct IsMetadataBoolean : std::false_type {}; +template <> struct IsMetadataBoolean : std::true_type {}; + +/** + * @brief Check if a C++ type can be represented as a string property type + */ +template struct IsMetadataString; +template struct IsMetadataString : std::false_type {}; +template <> struct IsMetadataString : std::true_type {}; + +/** + * @brief Check if a C++ type can be represented as an array. + */ +template struct IsMetadataArray; +template struct IsMetadataArray : std::false_type {}; +template +struct IsMetadataArray> : std::true_type {}; + +/** + * @brief Check if a C++ type can be represented as an array of numeric elements + * property type + */ +template struct IsMetadataNumericArray; +template struct IsMetadataNumericArray : std::false_type {}; +template struct IsMetadataNumericArray> { + static constexpr bool value = IsMetadataNumeric::value; +}; + +/** + * @brief Check if a C++ type can be represented as an array of booleans + * property type + */ +template struct IsMetadataBooleanArray; +template struct IsMetadataBooleanArray : std::false_type {}; +template <> +struct IsMetadataBooleanArray> : std::true_type {}; + +/** + * @brief Check if a C++ type can be represented as an array of strings property + * type + */ +template struct IsMetadataStringArray; +template struct IsMetadataStringArray : std::false_type {}; +template <> +struct IsMetadataStringArray> + : std::true_type {}; + +/** + * @brief Retrieve the component type of a metadata array + */ +template struct MetadataArrayType; +template +struct MetadataArrayType> { + using type = T; +}; + +/** + * @brief Convert a C++ type to PropertyType and PropertyComponentType + */ +template struct TypeToPropertyType; + +#pragma region Scalar Property Types + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint8; + static constexpr PropertyType value = PropertyType::Scalar; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int8; + static constexpr PropertyType value = PropertyType::Scalar; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint16; + static constexpr PropertyType value = PropertyType::Scalar; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int16; + static constexpr PropertyType value = PropertyType::Scalar; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint32; + static constexpr PropertyType value = PropertyType::Scalar; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int32; + static constexpr PropertyType value = PropertyType::Scalar; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint64; + static constexpr PropertyType value = PropertyType::Scalar; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int64; + static constexpr PropertyType value = PropertyType::Scalar; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float32; + static constexpr PropertyType value = PropertyType::Scalar; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float64; + static constexpr PropertyType value = PropertyType::Scalar; +}; +#pragma endregion + +#pragma region Vec2 Property Types + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint8; + static constexpr PropertyType value = PropertyType::Vec2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int8; + static constexpr PropertyType value = PropertyType::Vec2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint16; + static constexpr PropertyType value = PropertyType::Vec2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int16; + static constexpr PropertyType value = PropertyType::Vec2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint32; + static constexpr PropertyType value = PropertyType::Vec2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int32; + static constexpr PropertyType value = PropertyType::Vec2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint64; + static constexpr PropertyType value = PropertyType::Vec2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int64; + static constexpr PropertyType value = PropertyType::Vec2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float32; + static constexpr PropertyType value = PropertyType::Vec2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float64; + static constexpr PropertyType value = PropertyType::Vec2; +}; +#pragma endregion + +#pragma region Vec3 Property Types + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint8; + static constexpr PropertyType value = PropertyType::Vec3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int8; + static constexpr PropertyType value = PropertyType::Vec3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint16; + static constexpr PropertyType value = PropertyType::Vec3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int16; + static constexpr PropertyType value = PropertyType::Vec3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint32; + static constexpr PropertyType value = PropertyType::Vec3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int32; + static constexpr PropertyType value = PropertyType::Vec3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint64; + static constexpr PropertyType value = PropertyType::Vec3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int64; + static constexpr PropertyType value = PropertyType::Vec3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float32; + static constexpr PropertyType value = PropertyType::Vec3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float64; + static constexpr PropertyType value = PropertyType::Vec3; +}; +#pragma endregion + +#pragma region Vec4 Property Types + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint8; + static constexpr PropertyType value = PropertyType::Vec4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int8; + static constexpr PropertyType value = PropertyType::Vec4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint16; + static constexpr PropertyType value = PropertyType::Vec4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int16; + static constexpr PropertyType value = PropertyType::Vec4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint32; + static constexpr PropertyType value = PropertyType::Vec4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int32; + static constexpr PropertyType value = PropertyType::Vec4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint64; + static constexpr PropertyType value = PropertyType::Vec4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int64; + static constexpr PropertyType value = PropertyType::Vec4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float32; + static constexpr PropertyType value = PropertyType::Vec4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float64; + static constexpr PropertyType value = PropertyType::Vec4; +}; +#pragma endregion + +#pragma region Mat2 Property Types + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint8; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int8; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint16; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int16; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint32; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int32; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint64; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int64; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float32; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float64; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +#pragma endregion + +#pragma region Mat3 Property Types + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint8; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int8; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint16; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int16; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint32; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int32; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint64; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int64; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float32; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float64; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +#pragma endregion + +#pragma region Mat4 Property Types + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint8; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int8; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint16; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int16; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint32; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int32; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Uint64; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Int64; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float32; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::Float64; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +#pragma endregion + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::None; + static constexpr PropertyType value = PropertyType::Boolean; +}; + +template <> struct TypeToPropertyType { + static constexpr PropertyComponentType component = + PropertyComponentType::None; + static constexpr PropertyType value = PropertyType::String; +}; + +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTypeTraits.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTypeTraits.cpp new file mode 100644 index 000000000..42c0a5313 --- /dev/null +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTypeTraits.cpp @@ -0,0 +1,524 @@ +#include "CesiumGltf/StructuralMetadataPropertyTypeTraits.h" + +#include + +using namespace CesiumGltf::StructuralMetadata; + +TEST_CASE("Test StructuralMetadata PropertyTypeTraits") { + SECTION("IsScalar") { + REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); + + REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); + + REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); + + REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); + + REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); + + REQUIRE(!IsMetadataScalar::value); + REQUIRE(!IsMetadataScalar::value); + REQUIRE(!IsMetadataScalar::value); + REQUIRE(!IsMetadataScalar::value); + } + + SECTION("IsVecN") { + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + + REQUIRE(!IsMetadataVecN::value); + REQUIRE(!IsMetadataVecN::value); + } + + SECTION("IsMatN") { + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + + REQUIRE(!IsMetadataMatN::value); + REQUIRE(!IsMetadataMatN::value); + } + + SECTION("IsBoolean") { + REQUIRE(IsMetadataBoolean::value); + REQUIRE(!IsMetadataBoolean::value); + REQUIRE(!IsMetadataBoolean::value); + } + + SECTION("IsString") { + REQUIRE(IsMetadataString::value); + REQUIRE(!IsMetadataString::value); + } + + SECTION("IsNumeric") { + REQUIRE(IsMetadataNumeric::value); + REQUIRE(IsMetadataNumeric::value); + REQUIRE(IsMetadataNumeric::value); + REQUIRE(IsMetadataNumeric::value); + REQUIRE(IsMetadataNumeric::value); + REQUIRE(IsMetadataNumeric::value); + REQUIRE(!IsMetadataNumeric::value); + REQUIRE(!IsMetadataNumeric::value); + } + + SECTION("IsNumericArray") { + REQUIRE(IsMetadataNumericArray>::value); + REQUIRE(IsMetadataNumericArray>::value); + REQUIRE(IsMetadataNumericArray>::value); + REQUIRE(!IsMetadataNumericArray>::value); + } + + SECTION("IsBooleanArray") { + REQUIRE(IsMetadataBooleanArray>::value); + REQUIRE(!IsMetadataBooleanArray>::value); + } + + SECTION("IsStringArray") { + REQUIRE(IsMetadataStringArray>::value); + REQUIRE(!IsMetadataStringArray>::value); + REQUIRE(!IsMetadataStringArray>::value); + } + + SECTION("ArrayType") { + using type = MetadataArrayType>::type; + REQUIRE(std::is_same_v); + } + + SECTION("TypeToPropertyType scalar") { + REQUIRE(TypeToPropertyType::value == PropertyType::Scalar); + REQUIRE( + TypeToPropertyType::component == PropertyComponentType::Uint8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Scalar); + REQUIRE( + TypeToPropertyType::component == PropertyComponentType::Int8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Scalar); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Scalar); + REQUIRE( + TypeToPropertyType::component == PropertyComponentType::Int16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Scalar); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Scalar); + REQUIRE( + TypeToPropertyType::component == PropertyComponentType::Int32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Scalar); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Scalar); + REQUIRE( + TypeToPropertyType::component == PropertyComponentType::Int64); + } + + SECTION("TypeToPropertyType vecN") { + // Vec2 + REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float64); + + // Vec3 + REQUIRE(TypeToPropertyType::value == PropertyType::Vec3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float64); + + // Vec4 + REQUIRE(TypeToPropertyType::value == PropertyType::Vec4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Vec4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float64); + } + + SECTION("TypeToPropertyType matN") { + // Mat2 + REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float64); + + // Mat3 + REQUIRE(TypeToPropertyType::value == PropertyType::Mat3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat3); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float64); + + // Mat4 + REQUIRE(TypeToPropertyType::value == PropertyType::Mat4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int8); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int16); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Uint64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Int64); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float32); + + REQUIRE(TypeToPropertyType::value == PropertyType::Mat4); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::Float64); + } + + SECTION("TypeToPropertyType boolean") { + REQUIRE(TypeToPropertyType::value == PropertyType::Boolean); + REQUIRE(TypeToPropertyType::component == PropertyComponentType::None); + } + + SECTION("TypeToPropertyType string") { + REQUIRE( + TypeToPropertyType::value == PropertyType::String); + REQUIRE( + TypeToPropertyType::component == + PropertyComponentType::None); + } +} From cf7c8bdd383a61c8544732e3dedf5214b46ec023 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Tue, 16 May 2023 22:18:37 +1000 Subject: [PATCH 005/121] Use partial specialization to reduce code duplication. --- .../StructuralMetadataPropertyTypeTraits.h | 64 ++----------------- 1 file changed, 4 insertions(+), 60 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h index 0998c3302..8f535980a 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h @@ -55,72 +55,16 @@ template <> struct IsMetadataFloating : std::true_type {}; */ template struct IsMetadataVecN; template struct IsMetadataVecN : std::false_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; -template <> struct IsMetadataVecN : std::true_type {}; +template +struct IsMetadataVecN> : IsMetadataScalar {}; /** * @brief Check if a C++ type can be represented as a matN type. */ template struct IsMetadataMatN; template struct IsMetadataMatN : std::false_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; -template <> struct IsMetadataMatN : std::true_type {}; +template +struct IsMetadataMatN> : IsMetadataScalar {}; /** * @brief Check if a C++ type can be represented as a numeric property, i.e. From cd9c32b591cfcd9ef407c6edc039d17f90bba832 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Tue, 16 May 2023 22:25:09 +1000 Subject: [PATCH 006/121] More partial specialization. --- .../StructuralMetadataPropertyTypeTraits.h | 375 +----------------- 1 file changed, 22 insertions(+), 353 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h index 8f535980a..f9606671f 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h @@ -205,387 +205,54 @@ template <> struct TypeToPropertyType { }; #pragma endregion -#pragma region Vec2 Property Types +#pragma region Vector Property Types -template <> struct TypeToPropertyType { +template +struct TypeToPropertyType> { static constexpr PropertyComponentType component = - PropertyComponentType::Uint8; - static constexpr PropertyType value = PropertyType::Vec2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int8; + TypeToPropertyType::component; static constexpr PropertyType value = PropertyType::Vec2; }; -template <> struct TypeToPropertyType { +template +struct TypeToPropertyType> { static constexpr PropertyComponentType component = - PropertyComponentType::Uint16; - static constexpr PropertyType value = PropertyType::Vec2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int16; - static constexpr PropertyType value = PropertyType::Vec2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint32; - static constexpr PropertyType value = PropertyType::Vec2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int32; - static constexpr PropertyType value = PropertyType::Vec2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint64; - static constexpr PropertyType value = PropertyType::Vec2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int64; - static constexpr PropertyType value = PropertyType::Vec2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float32; - static constexpr PropertyType value = PropertyType::Vec2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float64; - static constexpr PropertyType value = PropertyType::Vec2; -}; -#pragma endregion - -#pragma region Vec3 Property Types - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint8; - static constexpr PropertyType value = PropertyType::Vec3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int8; - static constexpr PropertyType value = PropertyType::Vec3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint16; - static constexpr PropertyType value = PropertyType::Vec3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int16; + TypeToPropertyType::component; static constexpr PropertyType value = PropertyType::Vec3; }; -template <> struct TypeToPropertyType { +template +struct TypeToPropertyType> { static constexpr PropertyComponentType component = - PropertyComponentType::Uint32; - static constexpr PropertyType value = PropertyType::Vec3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int32; - static constexpr PropertyType value = PropertyType::Vec3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint64; - static constexpr PropertyType value = PropertyType::Vec3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int64; - static constexpr PropertyType value = PropertyType::Vec3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float32; - static constexpr PropertyType value = PropertyType::Vec3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float64; - static constexpr PropertyType value = PropertyType::Vec3; -}; -#pragma endregion - -#pragma region Vec4 Property Types - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint8; - static constexpr PropertyType value = PropertyType::Vec4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int8; - static constexpr PropertyType value = PropertyType::Vec4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint16; - static constexpr PropertyType value = PropertyType::Vec4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int16; - static constexpr PropertyType value = PropertyType::Vec4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint32; - static constexpr PropertyType value = PropertyType::Vec4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int32; - static constexpr PropertyType value = PropertyType::Vec4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint64; + TypeToPropertyType::component; static constexpr PropertyType value = PropertyType::Vec4; }; -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int64; - static constexpr PropertyType value = PropertyType::Vec4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float32; - static constexpr PropertyType value = PropertyType::Vec4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float64; - static constexpr PropertyType value = PropertyType::Vec4; -}; #pragma endregion -#pragma region Mat2 Property Types +#pragma region Matrix Property Types -template <> struct TypeToPropertyType { +template +struct TypeToPropertyType> { static constexpr PropertyComponentType component = - PropertyComponentType::Uint8; + TypeToPropertyType::component; static constexpr PropertyType value = PropertyType::Mat2; }; -template <> struct TypeToPropertyType { +template +struct TypeToPropertyType> { static constexpr PropertyComponentType component = - PropertyComponentType::Int8; - static constexpr PropertyType value = PropertyType::Mat2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint16; - static constexpr PropertyType value = PropertyType::Mat2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int16; - static constexpr PropertyType value = PropertyType::Mat2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint32; - static constexpr PropertyType value = PropertyType::Mat2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int32; - static constexpr PropertyType value = PropertyType::Mat2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint64; - static constexpr PropertyType value = PropertyType::Mat2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int64; - static constexpr PropertyType value = PropertyType::Mat2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float32; - static constexpr PropertyType value = PropertyType::Mat2; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float64; - static constexpr PropertyType value = PropertyType::Mat2; -}; - -#pragma endregion - -#pragma region Mat3 Property Types - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint8; - static constexpr PropertyType value = PropertyType::Mat3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int8; - static constexpr PropertyType value = PropertyType::Mat3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint16; - static constexpr PropertyType value = PropertyType::Mat3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int16; - static constexpr PropertyType value = PropertyType::Mat3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint32; - static constexpr PropertyType value = PropertyType::Mat3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int32; - static constexpr PropertyType value = PropertyType::Mat3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint64; - static constexpr PropertyType value = PropertyType::Mat3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int64; - static constexpr PropertyType value = PropertyType::Mat3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float32; - static constexpr PropertyType value = PropertyType::Mat3; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float64; + TypeToPropertyType::component; static constexpr PropertyType value = PropertyType::Mat3; }; -#pragma endregion - -#pragma region Mat4 Property Types - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint8; - static constexpr PropertyType value = PropertyType::Mat4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int8; - static constexpr PropertyType value = PropertyType::Mat4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint16; - static constexpr PropertyType value = PropertyType::Mat4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int16; - static constexpr PropertyType value = PropertyType::Mat4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint32; - static constexpr PropertyType value = PropertyType::Mat4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int32; - static constexpr PropertyType value = PropertyType::Mat4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint64; - static constexpr PropertyType value = PropertyType::Mat4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int64; - static constexpr PropertyType value = PropertyType::Mat4; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float32; - static constexpr PropertyType value = PropertyType::Mat4; -}; - -template <> struct TypeToPropertyType { +template +struct TypeToPropertyType> { static constexpr PropertyComponentType component = - PropertyComponentType::Float64; + TypeToPropertyType::component; static constexpr PropertyType value = PropertyType::Mat4; }; -#pragma endregion - template <> struct TypeToPropertyType { static constexpr PropertyComponentType component = PropertyComponentType::None; @@ -598,5 +265,7 @@ template <> struct TypeToPropertyType { static constexpr PropertyType value = PropertyType::String; }; +#pragma endregion + } // namespace StructuralMetadata } // namespace CesiumGltf From 90377e8f6ca04ca97574e7850d5529117d24a157 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 16 May 2023 11:23:10 -0400 Subject: [PATCH 007/121] Fix formatting and move pragma --- .../CesiumGltf/StructuralMetadataArrayView.h | 17 +++++------------ .../StructuralMetadataPropertyTypeTraits.h | 4 ++-- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h index c76abfcca..65eaf0117 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h @@ -24,16 +24,13 @@ template class MetadataArrayView { MetadataArrayView() : _values{} {} MetadataArrayView(const gsl::span& buffer) noexcept - : _values{ - CesiumUtility::reintepretCastSpan(buffer)} {} + : _values{CesiumUtility::reintepretCastSpan(buffer)} {} const ElementType& operator[](int64_t index) const noexcept { return _values[index]; } - int64_t size() const noexcept { - return static_cast(_values.size()); - } + int64_t size() const noexcept { return static_cast(_values.size()); } private: gsl::span _values; @@ -41,23 +38,19 @@ template class MetadataArrayView { template <> class MetadataArrayView { public: - MetadataArrayView() - : _values{}, _bitOffset{0}, _instanceCount{0} {} + MetadataArrayView() : _values{}, _bitOffset{0}, _instanceCount{0} {} MetadataArrayView( const gsl::span& buffer, int64_t bitOffset, int64_t instanceCount) noexcept - : _values{buffer}, - _bitOffset{bitOffset}, - _instanceCount{instanceCount} {} + : _values{buffer}, _bitOffset{bitOffset}, _instanceCount{instanceCount} {} bool operator[](int64_t index) const noexcept { index += _bitOffset; const int64_t byteIndex = index / 8; const int64_t bitIndex = index % 8; - const int bitValue = - static_cast(_values[byteIndex] >> bitIndex) & 1; + const int bitValue = static_cast(_values[byteIndex] >> bitIndex) & 1; return bitValue == 1; } diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h index f9606671f..972c6055e 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h @@ -253,6 +253,8 @@ struct TypeToPropertyType> { static constexpr PropertyType value = PropertyType::Mat4; }; +#pragma endregion + template <> struct TypeToPropertyType { static constexpr PropertyComponentType component = PropertyComponentType::None; @@ -265,7 +267,5 @@ template <> struct TypeToPropertyType { static constexpr PropertyType value = PropertyType::String; }; -#pragma endregion - } // namespace StructuralMetadata } // namespace CesiumGltf From da5355387c3696ae7c965c92132c16b830fd8f4b Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 16 May 2023 15:52:39 -0400 Subject: [PATCH 008/121] Fix formatting and minor changes --- .../CesiumGltf/StructuralMetadataArrayView.h | 74 ++++--------------- .../StructuralMetadataPropertyType.h | 12 +-- 2 files changed, 22 insertions(+), 64 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h index c76abfcca..a886b62c3 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h @@ -1,6 +1,7 @@ #pragma once #include "CesiumGltf/StructuralMetadataPropertyType.h" +#include "getOffsetFromOffsetsBuffer.h" #include @@ -9,6 +10,9 @@ #include #include +namespace CesiumGltf { +namespace StructuralMetadata { + /** * @brief A view on an array element of a * ExtensionExtStructuralMetadataPropertyTableProperty. @@ -16,57 +20,47 @@ * Provides utility to retrieve the data stored in the array of * elements via the array index operator. */ -namespace CesiumGltf { -namespace StructuralMetadata { - template class MetadataArrayView { public: MetadataArrayView() : _values{} {} MetadataArrayView(const gsl::span& buffer) noexcept - : _values{ - CesiumUtility::reintepretCastSpan(buffer)} {} + : _values{CesiumUtility::reintepretCastSpan(buffer)} {} const ElementType& operator[](int64_t index) const noexcept { return _values[index]; } - int64_t size() const noexcept { - return static_cast(_values.size()); - } + int64_t size() const noexcept { return static_cast(_values.size()); } private: - gsl::span _values; + const gsl::span _values; }; template <> class MetadataArrayView { public: - MetadataArrayView() - : _values{}, _bitOffset{0}, _instanceCount{0} {} + MetadataArrayView() : _values{}, _bitOffset{0}, _size{0} {} MetadataArrayView( const gsl::span& buffer, int64_t bitOffset, - int64_t instanceCount) noexcept - : _values{buffer}, - _bitOffset{bitOffset}, - _instanceCount{instanceCount} {} + int64_t size) noexcept + : _values{buffer}, _bitOffset{bitOffset}, _size{size} {} bool operator[](int64_t index) const noexcept { index += _bitOffset; const int64_t byteIndex = index / 8; const int64_t bitIndex = index % 8; - const int bitValue = - static_cast(_values[byteIndex] >> bitIndex) & 1; + const int bitValue = static_cast(_values[byteIndex] >> bitIndex) & 1; return bitValue == 1; } - int64_t size() const noexcept { return _instanceCount; } + int64_t size() const noexcept { return _size; } private: gsl::span _values; int64_t _bitOffset; - int64_t _instanceCount; + int64_t _size; }; template <> class MetadataArrayView { @@ -85,11 +79,9 @@ template <> class MetadataArrayView { _size{size} {} std::string_view operator[](int64_t index) const noexcept { - const size_t currentOffset = getOffsetFromStringOffsetsBuffer( - index, - _stringOffsets, - _stringOffsetType); - const size_t nextOffset = getOffsetFromStringOffsetsBuffer( + const size_t currentOffset = + getOffsetFromOffsetsBuffer(index, _stringOffsets, _stringOffsetType); + const size_t nextOffset = getOffsetFromOffsetsBuffer( index + 1, _stringOffsets, _stringOffsetType); @@ -101,40 +93,6 @@ template <> class MetadataArrayView { int64_t size() const noexcept { return _size; } private: - static size_t getOffsetFromStringOffsetsBuffer( - size_t instance, - const gsl::span& stringOffsetBuffer, - StructuralMetadata::PropertyComponentType offsetType) noexcept { - switch (offsetType) { - case StructuralMetadata::PropertyComponentType::Uint8: { - assert(instance < stringOffsetBuffer.size() / sizeof(uint8_t)); - const uint8_t offset = *reinterpret_cast( - stringOffsetBuffer.data() + instance * sizeof(uint8_t)); - return static_cast(offset); - } - case StructuralMetadata::PropertyComponentType::Uint16: { - assert(instance < stringOffsetBuffer.size() / sizeof(uint16_t)); - const uint16_t offset = *reinterpret_cast( - stringOffsetBuffer.data() + instance * sizeof(uint16_t)); - return static_cast(offset); - } - case StructuralMetadata::PropertyComponentType::Uint32: { - assert(instance < stringOffsetBuffer.size() / sizeof(uint32_t)); - const uint32_t offset = *reinterpret_cast( - stringOffsetBuffer.data() + instance * sizeof(uint32_t)); - return static_cast(offset); - } - case StructuralMetadata::PropertyComponentType::Uint64: { - assert(instance < stringOffsetBuffer.size() / sizeof(uint64_t)); - const uint64_t offset = *reinterpret_cast( - stringOffsetBuffer.data() + instance * sizeof(uint64_t)); - return static_cast(offset); - } - default: - assert(false && "Offset type has unknown type"); - return 0; - } - } gsl::span _values; gsl::span _stringOffsets; StructuralMetadata::PropertyComponentType _stringOffsetType; diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h index 67d92d232..b33d8ddee 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h @@ -36,21 +36,21 @@ enum class PropertyComponentType { }; std::string -convertPropertyTypeToString(CesiumGltf::StructuralMetadata::PropertyType type); +convertPropertyTypeToString(PropertyType type); -CesiumGltf::StructuralMetadata::PropertyType +PropertyType convertStringToPropertyType(const std::string& str); std::string convertPropertyComponentTypeToString( - CesiumGltf::StructuralMetadata::PropertyComponentType componentType); + PropertyComponentType componentType); -CesiumGltf::StructuralMetadata::PropertyComponentType +PropertyComponentType convertStringToPropertyComponentType(const std::string& str); -CesiumGltf::StructuralMetadata::PropertyComponentType +PropertyComponentType convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str); -CesiumGltf::StructuralMetadata::PropertyComponentType +PropertyComponentType convertStringOffsetTypeStringToPropertyComponentType(const std::string& str); } // namespace StructuralMetadata From 671033c1e11e1e1090b916a57cd533eb26d5ad13 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 16 May 2023 15:53:40 -0400 Subject: [PATCH 009/121] Add StructuralMetadataPropertyView --- .../StructuralMetadataPropertyView.h | 412 ++++++++++++++++++ .../CesiumGltf/getOffsetFromOffsetsBuffer.h | 52 +++ 2 files changed, 464 insertions(+) create mode 100644 CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h create mode 100644 CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h new file mode 100644 index 000000000..3039d9652 --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h @@ -0,0 +1,412 @@ +#pragma once + +#include "CesiumGltf/StructuralMetadataArrayView.h" +#include "CesiumGltf/StructuralMetadataPropertyTypeTraits.h" + +#include + +#include +#include +#include +#include +#include + +namespace CesiumGltf { +namespace StructuralMetadata { + +/** + * @brief Indicates the status of a property view. + * + * The {@link MetadataPropertyView} constructor always completes successfully. However, + * it may not always reflect the actual content of the {@link ExtensionExtStructuralMetadataPropertyTableProperty}, but + * instead indicate that its {@link MetadataPropertyView::size} is 0. This enumeration + * provides the reason. + */ + +enum class MetadataPropertyViewStatus { + /** + * @brief This property view is valid and ready to use. + */ + Valid, + + /** + * @brief This property view does not exist in the + * ExtensionExtStructuralMetadataPropertyTable. + */ + InvalidPropertyDoesNotExist, + + /** + * @brief This property view does not have a correct type with what is + * specified in {@link ExtensionExtStructuralMetadataClassProperty::type}. + */ + InvalidTypeMismatch, + + /** + * @brief This property view does not have a correct component type with what + * is specified in {@link ExtensionExtStructuralMetadataClassProperty::componentType}. + */ + InvalidComponentTypeMismatch, + + /** + * @brief This property view does not have a valid value buffer view index. + */ + InvalidValueBufferView, + + /** + * @brief This array property view does not have a valid array offset buffer + * view index. + */ + InvalidArrayOffsetBufferViewIndex, + + /** + * @brief This string property view does not have a valid string offset buffer + * view index. + */ + InvalidStringOffsetBufferViewIndex, + + /** + * @brief This property view has a valid value buffer view, but the buffer + * view specifies an invalid buffer index. + */ + InvalidValueBufferIndex, + + /** + * @brief This property view has a valid array string buffer view, but the + * buffer view specifies an invalid buffer index. + */ + InvalidArrayOffsetBufferIndex, + + /** + * @brief This property view has a valid string offset buffer view, but the + * buffer view specifies an invalid buffer index. + */ + InvalidStringOffsetBufferIndex, + + /** + * @brief This property view has an out-of-bounds buffer view + */ + InvalidBufferViewOutOfBounds, + + /** + * @brief This property view has an invalid buffer view's length which is not + * a multiple of the size of its type or offset type + */ + InvalidBufferViewSizeNotDivisibleByTypeSize, + + /** + * @brief This property view has an invalid buffer view's length which cannot + * fit all the instances of the feature table + */ + InvalidBufferViewSizeNotFitInstanceCount, + + /** + * @brief This array property view has both count and offset buffer + * view defined. + */ + InvalidArrayCountAndOffsetBufferCoexist, + + /** + * @brief This array property view doesn't have count nor offset buffer view + * defined. + */ + InvalidArrayCountAndOffsetBufferDontExist, + + /** + * @brief This property view has an unknown array offset type. + */ + InvalidArrayOffsetType, + + /** + * @brief This property view has an unknown string offset type. + */ + InvalidStringOffsetType, + + /** + * @brief This property view's array offset values are not sorted in ascending + * order. + */ + InvalidArrayOffsetValuesNotSorted, + + /** + * @brief This property view's string offset values are not sorted in + * ascending order. + */ + InvalidStringOffsetValuesNotSorted, + + /** + * @brief This property view has an array offset that is out of bounds. + */ + InvalidArrayOffsetValueOutOfBounds, + + /** + * @brief This property view has a string offset that is out of bounds. + */ + InvalidStringOffsetValueOutOfBounds +}; + +/** + * @brief A view on the data of the + * ExtensionExtStructuralMetadataPropertyTableProperty + * + * It provides utility to retrieve the actual data stored in the + * {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} like an array of elements. + * Data of each instance can be accessed through the {@link get(int64_t instance)} method + * + * @param ElementType must be a scalar (uin8_t, int8_t, uint16_t, int16_t, + * uint32_t, int32_t, uint64_t, int64_t, float, double), vecN, matN, bool, + * std::string_view, or MetadataArrayView with T as one of the aforementioned + * types. + */ +template class MetadataPropertyView { +public: + /** + * @brief Constructs a new instance viewing a non-existent property. + */ + MetadataPropertyView() + : _status{MetadataPropertyViewStatus::InvalidPropertyDoesNotExist}, + _values{}, + _componentCount{}, + _instanceCount{}, + _normalized{} {} + + /** + * @brief Construct a new instance pointing to the data specified by + * ExtensionExtStructuralMetadataPropertyTableProperty + * @param values The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} + * @param arrayOffsets The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::arrayOffsets} + * @param stringOffsets The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::stringOffsets} + * @param offsetType The offset type of arrayOffsets specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::arrayOffsetType} + * @param offsetType The offset type of stringOffsets specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::stringOffsetType} + * @param fixedArrayCount The number of elements in each array value specified by {@link ExtensionExtStructuralMetadataClassProperty::count} + * @param size The number of elements in the property table specified by {@link ExtensionExtStructuralMetadataPropertyTable::count} + * @param normalized Whether this property has a normalized integer type. + */ + MetadataPropertyView( + MetadataPropertyViewStatus status, + gsl::span values, + gsl::span arrayOffsets, + gsl::span stringOffsets, + StructuralMetadata::PropertyComponentType arrayOffsetType, + StructuralMetadata::PropertyComponentType stringOffsetType, + int64_t fixedLengthArrayCount, + int64_t size, + bool normalized) noexcept + : _status{status}, + _values{values}, + _arrayOffsets{arrayOffsets}, + _arrayOffsetType{arrayOffsetType}, + _arrayOffsetTypeSize{getOffsetTypeSize(arrayOffsetType)}, + _stringOffsets{stringOffsets}, + _stringOffsetType{stringOffsetType}, + _stringOffsetTypeSize{getOffsetTypeSize(stringOffsetType)}, + _fixedLengthArrayCount{fixedLengthArrayCount}, + _size{size}, + _normalized{normalized} {} + + /** + * @brief Gets the status of this property view. + * + * Indicates whether the view accurately reflects the property's data, or + * whether an error occurred. + */ + MetadataPropertyViewStatus status() const noexcept { return _status; } + + /** + * @brief Get the value of an element of the FeatureTable. + * @param index The element index + * @return The value of the element + */ + ElementType get(int64_t index) const noexcept { + assert( + _status == MetadataPropertyViewStatus::Valid && + "Check the status() first to make sure view is valid"); + assert( + size() > 0 && + "Check the size() of the view to make sure it's not empty"); + assert(index >= 0 && "index must be positive"); + + if constexpr (IsMetadataNumeric::value) { + return getNumericValue(index); + } + + if constexpr (IsMetadataBoolean::value) { + return getBooleanValue(index); + } + + if constexpr (IsMetadataString::value) { + return getStringValue(index); + } + + if constexpr (IsMetadataNumericArray::value) { + return getNumericArrayValues< + typename MetadataArrayType::type>(index); + } + + if constexpr (IsMetadataBooleanArray::value) { + return getBooleanArrayValues(index); + } + + if constexpr (IsMetadataStringArray::value) { + return getStringArrayValues(index); + } + } + + /** + * @brief Get the number of elements in the + * ExtensionExtStructuralMetadataPropertyTable. + * + * @return The number of elements in the + * ExtensionExtStructuralMetadataPropertyTable. + */ + int64_t size() const noexcept { return _size; } + + /** + * @brief Get the element count of the fixed-length arrays in this property. + * Only applicable when the property is an array type. + * + * @return The count of this property. + */ + int64_t getFixedLengthArrayCount() const noexcept { return _fixedArrayCount; } + + /** + * @brief Whether this property has a normalized integer type. + * + * @return Whether this property has a normalized integer type. + */ + bool isNormalized() const noexcept { return _normalized; } + +private: + ElementType getNumericValue(int64_t index) const noexcept { + return reinterpret_cast(_values.data())[index]; + } + + bool getBooleanValue(int64_t index) const noexcept { + const int64_t byteIndex = index / 8; + const int64_t bitIndex = index % 8; + const int bitValue = static_cast(_values[byteIndex] >> bitIndex) & 1; + return bitValue == 1; + } + + std::string_view getStringValue(int64_t index) const noexcept { + const size_t currentOffset = + getOffsetFromOffsetsBuffer(index, _stringOffsets, _stringOffsetType); + const size_t nextOffset = getOffsetFromOffsetsBuffer( + index + 1, + _stringOffsets, + _stringOffsetType); + return std::string_view( + reinterpret_cast(_values.data() + currentOffset), + nextOffset - currentOffset); + } + + template + MetadataArrayView getNumericArrayValues(int64_t index) const noexcept { + // Handle fixed-length arrays + if (_fixedLengthArrayCount > 0) { + size_t arraySize = _fixedLengthArrayCount * sizeof(T); + const gsl::span values( + _values.data() + index * arraySize, + arraySize); + return MetadataArrayView{values}; + } + + // Handle variable-length arrays + const size_t currentOffset = + getOffsetFromOffsetsBuffer(index, _arrayOffsets, _arrayOffsetType); + const size_t nextOffset = + getOffsetFromOffsetsBuffer(index + 1, _arrayOffsets, _arrayOffsetType); + const gsl::span values( + _values.data() + currentOffset, + nextOffset - currentOffset); + return MetadataArrayView{values}; + } + + MetadataArrayView + getStringArrayValues(int64_t index) const noexcept { + // Handle fixed-length arrays + if (_fixedLengthArrayCount > 0) { + size_t arraySize = _fixedLengthArrayCount * _stringOffsetTypeSize; + const gsl::span stringOffsetValues( + _stringOffsets.data() + index * arraySize, + arraySize); + return MetadataArrayView( + _values, + stringOffsetValues, + _stringOffsetType, + _count); + } + + const size_t currentArrayOffset = + getOffsetFromOffsetsBuffer(index, _arrayOffsets, _arrayOffsetType); + const size_t nextArrayOffset = + getOffsetFromOffsetsBuffer(index + 1, _arrayOffsets, _arrayOffsetType); + const size_t length = currentArrayOffset - nextArrayOffset; + const gsl::span stringOffsetValues( + _stringOffsets.data() + currentOffset, + length * _arrayOffsetTypeSize); + return MetadataArrayView( + _values, + stringOffsetValues, + _stringOffsetType, + length / _stringOffsetTypeSize); + } + + MetadataArrayView getBooleanArrayValues(int64_t index) const noexcept { + // Handle fixed-length arrays + if (_fixedLengthArrayCount > 0) { + const size_t offsetBits = _fixedLengthArrayCount * index; + const size_t nextOffsetBits = _fixedLengthArrayCount * (index + 1); + const gsl::span buffer( + _values.data() + offsetBits / 8, + (nextOffsetBits / 8 - offsetBits / 8 + 1)); + return MetadataArrayView( + buffer, + offsetBits % 8, + _fixedLengthArrayCount); + } + + // Handle variable-length arrays + const size_t currentOffset = + getOffsetFromOffsetsBuffer(index, _arrayOffsets, _arrayOffsetType); + const size_t nextOffset = + getOffsetFromOffsetsBuffer(index + 1, _arrayOffsets, _arrayOffsetType); + const size_t totalBits = nextOffset - currentOffset; + const gsl::span buffer( + _values.data() + currentOffset / 8, + (nextOffset / 8 - currentOffset / 8 + 1)); + return MetadataArrayView(buffer, currentOffset % 8, totalBits); + } + + static int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { + switch (offsetType) { + case PropertyComponentType::Uint8: + return sizeof(uint8_t); + case PropertyComponentType::Uint16: + return sizeof(uint16_t); + case PropertyComponentType::Uint32: + return sizeof(uint32_t); + case PropertyComponentType::Uint64: + return sizeof(uint64_t); + default: + return 0; + } + } + + MetadataPropertyViewStatus _status; + gsl::span _values; + + gsl::span _arrayOffsets; + PropertyComponentType _arrayOffsetType; + int64_t _arrayOffsetTypeSize; + + gsl::span _stringOffsets; + PropertyComponentType _stringOffsetType; + int64_t _stringOffsetTypeSize; + + int64_t _fixedLengthArrayCount; + int64_t _size; + bool _normalized; +}; + +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h b/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h new file mode 100644 index 000000000..5374f2423 --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h @@ -0,0 +1,52 @@ +#pragma once + +#include "CesiumGltf/StructuralMetadataPropertyType.h" + +#include + +#include + +#include +#include + +namespace CesiumGltf { +namespace StructuralMetadata { + +static size_t getOffsetFromOffsetsBuffer( + size_t index, + const gsl::span& offsetBuffer, + PropertyComponentType offsetType) noexcept { + switch (offsetType) { + case PropertyComponentType::Uint8: { + assert(index < offsetBuffer.size() / sizeof(uint8_t)); + const uint8_t offset = *reinterpret_cast( + offsetBuffer.data() + index * sizeof(uint8_t)); + return static_cast(offset); + } + case PropertyComponentType::Uint16: { + assert(index < offsetBuffer.size() / sizeof(uint16_t)); + const uint16_t offset = *reinterpret_cast( + offsetBuffer.data() + index * sizeof(uint16_t)); + return static_cast(offset); + } + case PropertyComponentType::Uint32: { + assert(index < offsetBuffer.size() / sizeof(uint32_t)); + const uint32_t offset = *reinterpret_cast( + offsetBuffer.data() + index * sizeof(uint32_t)); + return static_cast(offset); + } + case PropertyComponentType::Uint64: { + assert(index < offsetBuffer.size() / sizeof(uint64_t)); + const uint64_t offset = *reinterpret_cast( + offsetBuffer.data() + index * sizeof(uint64_t)); + return static_cast(offset); + } + default: + assert(false && "Offset type is invalid"); + return 0; + } + + } + +} // namespace StructuralMetadata +} // namespace CesiumGltf From 72fe4a960efec7dcb9eba95b56dba4346075554c Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 17 May 2023 07:37:26 +1000 Subject: [PATCH 010/121] Fix test failures on GCC9. --- .../include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h index 972c6055e..535667d9a 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h @@ -55,7 +55,7 @@ template <> struct IsMetadataFloating : std::true_type {}; */ template struct IsMetadataVecN; template struct IsMetadataVecN : std::false_type {}; -template +template struct IsMetadataVecN> : IsMetadataScalar {}; /** @@ -63,7 +63,7 @@ struct IsMetadataVecN> : IsMetadataScalar {}; */ template struct IsMetadataMatN; template struct IsMetadataMatN : std::false_type {}; -template +template struct IsMetadataMatN> : IsMetadataScalar {}; /** From dccb99e66608f2016d11701ae5c9535845684910 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 17 May 2023 07:38:44 +1000 Subject: [PATCH 011/121] Formatting. --- CesiumGltf/test/TestStructuralMetadataPropertyType.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyType.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyType.cpp index 759a485ec..fbd27e44a 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyType.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyType.cpp @@ -225,7 +225,7 @@ TEST_CASE("Test StructuralMetadata PropertyType utilities function") { PropertyComponentType::None); } - SECTION("Convert string offset type string to PropertyComponentType") { + SECTION("Convert string offset type string to PropertyComponentType") { REQUIRE( convertStringOffsetTypeStringToPropertyComponentType( ExtensionExtStructuralMetadataPropertyTableProperty:: From 25a3320be0ec9c582486a0f09ddecb7aafdc97c0 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 16 May 2023 18:15:05 -0400 Subject: [PATCH 012/121] Add missing file --- .../CesiumGltf/getOffsetFromOffsetsBuffer.h | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h diff --git a/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h b/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h new file mode 100644 index 000000000..5374f2423 --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h @@ -0,0 +1,52 @@ +#pragma once + +#include "CesiumGltf/StructuralMetadataPropertyType.h" + +#include + +#include + +#include +#include + +namespace CesiumGltf { +namespace StructuralMetadata { + +static size_t getOffsetFromOffsetsBuffer( + size_t index, + const gsl::span& offsetBuffer, + PropertyComponentType offsetType) noexcept { + switch (offsetType) { + case PropertyComponentType::Uint8: { + assert(index < offsetBuffer.size() / sizeof(uint8_t)); + const uint8_t offset = *reinterpret_cast( + offsetBuffer.data() + index * sizeof(uint8_t)); + return static_cast(offset); + } + case PropertyComponentType::Uint16: { + assert(index < offsetBuffer.size() / sizeof(uint16_t)); + const uint16_t offset = *reinterpret_cast( + offsetBuffer.data() + index * sizeof(uint16_t)); + return static_cast(offset); + } + case PropertyComponentType::Uint32: { + assert(index < offsetBuffer.size() / sizeof(uint32_t)); + const uint32_t offset = *reinterpret_cast( + offsetBuffer.data() + index * sizeof(uint32_t)); + return static_cast(offset); + } + case PropertyComponentType::Uint64: { + assert(index < offsetBuffer.size() / sizeof(uint64_t)); + const uint64_t offset = *reinterpret_cast( + offsetBuffer.data() + index * sizeof(uint64_t)); + return static_cast(offset); + } + default: + assert(false && "Offset type is invalid"); + return 0; + } + + } + +} // namespace StructuralMetadata +} // namespace CesiumGltf From c0c8e3a6195068332fb94424f6ff570461791f70 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Wed, 17 May 2023 08:44:39 +1000 Subject: [PATCH 013/121] Formatting. --- CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h b/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h index 5374f2423..431430bf4 100644 --- a/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h +++ b/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h @@ -45,8 +45,7 @@ static size_t getOffsetFromOffsetsBuffer( assert(false && "Offset type is invalid"); return 0; } - - } +} } // namespace StructuralMetadata } // namespace CesiumGltf From e1305361b498e45ebaafd3b758c3822571c66311 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 17 May 2023 14:01:40 -0400 Subject: [PATCH 014/121] Add tests for new property view --- .../StructuralMetadataPropertyView.h | 29 +- .../TestStructuralMetadataPropertyView.cpp | 1052 +++++++++++++++++ 2 files changed, 1068 insertions(+), 13 deletions(-) create mode 100644 CesiumGltf/test/TestStructuralMetadataPropertyView.cpp diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h index 3039d9652..5f356fdb6 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h @@ -152,15 +152,16 @@ enum class MetadataPropertyViewStatus { * {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} like an array of elements. * Data of each instance can be accessed through the {@link get(int64_t instance)} method * - * @param ElementType must be a scalar (uin8_t, int8_t, uint16_t, int16_t, - * uint32_t, int32_t, uint64_t, int64_t, float, double), vecN, matN, bool, - * std::string_view, or MetadataArrayView with T as one of the aforementioned - * types. + * @param ElementType must be one of the following: a scalar (uin8_t, int8_t, + * uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double), vecN + * composed of one of the scalar types, matN composed of one of the scalar + * types, bool, std::string_view, or MetadataArrayView with T as one of the + * aforementioned types. */ template class MetadataPropertyView { public: /** - * @brief Constructs a new instance viewing a non-existent property. + * @brief Constructs a new instance with a non-existent property. */ MetadataPropertyView() : _status{MetadataPropertyViewStatus::InvalidPropertyDoesNotExist}, @@ -171,7 +172,7 @@ template class MetadataPropertyView { /** * @brief Construct a new instance pointing to the data specified by - * ExtensionExtStructuralMetadataPropertyTableProperty + * ExtensionExtStructuralMetadataPropertyTableProperty. * @param values The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} * @param arrayOffsets The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::arrayOffsets} * @param stringOffsets The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::stringOffsets} @@ -325,30 +326,32 @@ template class MetadataPropertyView { getStringArrayValues(int64_t index) const noexcept { // Handle fixed-length arrays if (_fixedLengthArrayCount > 0) { - size_t arraySize = _fixedLengthArrayCount * _stringOffsetTypeSize; + // Copy the corresponding string offsets to pass to the MetadataArrayView. + const size_t arraySize = _fixedLengthArrayCount * _stringOffsetTypeSize; const gsl::span stringOffsetValues( _stringOffsets.data() + index * arraySize, - arraySize); + arraySize + _stringOffsetTypeSize); return MetadataArrayView( _values, stringOffsetValues, _stringOffsetType, - _count); + _fixedLengthArrayCount); } + // Handle variable-length arrays const size_t currentArrayOffset = getOffsetFromOffsetsBuffer(index, _arrayOffsets, _arrayOffsetType); const size_t nextArrayOffset = getOffsetFromOffsetsBuffer(index + 1, _arrayOffsets, _arrayOffsetType); - const size_t length = currentArrayOffset - nextArrayOffset; + const size_t arraySize = nextArrayOffset - currentArrayOffset; const gsl::span stringOffsetValues( - _stringOffsets.data() + currentOffset, - length * _arrayOffsetTypeSize); + _stringOffsets.data() + currentArrayOffset, + arraySize + _arrayOffsetTypeSize); return MetadataArrayView( _values, stringOffsetValues, _stringOffsetType, - length / _stringOffsetTypeSize); + arraySize / _arrayOffsetTypeSize); } MetadataArrayView getBooleanArrayValues(int64_t index) const noexcept { diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyView.cpp new file mode 100644 index 000000000..bd5ab17ec --- /dev/null +++ b/CesiumGltf/test/TestStructuralMetadataPropertyView.cpp @@ -0,0 +1,1052 @@ +#include "CesiumGltf/StructuralMetadataPropertyView.h" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace CesiumGltf::StructuralMetadata; + +template static void checkNumeric(const std::vector& expected) { + std::vector data; + data.resize(expected.size() * sizeof(T)); + std::memcpy(data.data(), expected.data(), data.size()); + + MetadataPropertyView property( + MetadataPropertyViewStatus::Valid, + gsl::span(data.data(), data.size()), + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None, + 0, + static_cast(expected.size()), + false); + + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.get(i) == expected[static_cast(i)]); + } +} + +template +static void checkVariableLengthArray( + const std::vector& data, + const std::vector offsets, + PropertyComponentType offsetType, + int64_t instanceCount) { + // copy data to buffer + std::vector buffer; + buffer.resize(data.size() * sizeof(DataType)); + std::memcpy(buffer.data(), data.data(), data.size() * sizeof(DataType)); + + // copy offset to buffer + std::vector offsetBuffer; + offsetBuffer.resize(offsets.size() * sizeof(OffsetType)); + std::memcpy( + offsetBuffer.data(), + offsets.data(), + offsets.size() * sizeof(OffsetType)); + + MetadataPropertyView> property( + MetadataPropertyViewStatus::Valid, + gsl::span(buffer.data(), buffer.size()), + gsl::span(offsetBuffer.data(), offsetBuffer.size()), + gsl::span(), + offsetType, + PropertyComponentType::None, + 0, + instanceCount, + false); + + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + MetadataArrayView values = property.get(i); + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == data[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == data.size()); +} + +template +static void checkFixedLengthArray( + const std::vector& data, + int64_t fixedLengthArrayCount, + int64_t instanceCount) { + std::vector buffer; + buffer.resize(data.size() * sizeof(T)); + std::memcpy(buffer.data(), data.data(), data.size() * sizeof(T)); + + MetadataPropertyView> property( + MetadataPropertyViewStatus::Valid, + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None, + fixedLengthArrayCount, + instanceCount, + false); + + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + MetadataArrayView values = property.get(i); + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == data[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == data.size()); +} + +TEST_CASE("Check StructuralMetadata scalar numeric property view") { + SECTION("Uint8 Scalar") { + std::vector data{12, 33, 56, 67}; + checkNumeric(data); + } + + SECTION("Int32 Scalar") { + std::vector data{111222, -11133, -56000, 670000}; + checkNumeric(data); + } + + SECTION("Float Scalar") { + std::vector data{12.3333f, -12.44555f, -5.6111f, 6.7421f}; + checkNumeric(data); + } + + SECTION("Double Scalar") { + std::vector data{ + 12222.3302121, + -12000.44555, + -5000.6113111, + 6.7421}; + checkNumeric(data); + } +} + +TEST_CASE("Check StructuralMetadata vecN numeric property view") { + SECTION("Float Vec2") { + std::vector data{ + glm::vec2(10.001f, 0.005f), + glm::vec2(-20.8f, 50.0f), + glm::vec2(99.9f, -9.9f), + glm::vec2(-64.456f, 12.01f)}; + checkNumeric(data); + } + + SECTION("Int32 Vec3") { + std::vector data{ + glm::ivec3(10, 0, -3), + glm::ivec3(-20, 10, 52), + glm::ivec3(9, 9, -9), + glm::ivec3(8, -40, 2)}; + checkNumeric(data); + } + + SECTION("Uint8 Vec4") { + std::vector data{ + glm::u8vec4(1, 2, 3, 0), + glm::u8vec4(4, 5, 6, 1), + glm::u8vec4(7, 8, 9, 0), + glm::u8vec4(0, 0, 0, 1)}; + checkNumeric(data); + } +} + +TEST_CASE("Check StructuralMetadata matN numeric property view") { + SECTION("Float Mat2") { + // clang-format off + std::vector data{ + glm::mat2( + 1.0f, 2.0f, + 3.0f, 4.0f), + glm::mat2( + -10.0f, 40.0f, + 0.08f, 5.4f), + glm::mat2( + 9.99f, -2.0f, + -0.4f, 0.23f) + }; + // clang-format on + checkNumeric(data); + } + + SECTION("Int16 Mat3") { + // clang-format off + std::vector data{ + glm::i16mat3x3( + 1, 2, 3, + 4, 5, 6, + 7, 8, 9), + glm::i16mat3x3( + 10, 0, 5, + -14, 35, 16, + -2, 3, 4), + glm::i16mat3x3( + -6, 5, 2, + 14, 4, -33, + 2, 1, 0) + }; + // clang-format on + checkNumeric(data); + } + + SECTION("Double Mat4") { + // clang-format off + std::vector data{ + glm::dmat4( + 1.0, 2.0, 3.0, 4.0, + 5.0, 6.0, 7.0, 8.0, + 9.0, 10.0, 11.0, 12.0, + 13.0, 14.0, 15.0, 16.0), + glm::dmat4( + 0.1, 0.2, 0.3, 0.4, + 0.5, 0.6, 0.7, 0.8, + -9.0, -10.0, -11.0, -12.0, + 13.0, 14.0, 15.0, 16.0), + glm::dmat4( + 1.0, 0.0, 0.0, 10.0, + 0.0, 0.0, -1.0, -3.5, + 0.0, 1.0, 0.0, 20.4, + 0.0, 0.0, 0.0, 1.0) + }; + // clang-format on + checkNumeric(data); + } +} + +TEST_CASE("Check StructuralMetadata boolean property") { + std::bitset bits = 0b11110101; + unsigned long val = bits.to_ulong(); + std::vector data(sizeof(val)); + std::memcpy(data.data(), &val, sizeof(val)); + + size_t instanceCount = sizeof(unsigned long) * CHAR_BIT; + MetadataPropertyView property( + MetadataPropertyViewStatus::Valid, + gsl::span(data.data(), data.size()), + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None, + 0, + static_cast(instanceCount), + false); + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.get(i) == bits[static_cast(i)]); + } +} + +TEST_CASE("Check StructuralMetadata string property") { + std::vector strings{ + "This is a fine test", + "What's going on", + "Good morning"}; + size_t totalSize = 0; + for (const auto& s : strings) { + totalSize += s.size(); + } + + uint32_t currentOffset = 0; + std::vector buffer; + buffer.resize(totalSize); + for (size_t i = 0; i < strings.size(); ++i) { + std::memcpy( + buffer.data() + currentOffset, + strings[i].data(), + strings[i].size()); + currentOffset += static_cast(strings[i].size()); + } + + // copy offset to buffer + std::vector offsetBuffer; + offsetBuffer.resize((strings.size() + 1) * sizeof(uint32_t)); + currentOffset = 0; + for (size_t i = 0; i < strings.size(); ++i) { + std::memcpy( + offsetBuffer.data() + i * sizeof(uint32_t), + ¤tOffset, + sizeof(uint32_t)); + currentOffset += static_cast(strings[i].size()); + } + std::memcpy( + offsetBuffer.data() + strings.size() * sizeof(uint32_t), + ¤tOffset, + sizeof(uint32_t)); + + MetadataPropertyView property( + MetadataPropertyViewStatus::Valid, + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(offsetBuffer.data(), offsetBuffer.size()), + PropertyComponentType::None, + PropertyComponentType::Uint32, + 0, + static_cast(strings.size()), + false); + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.get(i) == strings[static_cast(i)]); + } +} + +TEST_CASE("Check StructuralMetadata fixed-length scalar array property") { + SECTION("Fixed-length array of 4 uint8_ts") { + // clang-format off + std::vector data{ + 210, 211, 3, 42, + 122, 22, 1, 45}; + // clang-format on + checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + } + + SECTION("Fixed-length array of 3 int8_ts") { + // clang-format off + std::vector data{ + 122, -12, 3, + 44, 11, -2, + 5, 6, -22, + 5, 6, 1}; + // clang-format on + checkFixedLengthArray(data, 3, static_cast(data.size() / 3)); + } + + SECTION("Fixed-length array of 4 int16_ts") { + // clang-format off + std::vector data{ + -122, 12, 3, 44, + 11, 2, 5, -6000, + 119, 30, 51, 200, + 22000, -500, 6000, 1}; + // clang-format on + checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + } + + SECTION("Fixed-length array of 6 uint32_ts") { + // clang-format off + std::vector data{ + 122, 12, 3, 44, 34444, 2222, + 11, 2, 5, 6000, 1111, 2222, + 119, 30, 51, 200, 12534, 11, + 22000, 500, 6000, 1, 3, 7}; + // clang-format on + checkFixedLengthArray(data, 6, static_cast(data.size() / 6)); + } + + SECTION("Fixed-length array of 2 int32_ts") { + // clang-format off + std::vector data{ + 122, 12, + 3, 44}; + // clang-format on + checkFixedLengthArray(data, 2, static_cast(data.size() / 2)); + } + + SECTION("Fixed-length array of 4 uint64_ts") { + // clang-format off + std::vector data{ + 10022, 120000, 2422, 1111, + 3, 440000, 333, 1455}; + // clang-format on + checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + } + + SECTION("Fixed-length array of 4 int64_ts") { + // clang-format off + std::vector data{ + 10022, -120000, 2422, 1111, + 3, 440000, -333, 1455}; + // clang-format on + checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + } + + SECTION("Fixed-length array of 4 floats") { + // clang-format off + std::vector data{ + 10.022f, -12.43f, 242.2f, 1.111f, + 3.333f, 440000.1f, -33.3f, 14.55f}; + // clang-format on + checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + } + + SECTION("Fixed-length array of 4 double") { + // clang-format off + std::vector data{ + 10.022, -12.43, 242.2, 1.111, + 3.333, 440000.1, -33.3, 14.55}; + // clang-format on + checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + } +} + +TEST_CASE("Check StructuralMetadata fixed-length vecN array property") { + SECTION("Fixed-length array of 4 u8vec2s") { + // clang-format off + std::vector data{ + glm::u8vec2(10, 21), + glm::u8vec2(3, 42), + glm::u8vec2(122, 22), + glm::u8vec2(1, 45), + glm::u8vec2(0, 0), + glm::u8vec2(32, 12), + glm::u8vec2(8, 19), + glm::u8vec2(6, 5)}; + // clang-format on + checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + } + + SECTION("Fixed-length array of 2 i8vec3s") { + // clang-format off + std::vector data{ + glm::i8vec3(122, -12, 3), + glm::i8vec3(44, 11, -2), + glm::i8vec3(5, 6, -22), + glm::i8vec3(5, 6, 1), + glm::i8vec3(8, -7, 7), + glm::i8vec3(-4, 36, 17)}; + // clang-format on + checkFixedLengthArray(data, 2, static_cast(data.size() / 2)); + } + + SECTION("Fixed-length array of 3 vec4s") { + // clang-format off + std::vector data{ + glm::vec4(40.2f, -1.2f, 8.8f, 1.0f), + glm::vec4(1.4f, 0.11, 34.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), + glm::vec4(1.0f, 2.0f, 3.0f, 6.0f), + glm::vec4(1.08f, -3.71f, 18.0f, -7.0f), + glm::vec4(-17.0f, 33.0f, 8.0f, -3.0f)}; + // clang-format on + checkFixedLengthArray(data, 3, static_cast(data.size() / 3)); + } +} + +TEST_CASE("Check StructuralMetadata fixed-length matN array property") { + SECTION("Fixed-length array of 4 i8mat2x2") { + // clang-format off + std::vector data{ + glm::i8mat2x2( + 10, 21, + 1, -2), + glm::i8mat2x2( + 3, 42, + -10, 12), + glm::i8mat2x2( + 122, 22, + 80, -4), + glm::i8mat2x2( + 15, -2, + 17, 6), + glm::i8mat2x2( + 0, 0, + -1, 1), + glm::i8mat2x2( + 32, -12, + 20, 4), + glm::i8mat2x2( + 8, 19, + -7, 1), + glm::i8mat2x2( + 6, 16, + 2, 5)}; + // clang-format on + checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + } + + SECTION("Fixed-length array of 2 dmat3s") { + // clang-format off + std::vector data{ + glm::dmat3( + 1.0, 2.0, 3.0, + 0.01, 0.02, 0.03, + 4.0, 5.0, 6.0), + glm::dmat3( + 0.2, -1.0, 8.0, + 40.0, -8.0, 9.0, + 10.0, 0.2, 0.34), + glm::dmat3( + 7.2, 16.5, 4.2, + 33.0, 3.5, -20.0, + 1.22, 1.02, 30.34), + glm::dmat3( + 1.2, 0.5, 0.0, + 0.0, 3.5, 0.0, + 0.76, 0.9, 1.1), + glm::dmat3( + 25.0, 50.4, 8.8, + 16.1, 23.0, 40.0, + 0.8, 8.9, 5.0), + glm::dmat3( + -4.0, 9.4, 11.2, + 5.5, 3.09, 0.301, + 4.5, 52.4, 1.05)}; + // clang-format on + checkFixedLengthArray(data, 2, static_cast(data.size() / 2)); + } + + SECTION("Fixed-length array of 3 u8mat4x4") { + // clang-format off + std::vector data{ + glm::u8mat4x4( + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16), + glm::u8mat4x4( + 0, 4, 2, 19, + 8, 7, 3, 5, + 43, 21, 10, 9, + 3, 10, 8, 6), + glm::u8mat4x4( + 1, 0, 0, 19, + 0, 1, 0, 2, + 0, 0, 4, 0, + 0, 0, 0, 1), + glm::u8mat4x4( + 6, 2, 7, 8, + 50, 11, 18, 2, + 3, 12, 6, 9, + 4, 20, 10, 4), + glm::u8mat4x4( + 10, 2, 46, 5, + 8, 7, 20, 13, + 24, 8, 6, 9, + 2, 15, 4, 3), + glm::u8mat4x4( + 3, 2, 1, 0, + 0, 1, 2, 3, + 8, 7, 6, 5, + 4, 3, 2, 1),}; + // clang-format on + checkFixedLengthArray(data, 3, static_cast(data.size() / 3)); + } +} + +TEST_CASE("Check StructuralMetadata variable-length scalar array property") { + SECTION("Variable-length array of uint8_t") { + // clang-format off + std::vector data{ + 3, 2, + 0, 45, 2, 1, 4, + 1, 3, 2, + 1, 3, 4, 1 + }; + std::vector offsets{ + 0, 2, 7, 10, 14 + }; + // clang-format on + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); + } + + SECTION("Variable-length array of int32_t") { + // clang-format off + std::vector data{ + 3, 200, + 0, 450, 200, 1, 4, + 1, 3, 2, + 1, 3, 4, 1 + }; + std::vector offsets{ + 0, 2 * sizeof(int32_t), 7 * sizeof(int32_t), 10 * sizeof(int32_t), 14 + * sizeof(int32_t) + }; + // clang-format on + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); + } + + SECTION("Variable-length array of double") { + // clang-format off + std::vector data{ + 3.333, 200.2, + 0.1122, 4.50, 2.30, 1.22, 4.444, + 1.4, 3.3, 2.2, + 1.11, 3.2, 4.111, 1.44 + }; + std::vector offsets{ + 0, 2 * sizeof(double), 7 * sizeof(double), 10 * sizeof(double), 14 * + sizeof(double) + }; + // clang-format on + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); + } +} + +TEST_CASE("Check StructuralMetadata variable-length vecN array property") { + SECTION("Variable-length array of ivec2") { + // clang-format off + std::vector data{ + glm::ivec2(3, -2), glm::ivec2(20, 3), + glm::ivec2(0, 45), glm::ivec2(-10, 2), glm::ivec2(4, 4), glm::ivec2(1, -1), + glm::ivec2(3, 1), glm::ivec2(3, 2), glm::ivec2(0, -5), + glm::ivec2(-9, 10), glm::ivec2(8, -2) + }; + // clang-format on + std::vector offsets{ + 0, + 2 * sizeof(glm::ivec2), + 6 * sizeof(glm::ivec2), + 9 * sizeof(glm::ivec2), + 11 * sizeof(glm::ivec2)}; + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); + } + + SECTION("Variable-length array of dvec3") { + // clang-format off + std::vector data{ + glm::dvec3(-0.02, 2.0, 1.0), glm::dvec3(9.92, 9.0, -8.0), + glm::dvec3(22.0, 5.5, -3.7), glm::dvec3(1.02, 9.0, -8.0), glm::dvec3(0.0, 0.5, 1.0), + glm::dvec3(-1.3, -5.0, -90.0), + glm::dvec3(4.4, 1.0, 2.3), glm::dvec3(5.8, 7.07, -4.0), + glm::dvec3(-2.0, 0.85, 0.22), glm::dvec3(-8.8, 5.1, 0.0), glm::dvec3(12.0, 8.0, -2.2), + }; + // clang-format on + std::vector offsets{ + 0, + 2 * sizeof(glm::dvec3), + 5 * sizeof(glm::dvec3), + 6 * sizeof(glm::dvec3), + 8 * sizeof(glm::dvec3), + 11 * sizeof(glm::dvec3)}; + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 5); + } + + SECTION("Variable-length array of u8vec4") { + // clang-format off + std::vector data{ + glm::u8vec4(1, 2, 3, 4), glm::u8vec4(5, 6, 7, 8), + glm::u8vec4(9, 2, 1, 0), + glm::u8vec4(8, 7, 10, 21), glm::u8vec4(3, 6, 8, 0), glm::u8vec4(0, 0, 0, 1), + glm::u8vec4(64, 8, 17, 5), glm::u8vec4(35, 23, 10, 0), + glm::u8vec4(99, 8, 1, 2) + }; + // clang-format on + + std::vector offsets{ + 0, + 2 * sizeof(glm::u8vec4), + 3 * sizeof(glm::u8vec4), + 6 * sizeof(glm::u8vec4), + 8 * sizeof(glm::u8vec4), + 9 * sizeof(glm::u8vec4)}; + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 5); + } +} + +TEST_CASE("Check StructuralMetadata variable-length matN array property") { + SECTION("Variable-length array of dmat2") { + // clang-format off + std::vector data0{ + glm::dmat2( + 3.23, -2.456, + 1.0, 0.003), + glm::dmat2( + 40.0, 3.66, + 8.567, -9.8) + }; + std::vector data1{ + glm::dmat2( + 1.1, 10.02, + 7.0, 0.0), + }; + std::vector data2{ + glm::dmat2( + 18.8, 0.0, + 1.0, 17.2), + glm::dmat2( + -4.0, -0.053, + -9.0, 1.0), + glm::dmat2( + 1.1, 8.88, + -99.0, 1.905), + }; + // clang-format on + + std::vector data; + data.reserve(data0.size() + data1.size() + data2.size()); + data.insert(data.end(), data0.begin(), data0.end()); + data.insert(data.end(), data1.begin(), data1.end()); + data.insert(data.end(), data2.begin(), data2.end()); + + std::vector offsets{ + 0, + 2 * sizeof(glm::dmat2), + 3 * sizeof(glm::dmat2), + 6 * sizeof(glm::dmat2), + }; + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 3); + } + + SECTION("Variable-length array of i16mat3x3") { + // clang-format off + std::vector data0{ + glm::i16mat3x3( + 1, 0, 0, + 0, -1, 0, + 0, 0, 1), + }; + std::vector data1{ + glm::i16mat3x3( + 2, 3, 0, + -9, 14, 4, + -2, -5, 10), + glm::i16mat3x3( + 0, 5, 10, + -8, 33, 2, + -9, 8, 41), + glm::i16mat3x3( + 10, -7, 8, + 21, -9, 2, + 3, 4, 5) + }; + std::vector data2{ + glm::i16mat3x3( + -10, 50, 30, + 8, 17, 2, + 16, 40, 3), + glm::i16mat3x3( + -9, 18, 8, + 20, 3, 4, + 16, 7, -9), + }; + // clang-format on + + std::vector data; + data.reserve(data0.size() + data1.size() + data2.size()); + data.insert(data.end(), data0.begin(), data0.end()); + data.insert(data.end(), data1.begin(), data1.end()); + data.insert(data.end(), data2.begin(), data2.end()); + + std::vector offsets{ + 0, + 1 * sizeof(glm::i16mat3x3), + 4 * sizeof(glm::i16mat3x3), + 6 * sizeof(glm::i16mat3x3)}; + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 3); + } + + SECTION("Variable-length array of u8mat4x4") { + // clang-format off + std::vector data0{ + glm::u8mat4x4( + 1, 0, 0, 0, + 0, 4, 0, 0, + 0, 0, 1, 10, + 0, 0, 0, 1), + glm::u8mat4x4( + 10, 0, 0, 8, + 0, 5, 0, 4, + 0, 0, 1, 3, + 0, 0, 0, 1), + glm::u8mat4x4( + 8, 0, 0, 9, + 0, 3, 0, 11, + 0, 0, 20, 0, + 0, 0, 0, 1), + }; + std::vector data1{ + glm::u8mat4x4( + 1, 2, 3, 4, + 4, 3, 2, 1, + 0, 9, 8, 7, + 6, 5, 5, 6), + }; + std::vector data2{ + glm::u8mat4x4( + 4, 1, 8, 9, + 2, 6, 50, 1, + 10, 20, 30, 9, + 8, 7, 20, 4), + glm::u8mat4x4( + 0, 2, 1, 0, + 25, 19, 8, 2, + 3, 6, 40, 50, + 15, 9, 0, 3), + }; + // clang-format on + + std::vector data; + data.reserve(data0.size() + data1.size() + data2.size()); + data.insert(data.end(), data0.begin(), data0.end()); + data.insert(data.end(), data1.begin(), data1.end()); + data.insert(data.end(), data2.begin(), data2.end()); + + std::vector offsets{ + 0, + 3 * sizeof(glm::u8mat4x4), + 4 * sizeof(glm::u8mat4x4), + 6 * sizeof(glm::u8mat4x4)}; + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 3); + } +} + +TEST_CASE("Check StructuralMetadata fixed-length array of string") { + std::vector strings{ + "Test 1", + "Test 2", + "Test 3", + "Test 4", + "Test 5", + "Test 6", + "This is a fine test", + "What's going on", + "Good morning"}; + size_t totalSize = 0; + for (const auto& str : strings) { + totalSize += str.size(); + } + + const size_t stringCount = strings.size(); + std::vector buffer; + buffer.resize(totalSize); + uint32_t currentStringOffset = 0; + for (size_t i = 0; i < stringCount; ++i) { + std::memcpy( + buffer.data() + currentStringOffset, + strings[i].data(), + strings[i].size()); + currentStringOffset += static_cast(strings[i].size()); + } + + // Create string offset buffer + std::vector stringOffsets; + stringOffsets.resize((stringCount + 1) * sizeof(uint32_t)); + currentStringOffset = 0; + for (size_t i = 0; i < stringCount; ++i) { + std::memcpy( + stringOffsets.data() + i * sizeof(uint32_t), + ¤tStringOffset, + sizeof(uint32_t)); + currentStringOffset += static_cast(strings[i].size()); + } + + std::memcpy( + stringOffsets.data() + stringCount * sizeof(uint32_t), + ¤tStringOffset, + sizeof(uint32_t)); + + MetadataPropertyView> property( + MetadataPropertyViewStatus::Valid, + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(stringOffsets.data(), stringOffsets.size()), + PropertyComponentType::None, + PropertyComponentType::Uint32, + 3, + static_cast(stringCount / 3), + false); + + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + MetadataArrayView values = property.get(i); + for (int64_t j = 0; j < values.size(); ++j) { + std::string_view v = values[j]; + REQUIRE(v == strings[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == stringCount); +} + +TEST_CASE( + "Check StructuralMetadata variable-length array of strings property") { + // clang-format off + std::vector arrayOffsets{ + 0, + 4 * sizeof(uint32_t), + 7 * sizeof(uint32_t), + 11 * sizeof(uint32_t) + }; + + std::vector strings{ + "Test 1", "Test 2", "Test 3", "Test 4", + "Test 5", "Test 6", "Test 7", + "test 8", "Test 9", "Test 10", "Test 11" + }; + // clang-format on + + size_t totalSize = 0; + for (const auto& str : strings) { + totalSize += str.size(); + } + + const size_t stringCount = strings.size(); + uint32_t currentOffset = 0; + std::vector buffer; + buffer.resize(totalSize); + for (size_t i = 0; i < stringCount; ++i) { + std::memcpy( + buffer.data() + currentOffset, + strings[i].data(), + strings[i].size()); + currentOffset += static_cast(strings[i].size()); + } + + std::vector stringOffsets; + stringOffsets.resize((stringCount + 1) * sizeof(uint32_t)); + currentOffset = 0; + for (size_t i = 0; i < stringCount; ++i) { + std::memcpy( + stringOffsets.data() + i * sizeof(uint32_t), + ¤tOffset, + sizeof(uint32_t)); + currentOffset += static_cast(strings[i].size()); + } + std::memcpy( + stringOffsets.data() + stringCount * sizeof(uint32_t), + ¤tOffset, + sizeof(uint32_t)); + + MetadataPropertyView> property( + MetadataPropertyViewStatus::Valid, + gsl::span(buffer.data(), buffer.size()), + gsl::span( + reinterpret_cast(arrayOffsets.data()), + arrayOffsets.size() * sizeof(uint32_t)), + gsl::span(stringOffsets.data(), stringOffsets.size()), + PropertyComponentType::Uint32, + PropertyComponentType::Uint32, + 0, + 3, + false); + + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + MetadataArrayView values = property.get(i); + for (int64_t j = 0; j < values.size(); ++j) { + std::string_view v = values[j]; + REQUIRE(v == strings[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == stringCount); +} + +TEST_CASE("Check StructuralMetadata fixed-length boolean array property") { + std::vector buffer{ + static_cast(0b10101111), + static_cast(0b11111010), + static_cast(0b11100111)}; + + MetadataPropertyView> property( + MetadataPropertyViewStatus::Valid, + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(), + PropertyComponentType::Uint32, + PropertyComponentType::None, + 12, + 2, + false); + + REQUIRE(property.size() == 2); + + MetadataArrayView val0 = property.get(0); + REQUIRE(val0.size() == 12); + REQUIRE(static_cast(val0[0]) == 1); + REQUIRE(static_cast(val0[1]) == 1); + REQUIRE(static_cast(val0[2]) == 1); + REQUIRE(static_cast(val0[3]) == 1); + REQUIRE(static_cast(val0[4]) == 0); + REQUIRE(static_cast(val0[5]) == 1); + REQUIRE(static_cast(val0[6]) == 0); + REQUIRE(static_cast(val0[7]) == 1); + REQUIRE(static_cast(val0[8]) == 0); + REQUIRE(static_cast(val0[9]) == 1); + REQUIRE(static_cast(val0[10]) == 0); + REQUIRE(static_cast(val0[11]) == 1); + + MetadataArrayView val1 = property.get(1); + REQUIRE(static_cast(val1[0]) == 1); + REQUIRE(static_cast(val1[1]) == 1); + REQUIRE(static_cast(val1[2]) == 1); + REQUIRE(static_cast(val1[3]) == 1); + REQUIRE(static_cast(val1[4]) == 1); + REQUIRE(static_cast(val1[5]) == 1); + REQUIRE(static_cast(val1[6]) == 1); + REQUIRE(static_cast(val1[7]) == 0); + REQUIRE(static_cast(val1[8]) == 0); + REQUIRE(static_cast(val1[9]) == 1); + REQUIRE(static_cast(val1[10]) == 1); + REQUIRE(static_cast(val1[11]) == 1); +} + +TEST_CASE("Check StructuralMetadata variable-length boolean array property") { + std::vector buffer{ + static_cast(0b10101111), + static_cast(0b11111010), + static_cast(0b11100111), + static_cast(0b11110110)}; + + std::vector offsetBuffer{0, 3, 12, 28}; + + MetadataPropertyView> property( + MetadataPropertyViewStatus::Valid, + gsl::span(buffer.data(), buffer.size()), + gsl::span( + reinterpret_cast(offsetBuffer.data()), + offsetBuffer.size() * sizeof(uint32_t)), + gsl::span(), + PropertyComponentType::Uint32, + PropertyComponentType::None, + 0, + 3, + false); + + REQUIRE(property.size() == 3); + + MetadataArrayView val0 = property.get(0); + REQUIRE(val0.size() == 3); + REQUIRE(static_cast(val0[0]) == 1); + REQUIRE(static_cast(val0[1]) == 1); + REQUIRE(static_cast(val0[2]) == 1); + + MetadataArrayView val1 = property.get(1); + REQUIRE(val1.size() == 9); + REQUIRE(static_cast(val1[0]) == 1); + REQUIRE(static_cast(val1[1]) == 0); + REQUIRE(static_cast(val1[2]) == 1); + REQUIRE(static_cast(val1[3]) == 0); + REQUIRE(static_cast(val1[4]) == 1); + REQUIRE(static_cast(val1[5]) == 0); + REQUIRE(static_cast(val1[6]) == 1); + REQUIRE(static_cast(val1[7]) == 0); + REQUIRE(static_cast(val1[8]) == 1); + + MetadataArrayView val2 = property.get(2); + REQUIRE(val2.size() == 16); + REQUIRE(static_cast(val2[0]) == 1); + REQUIRE(static_cast(val2[1]) == 1); + REQUIRE(static_cast(val2[2]) == 1); + REQUIRE(static_cast(val2[3]) == 1); + REQUIRE(static_cast(val2[4]) == 1); + REQUIRE(static_cast(val2[5]) == 1); + REQUIRE(static_cast(val2[6]) == 1); + REQUIRE(static_cast(val2[7]) == 0); + REQUIRE(static_cast(val2[8]) == 0); + REQUIRE(static_cast(val2[9]) == 1); + REQUIRE(static_cast(val2[10]) == 1); + REQUIRE(static_cast(val2[11]) == 1); + REQUIRE(static_cast(val2[12]) == 0); + REQUIRE(static_cast(val2[13]) == 1); + REQUIRE(static_cast(val2[14]) == 1); + REQUIRE(static_cast(val2[15]) == 0); +} From 2228f75d6cceb1b5b7bfe61c1513831beda0295b Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 17 May 2023 14:50:59 -0400 Subject: [PATCH 015/121] Rename enums and fix documentation --- .../StructuralMetadataPropertyView.h | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h index 5f356fdb6..b2a86194c 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h @@ -33,115 +33,115 @@ enum class MetadataPropertyViewStatus { * @brief This property view does not exist in the * ExtensionExtStructuralMetadataPropertyTable. */ - InvalidPropertyDoesNotExist, + ErrorPropertyDoesNotExist, /** * @brief This property view does not have a correct type with what is * specified in {@link ExtensionExtStructuralMetadataClassProperty::type}. */ - InvalidTypeMismatch, + ErrorTypeMismatch, /** * @brief This property view does not have a correct component type with what * is specified in {@link ExtensionExtStructuralMetadataClassProperty::componentType}. */ - InvalidComponentTypeMismatch, + ErrorComponentTypeMismatch, /** * @brief This property view does not have a valid value buffer view index. */ - InvalidValueBufferView, + ErrorInvalidValueBufferView, /** * @brief This array property view does not have a valid array offset buffer * view index. */ - InvalidArrayOffsetBufferViewIndex, + ErrorInvalidArrayOffsetBufferView, /** * @brief This string property view does not have a valid string offset buffer * view index. */ - InvalidStringOffsetBufferViewIndex, + ErrorInvalidStringOffsetBufferView, /** * @brief This property view has a valid value buffer view, but the buffer * view specifies an invalid buffer index. */ - InvalidValueBufferIndex, + ErrorInvalidValueBuffer, /** * @brief This property view has a valid array string buffer view, but the * buffer view specifies an invalid buffer index. */ - InvalidArrayOffsetBufferIndex, + ErrorInvalidArrayOffsetBuffer, /** * @brief This property view has a valid string offset buffer view, but the * buffer view specifies an invalid buffer index. */ - InvalidStringOffsetBufferIndex, + ErrorInvalidStringOffsetBuffer, /** * @brief This property view has an out-of-bounds buffer view */ - InvalidBufferViewOutOfBounds, + ErrorBufferViewOutOfBounds, /** - * @brief This property view has an invalid buffer view's length which is not - * a multiple of the size of its type or offset type + * @brief This property view has an invalid buffer view; its length is not + * a multiple of the size of its type / offset type. */ - InvalidBufferViewSizeNotDivisibleByTypeSize, + ErrorBufferViewSizeNotDivisibleByTypeSize, /** - * @brief This property view has an invalid buffer view's length which cannot - * fit all the instances of the feature table + * @brief This property view has an invalid buffer view; its length does not + * match the size of the property table. */ - InvalidBufferViewSizeNotFitInstanceCount, + ErrorBufferViewSizeDoesNotMatchPropertyTableCount, /** * @brief This array property view has both count and offset buffer * view defined. */ - InvalidArrayCountAndOffsetBufferCoexist, + ErrorArrayCountAndOffsetBufferCoexist, /** * @brief This array property view doesn't have count nor offset buffer view * defined. */ - InvalidArrayCountAndOffsetBufferDontExist, + ErrorArrayCountAndOffsetBufferDontExist, /** * @brief This property view has an unknown array offset type. */ - InvalidArrayOffsetType, + ErrorInvalidArrayOffsetType, /** * @brief This property view has an unknown string offset type. */ - InvalidStringOffsetType, + ErrorInvalidStringOffsetType, /** * @brief This property view's array offset values are not sorted in ascending * order. */ - InvalidArrayOffsetValuesNotSorted, + ErrorArrayOffsetsNotSorted, /** * @brief This property view's string offset values are not sorted in * ascending order. */ - InvalidStringOffsetValuesNotSorted, + ErrorStringOffsetsNotSorted, /** * @brief This property view has an array offset that is out of bounds. */ - InvalidArrayOffsetValueOutOfBounds, + ErrorArrayOffsetOutOfBounds, /** * @brief This property view has a string offset that is out of bounds. */ - InvalidStringOffsetValueOutOfBounds + ErrorStringOffsetOutOfBounds }; /** @@ -152,11 +152,11 @@ enum class MetadataPropertyViewStatus { * {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} like an array of elements. * Data of each instance can be accessed through the {@link get(int64_t instance)} method * - * @param ElementType must be one of the following: a scalar (uin8_t, int8_t, - * uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double), vecN - * composed of one of the scalar types, matN composed of one of the scalar - * types, bool, std::string_view, or MetadataArrayView with T as one of the - * aforementioned types. + * @param ElementType must be one of the following: a scalar (uint8_t, int8_t, + * uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double), a + * glm vecN composed of one of the scalar types, a glm matN composed of one of + * the scalar types, bool, std::string_view, or MetadataArrayView with T as + * one of the aforementioned types. */ template class MetadataPropertyView { public: From f52e1bab0168d73d373c6e62622d996b2197a232 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 17 May 2023 14:52:38 -0400 Subject: [PATCH 016/121] Fix incorrect variable names --- .../CesiumGltf/StructuralMetadataPropertyView.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h index b2a86194c..ddba25835 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h @@ -166,8 +166,8 @@ template class MetadataPropertyView { MetadataPropertyView() : _status{MetadataPropertyViewStatus::InvalidPropertyDoesNotExist}, _values{}, - _componentCount{}, - _instanceCount{}, + _fixedLengthArrayCount{}, + _size{}, _normalized{} {} /** @@ -178,7 +178,7 @@ template class MetadataPropertyView { * @param stringOffsets The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::stringOffsets} * @param offsetType The offset type of arrayOffsets specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::arrayOffsetType} * @param offsetType The offset type of stringOffsets specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::stringOffsetType} - * @param fixedArrayCount The number of elements in each array value specified by {@link ExtensionExtStructuralMetadataClassProperty::count} + * @param fixedLengthArrayCount The number of elements in each array value specified by {@link ExtensionExtStructuralMetadataClassProperty::count} * @param size The number of elements in the property table specified by {@link ExtensionExtStructuralMetadataPropertyTable::count} * @param normalized Whether this property has a normalized integer type. */ @@ -267,7 +267,9 @@ template class MetadataPropertyView { * * @return The count of this property. */ - int64_t getFixedLengthArrayCount() const noexcept { return _fixedArrayCount; } + int64_t getFixedLengthArrayCount() const noexcept { + return _fixedLengthArrayCount; + } /** * @brief Whether this property has a normalized integer type. From 9f7b66c7bb67cf281c428e5a34146bd47187bc95 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 17 May 2023 15:14:35 -0400 Subject: [PATCH 017/121] Fix enum names --- .../StructuralMetadataPropertyView.h | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h index ddba25835..cbe2dd43c 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h @@ -36,17 +36,23 @@ enum class MetadataPropertyViewStatus { ErrorPropertyDoesNotExist, /** - * @brief This property view does not have a correct type with what is + * @brief This property view's type does not match what is * specified in {@link ExtensionExtStructuralMetadataClassProperty::type}. */ ErrorTypeMismatch, /** - * @brief This property view does not have a correct component type with what + * @brief This property view's component type does not match what * is specified in {@link ExtensionExtStructuralMetadataClassProperty::componentType}. */ ErrorComponentTypeMismatch, + /** + * @brief This property view differs from what is specified in + * {@link ExtensionExtStructuralMetadataClassProperty::array}. + */ + ErrorArrayTypeMismatch, + /** * @brief This property view does not have a valid value buffer view index. */ @@ -83,7 +89,8 @@ enum class MetadataPropertyViewStatus { ErrorInvalidStringOffsetBuffer, /** - * @brief This property view has an out-of-bounds buffer view + * @brief This property view has a buffer view that points outside the bounds + * of its target buffer. */ ErrorBufferViewOutOfBounds, @@ -100,14 +107,14 @@ enum class MetadataPropertyViewStatus { ErrorBufferViewSizeDoesNotMatchPropertyTableCount, /** - * @brief This array property view has both count and offset buffer - * view defined. + * @brief This array property view has both a fixed length and an offset + * buffer view defined. */ ErrorArrayCountAndOffsetBufferCoexist, /** - * @brief This array property view doesn't have count nor offset buffer view - * defined. + * @brief This array property view has neither a fixed length nor an offset + * buffer view defined. */ ErrorArrayCountAndOffsetBufferDontExist, @@ -164,7 +171,7 @@ template class MetadataPropertyView { * @brief Constructs a new instance with a non-existent property. */ MetadataPropertyView() - : _status{MetadataPropertyViewStatus::InvalidPropertyDoesNotExist}, + : _status{MetadataPropertyViewStatus::ErrorPropertyDoesNotExist}, _values{}, _fixedLengthArrayCount{}, _size{}, From 5e999deef4ca1a9c01df5830bf9d9f4986f099e4 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 18 May 2023 11:18:33 -0400 Subject: [PATCH 018/121] Add StructuralMetadataPropertyTableView --- .../StructuralMetadataPropertyTableView.h | 793 ++++++++++++++++++ .../StructuralMetadataPropertyType.h | 4 + .../StructuralMetadataPropertyView.h | 3 +- .../StructuralMetadataPropertyTableView.cpp | 493 +++++++++++ .../src/StructuralMetadataPropertyType.cpp | 34 +- 5 files changed, 1314 insertions(+), 13 deletions(-) create mode 100644 CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h create mode 100644 CesiumGltf/src/StructuralMetadataPropertyTableView.cpp diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h new file mode 100644 index 000000000..9e555dca5 --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -0,0 +1,793 @@ +#pragma once + +#include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" +#include "CesiumGltf/Model.h" +#include "CesiumGltf/StructuralMetadataPropertyType.h" +#include "CesiumGltf/StructuralMetadataPropertyView.h" + +#include + +#include + +namespace CesiumGltf { +namespace StructuralMetadata { + +/** + * @brief Utility to retrieve the data of + * ExtensionExtStructuralMetadataPropertyTable. + * + * This should be used to get a {@link MetadataPropertyView} of a property. + * It will validate the EXT_structural_metadata format and ensure {@link MetadataPropertyView} + * does not access out of bounds. + */ + +class MetadataPropertyTableView { +public: + /** + * @brief Create an instance of MetadataPropertyTableView. + * @param pModel The Gltf Model that stores property table data + * @param pPropertyTable The ExtensionExtStructuralMetadataPropertyTable from + * which the view will retrieve data. + */ + MetadataPropertyTableView( + const Model* pModel, + const ExtensionExtStructuralMetadataPropertyTable* pPropertyTable); + + /** + * @brief Find the {@link ExtensionExtStructuralMetadataClassProperty} which + * stores the type information of a property based on the property's name. + * @param propertyName The name of the property to retrieve type info + * @return Pointer to the ExtensionExtStructuralMetadataClassProperty. Return + * nullptr if no property was found. + */ + const ExtensionExtStructuralMetadataClassProperty* + getClassProperty(const std::string& propertyName) const; + + /** + * @brief Gets a MetadataPropertyView to view the data of a property stored in + * the ExtensionExtStructuralMetadataPropertyTable. + * + * This method will validate the EXT_structural_metadata format to ensure + * MetadataPropertyView retrieves the correct data. T must be one of the + * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, + * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar + * types, a glm matN composed of one of the scalar types, bool, + * std::string_view, or MetadataArrayView with T as one of the + * aforementioned types. + * + * @param propertyName The name of the property to retrieve data from + * @return MetadataPropertyView of a property. The property view will be + * invalid if no property is found. + */ + template + MetadataPropertyView + getPropertyView(const std::string& propertyName) const { + if (_pPropertyTable->count <= 0) { + return createInvalidPropertyView( + StructuralMetadata::MetadataPropertyViewStatus:: + ErrorPropertyDoesNotExist); + } + + const ExtensionExtStructuralMetadataClassProperty* pClassProperty = + getClassProperty(propertyName); + if (!pClassProperty) { + return createInvalidPropertyView( + StructuralMetadata::MetadataPropertyViewStatus:: + ErrorPropertyDoesNotExist); + } + + return getPropertyViewImpl(propertyName, *pClassProperty); + } + + /** + * @brief Gets a MetadataPropertyView through a callback that accepts a + * property name and a std::optional> to view the data + * of a property stored in the ExtensionExtStructuralMetadataPropertyTable. + * + * This method will validate the EXT_structural_metadata format to ensure + * MetadataPropertyView retrieves the correct data. T must be one of the + * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, + * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar + * types, a glm matN composed of one of the scalar types, bool, + * std::string_view, or MetadataArrayView with T as one of the + * aforementioned types. If the property is invalid, std::nullopt 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 + * std::optional> + */ + template + void + getPropertyView(const std::string& propertyName, Callback&& callback) const { + const ExtensionExtStructuralMetadataClassProperty* pClassProperty = + getClassProperty(propertyName); + if (!pClassProperty) { + return; + } + + PropertyType type = convertStringToPropertyType(pClassProperty->type); + PropertyComponentType componentType = + convertStringToPropertyType(pClassProperty->componentType); + + if (pClassProperty->array) { + getArrayPropertyViewImpl( + propertyName, + *pClassProperty, + componentType, + std::forward(callback)); + } else if (isPropertyTypeVecN(type)) { + getVecNPropertyViewImpl( + propertyName, + *pClassProperty, + componentType, + std::forward(callback)); + } else if (isPropertyTypeMatN(type)) { + getMatNPropertyViewImpl( + propertyName, + *pClassProperty, + componentType, + std::forward(callback)); + } else { + getPrimitivePropertyViewImpl( + propertyName, + *pClassProperty, + type, + std::forward(callback)); + } + } + + /** + * @brief Iterates over each property in the + * ExtensionExtStructuralMetadataPropertyTable with a callback that accepts a + * property name and a std::optional> to view the data + * stored in the ExtensionExtStructuralMetadataPropertyTableProperty. + * + * This method will validate the EXT_structural_metadata format to ensure + * MetadataPropertyView retrieves the correct data. T must be one of the + * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, + * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar + * types, a glm matN composed of one of the scalar types, bool, + * std::string_view, or MetadataArrayView with T as one of the + * aforementioned types. If the property is invalid, std::nullopt 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 + * std::optional> + */ + template void forEachProperty(Callback&& callback) const { + for (const auto& property : this->_pClass->properties) { + getPropertyView(property.first, std::forward(callback)); + } + } + +private: + template + void getArrayPropertyViewImpl( + const std::string& propertyName, + const ExtensionExtStructuralMetadataClassProperty& classProperty, + StructuralMetadata::PropertyType type, + Callback&& callback) const { + switch (type) { + case PropertyType::Int8: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::Uint8: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::Int16: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::Uint16: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::Int32: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::Uint32: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::Int64: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::Uint64: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::Float32: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::Float64: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::Boolean: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyType::String: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + default: + break; + } + } + + template + void getVecNPropertyViewImpl( + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty, + PropertyType type, + PropertyComponentType componentType, + Callback&& callback) { + glm::length_t N; + switch (type) { + case PropertyType::Vec2: + N = 2; + break; + case PropertyType::Vec3: + N = 3; + break; + case PropertyType::Vec4: + N = 4; + break; + default: + return; + } + + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint8: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int32: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint32: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int64: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint64: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Float32: + callback( + propertyName, + getPropertyViewImpl>(propertyName, classProperty)); + break; + case PropertyComponentType::Float64: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + default: + break; + } + } + + template + void getMatNPropertyViewImpl( + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty, + PropertyType type, + PropertyComponentType componentType, + Callback&& callback) { + glm::length_t N; + switch (type) { + case PropertyType::Mat2: + N = 2; + break; + case PropertyType::Mat3: + N = 3; + break; + case PropertyType::Mat4: + N = 4; + break; + default: + return; + } + + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl < + glm::mat(propertyName, classProperty)); + break; + case PropertyComponentType::Uint8: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int32: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint32: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int64: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint64: + callback( + propertyName, + getPropertyViewImp>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Float32: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Float64: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + default: + break; + } + } + + template + void getPrimitivePropertyViewImpl( + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty, + PropertyComponentType type, + Callback&& callback) const { + switch (type) { + case PropertyType::Int8: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::Uint8: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::Int16: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::Uint16: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::Int32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::Uint32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::Int64: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::Uint64: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::Float32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::Float64: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::Boolean: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyType::String: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + default: + break; + } + } + + template + MetadataPropertyView getPropertyViewImpl( + const std::string& propertyName, + const ExtensionExtStructuralMetadataClassProperty& classProperty) const { + auto propertyTablePropertyIter = + _pPropertyTable->properties.find(propertyName); + if (propertyTablePropertyIter == _pPropertyTable->properties.end()) { + return createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorPropertyDoesNotExist); + } + + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty = propertyTablePropertyIter->second; + + if constexpr (IsMetadataNumeric::value || IsMetadataBoolean::value) { + return getNumericOrBooleanPropertyValues( + classProperty, + propertyTableProperty); + } + + if constexpr (IsMetadataString::value) { + return getStringPropertyValues(classProperty, propertyTableProperty); + } + + if constexpr ( + IsMetadataNumericArray::value || IsMetadataBooleanArray::value) { + return getPrimitiveArrayPropertyValues< + typename MetadataArrayType::type>( + classProperty, + propertyTableProperty); + } + + if constexpr (IsMetadataStringArray::value) { + return getStringArrayPropertyValues(classProperty, propertyTableProperty); + } + } + + template + StructuralMetadata::MetadataPropertyView getNumericOrBooleanPropertyValues( + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty) const { + if (classProperty.array) { + return createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + const PropertyType type = convertStringToPropertyType(classProperty.type); + if (TypeToPropertyType::value != type) { + return createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + const PropertyComponentType componentType = + convertStringToPropertyComponentType( + classProperty.componentType.value_or("")); + if (TypeToPropertyType::component != componentType) { + return createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + } + + gsl::span values; + const auto status = getBufferSafe(propertyTableProperty.values, values); + if (status != MetadataPropertyViewStatus::Valid) { + return createInvalidPropertyView(status); + } + + if (values.size() % sizeof(T) != 0) { + return createInvalidPropertyView( + StructuralMetadata::MetadataPropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + size_t maxRequiredBytes = 0; + if (IsMetadataBoolean::value) { + maxRequiredBytes = static_cast( + glm::ceil(static_cast(_pPropertyTable->count) / 8.0)); + } else { + maxRequiredBytes = _pPropertyTable->count * sizeof(T); + } + + if (values.size() < maxRequiredBytes) { + return createInvalidPropertyView( + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } + + return MetadataPropertyView( + MetadataPropertyViewStatus::Valid, + values, + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None, + 0, + _pPropertyTable->count, + classProperty.normalized); + } + + MetadataPropertyView getStringPropertyValues( + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty) const; + + template + MetadataPropertyView> getPrimitiveArrayPropertyValues( + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty) const { + if (!classProperty.array) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + const PropertyType type = convertStringToPropertyType(classProperty.type); + if (TypeToPropertyType::value != type) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + const PropertyComponentType componentType = + convertStringToPropertyComponentType( + classProperty.componentType.value_or("")); + if (TypeToPropertyType::component != componentType) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + } + + gsl::span values; + auto status = getBufferSafe(propertyTableProperty.values, values); + if (status != MetadataPropertyViewStatus::Valid) { + return createInvalidPropertyView>(status); + } + + if (values.size() % sizeof(T) != 0) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + const int64_t fixedLengthArrayCount = classProperty.count.value_or(0); + if (fixedLengthArrayCount > 0 && propertyTableProperty.arrayOffsets >= 0) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } + + if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + } + + // Handle fixed-length arrays + if (fixedLengthArrayCount > 0) { + size_t maxRequiredBytes = 0; + if constexpr (IsMetadataBoolean::value) { + maxRequiredBytes = static_cast(glm::ceil( + static_cast( + _pPropertyTable->count * fixedLengthArrayCount) / + 8.0)); + } else { + maxRequiredBytes = static_cast( + _pPropertyTable->count * fixedLengthArrayCount * sizeof(T)); + } + + if (values.size() < maxRequiredBytes) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } + + return MetadataPropertyView>( + MetadataPropertyViewStatus::Valid, + values, + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None, + static_cast(fixedLengthArrayCount), + static_cast(_pPropertyTable->count), + classProperty.normalized); + } + + // Handle variable-length arrays + const PropertyComponentType arrayOffsetType = + convertArrayOffsetTypeStringToPropertyComponentType( + propertyTableProperty.arrayOffsetType); + if (arrayOffsetType == PropertyComponentType::None) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + constexpr bool checkBitsSize = IsMetadataBoolean::value; + gsl::span arrayOffsets; + status = getArrayOffsetsBufferSafe( + propertyTableProperty.arrayOffsets, + arrayOffsetType, + values.size(), + static_cast(_pPropertyTable->count), + checkBitsSize, + arrayOffsets); + if (status != MetadataPropertyViewStatus::Valid) { + return createInvalidPropertyView>(status); + } + + return MetadataPropertyView>( + MetadataPropertyViewStatus::Valid, + values, + arrayOffsets, + gsl::span(), + arrayOffsetType, + PropertyComponentType::None, + 0, + static_cast(_pPropertyTable->count), + classProperty.normalized); + } + + MetadataPropertyView> + getStringArrayPropertyValues( + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty) const; + + MetadataPropertyViewStatus getBufferSafe( + int32_t bufferView, + gsl::span& buffer) const noexcept; + + MetadataPropertyViewStatus getArrayOffsetsBufferSafe( + int32_t arrayOffsetsBufferView, + PropertyComponentType arrayOffsetType, + size_t valuesBufferSize, + size_t propertyTableCount, + bool checkBitsSize, + gsl::span& arrayOffsetsBuffer) const noexcept; + + MetadataPropertyViewStatus getStringOffsetsBufferSafe( + int32_t stringOffsetsBufferView, + PropertyComponentType stringOffsetType, + size_t valuesBufferSize, + size_t propertyTableCount, + gsl::span& stringOffsetsBuffer) const noexcept; + + template + static MetadataPropertyView + createInvalidPropertyView(MetadataPropertyViewStatus invalidStatus) noexcept { + return MetadataPropertyView( + invalidStatus, + gsl::span(), + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None, + 0, + 0, + false); + } + + const Model* _pModel; + const ExtensionExtStructuralMetadataPropertyTable* _pPropertyTable; + const ExtensionExtStructuralMetadataClass* _pClass; +}; + +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h index 3233d52a3..4648c7c12 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h @@ -51,5 +51,9 @@ convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str); PropertyComponentType convertStringOffsetTypeStringToPropertyComponentType(const std::string& str); +bool isPropertyTypeVecN(PropertyType type); + +bool isPropertyTypeMatN(PropertyType type); + } // namespace StructuralMetadata } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h index cbe2dd43c..529e092df 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h @@ -231,7 +231,8 @@ template class MetadataPropertyView { assert( size() > 0 && "Check the size() of the view to make sure it's not empty"); - assert(index >= 0 && "index must be positive"); + assert(index >= 0 && "index must be non-negative"); + assert(index < size() && "index must be less than size"); if constexpr (IsMetadataNumeric::value) { return getNumericValue(index); diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp new file mode 100644 index 000000000..4843fabe2 --- /dev/null +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -0,0 +1,493 @@ +#include "CesiumGltf/StructuralMetadataPropertyTableView.h" + +namespace CesiumGltf { +namespace StructuralMetadata { + +template +static MetadataPropertyViewStatus checkOffsetsBuffer( + const gsl::span& offsetBuffer, + size_t valueBufferSize, + size_t instanceCount, + bool checkBitSize, + MetadataPropertyViewStatus offsetsNotSortedError, + MetadataPropertyViewStatus offsetOutOfBoundsError) noexcept { + if (offsetBuffer.size() % sizeof(T) != 0) { + return MetadataPropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize; + } + + const size_t size = offsetBuffer.size() / sizeof(T); + if (size != instanceCount + 1) { + return MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount; + } + + const gsl::span offsetValues( + reinterpret_cast(offsetBuffer.data()), + size); + + for (size_t i = 1; i < offsetValues.size(); ++i) { + if (offsetValues[i] < offsetValues[i - 1]) { + return offsetsNotSortedError; + } + } + + if (checkBitSize) { + if (offsetValues.back() / 8 <= valueBufferSize) { + return MetadataPropertyViewStatus::Valid; + } + + return offsetOutOfBoundsError; + } + + if (offsetValues.back() <= valueBufferSize) { + return MetadataPropertyViewStatus::Valid; + } + + return offsetOutOfBoundsError; +} + +template +static MetadataPropertyViewStatus checkStringAndArrayOffsetsBuffers( + const gsl::span& arrayOffsets, + const gsl::span& stringOffsets, + size_t valueBufferSize, + PropertyComponentType stringOffsetType, + size_t propertyTableCount) noexcept { + const auto status = checkOffsetsBuffer( + arrayOffsets, + stringOffsets.size(), + propertyTableCount, + false, + MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + + if (status != MetadataPropertyViewStatus::Valid) { + return status; + } + + const T* pValue = reinterpret_cast(arrayOffsets.data()); + + switch (stringOffsetType) { + case PropertyComponentType::Uint8: + return checkOffsetsBuffer( + stringOffsets, + valueBufferSize, + pValue[propertyTableCount] / sizeof(T), + false, + MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + case PropertyComponentType::Uint16: + return checkOffsetsBuffer( + stringOffsets, + valueBufferSize, + pValue[propertyTableCount] / sizeof(T), + false, + MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + case PropertyComponentType::Uint32: + return checkOffsetsBuffer( + stringOffsets, + valueBufferSize, + pValue[propertyTableCount] / sizeof(T), + false, + MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + case PropertyComponentType::Uint64: + return checkOffsetsBuffer( + stringOffsets, + valueBufferSize, + pValue[propertyTableCount] / sizeof(T), + false, + MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + default: + return MetadataPropertyViewStatus::ErrorInvalidStringOffsetType; + } +} + +MetadataPropertyTableView::MetadataPropertyTableView( + const Model* pModel, + const ExtensionExtStructuralMetadataPropertyTable* pPropertyTable) + : _pModel{pModel}, _pPropertyTable{pPropertyTable}, _pClass{nullptr} { + assert(pModel != nullptr && "pModel must not be nullptr"); + assert(pPropertyTable != nullptr && "pPropertyTable must not be nullptr"); + + const ExtensionModelExtStructuralMetadata* pMetadata = + pModel->getExtension(); + assert( + pMetadata != nullptr && + "Model must contain ExtensionModelExtStructuralMetadata to use " + "MetadataPropertyTableView"); + + const std::optional& schema = + pMetadata->schema; + assert( + schema != std::nullopt && + "ExtensionModelExtStructuralMetadata must contain " + "Schema to use MetadataPropertyTableView"); + + auto classIter = schema->classes.find(_pPropertyTable->classProperty); + if (classIter != schema->classes.end()) { + _pClass = &classIter->second; + } +} + +const ExtensionExtStructuralMetadataClassProperty* +MetadataPropertyTableView::getClassProperty( + const std::string& propertyName) const { + if (_pClass == nullptr) { + return nullptr; + } + + auto propertyIter = _pClass->properties.find(propertyName); + if (propertyIter == _pClass->properties.end()) { + return nullptr; + } + + return &propertyIter->second; +} + +MetadataPropertyViewStatus MetadataPropertyTableView::getBufferSafe( + int32_t bufferViewIdx, + gsl::span& buffer) const noexcept { + buffer = {}; + + const BufferView* pBufferView = + _pModel->getSafe(&_pModel->bufferViews, bufferViewIdx); + if (!pBufferView) { + return MetadataPropertyViewStatus::ErrorInvalidValueBufferView; + } + + const Buffer* pBuffer = + _pModel->getSafe(&_pModel->buffers, pBufferView->buffer); + if (!pBuffer) { + return MetadataPropertyViewStatus::ErrorInvalidValueBuffer; + } + + if (pBufferView->byteOffset + pBufferView->byteLength > + static_cast(pBuffer->cesium.data.size())) { + return MetadataPropertyViewStatus::ErrorBufferViewOutOfBounds; + } + + buffer = gsl::span( + pBuffer->cesium.data.data() + pBufferView->byteOffset, + static_cast(pBufferView->byteLength)); + return MetadataPropertyViewStatus::Valid; +} + +MetadataPropertyViewStatus MetadataPropertyTableView::getArrayOffsetsBufferSafe( + int32_t arrayOffsetsBufferView, + PropertyComponentType arrayOffsetType, + size_t valueBufferSize, + size_t propertyTableCount, + bool checkBitsSize, + gsl::span& arrayOffsetsBuffer) const noexcept { + const MetadataPropertyViewStatus bufferStatus = + getBufferSafe(arrayOffsetsBufferView, arrayOffsetsBuffer); + if (bufferStatus != MetadataPropertyViewStatus::Valid) { + return bufferStatus; + } + + switch (arrayOffsetType) { + case PropertyComponentType::Uint8: + return checkOffsetsBuffer( + arrayOffsetsBuffer, + valueBufferSize, + propertyTableCount, + checkBitsSize, + MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + case PropertyComponentType::Uint16: + return checkOffsetsBuffer( + arrayOffsetsBuffer, + valueBufferSize, + propertyTableCount, + checkBitsSize, + MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + case PropertyComponentType::Uint32: + return checkOffsetsBuffer( + arrayOffsetsBuffer, + valueBufferSize, + propertyTableCount, + checkBitsSize, + MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + case PropertyComponentType::Uint64: + return checkOffsetsBuffer( + arrayOffsetsBuffer, + valueBufferSize, + propertyTableCount, + checkBitsSize, + MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + default: + return MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType; + } +} + +MetadataPropertyViewStatus +MetadataPropertyTableView::getStringOffsetsBufferSafe( + int32_t stringOffsetsBufferView, + PropertyComponentType stringOffsetType, + size_t valueBufferSize, + size_t propertyTableCount, + gsl::span& stringOffsetsBuffer) const noexcept { + const MetadataPropertyViewStatus bufferStatus = + getBufferSafe(stringOffsetsBufferView, stringOffsetsBuffer); + if (bufferStatus != MetadataPropertyViewStatus::Valid) { + return bufferStatus; + } + + switch (stringOffsetType) { + case PropertyComponentType::Uint8: + return checkOffsetsBuffer( + stringOffsetsBuffer, + valueBufferSize, + propertyTableCount, + false, + MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + case PropertyComponentType::Uint16: + return checkOffsetsBuffer( + stringOffsetsBuffer, + valueBufferSize, + propertyTableCount, + false, + MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + case PropertyComponentType::Uint32: + return checkOffsetsBuffer( + stringOffsetsBuffer, + valueBufferSize, + propertyTableCount, + false, + MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + case PropertyComponentType::Uint64: + return checkOffsetsBuffer( + stringOffsetsBuffer, + valueBufferSize, + propertyTableCount, + false, + MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, + MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + default: + return MetadataPropertyViewStatus::ErrorInvalidStringOffsetType; + } +} + +MetadataPropertyView +MetadataPropertyTableView::getStringPropertyValues( + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty) const { + if (classProperty.array) { + return createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + if (classProperty.type != + ExtensionExtStructuralMetadataClassProperty::Type::STRING) { + return createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + gsl::span values; + auto status = getBufferSafe(propertyTableProperty.values, values); + if (status != MetadataPropertyViewStatus::Valid) { + return createInvalidPropertyView(status); + } + + const PropertyComponentType offsetType = + convertStringOffsetTypeStringToPropertyComponentType( + propertyTableProperty.stringOffsetType); + if (offsetType == PropertyComponentType::None) { + return createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + } + + gsl::span stringOffsets; + status = getStringOffsetsBufferSafe( + propertyTableProperty.stringOffsets, + offsetType, + values.size(), + static_cast(_pPropertyTable->count), + stringOffsets); + if (status != MetadataPropertyViewStatus::Valid) { + return createInvalidPropertyView(status); + } + + return MetadataPropertyView( + MetadataPropertyViewStatus::Valid, + values, + gsl::span(), + stringOffsets, + PropertyComponentType::None, + offsetType, + 0, + _pPropertyTable->count, + classProperty.normalized); +} + +MetadataPropertyView> +MetadataPropertyTableView::getStringArrayPropertyValues( + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty) const { + if (!classProperty.array) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + if (classProperty.type != + ExtensionExtStructuralMetadataClassProperty::Type::STRING) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + gsl::span values; + auto status = getBufferSafe(propertyTableProperty.values, values); + if (status != MetadataPropertyViewStatus::Valid) { + return createInvalidPropertyView>( + status); + } + + // Check if array is fixed or variable length + const int64_t fixedLengthArrayCount = classProperty.count.value_or(0); + if (fixedLengthArrayCount > 0 && propertyTableProperty.arrayOffsets >= 0) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } + + if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + } + + // Get offset types + const PropertyComponentType arrayOffsetType = + convertArrayOffsetTypeStringToPropertyComponentType( + propertyTableProperty.arrayOffsetType); + if (arrayOffsetType == PropertyComponentType::None) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + const PropertyComponentType stringOffsetType = + convertStringOffsetTypeStringToPropertyComponentType( + propertyTableProperty.stringOffsetType); + if (stringOffsetType == PropertyComponentType::None) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + } + + if (propertyTableProperty.arrayOffsets < 0) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetBuffer); + } + + if (propertyTableProperty.stringOffsets < 0) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorInvalidStringOffsetBuffer); + } + + // Handle fixed-length arrays + if (fixedLengthArrayCount > 0) { + gsl::span stringOffsets; + status = getStringOffsetsBufferSafe( + propertyTableProperty.stringOffsets, + stringOffsetType, + values.size(), + static_cast(_pPropertyTable->count * fixedLengthArrayCount), + stringOffsets); + if (status != MetadataPropertyViewStatus::Valid) { + return createInvalidPropertyView>( + status); + } + + return MetadataPropertyView>( + MetadataPropertyViewStatus::Valid, + values, + gsl::span(), + stringOffsets, + PropertyComponentType::None, + stringOffsetType, + fixedLengthArrayCount, + _pPropertyTable->count, + classProperty.normalized); + } + + // Handle variable-length arrays + gsl::span stringOffsets; + status = getBufferSafe(propertyTableProperty.stringOffsets, stringOffsets); + if (status != MetadataPropertyViewStatus::Valid) { + return createInvalidPropertyView>( + status); + } + + gsl::span arrayOffsets; + status = getBufferSafe(propertyTableProperty.arrayOffsets, arrayOffsets); + if (status != MetadataPropertyViewStatus::Valid) { + return createInvalidPropertyView>( + status); + } + + switch (arrayOffsetType) { + case PropertyComponentType::Uint8: + status = checkStringAndArrayOffsetsBuffers( + arrayOffsets, + stringOffsets, + values.size(), + stringOffsetType, + static_cast(_pPropertyTable->count)); + break; + case PropertyComponentType::Uint16: + status = checkStringAndArrayOffsetsBuffers( + arrayOffsets, + stringOffsets, + values.size(), + stringOffsetType, + static_cast(_pPropertyTable->count)); + break; + case PropertyComponentType::Uint32: + status = checkStringAndArrayOffsetsBuffers( + arrayOffsets, + stringOffsets, + values.size(), + stringOffsetType, + static_cast(_pPropertyTable->count)); + break; + case PropertyComponentType::Uint64: + status = checkStringAndArrayOffsetsBuffers( + arrayOffsets, + stringOffsets, + values.size(), + stringOffsetType, + static_cast(_pPropertyTable->count)); + break; + default: + status = MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType; + break; + } + + if (status != MetadataPropertyViewStatus::Valid) { + return createInvalidPropertyView>( + status); + } + + return MetadataPropertyView>( + MetadataPropertyViewStatus::Valid, + values, + arrayOffsets, + stringOffsets, + arrayOffsetType, + stringOffsetType, + 0, + _pPropertyTable->count, + classProperty.normalized); +} + +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/src/StructuralMetadataPropertyType.cpp b/CesiumGltf/src/StructuralMetadataPropertyType.cpp index 56a8262b1..ca7613023 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyType.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyType.cpp @@ -39,39 +39,39 @@ PropertyType convertStringToPropertyType(const std::string& str) { } if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC2) { - return StructuralMetadata::PropertyType::Vec2; + return PropertyType::Vec2; } if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC3) { - return StructuralMetadata::PropertyType::Vec3; + return PropertyType::Vec3; } if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC4) { - return StructuralMetadata::PropertyType::Vec4; + return PropertyType::Vec4; } if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT2) { - return StructuralMetadata::PropertyType::Mat2; + return PropertyType::Mat2; } if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT3) { - return StructuralMetadata::PropertyType::Mat3; + return PropertyType::Mat3; } if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT4) { - return StructuralMetadata::PropertyType::Mat4; + return PropertyType::Mat4; } if (str == ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN) { - return StructuralMetadata::PropertyType::Boolean; + return PropertyType::Boolean; } if (str == ExtensionExtStructuralMetadataClassProperty::Type::STRING) { - return StructuralMetadata::PropertyType::String; + return PropertyType::String; } if (str == ExtensionExtStructuralMetadataClassProperty::Type::ENUM) { - return StructuralMetadata::PropertyType::Enum; + return PropertyType::Enum; } return PropertyType::Invalid; @@ -106,7 +106,7 @@ std::string convertPropertyComponentTypeToString(PropertyComponentType type) { } } -StructuralMetadata::PropertyComponentType +PropertyComponentType convertStringToPropertyComponentType(const std::string& str) { if (str == ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8) { @@ -160,7 +160,7 @@ convertStringToPropertyComponentType(const std::string& str) { return PropertyComponentType::None; } -StructuralMetadata::PropertyComponentType +PropertyComponentType convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str) { if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: ArrayOffsetType::UINT8) { @@ -185,7 +185,7 @@ convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str) { return PropertyComponentType::None; } -StructuralMetadata::PropertyComponentType +PropertyComponentType convertStringOffsetTypeStringToPropertyComponentType(const std::string& str) { if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: StringOffsetType::UINT8) { @@ -210,5 +210,15 @@ convertStringOffsetTypeStringToPropertyComponentType(const std::string& str) { return PropertyComponentType::None; } +bool isPropertyTypeVecN(PropertyType type) { + return type == PropertyType::Vec2 || type == PropertyType::Vec3 || + type == PropertyType::Vec4; +} + +bool isPropertyTypeMatN(PropertyType type) { + return type == PropertyType::Mat2 || type == PropertyType::Mat3 || + type == PropertyType::Mat4; +} + } // namespace StructuralMetadata } // namespace CesiumGltf From 2b8e5349fa3b8ae8c2e932cca0e2eae3f1e368ff Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 19 May 2023 15:41:54 -0400 Subject: [PATCH 019/121] Add tests for StructuralMetadataPropertyTableView --- .../StructuralMetadataPropertyTableView.h | 407 ++- .../StructuralMetadataPropertyTableView.cpp | 32 +- ...estStructuralMetadataPropertyTableView.cpp | 2591 +++++++++++++++++ 3 files changed, 2914 insertions(+), 116 deletions(-) create mode 100644 CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index 9e555dca5..b656b37c3 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -115,6 +115,7 @@ class MetadataPropertyTableView { getArrayPropertyViewImpl( propertyName, *pClassProperty, + type, componentType, std::forward(callback)); } else if (isPropertyTypeVecN(type)) { @@ -134,6 +135,7 @@ class MetadataPropertyTableView { propertyName, *pClassProperty, type, + componentType, std::forward(callback)); } } @@ -165,94 +167,184 @@ class MetadataPropertyTableView { } private: + glm::length_t getDimensionsFromType(PropertyType type) { + switch (type) { + case PropertyType::Vec2: + case PropertyType::Mat2: + return 2; + case PropertyType::Vec3: + case PropertyType::Mat3: + return 3; + case PropertyType::Vec4: + case PropertyType::Mat4: + return 4; + default: + return 0; + } + } + template - void getArrayPropertyViewImpl( + void getScalarArrayPropertyViewImpl( const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty, - StructuralMetadata::PropertyType type, + PropertyComponentType componentType, Callback&& callback) const { - switch (type) { - case PropertyType::Int8: + switch (componentType) { + case PropertyComponentType::Int8: callback( propertyName, getPropertyViewImpl>( propertyName, classProperty)); break; - case PropertyType::Uint8: + case PropertyComponentType::Uint8: callback( propertyName, getPropertyViewImpl>( propertyName, classProperty)); break; - case PropertyType::Int16: + case PropertyComponentType::Int16: callback( propertyName, getPropertyViewImpl>( propertyName, classProperty)); break; - case PropertyType::Uint16: + case PropertyComponentType::Uint16: callback( propertyName, getPropertyViewImpl>( propertyName, classProperty)); break; - case PropertyType::Int32: + case PropertyComponentType::Int32: callback( propertyName, getPropertyViewImpl>( propertyName, classProperty)); break; - case PropertyType::Uint32: + case PropertyComponentType::Uint32: callback( propertyName, getPropertyViewImpl>( propertyName, classProperty)); break; - case PropertyType::Int64: + case PropertyComponentType::Int64: callback( propertyName, getPropertyViewImpl>( propertyName, classProperty)); break; - case PropertyType::Uint64: + case PropertyComponentType::Uint64: callback( propertyName, getPropertyViewImpl>( propertyName, classProperty)); break; - case PropertyType::Float32: + case PropertyComponentType::Float32: callback( propertyName, getPropertyViewImpl>( propertyName, classProperty)); break; - case PropertyType::Float64: + case PropertyComponentType::Float64: callback( propertyName, getPropertyViewImpl>( propertyName, classProperty)); break; - case PropertyType::Boolean: + default: + break; + } + } + + template + void getVecNArrayPropertyViewImpl( + const std::string& propertyName, + const ExtensionExtStructuralMetadataClassProperty& classProperty, + PropertyType type, + PropertyComponentType componentType, + Callback&& callback) const { + glm::length_t N = getDimensionsFromType(type); + if (N <= 1) { + return; + } + + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>>( propertyName, classProperty)); break; - case PropertyType::String: + case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int32: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint32: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int64: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint64: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Float32: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Float64: + callback( + propertyName, + getPropertyViewImpl>>( propertyName, classProperty)); break; @@ -262,25 +354,147 @@ class MetadataPropertyTableView { } template - void getVecNPropertyViewImpl( + void getMatNArrayPropertyViewImpl( + const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty, PropertyType type, PropertyComponentType componentType, - Callback&& callback) { - glm::length_t N; - switch (type) { - case PropertyType::Vec2: - N = 2; + Callback&& callback) const { + glm::length_t N = getDimensionsFromType(type); + if (N <= 1) { + return; + } + + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); break; - case PropertyType::Vec3: - N = 3; + case PropertyComponentType::Uint8: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); break; - case PropertyType::Vec4: - N = 4; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int32: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint32: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int64: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint64: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Float32: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Float64: + callback( + propertyName, + getPropertyViewImpl>>( + propertyName, + classProperty)); break; default: + break; + } + } + + template + void getArrayPropertyViewImpl( + const std::string& propertyName, + const ExtensionExtStructuralMetadataClassProperty& classProperty, + PropertyType type, + PropertyComponentType componentType, + Callback&& callback) const { + if (type == PropertyType::Scalar) { + getScalarArrayPropertyViewImpl( + propertyName, + classProperty, + componentType, + std::forward(callback)) + } else if (isPropertyTypeVecN(type)) { + getVecNArrayPropertyViewImpl( + propertyName, + classProperty, + type, + componentType, + std::forward(callback)); + } else if (isPropertyTypeMatN(type)) { + getMatNArrayPropertyViewImpl( + propertyName, + classProperty, + type, + componentType, + std::forward(callback)); + + } else if (type == PropertyType::Boolean) { + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + + } else if (type == PropertyType::String) { + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + } + } + + template + void getVecNPropertyViewImpl( + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTableProperty& + propertyTableProperty, + PropertyType type, + PropertyComponentType componentType, + Callback&& callback) { + glm::length_t N = getDimensionsFromType(type); + if (N <= 1) { return; } @@ -366,18 +580,8 @@ class MetadataPropertyTableView { PropertyType type, PropertyComponentType componentType, Callback&& callback) { - glm::length_t N; - switch (type) { - case PropertyType::Mat2: - N = 2; - break; - case PropertyType::Mat3: - N = 3; - break; - case PropertyType::Mat4: - N = 4; - break; - default: + glm::length_t N = getDimensionsFromType(type); + if (N <= 1) { return; } @@ -461,71 +665,72 @@ class MetadataPropertyTableView { const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, - PropertyComponentType type, + PropertyType type, + PropertyComponentType componentType, Callback&& callback) const { - switch (type) { - case PropertyType::Int8: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Uint8: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Int16: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Uint16: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Int32: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Uint32: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Int64: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Uint64: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Float32: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Float64: + if (type == PropertyType::Scalar) { + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Uint8: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Int32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Uint32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Int64: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Uint64: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Float32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Float64: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + default: + break; + } + } else if (type == PropertyType::String) { callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Boolean: + getPropertyViewImpl(propertyName, classProperty)); + } else if (type == PropertyType::Boolean) { callback( propertyName, getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::String: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - default: - break; } } @@ -567,7 +772,7 @@ class MetadataPropertyTableView { } template - StructuralMetadata::MetadataPropertyView getNumericOrBooleanPropertyValues( + MetadataPropertyView getNumericOrBooleanPropertyValues( const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty) const { diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp index 4843fabe2..2c17c1259 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -366,15 +366,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); } - // Get offset types - const PropertyComponentType arrayOffsetType = - convertArrayOffsetTypeStringToPropertyComponentType( - propertyTableProperty.arrayOffsetType); - if (arrayOffsetType == PropertyComponentType::None) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); - } - + // Get string offset type const PropertyComponentType stringOffsetType = convertStringOffsetTypeStringToPropertyComponentType( propertyTableProperty.stringOffsetType); @@ -383,14 +375,9 @@ MetadataPropertyTableView::getStringArrayPropertyValues( MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); } - if (propertyTableProperty.arrayOffsets < 0) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetBuffer); - } - if (propertyTableProperty.stringOffsets < 0) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorInvalidStringOffsetBuffer); + MetadataPropertyViewStatus::ErrorInvalidStringOffsetBufferView); } // Handle fixed-length arrays @@ -419,6 +406,21 @@ MetadataPropertyTableView::getStringArrayPropertyValues( classProperty.normalized); } + // Get array offset type + const PropertyComponentType arrayOffsetType = + convertArrayOffsetTypeStringToPropertyComponentType( + propertyTableProperty.arrayOffsetType); + if (arrayOffsetType == PropertyComponentType::None) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + if (propertyTableProperty.arrayOffsets < 0) { + return createInvalidPropertyView>( + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetBufferView); + } + + // Handle variable-length arrays gsl::span stringOffsets; status = getBufferSafe(propertyTableProperty.stringOffsets, stringOffsets); diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp new file mode 100644 index 000000000..e948a5dc6 --- /dev/null +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -0,0 +1,2591 @@ +#include "CesiumGltf/StructuralMetadataPropertyTableView.h" + +#include + +#include + +using namespace CesiumGltf; +using namespace CesiumGltf::StructuralMetadata; + +TEST_CASE("Test StructuralMetadata scalar property") { + Model model; + + std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; + + size_t valueBufferIndex = 0; + size_t valueBufferViewIndex = 0; + + // Buffers are constructed in scope to ensure that the tests don't use their + // temporary variables. + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + MetadataPropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(uint32Property.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(uint32Property.size() > 0); + + for (int64_t i = 0; i < uint32Property.size(); ++i) { + REQUIRE(uint32Property.get(i) == values[static_cast(i)]); + } + } + + SECTION("Access wrong type") { + MetadataPropertyView uvec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uvec3Invalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView u32mat3x3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat3x3Invalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView boolInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolInvalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView stringInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringInvalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + MetadataPropertyView uint8Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Invalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + + MetadataPropertyView int32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + int32Invalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + + MetadataPropertyView uint64Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint64Invalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + MetadataPropertyView> uint32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint32ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Wrong buffer index") { + model.bufferViews[valueBufferViewIndex].buffer = 2; + MetadataPropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Property.status() == + MetadataPropertyViewStatus::ErrorInvalidValueBuffer); + } + + SECTION("Wrong buffer view index") { + propertyTableProperty.values = -1; + MetadataPropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Property.status() == + MetadataPropertyViewStatus::ErrorInvalidValueBufferView); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[valueBufferIndex].cesium.data.resize(12); + MetadataPropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Property.status() == + MetadataPropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Buffer view length isn't multiple of sizeof(T)") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + MetadataPropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Property.status() == + MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Buffer view length doesn't match with propertyTableCount") { + model.bufferViews[valueBufferViewIndex].byteLength = 12; + MetadataPropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Property.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test StructuralMetadata vecN property") { + Model model; + + std::vector values = { + glm::ivec3(-12, 34, 30), + glm::ivec3(11, 73, 0), + glm::ivec3(-2, 6, 12), + glm::ivec3(-4, 8, -13)}; + + size_t valueBufferIndex = 0; + size_t valueBufferViewIndex = 0; + + // Buffers are constructed in scope to ensure that the tests don't use their + // temporary variables. + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(glm::ivec3)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::VEC3; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + MetadataPropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(ivec3Property.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(ivec3Property.size() > 0); + + for (int64_t i = 0; i < ivec3Property.size(); ++i) { + REQUIRE(ivec3Property.get(i) == values[i]); + } + } + + SECTION("Access wrong type") { + MetadataPropertyView int32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + int32Invalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView ivec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec2Invalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView i32mat3x3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i32mat3x3Invalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView boolInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolInvalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView stringInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringInvalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + MetadataPropertyView u8vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec3Invalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + + MetadataPropertyView i16vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i16vec3Invalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + + MetadataPropertyView vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + vec3Invalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + MetadataPropertyView> ivec3ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + ivec3ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Wrong buffer index") { + model.bufferViews[valueBufferViewIndex].buffer = 2; + MetadataPropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + MetadataPropertyViewStatus::ErrorInvalidValueBuffer); + } + + SECTION("Wrong buffer view index") { + propertyTableProperty.values = -1; + MetadataPropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + MetadataPropertyViewStatus::ErrorInvalidValueBufferView); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[valueBufferIndex].cesium.data.resize(12); + MetadataPropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + MetadataPropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Buffer view length isn't multiple of sizeof(T)") { + model.bufferViews[valueBufferViewIndex].byteLength = 11; + MetadataPropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Buffer view length doesn't match with propertyTableCount") { + model.bufferViews[valueBufferViewIndex].byteLength = 12; + MetadataPropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test StructuralMetadata matN property") { + Model model; + + // clang-format off + std::vector values = { + glm::u32mat2x2( + 12, 34, + 30, 1), + glm::u32mat2x2( + 11, 8, + 73, 102), + glm::u32mat2x2( + 1, 0, + 63, 2), + glm::u32mat2x2( + 4, 8, + 3, 23)}; + // clang-format on + + size_t valueBufferIndex = 0; + size_t valueBufferViewIndex = 0; + + // Buffers are constructed in scope to ensure that the tests don't use their + // temporary variables. + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(glm::u32mat2x2)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::MAT2; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::MAT2); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + MetadataPropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(u32mat2x2Property.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(u32mat2x2Property.size() > 0); + + for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { + REQUIRE(u32mat2x2Property.get(i) == values[i]); + } + } + + SECTION("Access wrong type") { + MetadataPropertyView uint32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Invalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView uvec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uvec2Invalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView u32mat4x4Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat4x4Invalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView boolInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolInvalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView stringInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringInvalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + MetadataPropertyView u8mat2x2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8mat2x2Invalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + + MetadataPropertyView i32mat2x2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i32mat2x2Invalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + + MetadataPropertyView mat2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + mat2Invalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + MetadataPropertyView> + u32mat2x2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + u32mat2x2ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Wrong buffer index") { + model.bufferViews[valueBufferViewIndex].buffer = 2; + MetadataPropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + MetadataPropertyViewStatus::ErrorInvalidValueBuffer); + } + + SECTION("Wrong buffer view index") { + propertyTableProperty.values = -1; + MetadataPropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + MetadataPropertyViewStatus::ErrorInvalidValueBufferView); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[valueBufferIndex].cesium.data.resize(sizeof(glm::u32mat2x2)); + MetadataPropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + MetadataPropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Buffer view length isn't multiple of sizeof(T)") { + model.bufferViews[valueBufferViewIndex].byteLength = + sizeof(glm::u32mat2x2) * 4 - 1; + MetadataPropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Buffer view length doesn't match with propertyTableCount") { + model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::u32mat2x2); + + MetadataPropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test StructuralMetadata boolean properties") { + Model model; + + int64_t instanceCount = 21; + std::vector expected; + std::vector values; + values.resize(3); + for (int64_t i = 0; i < instanceCount; ++i) { + if (i % 2 == 0) { + expected.emplace_back(true); + } else { + expected.emplace_back(false); + } + + uint8_t expectedValue = expected.back(); + int64_t byteIndex = i / 8; + int64_t bitIndex = i % 8; + values[static_cast(byteIndex)] = static_cast( + (expectedValue << bitIndex) | values[static_cast(byteIndex)]); + } + + // Buffers are constructed in scope to ensure that the tests don't use their + // temporary variables. + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size()); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(instanceCount); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->componentType == std::nullopt); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + MetadataPropertyView boolProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE(boolProperty.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(boolProperty.size() == instanceCount); + for (int64_t i = 0; i < boolProperty.size(); ++i) { + bool expectedValue = expected[static_cast(i)]; + REQUIRE(boolProperty.get(i) == expectedValue); + } + } + + SECTION("Buffer size doesn't match with propertyTableCount") { + propertyTable.count = 66; + MetadataPropertyView boolProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test StructuralMetadata string property") { + Model model; + + std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; + size_t totalBytes = 0; + for (const std::string& expectedValue : expected) { + totalBytes += expectedValue.size(); + } + + std::vector stringOffsets( + (expected.size() + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(stringOffsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + const std::string& expectedValue = expected[i]; + std::memcpy( + values.data() + offsetValue[i], + expectedValue.c_str(), + expectedValue.size()); + offsetValue[i + 1] = + offsetValue[i] + static_cast(expectedValue.size()); + } + + // Buffers are constructed in scope to ensure that the tests don't use their + // temporary variables. + size_t valueBufferIndex = 0; + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.byteLength = static_cast(values.size()); + valueBuffer.cesium.data = std::move(values); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(valueBufferIndex); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + size_t offsetBufferIndex = 0; + size_t offsetBufferViewIndex = 0; + { + Buffer& offsetBuffer = model.buffers.emplace_back(); + offsetBuffer.byteLength = static_cast(stringOffsets.size()); + offsetBuffer.cesium.data = std::move(stringOffsets); + offsetBufferIndex = model.buffers.size() - 1; + + BufferView& offsetBufferView = model.bufferViews.emplace_back(); + offsetBufferView.buffer = static_cast(offsetBufferIndex); + offsetBufferView.byteOffset = 0; + offsetBufferView.byteLength = offsetBuffer.byteLength; + offsetBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::STRING; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.stringOffsets = + static_cast(offsetBufferViewIndex); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::STRING); + REQUIRE(classProperty->componentType == std::nullopt); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + MetadataPropertyView stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE(stringProperty.status() == MetadataPropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + REQUIRE(stringProperty.get(static_cast(i)) == expected[i]); + } + } + + SECTION("Wrong offset type") { + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT8; + MetadataPropertyView stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT64; + stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.stringOffsetType = "NONSENSE"; + stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + + propertyTableProperty.stringOffsetType = ""; + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT32; + stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + uint32_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[2] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + MetadataPropertyView stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint32_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + MetadataPropertyView stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + } +} + +TEST_CASE("Test StructuralMetadata fixed-length scalar array") { + Model model; + + std::vector values = + {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; + + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + testClassProperty.array = true; + testClassProperty.count = 3; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + + SECTION("Access the right type") { + MetadataPropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE(arrayProperty.status() == MetadataPropertyViewStatus::Valid); + + for (int64_t i = 0; i < arrayProperty.size(); ++i) { + MetadataArrayView member = arrayProperty.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 3 + j)]); + } + } + } + + SECTION("Wrong type") { + MetadataPropertyView> boolArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView> uvec2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + uvec2ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Wrong component type") { + MetadataPropertyView> int32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + int32ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Not an array type") { + MetadataPropertyView uint32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Invalid.status() == + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Buffer size is not a multiple of type size") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + MetadataPropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Negative component count") { + testClassProperty.count = -1; + MetadataPropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Value buffer doesn't fit into property table count") { + testClassProperty.count = 55; + MetadataPropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test Structural Metadata variable-length scalar array") { + Model model; + + std::vector> expected{ + {12, 33, 11, 344, 112, 444, 1}, + {}, + {}, + {122, 23, 333, 12}, + {}, + {333, 311, 22, 34}, + {}, + {33, 1888, 233, 33019}}; + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + std::vector values(numOfElements * sizeof(uint16_t)); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + std::memcpy( + values.data() + offsetValue[i], + expected[i].data(), + expected[i].size() * sizeof(uint16_t)); + offsetValue[i + 1] = offsetValue[i] + expected[i].size() * sizeof(uint16_t); + } + + size_t valueBufferIndex = 0; + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.byteLength = static_cast(values.size()); + valueBuffer.cesium.data = std::move(values); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + size_t offsetBufferIndex = 0; + size_t offsetBufferViewIndex = 0; + { + Buffer& offsetBuffer = model.buffers.emplace_back(); + offsetBuffer.byteLength = static_cast(offsets.size()); + offsetBuffer.cesium.data = std::move(offsets); + offsetBufferIndex = model.buffers.size() - 1; + + BufferView& offsetBufferView = model.bufferViews.emplace_back(); + offsetBufferView.buffer = static_cast(model.buffers.size() - 1); + offsetBufferView.byteOffset = 0; + offsetBufferView.byteLength = offsetBuffer.byteLength; + offsetBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16; + testClassProperty.array = true; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT64; + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + + SECTION("Access the correct type") { + MetadataPropertyView> property = + view.getPropertyView>("TestClassProperty"); + REQUIRE(property.status() == MetadataPropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + MetadataArrayView valueMember = + property.get(static_cast(i)); + REQUIRE(valueMember.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + REQUIRE(expected[i][j] == valueMember[static_cast(j)]); + } + } + } + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT8; + MetadataPropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT16; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT64; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + MetadataPropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + MetadataPropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer are both present") { + testClassProperty.count = 3; + MetadataPropertyView> property = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + property.status() == + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test StructuralMetadata fixed-length vecN array") { + Model model; + + std::vector values = { + glm::ivec3(12, 34, -30), + glm::ivec3(-2, 0, 1), + glm::ivec3(1, 2, 8), + glm::ivec3(-100, 84, 6), + glm::ivec3(2, -2, -2), + glm::ivec3(40, 61, 3), + }; + + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(glm::ivec3)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::VEC3; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + SECTION("Access the right type") { + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(arrayProperty.status() == MetadataPropertyViewStatus::Valid); + + for (int64_t i = 0; i < arrayProperty.size(); ++i) { + MetadataArrayView member = arrayProperty.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + } + } + } + + SECTION("Wrong type") { + MetadataPropertyView> int32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + int32ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView> ivec2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + ivec2ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Wrong component type") { + MetadataPropertyView> uvec3ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + uvec3ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Not an array type") { + MetadataPropertyView ivec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Invalid.status() == + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Buffer size is not a multiple of type size") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Negative component count") { + testClassProperty.count = -1; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Value buffer doesn't fit into property table count") { + testClassProperty.count = 55; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test Structural Metadata variable-length vecN array") { + Model model; + + // clang-format off + std::vector> expected{ + { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1) }, + { glm::ivec3(1, 2, 8), }, + {}, + { glm::ivec3(-100, 84, 6), glm::ivec3(2, -2, -2), glm::ivec3(40, 61, 3) }, + { glm::ivec3(-1, 4, -7) }, + }; + // clang-format on + + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + std::vector values(numOfElements * sizeof(glm::ivec3)); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + std::memcpy( + values.data() + offsetValue[i], + expected[i].data(), + expected[i].size() * sizeof(glm::ivec3)); + offsetValue[i + 1] = + offsetValue[i] + expected[i].size() * sizeof(glm::ivec3); + } + + size_t valueBufferIndex = 0; + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.byteLength = static_cast(values.size()); + valueBuffer.cesium.data = std::move(values); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + size_t offsetBufferIndex = 0; + size_t offsetBufferViewIndex = 0; + { + Buffer& offsetBuffer = model.buffers.emplace_back(); + offsetBuffer.byteLength = static_cast(offsets.size()); + offsetBuffer.cesium.data = std::move(offsets); + offsetBufferIndex = model.buffers.size() - 1; + + BufferView& offsetBufferView = model.bufferViews.emplace_back(); + offsetBufferView.buffer = static_cast(model.buffers.size() - 1); + offsetBufferView.byteOffset = 0; + offsetBufferView.byteLength = offsetBuffer.byteLength; + offsetBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::VEC3; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + testClassProperty.array = true; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT64; + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + + SECTION("Access the correct type") { + MetadataPropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(property.status() == MetadataPropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + MetadataArrayView valueMember = + property.get(static_cast(i)); + REQUIRE(valueMember.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + REQUIRE(expected[i][j] == valueMember[static_cast(j)]); + } + } + } + + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT8; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT16; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT64; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer are both present") { + testClassProperty.count = 3; + MetadataPropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + property.status() == + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test StructuralMetadata fixed-length matN array") { + Model model; + + // clang-format off + std::vector values = { + glm::i32mat2x2( + 12, 34, + -30, 20), + glm::i32mat2x2( + -2, -2, + 0, 1), + glm::i32mat2x2( + 1, 2, + 8, 5), + glm::i32mat2x2( + -100, 3, + 84, 6), + glm::i32mat2x2( + 2, 12, + -2, -2), + glm::i32mat2x2( + 40, 61, + 7, -3), + }; + // clang-format on + + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(glm::i32mat2x2)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::MAT2; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::MAT2); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + SECTION("Access the right type") { + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(arrayProperty.status() == MetadataPropertyViewStatus::Valid); + + for (int64_t i = 0; i < arrayProperty.size(); ++i) { + MetadataArrayView member = arrayProperty.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + } + } + } + + SECTION("Wrong type") { + MetadataPropertyView> int32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + int32ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + + MetadataPropertyView> ivec2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + ivec2ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Wrong component type") { + MetadataPropertyView> + u32mat2x2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + u32mat2x2ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Not an array type") { + MetadataPropertyView ivec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Invalid.status() == + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Buffer size is not a multiple of type size") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Negative component count") { + testClassProperty.count = -1; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Value buffer doesn't fit into property table count") { + testClassProperty.count = 55; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test Structural Metadata variable-length matN array") { + Model model; + + // clang-format off + std::vector data0{ + glm::i32mat2x2( + 3, -2, + 1, 0), + glm::i32mat2x2( + 40, 3, + 8, -9) + }; + std::vector data1{ + glm::i32mat2x2( + 1, 10, + 7, 8), + }; + std::vector data2{ + glm::i32mat2x2( + 18, 0, + 1, 17), + glm::i32mat2x2( + -4, -2, + -9, 1), + glm::i32mat2x2( + 1, 8, + -99, 3), + }; + // clang-format on + + std::vector> + expected{data0, {}, data1, data2, {}}; + + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + std::vector values(numOfElements * sizeof(glm::i32mat2x2)); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + std::memcpy( + values.data() + offsetValue[i], + expected[i].data(), + expected[i].size() * sizeof(glm::i32mat2x2)); + offsetValue[i + 1] = + offsetValue[i] + expected[i].size() * sizeof(glm::i32mat2x2); + } + + size_t valueBufferIndex = 0; + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.byteLength = static_cast(values.size()); + valueBuffer.cesium.data = std::move(values); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + size_t offsetBufferIndex = 0; + size_t offsetBufferViewIndex = 0; + { + Buffer& offsetBuffer = model.buffers.emplace_back(); + offsetBuffer.byteLength = static_cast(offsets.size()); + offsetBuffer.cesium.data = std::move(offsets); + offsetBufferIndex = model.buffers.size() - 1; + + BufferView& offsetBufferView = model.bufferViews.emplace_back(); + offsetBufferView.buffer = static_cast(model.buffers.size() - 1); + offsetBufferView.byteOffset = 0; + offsetBufferView.byteLength = offsetBuffer.byteLength; + offsetBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::MAT2; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + testClassProperty.array = true; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT64; + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::MAT2); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + + SECTION("Access the correct type") { + MetadataPropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(property.status() == MetadataPropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + MetadataArrayView valueMember = + property.get(static_cast(i)); + REQUIRE(valueMember.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + REQUIRE(expected[i][j] == valueMember[static_cast(j)]); + } + } + } + + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT8; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT16; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT64; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer are both present") { + testClassProperty.count = 3; + MetadataPropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + property.status() == + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test StructuralMetadata fixed-length boolean array") { + Model model; + + std::vector expected = { + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true}; + std::vector values; + size_t requiredBytesSize = static_cast( + glm::ceil(static_cast(expected.size()) / 8.0)); + values.resize(requiredBytesSize); + for (size_t i = 0; i < expected.size(); ++i) { + uint8_t expectedValue = expected[i]; + size_t byteIndex = i / 8; + size_t bitIndex = i % 8; + values[byteIndex] = + static_cast((expectedValue << bitIndex) | values[byteIndex]); + } + + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size()); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + testClassProperty.array = true; + testClassProperty.count = 3; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + expected.size() / static_cast(testClassProperty.count.value())); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + + SECTION("Access correct type") { + MetadataPropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE(boolArrayProperty.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(boolArrayProperty.size() == propertyTable.count); + REQUIRE(boolArrayProperty.size() > 0); + for (int64_t i = 0; i < boolArrayProperty.size(); ++i) { + MetadataArrayView valueMember = boolArrayProperty.get(i); + for (int64_t j = 0; j < valueMember.size(); ++j) { + REQUIRE(valueMember[j] == expected[static_cast(i * 3 + j)]); + } + } + } + + SECTION("Wrong type") { + MetadataPropertyView> uint8ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("View is not array type") { + MetadataPropertyView boolInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolInvalid.status() == + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Value buffer doesn't have enough required bytes") { + testClassProperty.count = 11; + MetadataPropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } + + SECTION("Count is negative") { + testClassProperty.count = -1; + MetadataPropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + } +} + +TEST_CASE("Test StructuralMetadata variable-length boolean array") { + Model model; + + std::vector> expected{ + {true, false, true, true, false, true, true}, + {}, + {}, + {}, + {false, false, false, false}, + {true, false, true}, + {false}, + {true, true, true, true, true, false, false}}; + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + size_t requiredBytesSize = + static_cast(glm::ceil(static_cast(numOfElements) / 8.0)); + std::vector values(requiredBytesSize); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + size_t indexSoFar = 0; + for (size_t i = 0; i < expected.size(); ++i) { + for (size_t j = 0; j < expected[i].size(); ++j) { + uint8_t expectedValue = expected[i][j]; + size_t byteIndex = indexSoFar / 8; + size_t bitIndex = indexSoFar % 8; + values[byteIndex] = static_cast( + (expectedValue << bitIndex) | static_cast(values[byteIndex])); + ++indexSoFar; + } + offsetValue[i + 1] = offsetValue[i] + expected[i].size(); + } + + size_t valueBufferViewIndex = 0; + size_t valueBufferIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.byteLength = static_cast(values.size()); + valueBuffer.cesium.data = std::move(values); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(valueBufferIndex); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + size_t offsetBufferIndex = 0; + size_t offsetBufferViewIndex = 0; + { + Buffer& offsetBuffer = model.buffers.emplace_back(); + offsetBuffer.byteLength = static_cast(offsets.size()); + offsetBuffer.cesium.data = std::move(offsets); + offsetBufferIndex = model.buffers.size() - 1; + + BufferView& offsetBufferView = model.bufferViews.emplace_back(); + offsetBufferView.buffer = static_cast(offsetBufferIndex); + offsetBufferView.byteOffset = 0; + offsetBufferView.byteLength = offsetBuffer.byteLength; + offsetBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + testClassProperty.array = true; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT64; + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + + SECTION("Access correct type") { + MetadataPropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE(boolArrayProperty.status() == MetadataPropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + MetadataArrayView arrayMember = + boolArrayProperty.get(static_cast(i)); + REQUIRE(arrayMember.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + REQUIRE(expected[i][j] == arrayMember[static_cast(j)]); + } + } + } + + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT8; + MetadataPropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT16; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT64; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + MetadataPropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = static_cast( + model.buffers[valueBufferIndex].byteLength * 8 + 20); + MetadataPropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer both present") { + testClassProperty.count = 3; + MetadataPropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { + Model model; + + std::vector expected{ + "What's up", + "Breaking news!!! Aliens no longer attacks the US first", + "But they still abduct my cows! Those milk thiefs! 👽 🐮", + "I'm not crazy. My mother had me tested 🤪", + "I love you, meat bags! ❤️", + "Book in the freezer"}; + + size_t totalBytes = 0; + for (const std::string& expectedValue : expected) { + totalBytes += expectedValue.size(); + } + + std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + const std::string& expectedValue = expected[i]; + std::memcpy( + values.data() + offsetValue[i], + expectedValue.c_str(), + expectedValue.size()); + offsetValue[i + 1] = + offsetValue[i] + static_cast(expectedValue.size()); + } + + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.byteLength = static_cast(values.size()); + valueBuffer.cesium.data = std::move(values); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + size_t offsetBufferViewIndex = 0; + { + Buffer& offsetBuffer = model.buffers.emplace_back(); + offsetBuffer.byteLength = static_cast(offsets.size()); + offsetBuffer.cesium.data = std::move(offsets); + + BufferView& offsetBufferView = model.bufferViews.emplace_back(); + offsetBufferView.buffer = static_cast(model.buffers.size() - 1); + offsetBufferView.byteOffset = 0; + offsetBufferView.byteLength = offsetBuffer.byteLength; + offsetBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::STRING; + testClassProperty.array = true; + testClassProperty.count = 2; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + expected.size() / static_cast(testClassProperty.count.value())); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.stringOffsets = + static_cast(offsetBufferViewIndex); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::STRING); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + SECTION("Access correct type") { + MetadataPropertyView> stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(stringProperty.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(stringProperty.size() == 3); + + MetadataArrayView v0 = stringProperty.get(0); + REQUIRE(v0.size() == 2); + REQUIRE(v0[0] == "What's up"); + REQUIRE(v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); + + MetadataArrayView v1 = stringProperty.get(1); + REQUIRE(v1.size() == 2); + REQUIRE(v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); + REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); + + MetadataArrayView v2 = stringProperty.get(2); + REQUIRE(v2.size() == 2); + REQUIRE(v2[0] == "I love you, meat bags! ❤️"); + REQUIRE(v2[1] == "Book in the freezer"); + } + + SECTION("Array type mismatch") { + MetadataPropertyView stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Count is negative") { + testClassProperty.count = -1; + MetadataPropertyView> stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Offset type is unknown") { + propertyTableProperty.stringOffsetType = "NONSENSE"; + MetadataPropertyView> stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + + propertyTableProperty.stringOffsetType = ""; + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT32; + stringProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + } + + SECTION("String offsets don't exist") { + propertyTableProperty.stringOffsets = -1; + MetadataPropertyView> stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + stringProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidStringOffsetBufferView); + } +} + +TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { + Model model; + + std::vector> expected{ + {"What's up"}, + {"Breaking news!!! Aliens no longer attacks the US first", + "But they still abduct my cows! Those milk thiefs! 👽 🐮"}, + {"I'm not crazy. My mother had me tested 🤪", + "I love you, meat bags! ❤️", + "Book in the freezer"}}; + + size_t totalBytes = 0; + size_t numOfElements = 0; + for (const auto& expectedValues : expected) { + for (const auto& value : expectedValues) { + totalBytes += value.size(); + } + + numOfElements += expectedValues.size(); + } + + std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); + std::vector stringOffsets((numOfElements + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(offsets.data()); + uint32_t* stringOffsetValue = + reinterpret_cast(stringOffsets.data()); + size_t strOffsetIdx = 0; + for (size_t i = 0; i < expected.size(); ++i) { + for (size_t j = 0; j < expected[i].size(); ++j) { + const std::string& expectedValue = expected[i][j]; + std::memcpy( + values.data() + stringOffsetValue[strOffsetIdx], + expectedValue.c_str(), + expectedValue.size()); + + stringOffsetValue[strOffsetIdx + 1] = + stringOffsetValue[strOffsetIdx] + + static_cast(expectedValue.size()); + ++strOffsetIdx; + } + + offsetValue[i + 1] = + offsetValue[i] + + static_cast(expected[i].size() * sizeof(uint32_t)); + } + + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.byteLength = static_cast(values.size()); + valueBuffer.cesium.data = std::move(values); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + size_t arrayOffsetBuffer = 0; + size_t arrayOffsetBufferView = 0; + { + Buffer& offsetBuffer = model.buffers.emplace_back(); + offsetBuffer.byteLength = static_cast(offsets.size()); + offsetBuffer.cesium.data = std::move(offsets); + arrayOffsetBuffer = model.buffers.size() - 1; + + BufferView& offsetBufferView = model.bufferViews.emplace_back(); + offsetBufferView.buffer = static_cast(arrayOffsetBuffer); + offsetBufferView.byteOffset = 0; + offsetBufferView.byteLength = offsetBuffer.byteLength; + arrayOffsetBufferView = model.bufferViews.size() - 1; + } + + size_t stringOffsetBuffer = 0; + size_t stringOffsetBufferView = 0; + { + Buffer& strOffsetBuffer = model.buffers.emplace_back(); + strOffsetBuffer.byteLength = static_cast(stringOffsets.size()); + strOffsetBuffer.cesium.data = std::move(stringOffsets); + stringOffsetBuffer = model.buffers.size() - 1; + + BufferView& strOffsetBufferView = model.bufferViews.emplace_back(); + strOffsetBufferView.buffer = static_cast(stringOffsetBuffer); + strOffsetBufferView.byteOffset = 0; + strOffsetBufferView.byteLength = strOffsetBuffer.byteLength; + stringOffsetBufferView = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::STRING; + testClassProperty.array = true; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT32; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(arrayOffsetBufferView); + propertyTableProperty.stringOffsets = + static_cast(stringOffsetBufferView); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::STRING); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->componentType); + REQUIRE(!classProperty->count); + + SECTION("Access correct type") { + MetadataPropertyView> stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(stringProperty.status() == MetadataPropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + MetadataArrayView stringArray = + stringProperty.get(static_cast(i)); + for (size_t j = 0; j < expected[i].size(); ++j) { + REQUIRE(stringArray[static_cast(j)] == expected[i][j]); + } + } + } + + SECTION("Wrong array offset type") { + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT8; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT16; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + propertyTableProperty.arrayOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: + UINT32; + } + + SECTION("Wrong string offset type") { + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT8; + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT16; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.stringOffsetType = "NONSENSE"; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT32; + } + + SECTION("Array offset values are not sorted ascending") { + uint32_t* offset = reinterpret_cast( + model.buffers[arrayOffsetBuffer].cesium.data.data()); + offset[0] = static_cast(1000); + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted); + offset[0] = 0; + } + + SECTION("String offset values are not sorted ascending") { + uint32_t* offset = reinterpret_cast( + model.buffers[stringOffsetBuffer].cesium.data.data()); + offset[0] = static_cast(1000); + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted); + offset[0] = 0; + } + + SECTION("Array offset value points outside of value buffer") { + uint32_t* offset = reinterpret_cast( + model.buffers[arrayOffsetBuffer].cesium.data.data()); + uint32_t previousValue = offset[propertyTable.count]; + offset[propertyTable.count] = static_cast(100000); + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + offset[propertyTable.count] = previousValue; + } + + SECTION("String offset value points outside of value buffer") { + uint32_t* offset = reinterpret_cast( + model.buffers[stringOffsetBuffer].cesium.data.data()); + uint32_t previousValue = offset[6]; + offset[6] = static_cast(100000); + MetadataPropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + offset[6] = previousValue; + } + + SECTION("Count and offset buffer both present") { + testClassProperty.count = 3; + MetadataPropertyView> + boolArrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} From 352d0d20bb22a586acc0806a5eb5825d644ab4ab Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 19 May 2023 16:20:38 -0400 Subject: [PATCH 020/121] Try to fix compile errors --- .../StructuralMetadataPropertyTableView.h | 17 +++++++++++------ .../src/StructuralMetadataPropertyTableView.cpp | 1 - 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index b656b37c3..372b0a87c 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -108,8 +108,11 @@ class MetadataPropertyTableView { } PropertyType type = convertStringToPropertyType(pClassProperty->type); - PropertyComponentType componentType = - convertStringToPropertyType(pClassProperty->componentType); + PropertyComponentType componentType = PropertyComponentType::None; + if (pClassProperty->componentType) { + componentType = + convertStringToPropertyComponentType(*pClassProperty->componentType); + } if (pClassProperty->array) { getArrayPropertyViewImpl( @@ -167,7 +170,7 @@ class MetadataPropertyTableView { } private: - glm::length_t getDimensionsFromType(PropertyType type) { + glm::length_t getDimensionsFromType(PropertyType type) const { switch (type) { case PropertyType::Vec2: case PropertyType::Mat2: @@ -360,7 +363,7 @@ class MetadataPropertyTableView { PropertyType type, PropertyComponentType componentType, Callback&& callback) const { - glm::length_t N = getDimensionsFromType(type); + const glm::length_t N = getDimensionsFromType(type); if (N <= 1) { return; } @@ -453,7 +456,7 @@ class MetadataPropertyTableView { propertyName, classProperty, componentType, - std::forward(callback)) + std::forward(callback)); } else if (isPropertyTypeVecN(type)) { getVecNArrayPropertyViewImpl( propertyName, @@ -487,13 +490,14 @@ class MetadataPropertyTableView { template void getVecNPropertyViewImpl( + const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, PropertyType type, PropertyComponentType componentType, Callback&& callback) { - glm::length_t N = getDimensionsFromType(type); + const glm::length_t N = getDimensionsFromType(type); if (N <= 1) { return; } @@ -574,6 +578,7 @@ class MetadataPropertyTableView { template void getMatNPropertyViewImpl( + const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp index 2c17c1259..115ad0129 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -420,7 +420,6 @@ MetadataPropertyTableView::getStringArrayPropertyValues( MetadataPropertyViewStatus::ErrorInvalidArrayOffsetBufferView); } - // Handle variable-length arrays gsl::span stringOffsets; status = getBufferSafe(propertyTableProperty.stringOffsets, stringOffsets); From d7f58dab33889884bda5202ea0c54be715618e54 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 22 May 2023 11:58:37 -0400 Subject: [PATCH 021/121] Rewrite how vecN / matN are handled --- .../StructuralMetadataPropertyTableView.h | 177 +++++++++++++++--- 1 file changed, 146 insertions(+), 31 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index 372b0a87c..155d758fd 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -125,12 +125,14 @@ class MetadataPropertyTableView { getVecNPropertyViewImpl( propertyName, *pClassProperty, + type, componentType, std::forward(callback)); } else if (isPropertyTypeMatN(type)) { getMatNPropertyViewImpl( propertyName, *pClassProperty, + type, componentType, std::forward(callback)); } else { @@ -268,18 +270,12 @@ class MetadataPropertyTableView { } } - template + template void getVecNArrayPropertyViewImpl( const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty, - PropertyType type, PropertyComponentType componentType, Callback&& callback) const { - glm::length_t N = getDimensionsFromType(type); - if (N <= 1) { - return; - } - switch (componentType) { case PropertyComponentType::Int8: callback( @@ -357,17 +353,46 @@ class MetadataPropertyTableView { } template - void getMatNArrayPropertyViewImpl( + void getVecNArrayPropertyViewImpl( const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty, PropertyType type, PropertyComponentType componentType, Callback&& callback) const { - const glm::length_t N = getDimensionsFromType(type); - if (N <= 1) { - return; + glm::length_t N = getDimensionsFromType(type); + switch (N) { + case 2: + getVecNArrayPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + case 3: + getVecNArrayPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + case 4: + getVecNArrayPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + default: + break; } + } + template + void getMatNArrayPropertyViewImpl( + const std::string& propertyName, + const ExtensionExtStructuralMetadataClassProperty& classProperty, + PropertyComponentType componentType, + Callback&& callback) const { switch (componentType) { case PropertyComponentType::Int8: callback( @@ -444,6 +469,41 @@ class MetadataPropertyTableView { } } + template + void getMatNArrayPropertyViewImpl( + const std::string& propertyName, + const ExtensionExtStructuralMetadataClassProperty& classProperty, + PropertyType type, + PropertyComponentType componentType, + Callback&& callback) const { + const glm::length_t N = getDimensionsFromType(type); + switch (N) { + case 2: + getMatNArrayPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + case 3: + getMatNArrayPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + case 4: + getMatNArrayPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + default: + break; + } + } + template void getArrayPropertyViewImpl( const std::string& propertyName, @@ -488,19 +548,12 @@ class MetadataPropertyTableView { } } - template + template void getVecNPropertyViewImpl( const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty, - PropertyType type, PropertyComponentType componentType, - Callback&& callback) { - const glm::length_t N = getDimensionsFromType(type); - if (N <= 1) { - return; - } + Callback&& callback) const { switch (componentType) { case PropertyComponentType::Int8: @@ -577,25 +630,53 @@ class MetadataPropertyTableView { } template - void getMatNPropertyViewImpl( + void getVecNPropertyViewImpl( const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty, PropertyType type, PropertyComponentType componentType, - Callback&& callback) { - glm::length_t N = getDimensionsFromType(type); - if (N <= 1) { - return; + Callback&& callback) const { + const glm::length_t N = getDimensionsFromType(type); + switch (N) { + case 2: + getVecNPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + case 3: + getVecNPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + case 4: + getVecNPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + default: + break; } + } + template + void getMatNPropertyViewImpl( + const std::string& propertyName, + const ExtensionExtStructuralMetadataClassProperty& classProperty, + PropertyComponentType componentType, + Callback&& callback) const { switch (componentType) { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl < - glm::mat(propertyName, classProperty)); + getPropertyViewImpl>( + propertyName, + classProperty)); break; case PropertyComponentType::Uint8: callback( @@ -665,11 +746,45 @@ class MetadataPropertyTableView { } } + template + void getMatNPropertyViewImpl( + const std::string& propertyName, + const ExtensionExtStructuralMetadataClassProperty& classProperty, + PropertyType type, + PropertyComponentType componentType, + Callback&& callback) const { + glm::length_t N = getDimensionsFromType(type); + switch (N) { + case 2: + getMatNPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + case 3: + getMatNPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + case 4: + getMatNPropertyViewImpl( + propertyName, + classProperty, + componentType, + callback); + break; + default: + break; + } + } + template void getPrimitivePropertyViewImpl( + const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty, PropertyType type, PropertyComponentType componentType, Callback&& callback) const { From efb95c565990a095672ac8047ee5da7c12b989db Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 22 May 2023 15:29:14 -0400 Subject: [PATCH 022/121] Verify that callbacks work with unit tests --- .../StructuralMetadataPropertyTableView.h | 26 +- ...estStructuralMetadataPropertyTableView.cpp | 471 ++++++++++++++++++ 2 files changed, 484 insertions(+), 13 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index 155d758fd..4a7664c40 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -366,21 +366,21 @@ class MetadataPropertyTableView { propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; case 3: getVecNArrayPropertyViewImpl( propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; case 4: getVecNArrayPropertyViewImpl( propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; default: break; @@ -483,21 +483,21 @@ class MetadataPropertyTableView { propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; case 3: getMatNArrayPropertyViewImpl( propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; case 4: getMatNArrayPropertyViewImpl( propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; default: break; @@ -643,21 +643,21 @@ class MetadataPropertyTableView { propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; case 3: getVecNPropertyViewImpl( propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; case 4: getVecNPropertyViewImpl( propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; default: break; @@ -723,7 +723,7 @@ class MetadataPropertyTableView { case PropertyComponentType::Uint64: callback( propertyName, - getPropertyViewImp>( + getPropertyViewImpl>( propertyName, classProperty)); break; @@ -760,21 +760,21 @@ class MetadataPropertyTableView { propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; case 3: getMatNPropertyViewImpl( propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; case 4: getMatNPropertyViewImpl( propertyName, classProperty, componentType, - callback); + std::forward(callback)); break; default: break; diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp index e948a5dc6..f0303449a 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -2589,3 +2589,474 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } } + +TEST_CASE("Test StructuralMetadata callback for scalar property") { + Model model; + std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; + + size_t valueBufferIndex = 0; + size_t valueBufferViewIndex = 0; + + // Buffers are constructed in scope to ensure that the tests don't use their + // temporary variables. + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->count == std::nullopt); + + view.getPropertyView( + "TestClassProperty", + [&values]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + MetadataPropertyView, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + REQUIRE( + static_cast(propertyValue.get(i)) == + values[static_cast(i)]); + } + } else { + FAIL("getPropertyView returned MetadataPropertyView of incorrect " + "type for TestClassProperty."); + } + }); +} + +TEST_CASE("Test StructuralMetadata callback for vecN property") { + Model model; + + std::vector values = { + glm::ivec3(-12, 34, 30), + glm::ivec3(11, 73, 0), + glm::ivec3(-2, 6, 12), + glm::ivec3(-4, 8, -13)}; + + size_t valueBufferIndex = 0; + size_t valueBufferViewIndex = 0; + + // Buffers are constructed in scope to ensure that the tests don't use their + // temporary variables. + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(glm::ivec3)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::VEC3; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + view.getPropertyView( + "TestClassProperty", + [&values]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + MetadataPropertyView, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + REQUIRE( + static_cast(propertyValue.get(i)) == + values[static_cast(i)]); + } + } else { + FAIL("getPropertyView returned MetadataPropertyView of incorrect " + "type for TestClassProperty."); + } + }); +} + +TEST_CASE("Test StructuralMetadata callback for matN property") { + Model model; + + // clang-format off + std::vector values = { + glm::u32mat2x2( + 12, 34, + 30, 1), + glm::u32mat2x2( + 11, 8, + 73, 102), + glm::u32mat2x2( + 1, 0, + 63, 2), + glm::u32mat2x2( + 4, 8, + 3, 23)}; + // clang-format on + + size_t valueBufferViewIndex = 0; + + // Buffers are constructed in scope to ensure that the tests don't use their + // temporary variables. + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(glm::u32mat2x2)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::MAT2; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::MAT2); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + view.getPropertyView( + "TestClassProperty", + [&values]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + MetadataPropertyView, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + REQUIRE( + static_cast(propertyValue.get(i)) == + values[static_cast(i)]); + } + } else { + FAIL("getPropertyView returned MetadataPropertyView of incorrect " + "type for TestClassProperty."); + } + }); +} + +TEST_CASE("Test StructuralMetadata callback for boolean property") { + Model model; + + int64_t instanceCount = 21; + std::vector expected; + std::vector values; + values.resize(3); + for (int64_t i = 0; i < instanceCount; ++i) { + if (i % 2 == 0) { + expected.emplace_back(true); + } else { + expected.emplace_back(false); + } + + uint8_t expectedValue = expected.back(); + int64_t byteIndex = i / 8; + int64_t bitIndex = i % 8; + values[static_cast(byteIndex)] = static_cast( + (expectedValue << bitIndex) | values[static_cast(byteIndex)]); + } + + // Buffers are constructed in scope to ensure that the tests don't use their + // temporary variables. + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size()); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(instanceCount); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->componentType == std::nullopt); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + view.getPropertyView( + "TestClassProperty", + [&expected]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + MetadataPropertyView, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + REQUIRE( + static_cast(propertyValue.get(i)) == + expected[static_cast(i)]); + } + } else { + FAIL("getPropertyView returned MetadataPropertyView of incorrect " + "type for TestClassProperty."); + } + }); +} + +TEST_CASE("Test StructuralMetadata callback for string property") { + Model model; + + std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; + size_t totalBytes = 0; + for (const std::string& expectedValue : expected) { + totalBytes += expectedValue.size(); + } + + std::vector stringOffsets( + (expected.size() + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(stringOffsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + const std::string& expectedValue = expected[i]; + std::memcpy( + values.data() + offsetValue[i], + expectedValue.c_str(), + expectedValue.size()); + offsetValue[i + 1] = + offsetValue[i] + static_cast(expectedValue.size()); + } + + // Buffers are constructed in scope to ensure that the tests don't use their + // temporary variables. + size_t valueBufferIndex = 0; + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.byteLength = static_cast(values.size()); + valueBuffer.cesium.data = std::move(values); + valueBufferIndex = model.buffers.size() - 1; + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(valueBufferIndex); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + size_t offsetBufferIndex = 0; + size_t offsetBufferViewIndex = 0; + { + Buffer& offsetBuffer = model.buffers.emplace_back(); + offsetBuffer.byteLength = static_cast(stringOffsets.size()); + offsetBuffer.cesium.data = std::move(stringOffsets); + offsetBufferIndex = model.buffers.size() - 1; + + BufferView& offsetBufferView = model.bufferViews.emplace_back(); + offsetBufferView.buffer = static_cast(offsetBufferIndex); + offsetBufferView.byteOffset = 0; + offsetBufferView.byteLength = offsetBuffer.byteLength; + offsetBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::STRING; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.stringOffsets = + static_cast(offsetBufferViewIndex); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::STRING); + REQUIRE(classProperty->componentType == std::nullopt); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + view.getPropertyView( + "TestClassProperty", + [&expected]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + MetadataPropertyView, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + REQUIRE( + static_cast(propertyValue.get(i)) == + expected[static_cast(i)]); + } + } else { + FAIL("getPropertyView returned MetadataPropertyView of incorrect " + "type for TestClassProperty."); + } + }); +} From 3dd83ab8d05fedb633d2f42eb58b523ee9470f80 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 22 May 2023 17:26:11 -0400 Subject: [PATCH 023/121] Add callback tests --- .../StructuralMetadataPropertyTableView.h | 197 +++++++++++------- ...estStructuralMetadataPropertyTableView.cpp | 140 ++++++++++++- 2 files changed, 252 insertions(+), 85 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index 4a7664c40..7caf8282c 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -81,7 +81,7 @@ class MetadataPropertyTableView { /** * @brief Gets a MetadataPropertyView through a callback that accepts a - * property name and a std::optional> to view the data + * property name and a MetadataPropertyView to view the data * of a property stored in the ExtensionExtStructuralMetadataPropertyTable. * * This method will validate the EXT_structural_metadata format to ensure @@ -90,13 +90,13 @@ class MetadataPropertyTableView { * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, * std::string_view, or MetadataArrayView with T as one of the - * aforementioned types. If the property is invalid, std::nullopt will be - * passed to the callback. Otherwise, a valid property view will be passed to - * the callback. + * aforementioned types. If the property is invalid, an empty + * MetadataPropertyView with an error status code 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 - * std::optional> + * MetadataPropertyView */ template void @@ -121,6 +121,12 @@ class MetadataPropertyTableView { type, componentType, std::forward(callback)); + } else if (type == PropertyType::Scalar) { + getScalarPropertyViewImpl( + propertyName, + *pClassProperty, + componentType, + std::forward(callback)); } else if (isPropertyTypeVecN(type)) { getVecNPropertyViewImpl( propertyName, @@ -135,20 +141,26 @@ class MetadataPropertyTableView { type, componentType, std::forward(callback)); + } else if (type == PropertyType::String) { + callback( + propertyName, + getPropertyViewImpl(propertyName, *pClassProperty)); + } else if (type == PropertyType::Boolean) { + callback( + propertyName, + getPropertyViewImpl(propertyName, *pClassProperty)); } else { - getPrimitivePropertyViewImpl( + callback( propertyName, - *pClassProperty, - type, - componentType, - std::forward(callback)); + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorTypeMismatch)); } } /** * @brief Iterates over each property in the * ExtensionExtStructuralMetadataPropertyTable with a callback that accepts a - * property name and a std::optional> to view the data + * property name and a MetadataPropertyView to view the data * stored in the ExtensionExtStructuralMetadataPropertyTableProperty. * * This method will validate the EXT_structural_metadata format to ensure @@ -157,13 +169,14 @@ class MetadataPropertyTableView { * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, * std::string_view, or MetadataArrayView with T as one of the - * aforementioned types. If the property is invalid, std::nullopt will be - * passed to the callback. Otherwise, a valid property view will be passed to + * aforementioned types. If the property is invalid, an empty + * MetadataPropertyView with an error status code 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 - * std::optional> + * MetadataPropertyView */ template void forEachProperty(Callback&& callback) const { for (const auto& property : this->_pClass->properties) { @@ -266,6 +279,10 @@ class MetadataPropertyTableView { classProperty)); break; default: + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); break; } } @@ -348,6 +365,10 @@ class MetadataPropertyTableView { classProperty)); break; default: + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); break; } } @@ -383,6 +404,10 @@ class MetadataPropertyTableView { std::forward(callback)); break; default: + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorTypeMismatch)); break; } } @@ -465,6 +490,10 @@ class MetadataPropertyTableView { classProperty)); break; default: + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); break; } } @@ -500,6 +529,10 @@ class MetadataPropertyTableView { std::forward(callback)); break; default: + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorTypeMismatch)); break; } } @@ -545,6 +578,11 @@ class MetadataPropertyTableView { getPropertyViewImpl>( propertyName, classProperty)); + } else { + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorTypeMismatch)); } } @@ -625,6 +663,10 @@ class MetadataPropertyTableView { classProperty)); break; default: + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); break; } } @@ -660,6 +702,10 @@ class MetadataPropertyTableView { std::forward(callback)); break; default: + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorTypeMismatch)); break; } } @@ -742,6 +788,10 @@ class MetadataPropertyTableView { classProperty)); break; default: + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); break; } } @@ -777,80 +827,77 @@ class MetadataPropertyTableView { std::forward(callback)); break; default: + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorTypeMismatch)); break; } } template - void getPrimitivePropertyViewImpl( + void getScalarPropertyViewImpl( const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty, - PropertyType type, PropertyComponentType componentType, Callback&& callback) const { - if (type == PropertyType::Scalar) { - switch (componentType) { - case PropertyComponentType::Int8: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyComponentType::Uint8: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyComponentType::Int16: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyComponentType::Uint16: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyComponentType::Int32: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyComponentType::Uint32: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyComponentType::Int64: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyComponentType::Uint64: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyComponentType::Float32: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyComponentType::Float64: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - default: - break; - } - } else if (type == PropertyType::String) { + switch (componentType) { + case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); - } else if (type == PropertyType::Boolean) { + getPropertyViewImpl(propertyName, classProperty)); + return; + case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl(propertyName, classProperty)); + return; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + return; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Int32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Uint32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Int64: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Uint64: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Float32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Float64: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + default: + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); + break; } } diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp index f0303449a..28e7fc7ee 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -250,7 +250,7 @@ TEST_CASE("Test StructuralMetadata vecN property") { REQUIRE(ivec3Property.size() > 0); for (int64_t i = 0; i < ivec3Property.size(); ++i) { - REQUIRE(ivec3Property.get(i) == values[i]); + REQUIRE(ivec3Property.get(i) == values[static_cast(i)]); } } @@ -441,7 +441,7 @@ TEST_CASE("Test StructuralMetadata matN property") { REQUIRE(u32mat2x2Property.size() > 0); for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { - REQUIRE(u32mat2x2Property.get(i) == values[i]); + REQUIRE(u32mat2x2Property.get(i) == values[static_cast(i)]); } } @@ -2590,11 +2590,51 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { } } +TEST_CASE("Test StructuralMetadata callback for invalid property") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["InvalidProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(5); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["InvalidProperty"]; + propertyTableProperty.values = static_cast(-1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("InvalidProperty"); + REQUIRE(classProperty); + + classProperty = view.getClassProperty("NonexistentProperty"); + REQUIRE(!classProperty); + + auto testCallback = [](const std::string& /*propertyName*/, + auto propertyValue) mutable { + REQUIRE(propertyValue.status() != MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() == 0); + }; + + view.getPropertyView("InvalidProperty", testCallback); + view.getPropertyView("NonexistentProperty", testCallback); +} + TEST_CASE("Test StructuralMetadata callback for scalar property") { Model model; std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; - size_t valueBufferIndex = 0; size_t valueBufferViewIndex = 0; // Buffers are constructed in scope to ensure that the tests don't use their @@ -2608,7 +2648,6 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") { valueBuffer.cesium.data.data(), values.data(), valueBuffer.cesium.data.size()); - valueBufferIndex = model.buffers.size() - 1; BufferView& valueBufferView = model.bufferViews.emplace_back(); valueBufferView.buffer = static_cast(model.buffers.size() - 1); @@ -2655,12 +2694,12 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") { [&values]( const std::string& /*propertyName*/, auto propertyValue) mutable { - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - if constexpr (std::is_same_v< MetadataPropertyView, decltype(propertyValue)>) { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + for (int64_t i = 0; i < propertyValue.size(); ++i) { REQUIRE( static_cast(propertyValue.get(i)) == @@ -2682,7 +2721,6 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { glm::ivec3(-2, 6, 12), glm::ivec3(-4, 8, -13)}; - size_t valueBufferIndex = 0; size_t valueBufferViewIndex = 0; // Buffers are constructed in scope to ensure that the tests don't use their @@ -2696,7 +2734,6 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { valueBuffer.cesium.data.data(), values.data(), valueBuffer.cesium.data.size()); - valueBufferIndex = model.buffers.size() - 1; BufferView& valueBufferView = model.bufferViews.emplace_back(); valueBufferView.buffer = static_cast(model.buffers.size() - 1); @@ -3038,7 +3075,7 @@ TEST_CASE("Test StructuralMetadata callback for string property") { REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); - view.getPropertyView( + view.getPropertyView( "TestClassProperty", [&expected]( const std::string& /*propertyName*/, @@ -3060,3 +3097,86 @@ TEST_CASE("Test StructuralMetadata callback for string property") { } }); } + +TEST_CASE("Test StructuralMetadata callback for scalar array") { + Model model; + + std::vector values = + {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; + + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + testClassProperty.array = true; + testClassProperty.count = 3; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + + view.getPropertyView( + "TestClassProperty", + [&values](const std::string& /*propertyName*/, auto propertyValue) { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + MetadataPropertyView>, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + MetadataArrayView member = propertyValue.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 3 + j)]); + } + } + } else { + FAIL("getPropertyView returned MetadataPropertyView of incorrect " + "type for TestClassProperty."); + } + }); +} From 64b8378019d129bf7d1bce17c6010b5d010f389a Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 22 May 2023 17:46:34 -0400 Subject: [PATCH 024/121] Add tests for callback on array property --- ...estStructuralMetadataPropertyTableView.cpp | 417 ++++++++++++++++++ 1 file changed, 417 insertions(+) diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp index 28e7fc7ee..122908c1b 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -3180,3 +3180,420 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { } }); } + +TEST_CASE("Test StructuralMetadata callback for vecN array") { + Model model; + + std::vector values = { + glm::ivec3(12, 34, -30), + glm::ivec3(-2, 0, 1), + glm::ivec3(1, 2, 8), + glm::ivec3(-100, 84, 6), + glm::ivec3(2, -2, -2), + glm::ivec3(40, 61, 3), + }; + + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(glm::ivec3)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::VEC3; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + view.getPropertyView( + "TestClassProperty", + [&values](const std::string& /*propertyName*/, auto propertyValue) { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + MetadataPropertyView>, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + MetadataArrayView member = propertyValue.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + } + } + } else { + FAIL("getPropertyView returned MetadataPropertyView of incorrect " + "type for TestClassProperty."); + } + }); +} + +TEST_CASE("Test StructuralMetadata callback for matN array") { + Model model; + + // clang-format off + std::vector values = { + glm::i32mat2x2( + 12, 34, + -30, 20), + glm::i32mat2x2( + -2, -2, + 0, 1), + glm::i32mat2x2( + 1, 2, + 8, 5), + glm::i32mat2x2( + -100, 3, + 84, 6), + glm::i32mat2x2( + 2, 12, + -2, -2), + glm::i32mat2x2( + 40, 61, + 7, -3), + }; + // clang-format on + + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(glm::i32mat2x2)); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::MAT2; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::MAT2); + REQUIRE( + classProperty->componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + view.getPropertyView( + "TestClassProperty", + [&values](const std::string& /*propertyName*/, auto propertyValue) { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + MetadataPropertyView< + MetadataArrayView>, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + MetadataArrayView member = propertyValue.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + } + } + } else { + FAIL("getPropertyView returned MetadataPropertyView of incorrect " + "type for TestClassProperty."); + } + }); +} + +TEST_CASE("Test StructuralMetadata callback for boolean array") { + Model model; + + std::vector expected = { + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true}; + std::vector values; + size_t requiredBytesSize = static_cast( + glm::ceil(static_cast(expected.size()) / 8.0)); + values.resize(requiredBytesSize); + for (size_t i = 0; i < expected.size(); ++i) { + uint8_t expectedValue = expected[i]; + size_t byteIndex = i / 8; + size_t bitIndex = i % 8; + values[byteIndex] = + static_cast((expectedValue << bitIndex) | values[byteIndex]); + } + + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size()); + valueBuffer.byteLength = + static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + testClassProperty.array = true; + testClassProperty.count = 3; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + expected.size() / static_cast(testClassProperty.count.value())); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + + view.getPropertyView( + "TestClassProperty", + [&expected](const std::string& /*propertyName*/, auto propertyValue) { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + MetadataPropertyView>, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + MetadataArrayView member = propertyValue.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == expected[static_cast(i * 3 + j)]); + } + } + } else { + FAIL("getPropertyView returned MetadataPropertyView of incorrect " + "type for TestClassProperty."); + } + }); +} + +TEST_CASE("Test StructuralMetadata callback for array of strings") { + Model model; + + std::vector expected{ + "What's up", + "Breaking news!!! Aliens no longer attacks the US first", + "But they still abduct my cows! Those milk thiefs! 👽 🐮", + "I'm not crazy. My mother had me tested 🤪", + "I love you, meat bags! ❤️", + "Book in the freezer"}; + + size_t totalBytes = 0; + for (const std::string& expectedValue : expected) { + totalBytes += expectedValue.size(); + } + + std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + const std::string& expectedValue = expected[i]; + std::memcpy( + values.data() + offsetValue[i], + expectedValue.c_str(), + expectedValue.size()); + offsetValue[i + 1] = + offsetValue[i] + static_cast(expectedValue.size()); + } + + size_t valueBufferViewIndex = 0; + { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.byteLength = static_cast(values.size()); + valueBuffer.cesium.data = std::move(values); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; + valueBufferViewIndex = model.bufferViews.size() - 1; + } + + size_t offsetBufferViewIndex = 0; + { + Buffer& offsetBuffer = model.buffers.emplace_back(); + offsetBuffer.byteLength = static_cast(offsets.size()); + offsetBuffer.cesium.data = std::move(offsets); + + BufferView& offsetBufferView = model.bufferViews.emplace_back(); + offsetBufferView.buffer = static_cast(model.buffers.size() - 1); + offsetBufferView.byteOffset = 0; + offsetBufferView.byteLength = offsetBuffer.byteLength; + offsetBufferViewIndex = model.bufferViews.size() - 1; + } + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::STRING; + testClassProperty.array = true; + testClassProperty.count = 2; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + expected.size() / static_cast(testClassProperty.count.value())); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.stringOffsets = + static_cast(offsetBufferViewIndex); + + MetadataPropertyTableView view(&model, &propertyTable); + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE( + classProperty->type == + ExtensionExtStructuralMetadataClassProperty::Type::STRING); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + view.getPropertyView( + "TestClassProperty", + [&expected](const std::string& /*propertyName*/, auto propertyValue) { + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + + if constexpr (std::is_same_v< + MetadataPropertyView< + MetadataArrayView>, + decltype(propertyValue)>) { + REQUIRE(propertyValue.size() == 3); + + MetadataArrayView v0 = propertyValue.get(0); + REQUIRE(v0.size() == 2); + REQUIRE(v0[0] == "What's up"); + REQUIRE( + v0[1] == + "Breaking news!!! Aliens no longer attacks the US first"); + + MetadataArrayView v1 = propertyValue.get(1); + REQUIRE(v1.size() == 2); + REQUIRE( + v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); + REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); + + MetadataArrayView v2 = propertyValue.get(2); + REQUIRE(v2.size() == 2); + REQUIRE(v2[0] == "I love you, meat bags! ❤️"); + REQUIRE(v2[1] == "Book in the freezer"); + } else { + FAIL("getPropertyView returned MetadataPropertyView of incorrect " + "type for TestClassProperty."); + } + }); +} From 551316928006a23f8b4382d6aa112af3d2fde5e6 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 22 May 2023 17:50:38 -0400 Subject: [PATCH 025/121] Remove unused variables --- CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp index 122908c1b..64d8b8bce 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -3104,7 +3104,6 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; - size_t valueBufferViewIndex = 0; { Buffer& valueBuffer = model.buffers.emplace_back(); valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); @@ -3119,7 +3118,6 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { valueBufferView.buffer = static_cast(model.buffers.size() - 1); valueBufferView.byteOffset = 0; valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; } ExtensionModelExtStructuralMetadata& metadata = @@ -3193,7 +3191,6 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { glm::ivec3(40, 61, 3), }; - size_t valueBufferViewIndex = 0; { Buffer& valueBuffer = model.buffers.emplace_back(); valueBuffer.cesium.data.resize(values.size() * sizeof(glm::ivec3)); @@ -3208,7 +3205,6 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { valueBufferView.buffer = static_cast(model.buffers.size() - 1); valueBufferView.byteOffset = 0; valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; } ExtensionModelExtStructuralMetadata& metadata = From 7e08eadf0730f686e5153b28adb1950598c254ef Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 23 May 2023 10:39:26 -0400 Subject: [PATCH 026/121] Remove final unused variable --- CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp index 64d8b8bce..d372b6c5e 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -3292,7 +3292,6 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { }; // clang-format on - size_t valueBufferViewIndex = 0; { Buffer& valueBuffer = model.buffers.emplace_back(); valueBuffer.cesium.data.resize(values.size() * sizeof(glm::i32mat2x2)); @@ -3307,7 +3306,6 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { valueBufferView.buffer = static_cast(model.buffers.size() - 1); valueBufferView.byteOffset = 0; valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; } ExtensionModelExtStructuralMetadata& metadata = From b8b3edea5144a29eb482a0a6f08e2123e0acf0c2 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 23 May 2023 11:42:34 -0400 Subject: [PATCH 027/121] Code cleanup --- .../StructuralMetadataPropertyTableView.h | 51 ++++++++----------- .../StructuralMetadataPropertyView.h | 24 +++++++++ .../StructuralMetadataPropertyTableView.cpp | 2 +- ...estStructuralMetadataPropertyTableView.cpp | 14 ++++- .../TestStructuralMetadataPropertyView.cpp | 10 ---- 5 files changed, 58 insertions(+), 43 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index 7caf8282c..e92a5aa2a 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -16,36 +16,38 @@ namespace StructuralMetadata { * @brief Utility to retrieve the data of * ExtensionExtStructuralMetadataPropertyTable. * - * This should be used to get a {@link MetadataPropertyView} of a property. + * This should be used to get a {@link MetadataPropertyView} of a property in the property table. * It will validate the EXT_structural_metadata format and ensure {@link MetadataPropertyView} - * does not access out of bounds. + * does not access out of bounds. */ class MetadataPropertyTableView { public: /** - * @brief Create an instance of MetadataPropertyTableView. - * @param pModel The Gltf Model that stores property table data - * @param pPropertyTable The ExtensionExtStructuralMetadataPropertyTable from - * which the view will retrieve data. + * @brief Creates an instance of MetadataPropertyTableView. + * @param pModel A pointer to the Gltf Model that contains property table + * data. + * @param pPropertyTable A pointer to the + * ExtensionExtStructuralMetadataPropertyTable from which the view will + * retrieve data. */ MetadataPropertyTableView( const Model* pModel, const ExtensionExtStructuralMetadataPropertyTable* pPropertyTable); /** - * @brief Find the {@link ExtensionExtStructuralMetadataClassProperty} which - * stores the type information of a property based on the property's name. - * @param propertyName The name of the property to retrieve type info - * @return Pointer to the ExtensionExtStructuralMetadataClassProperty. Return - * nullptr if no property was found. + * @brief Finds the {@link ExtensionExtStructuralMetadataClassProperty} that + * describes the type information of the property with the specified name. + * @param propertyName The name of the property to retrieve the class for. + * @return A pointer to the ExtensionExtStructuralMetadataClassProperty. + * Return nullptr if no property was found. */ const ExtensionExtStructuralMetadataClassProperty* getClassProperty(const std::string& propertyName) const; /** - * @brief Gets a MetadataPropertyView to view the data of a property stored in - * the ExtensionExtStructuralMetadataPropertyTable. + * @brief Gets a MetadataPropertyView that views the data of a property stored + * in the ExtensionExtStructuralMetadataPropertyTable. * * This method will validate the EXT_structural_metadata format to ensure * MetadataPropertyView retrieves the correct data. T must be one of the @@ -56,8 +58,8 @@ class MetadataPropertyTableView { * aforementioned types. * * @param propertyName The name of the property to retrieve data from - * @return MetadataPropertyView of a property. The property view will be - * invalid if no property is found. + * @return A MetadataPropertyView of the property. If no valid property is + * found, the property view will be invalid. */ template MetadataPropertyView @@ -81,8 +83,8 @@ class MetadataPropertyTableView { /** * @brief Gets a MetadataPropertyView through a callback that accepts a - * property name and a MetadataPropertyView to view the data - * of a property stored in the ExtensionExtStructuralMetadataPropertyTable. + * property name and a MetadataPropertyView that views the data + * of the property with the specified name. * * This method will validate the EXT_structural_metadata format to ensure * MetadataPropertyView retrieves the correct data. T must be one of the @@ -91,11 +93,11 @@ class MetadataPropertyTableView { * types, a glm matN composed of one of the scalar types, bool, * std::string_view, or MetadataArrayView with T as one of the * aforementioned types. If the property is invalid, an empty - * MetadataPropertyView with an error status code will be passed to the + * MetadataPropertyView 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 + * @tparam callback A callback function that accepts a property name and a * MetadataPropertyView */ template @@ -564,7 +566,6 @@ class MetadataPropertyTableView { type, componentType, std::forward(callback)); - } else if (type == PropertyType::Boolean) { callback( propertyName, @@ -990,11 +991,6 @@ class MetadataPropertyTableView { return MetadataPropertyView( MetadataPropertyViewStatus::Valid, values, - gsl::span(), - gsl::span(), - PropertyComponentType::None, - PropertyComponentType::None, - 0, _pPropertyTable->count, classProperty.normalized); } @@ -1147,11 +1143,6 @@ class MetadataPropertyTableView { return MetadataPropertyView( invalidStatus, gsl::span(), - gsl::span(), - gsl::span(), - PropertyComponentType::None, - PropertyComponentType::None, - 0, 0, false); } diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h index 529e092df..1be6dd014 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h @@ -177,6 +177,30 @@ template class MetadataPropertyView { _size{}, _normalized{} {} + /** + * @brief Construct a new instance pointing to non-array data specified by + * ExtensionExtStructuralMetadataPropertyTableProperty. + * @param values The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} + * @param size The number of elements in the property table specified by {@link ExtensionExtStructuralMetadataPropertyTable::count} + * @param normalized Whether this property has a normalized integer type. + */ + MetadataPropertyView( + MetadataPropertyViewStatus status, + gsl::span values, + int64_t size, + bool normalized) noexcept + : _status{status}, + _values{values}, + _arrayOffsets{}, + _arrayOffsetType{PropertyComponentType::None}, + _arrayOffsetTypeSize{0}, + _stringOffsets{}, + _stringOffsetType{PropertyComponentType::None}, + _stringOffsetTypeSize{0}, + _fixedLengthArrayCount{0}, + _size{size}, + _normalized{normalized} {} + /** * @brief Construct a new instance pointing to the data specified by * ExtensionExtStructuralMetadataPropertyTableProperty. diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp index 115ad0129..ed0fa157b 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -338,7 +338,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( propertyTableProperty) const { if (!classProperty.array) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorTypeMismatch); + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); } if (classProperty.type != diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp index d372b6c5e..cf2d6a567 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -554,7 +554,7 @@ TEST_CASE("Test StructuralMetadata matN property") { } } -TEST_CASE("Test StructuralMetadata boolean properties") { +TEST_CASE("Test StructuralMetadata boolean property") { Model model; int64_t instanceCount = 21; @@ -743,6 +743,16 @@ TEST_CASE("Test StructuralMetadata string property") { } } + SECTION("Wrong array type") { + MetadataPropertyView> + stringArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + stringArrayInvalid.status() == + MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + } + SECTION("Wrong offset type") { propertyTableProperty.stringOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: @@ -3559,7 +3569,7 @@ TEST_CASE("Test StructuralMetadata callback for array of strings") { view.getPropertyView( "TestClassProperty", - [&expected](const std::string& /*propertyName*/, auto propertyValue) { + [](const std::string& /*propertyName*/, auto propertyValue) { REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); if constexpr (std::is_same_v< diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyView.cpp index bd5ab17ec..4c8103b08 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyView.cpp @@ -19,11 +19,6 @@ template static void checkNumeric(const std::vector& expected) { MetadataPropertyView property( MetadataPropertyViewStatus::Valid, gsl::span(data.data(), data.size()), - gsl::span(), - gsl::span(), - PropertyComponentType::None, - PropertyComponentType::None, - 0, static_cast(expected.size()), false); @@ -233,11 +228,6 @@ TEST_CASE("Check StructuralMetadata boolean property") { MetadataPropertyView property( MetadataPropertyViewStatus::Valid, gsl::span(data.data(), data.size()), - gsl::span(), - gsl::span(), - PropertyComponentType::None, - PropertyComponentType::None, - 0, static_cast(instanceCount), false); for (int64_t i = 0; i < property.size(); ++i) { From 1cce7f82020038d7da4b53f36cf9408473f7a9b5 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 24 May 2023 11:04:45 -0400 Subject: [PATCH 028/121] Use references instead of pointers, add missing doc links --- .../CesiumGltf/StructuralMetadataArrayView.h | 2 +- .../StructuralMetadataPropertyTableView.h | 70 +++++++++---------- .../StructuralMetadataPropertyView.h | 14 ++-- .../StructuralMetadataPropertyTableView.cpp | 36 +++++----- ...estStructuralMetadataPropertyTableView.cpp | 52 +++++++------- 5 files changed, 83 insertions(+), 91 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h index a886b62c3..e315584f4 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h @@ -15,7 +15,7 @@ namespace StructuralMetadata { /** * @brief A view on an array element of a - * ExtensionExtStructuralMetadataPropertyTableProperty. + * {@link ExtensionExtStructuralMetadataPropertyTableProperty}. * * Provides utility to retrieve the data stored in the array of * elements via the array index operator. diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index e92a5aa2a..492fca629 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -14,32 +14,29 @@ namespace StructuralMetadata { /** * @brief Utility to retrieve the data of - * ExtensionExtStructuralMetadataPropertyTable. + * {@link ExtensionExtStructuralMetadataPropertyTable}. * * This should be used to get a {@link MetadataPropertyView} of a property in the property table. * It will validate the EXT_structural_metadata format and ensure {@link MetadataPropertyView} * does not access out of bounds. */ - class MetadataPropertyTableView { public: /** * @brief Creates an instance of MetadataPropertyTableView. - * @param pModel A pointer to the Gltf Model that contains property table - * data. - * @param pPropertyTable A pointer to the - * ExtensionExtStructuralMetadataPropertyTable from which the view will - * retrieve data. + * @param model The Gltf Model that contains property table data. + * @param propertyTable The {@link ExtensionExtStructuralMetadataPropertyTable} + * from which the view will retrieve data. */ MetadataPropertyTableView( - const Model* pModel, - const ExtensionExtStructuralMetadataPropertyTable* pPropertyTable); + const Model& model, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable); /** * @brief Finds the {@link ExtensionExtStructuralMetadataClassProperty} that * describes the type information of the property with the specified name. * @param propertyName The name of the property to retrieve the class for. - * @return A pointer to the ExtensionExtStructuralMetadataClassProperty. + * @return A pointer to the {@link ExtensionExtStructuralMetadataClassProperty}. * Return nullptr if no property was found. */ const ExtensionExtStructuralMetadataClassProperty* @@ -64,7 +61,7 @@ class MetadataPropertyTableView { template MetadataPropertyView getPropertyView(const std::string& propertyName) const { - if (_pPropertyTable->count <= 0) { + if (_propertyTable.count <= 0) { return createInvalidPropertyView( StructuralMetadata::MetadataPropertyViewStatus:: ErrorPropertyDoesNotExist); @@ -82,23 +79,23 @@ class MetadataPropertyTableView { } /** - * @brief Gets a MetadataPropertyView through a callback that accepts a - * property name and a MetadataPropertyView that views the data + * @brief Gets a {@link MetadataPropertyView} through a callback that accepts a + * property name and a {@link MetadataPropertyView} that views the data * of the property with the specified name. * * This method will validate the EXT_structural_metadata format to ensure - * MetadataPropertyView retrieves the correct data. T must be one of the + * {@link MetadataPropertyView} retrieves the correct data. T must be one of the * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, - * std::string_view, or MetadataArrayView with T as one of the + * std::string_view, or {@link MetadataArrayView} with T as one of the * aforementioned types. If the property is invalid, an empty - * MetadataPropertyView with an error status will be passed to the + * {@link MetadataPropertyView} 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 - * MetadataPropertyView + * {@link MetadataPropertyView} */ template void @@ -161,24 +158,24 @@ class MetadataPropertyTableView { /** * @brief Iterates over each property in the - * ExtensionExtStructuralMetadataPropertyTable with a callback that accepts a - * property name and a MetadataPropertyView to view the data - * stored in the ExtensionExtStructuralMetadataPropertyTableProperty. + * {@link ExtensionExtStructuralMetadataPropertyTable} with a callback that accepts a + * property name and a {@link MetadataPropertyView} to view the data + * stored in the {@link ExtensionExtStructuralMetadataPropertyTableProperty}. * * This method will validate the EXT_structural_metadata format to ensure - * MetadataPropertyView retrieves the correct data. T must be one of the + * {@link MetadataPropertyView} retrieves the correct data. T must be one of the * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, - * std::string_view, or MetadataArrayView with T as one of the + * std::string_view, or {@link MetadataArrayView} with T as one of the * aforementioned types. If the property is invalid, an empty - * MetadataPropertyView with an error status code will be passed to the + * {@link MetadataPropertyView} with an error status code 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 - * MetadataPropertyView + * {@link MetadataPropertyView} */ template void forEachProperty(Callback&& callback) const { for (const auto& property : this->_pClass->properties) { @@ -907,8 +904,8 @@ class MetadataPropertyTableView { const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty) const { auto propertyTablePropertyIter = - _pPropertyTable->properties.find(propertyName); - if (propertyTablePropertyIter == _pPropertyTable->properties.end()) { + _propertyTable.properties.find(propertyName); + if (propertyTablePropertyIter == _propertyTable.properties.end()) { return createInvalidPropertyView( MetadataPropertyViewStatus::ErrorPropertyDoesNotExist); } @@ -977,9 +974,9 @@ class MetadataPropertyTableView { size_t maxRequiredBytes = 0; if (IsMetadataBoolean::value) { maxRequiredBytes = static_cast( - glm::ceil(static_cast(_pPropertyTable->count) / 8.0)); + glm::ceil(static_cast(_propertyTable.count) / 8.0)); } else { - maxRequiredBytes = _pPropertyTable->count * sizeof(T); + maxRequiredBytes = _propertyTable.count * sizeof(T); } if (values.size() < maxRequiredBytes) { @@ -991,7 +988,7 @@ class MetadataPropertyTableView { return MetadataPropertyView( MetadataPropertyViewStatus::Valid, values, - _pPropertyTable->count, + _propertyTable.count, classProperty.normalized); } @@ -1052,12 +1049,11 @@ class MetadataPropertyTableView { size_t maxRequiredBytes = 0; if constexpr (IsMetadataBoolean::value) { maxRequiredBytes = static_cast(glm::ceil( - static_cast( - _pPropertyTable->count * fixedLengthArrayCount) / + static_cast(_propertyTable.count * fixedLengthArrayCount) / 8.0)); } else { maxRequiredBytes = static_cast( - _pPropertyTable->count * fixedLengthArrayCount * sizeof(T)); + _propertyTable.count * fixedLengthArrayCount * sizeof(T)); } if (values.size() < maxRequiredBytes) { @@ -1074,7 +1070,7 @@ class MetadataPropertyTableView { PropertyComponentType::None, PropertyComponentType::None, static_cast(fixedLengthArrayCount), - static_cast(_pPropertyTable->count), + static_cast(_propertyTable.count), classProperty.normalized); } @@ -1093,7 +1089,7 @@ class MetadataPropertyTableView { propertyTableProperty.arrayOffsets, arrayOffsetType, values.size(), - static_cast(_pPropertyTable->count), + static_cast(_propertyTable.count), checkBitsSize, arrayOffsets); if (status != MetadataPropertyViewStatus::Valid) { @@ -1108,7 +1104,7 @@ class MetadataPropertyTableView { arrayOffsetType, PropertyComponentType::None, 0, - static_cast(_pPropertyTable->count), + static_cast(_propertyTable.count), classProperty.normalized); } @@ -1147,8 +1143,8 @@ class MetadataPropertyTableView { false); } - const Model* _pModel; - const ExtensionExtStructuralMetadataPropertyTable* _pPropertyTable; + const Model& _model; + const ExtensionExtStructuralMetadataPropertyTable& _propertyTable; const ExtensionExtStructuralMetadataClass* _pClass; }; diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h index 1be6dd014..e98134dd1 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h @@ -31,7 +31,7 @@ enum class MetadataPropertyViewStatus { /** * @brief This property view does not exist in the - * ExtensionExtStructuralMetadataPropertyTable. + * {@link ExtensionExtStructuralMetadataPropertyTable}. */ ErrorPropertyDoesNotExist, @@ -153,7 +153,7 @@ enum class MetadataPropertyViewStatus { /** * @brief A view on the data of the - * ExtensionExtStructuralMetadataPropertyTableProperty + * {@link ExtensionExtStructuralMetadataPropertyTableProperty} * * It provides utility to retrieve the actual data stored in the * {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} like an array of elements. @@ -179,7 +179,7 @@ template class MetadataPropertyView { /** * @brief Construct a new instance pointing to non-array data specified by - * ExtensionExtStructuralMetadataPropertyTableProperty. + * {@link ExtensionExtStructuralMetadataPropertyTableProperty}. * @param values The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} * @param size The number of elements in the property table specified by {@link ExtensionExtStructuralMetadataPropertyTable::count} * @param normalized Whether this property has a normalized integer type. @@ -203,7 +203,7 @@ template class MetadataPropertyView { /** * @brief Construct a new instance pointing to the data specified by - * ExtensionExtStructuralMetadataPropertyTableProperty. + * {@link ExtensionExtStructuralMetadataPropertyTableProperty}. * @param values The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} * @param arrayOffsets The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::arrayOffsets} * @param stringOffsets The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::stringOffsets} @@ -244,7 +244,7 @@ template class MetadataPropertyView { MetadataPropertyViewStatus status() const noexcept { return _status; } /** - * @brief Get the value of an element of the FeatureTable. + * @brief Get the value of an element of the {@link ExtensionExtStructuralMetadataPropertyTable}. * @param index The element index * @return The value of the element */ @@ -286,10 +286,10 @@ template class MetadataPropertyView { /** * @brief Get the number of elements in the - * ExtensionExtStructuralMetadataPropertyTable. + * {@link ExtensionExtStructuralMetadataPropertyTable}. * * @return The number of elements in the - * ExtensionExtStructuralMetadataPropertyTable. + * {@link ExtensionExtStructuralMetadataPropertyTable}. */ int64_t size() const noexcept { return _size; } diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp index ed0fa157b..e48f26f6c 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -107,14 +107,11 @@ static MetadataPropertyViewStatus checkStringAndArrayOffsetsBuffers( } MetadataPropertyTableView::MetadataPropertyTableView( - const Model* pModel, - const ExtensionExtStructuralMetadataPropertyTable* pPropertyTable) - : _pModel{pModel}, _pPropertyTable{pPropertyTable}, _pClass{nullptr} { - assert(pModel != nullptr && "pModel must not be nullptr"); - assert(pPropertyTable != nullptr && "pPropertyTable must not be nullptr"); - + const Model& model, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable) + : _model{model}, _propertyTable{propertyTable}, _pClass{nullptr} { const ExtensionModelExtStructuralMetadata* pMetadata = - pModel->getExtension(); + model.getExtension(); assert( pMetadata != nullptr && "Model must contain ExtensionModelExtStructuralMetadata to use " @@ -127,7 +124,7 @@ MetadataPropertyTableView::MetadataPropertyTableView( "ExtensionModelExtStructuralMetadata must contain " "Schema to use MetadataPropertyTableView"); - auto classIter = schema->classes.find(_pPropertyTable->classProperty); + auto classIter = schema->classes.find(_propertyTable.classProperty); if (classIter != schema->classes.end()) { _pClass = &classIter->second; } @@ -154,13 +151,12 @@ MetadataPropertyViewStatus MetadataPropertyTableView::getBufferSafe( buffer = {}; const BufferView* pBufferView = - _pModel->getSafe(&_pModel->bufferViews, bufferViewIdx); + _model.getSafe(&_model.bufferViews, bufferViewIdx); if (!pBufferView) { return MetadataPropertyViewStatus::ErrorInvalidValueBufferView; } - const Buffer* pBuffer = - _pModel->getSafe(&_pModel->buffers, pBufferView->buffer); + const Buffer* pBuffer = _model.getSafe(&_model.buffers, pBufferView->buffer); if (!pBuffer) { return MetadataPropertyViewStatus::ErrorInvalidValueBuffer; } @@ -313,7 +309,7 @@ MetadataPropertyTableView::getStringPropertyValues( propertyTableProperty.stringOffsets, offsetType, values.size(), - static_cast(_pPropertyTable->count), + static_cast(_propertyTable.count), stringOffsets); if (status != MetadataPropertyViewStatus::Valid) { return createInvalidPropertyView(status); @@ -327,7 +323,7 @@ MetadataPropertyTableView::getStringPropertyValues( PropertyComponentType::None, offsetType, 0, - _pPropertyTable->count, + _propertyTable.count, classProperty.normalized); } @@ -387,7 +383,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( propertyTableProperty.stringOffsets, stringOffsetType, values.size(), - static_cast(_pPropertyTable->count * fixedLengthArrayCount), + static_cast(_propertyTable.count * fixedLengthArrayCount), stringOffsets); if (status != MetadataPropertyViewStatus::Valid) { return createInvalidPropertyView>( @@ -402,7 +398,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( PropertyComponentType::None, stringOffsetType, fixedLengthArrayCount, - _pPropertyTable->count, + _propertyTable.count, classProperty.normalized); } @@ -442,7 +438,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( stringOffsets, values.size(), stringOffsetType, - static_cast(_pPropertyTable->count)); + static_cast(_propertyTable.count)); break; case PropertyComponentType::Uint16: status = checkStringAndArrayOffsetsBuffers( @@ -450,7 +446,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( stringOffsets, values.size(), stringOffsetType, - static_cast(_pPropertyTable->count)); + static_cast(_propertyTable.count)); break; case PropertyComponentType::Uint32: status = checkStringAndArrayOffsetsBuffers( @@ -458,7 +454,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( stringOffsets, values.size(), stringOffsetType, - static_cast(_pPropertyTable->count)); + static_cast(_propertyTable.count)); break; case PropertyComponentType::Uint64: status = checkStringAndArrayOffsetsBuffers( @@ -466,7 +462,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( stringOffsets, values.size(), stringOffsetType, - static_cast(_pPropertyTable->count)); + static_cast(_propertyTable.count)); break; default: status = MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType; @@ -486,7 +482,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( arrayOffsetType, stringOffsetType, 0, - _pPropertyTable->count, + _propertyTable.count, classProperty.normalized); } diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp index cf2d6a567..1bcdd26dc 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -56,7 +56,7 @@ TEST_CASE("Test StructuralMetadata scalar property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -231,7 +231,7 @@ TEST_CASE("Test StructuralMetadata vecN property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -422,7 +422,7 @@ TEST_CASE("Test StructuralMetadata matN property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -613,7 +613,7 @@ TEST_CASE("Test StructuralMetadata boolean property") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -724,7 +724,7 @@ TEST_CASE("Test StructuralMetadata string property") { propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -866,7 +866,7 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -1036,7 +1036,7 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT64; - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -1191,7 +1191,7 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -1368,7 +1368,7 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT64; - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -1543,7 +1543,7 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -1741,7 +1741,7 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT64; - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -1914,7 +1914,7 @@ TEST_CASE("Test StructuralMetadata fixed-length boolean array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -2063,7 +2063,7 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT64; - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -2243,7 +2243,7 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -2444,7 +2444,7 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { propertyTableProperty.stringOffsets = static_cast(stringOffsetBufferView); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -2623,7 +2623,7 @@ TEST_CASE("Test StructuralMetadata callback for invalid property") { propertyTable.properties["InvalidProperty"]; propertyTableProperty.values = static_cast(-1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("InvalidProperty"); REQUIRE(classProperty); @@ -2687,7 +2687,7 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -2773,7 +2773,7 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -2869,7 +2869,7 @@ TEST_CASE("Test StructuralMetadata callback for matN property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -2963,7 +2963,7 @@ TEST_CASE("Test StructuralMetadata callback for boolean property") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -3075,7 +3075,7 @@ TEST_CASE("Test StructuralMetadata callback for string property") { propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -3155,7 +3155,7 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -3242,7 +3242,7 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -3343,7 +3343,7 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -3445,7 +3445,7 @@ TEST_CASE("Test StructuralMetadata callback for boolean array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( @@ -3558,7 +3558,7 @@ TEST_CASE("Test StructuralMetadata callback for array of strings") { propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); - MetadataPropertyTableView view(&model, &propertyTable); + MetadataPropertyTableView view(model, propertyTable); const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE( From d9e234ab5f3723c8fd96d88b80c21364f2a6c96f Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 24 May 2023 11:48:13 -0400 Subject: [PATCH 029/121] Refactor error handling in MetadataPropertyTableView --- .../StructuralMetadataPropertyTableView.h | 77 +++++++++++++++++-- .../StructuralMetadataPropertyView.h | 33 +++++--- .../StructuralMetadataPropertyTableView.cpp | 30 +++++--- 3 files changed, 111 insertions(+), 29 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index 492fca629..7cae91744 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -12,6 +12,38 @@ namespace CesiumGltf { namespace StructuralMetadata { +/** + * @brief Indicates the status of a property table view. + * + * The {@link MetadataPropertyTableView} constructor always completes successfully. + * However, it may not always reflect the actual content of the + * {@link ExtensionExtStructuralMetadataPropertyTable}, but instead indicate that its + * {@link MetadataPropertyTableView::size} is 0. This enumeration provides the reason. + */ +enum class MetadataPropertyTableViewStatus { + /** + * @brief This property table view is valid and ready to use. + */ + Valid, + + /** + * @brief The property table view's model does not contain an + * EXT_structural_metadata extension. + */ + ErrorNoStructuralMetadataExtension, + + /** + * @brief The property table view's model does not have a schema in its + * EXT_structural_metadata extension. + */ + ErrorNoSchema, + + /** + * @brief The class of the property table does not exist in the schema. + */ + ErrorPropertyTableClassDoesNotExist +}; + /** * @brief Utility to retrieve the data of * {@link ExtensionExtStructuralMetadataPropertyTable}. @@ -32,39 +64,63 @@ class MetadataPropertyTableView { const Model& model, const ExtensionExtStructuralMetadataPropertyTable& propertyTable); + /** + * @brief Gets the status of this property table view. + * + * Indicates whether the view accurately reflects the property table's data, + * or whether an error occurred. + * + * @return The status of this property table view. + */ + MetadataPropertyTableViewStatus status() const noexcept { return _status; } + + /** + * @brief Get the number of elements in this MetadataPropertyTableView. If the + * view is valid, this returns + * {@link ExtensionExtStructuralMetadataPropertyTable::count}. Otherwise, this returns 0. + * + * @return The number of elements in this MetadataPropertyTableView. + */ + int64_t size() const noexcept { + return _status == MetadataPropertyTableViewStatus::Valid + ? _propertyTable.count + : 0; + } + /** * @brief Finds the {@link ExtensionExtStructuralMetadataClassProperty} that * describes the type information of the property with the specified name. * @param propertyName The name of the property to retrieve the class for. * @return A pointer to the {@link ExtensionExtStructuralMetadataClassProperty}. - * Return nullptr if no property was found. + * Return nullptr if the MetadataPropertyTableView is invalid or if no class + * property was found. */ const ExtensionExtStructuralMetadataClassProperty* getClassProperty(const std::string& propertyName) const; /** - * @brief Gets a MetadataPropertyView that views the data of a property stored - * in the ExtensionExtStructuralMetadataPropertyTable. + * @brief Gets a {@link MetadataPropertyView} that views the data of a property stored + * in the {@link ExtensionExtStructuralMetadataPropertyTable}. * * This method will validate the EXT_structural_metadata format to ensure - * MetadataPropertyView retrieves the correct data. T must be one of the + * {@link MetadataPropertyView} retrieves the correct data. T must be one of the * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, - * std::string_view, or MetadataArrayView with T as one of the + * std::string_view, or {@link MetadataArrayView} with T as one of the * aforementioned types. * * @param propertyName The name of the property to retrieve data from - * @return A MetadataPropertyView of the property. If no valid property is + * @return A {@link MetadataPropertyView} of the property. If no valid property is * found, the property view will be invalid. */ template MetadataPropertyView getPropertyView(const std::string& propertyName) const { - if (_propertyTable.count <= 0) { + if (this->size() <= 0) { return createInvalidPropertyView( StructuralMetadata::MetadataPropertyViewStatus:: - ErrorPropertyDoesNotExist); + ErrorInvalidPropertyTable); } const ExtensionExtStructuralMetadataClassProperty* pClassProperty = @@ -103,6 +159,10 @@ class MetadataPropertyTableView { const ExtensionExtStructuralMetadataClassProperty* pClassProperty = getClassProperty(propertyName); if (!pClassProperty) { + callback( + propertyName, + createInvalidPropertyView( + MetadataPropertyViewStatus::ErrorPropertyDoesNotExist)); return; } @@ -1146,6 +1206,7 @@ class MetadataPropertyTableView { const Model& _model; const ExtensionExtStructuralMetadataPropertyTable& _propertyTable; const ExtensionExtStructuralMetadataClass* _pClass; + MetadataPropertyTableViewStatus _status; }; } // namespace StructuralMetadata diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h index e98134dd1..4ad34057b 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h @@ -17,18 +17,24 @@ namespace StructuralMetadata { /** * @brief Indicates the status of a property view. * - * The {@link MetadataPropertyView} constructor always completes successfully. However, - * it may not always reflect the actual content of the {@link ExtensionExtStructuralMetadataPropertyTableProperty}, but - * instead indicate that its {@link MetadataPropertyView::size} is 0. This enumeration + * The {@link MetadataPropertyView} constructor always completes successfully. + * However, it may not always reflect the actual content of the + * {@link ExtensionExtStructuralMetadataPropertyTableProperty}, but instead + * indicate that its {@link MetadataPropertyView::size} is 0. This enumeration * provides the reason. */ - enum class MetadataPropertyViewStatus { /** * @brief This property view is valid and ready to use. */ Valid, + /** + * @brief This property view was attempting to view an invalid + * {@link ExtensionExtStructuralMetadataPropertyTable}. + */ + ErrorInvalidPropertyTable, + /** * @brief This property view does not exist in the * {@link ExtensionExtStructuralMetadataPropertyTable}. @@ -153,11 +159,12 @@ enum class MetadataPropertyViewStatus { /** * @brief A view on the data of the - * {@link ExtensionExtStructuralMetadataPropertyTableProperty} + * {@link ExtensionExtStructuralMetadataPropertyTableProperty that is created by + * a {@link MetadataPropertyTableView}. * * It provides utility to retrieve the actual data stored in the * {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} like an array of elements. - * Data of each instance can be accessed through the {@link get(int64_t instance)} method + * Data of each instance can be accessed through the {@link get(int64_t instance)} method. * * @param ElementType must be one of the following: a scalar (uint8_t, int8_t, * uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double), a @@ -240,6 +247,8 @@ template class MetadataPropertyView { * * Indicates whether the view accurately reflects the property's data, or * whether an error occurred. + * + * @return The status of this property view. */ MetadataPropertyViewStatus status() const noexcept { return _status; } @@ -285,13 +294,15 @@ template class MetadataPropertyView { } /** - * @brief Get the number of elements in the - * {@link ExtensionExtStructuralMetadataPropertyTable}. + * @brief Get the number of elements in this MetadataPropertyView. If the view + * is valid, this returns + * {@link ExtensionExtStructuralMetadataPropertyTable::count}. Otherwise, this returns 0. * - * @return The number of elements in the - * {@link ExtensionExtStructuralMetadataPropertyTable}. + * @return The number of elements in this MetadataPropertyView. */ - int64_t size() const noexcept { return _size; } + int64_t size() const noexcept { + return status() == MetadataPropertyViewStatus::Valid ? _size : 0; + } /** * @brief Get the element count of the fixed-length arrays in this property. diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp index e48f26f6c..d47d48a0c 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -109,31 +109,41 @@ static MetadataPropertyViewStatus checkStringAndArrayOffsetsBuffers( MetadataPropertyTableView::MetadataPropertyTableView( const Model& model, const ExtensionExtStructuralMetadataPropertyTable& propertyTable) - : _model{model}, _propertyTable{propertyTable}, _pClass{nullptr} { + : _model{model}, + _propertyTable{propertyTable}, + _pClass{nullptr}, + _status() { const ExtensionModelExtStructuralMetadata* pMetadata = model.getExtension(); - assert( - pMetadata != nullptr && - "Model must contain ExtensionModelExtStructuralMetadata to use " - "MetadataPropertyTableView"); + + if (!pMetadata) { + _status = + MetadataPropertyTableViewStatus::ErrorNoStructuralMetadataExtension; + return; + } const std::optional& schema = pMetadata->schema; - assert( - schema != std::nullopt && - "ExtensionModelExtStructuralMetadata must contain " - "Schema to use MetadataPropertyTableView"); + if (!schema) { + _status = MetadataPropertyTableViewStatus::ErrorNoSchema; + return; + } auto classIter = schema->classes.find(_propertyTable.classProperty); if (classIter != schema->classes.end()) { _pClass = &classIter->second; } + + if (!_pClass) { + _status = + MetadataPropertyTableViewStatus::ErrorPropertyTableClassDoesNotExist; + } } const ExtensionExtStructuralMetadataClassProperty* MetadataPropertyTableView::getClassProperty( const std::string& propertyName) const { - if (_pClass == nullptr) { + if (_status != MetadataPropertyTableViewStatus::Valid) { return nullptr; } From bae45489ed9b342fd65851862f36534e2e484852 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 24 May 2023 12:36:28 -0400 Subject: [PATCH 030/121] Add tests --- .../StructuralMetadataPropertyTableView.h | 9 + ...estStructuralMetadataPropertyTableView.cpp | 311 +++++++++++++++++- 2 files changed, 306 insertions(+), 14 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index 7cae91744..6d8b0cca7 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -156,6 +156,15 @@ class MetadataPropertyTableView { template void getPropertyView(const std::string& propertyName, Callback&& callback) const { + if (this->size() <= 0) { + callback( + propertyName, + createInvalidPropertyView( + StructuralMetadata::MetadataPropertyViewStatus:: + ErrorInvalidPropertyTable)); + return; + } + const ExtensionExtStructuralMetadataClassProperty* pClassProperty = getClassProperty(propertyName); if (!pClassProperty) { diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp index 1bcdd26dc..4fb419302 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -7,6 +7,88 @@ using namespace CesiumGltf; using namespace CesiumGltf::StructuralMetadata; +TEST_CASE("Test model without EXT_structural_metadata extension") { + Model model; + + // Create an erroneously isolated property table. + ExtensionExtStructuralMetadataPropertyTable propertyTable; + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(10); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(0); + + MetadataPropertyTableView view(model, propertyTable); + REQUIRE( + view.status() == + MetadataPropertyTableViewStatus::ErrorNoStructuralMetadataExtension); + REQUIRE(view.size() == 0); + + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test model without metadata schema") { + Model model; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(10); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(0); + + MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::ErrorNoSchema); + REQUIRE(view.size() == 0); + + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test property table with nonexistent class") { + Model model; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "I Don't Exist"; + propertyTable.count = static_cast(10); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(0); + + MetadataPropertyTableView view(model, propertyTable); + REQUIRE( + view.status() == + MetadataPropertyTableViewStatus::ErrorPropertyTableClassDoesNotExist); + REQUIRE(view.size() == 0); + + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + TEST_CASE("Test StructuralMetadata scalar property") { Model model; @@ -57,8 +139,12 @@ TEST_CASE("Test StructuralMetadata scalar property") { propertyTableProperty.values = static_cast(valueBufferViewIndex); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); @@ -232,8 +318,12 @@ TEST_CASE("Test StructuralMetadata vecN property") { propertyTableProperty.values = static_cast(valueBufferViewIndex); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::VEC3); @@ -423,8 +513,12 @@ TEST_CASE("Test StructuralMetadata matN property") { propertyTableProperty.values = static_cast(valueBufferViewIndex); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::MAT2); @@ -614,8 +708,12 @@ TEST_CASE("Test StructuralMetadata boolean property") { static_cast(model.bufferViews.size() - 1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); @@ -725,8 +823,12 @@ TEST_CASE("Test StructuralMetadata string property") { static_cast(offsetBufferViewIndex); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::STRING); @@ -867,8 +969,12 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { static_cast(model.bufferViews.size() - 1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); @@ -1037,8 +1143,12 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { UINT64; MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); @@ -1192,8 +1302,12 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { static_cast(model.bufferViews.size() - 1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::VEC3); @@ -1369,8 +1483,12 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { UINT64; MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::VEC3); @@ -1544,8 +1662,12 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { static_cast(model.bufferViews.size() - 1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::MAT2); @@ -1742,8 +1864,12 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { UINT64; MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::MAT2); @@ -1915,8 +2041,12 @@ TEST_CASE("Test StructuralMetadata fixed-length boolean array") { static_cast(model.bufferViews.size() - 1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); @@ -2064,8 +2194,12 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { UINT64; MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); @@ -2244,8 +2378,12 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { static_cast(offsetBufferViewIndex); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::STRING); @@ -2445,8 +2583,12 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { static_cast(stringOffsetBufferView); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::STRING); @@ -2600,6 +2742,48 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { } } +TEST_CASE("Test StructuralMetadata callback on invalid property table view") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + metadata.schema.emplace(); + + // Property table has a nonexistent class. + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(5); + + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(-1); + + MetadataPropertyTableView view(model, propertyTable); + REQUIRE( + view.status() == + MetadataPropertyTableViewStatus::ErrorPropertyTableClassDoesNotExist); + REQUIRE(view.size() == 0); + + const ExtensionExtStructuralMetadataClassProperty* 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() == + MetadataPropertyViewStatus::ErrorInvalidPropertyTable); + REQUIRE(propertyValue.size() == 0); + }); + + REQUIRE(invokedCallbackCount == 1); +} + TEST_CASE("Test StructuralMetadata callback for invalid property") { Model model; ExtensionModelExtStructuralMetadata& metadata = @@ -2624,6 +2808,9 @@ TEST_CASE("Test StructuralMetadata callback for invalid property") { propertyTableProperty.values = static_cast(-1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("InvalidProperty"); REQUIRE(classProperty); @@ -2631,14 +2818,19 @@ TEST_CASE("Test StructuralMetadata callback for invalid property") { classProperty = view.getClassProperty("NonexistentProperty"); REQUIRE(!classProperty); - auto testCallback = [](const std::string& /*propertyName*/, - auto propertyValue) mutable { + uint32_t invokedCallbackCount = 0; + auto testCallback = [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; REQUIRE(propertyValue.status() != MetadataPropertyViewStatus::Valid); REQUIRE(propertyValue.size() == 0); }; view.getPropertyView("InvalidProperty", testCallback); view.getPropertyView("NonexistentProperty", testCallback); + + REQUIRE(invokedCallbackCount == 2); } TEST_CASE("Test StructuralMetadata callback for scalar property") { @@ -2688,8 +2880,12 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") { propertyTableProperty.values = static_cast(valueBufferViewIndex); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); @@ -2699,11 +2895,13 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") { REQUIRE(!classProperty->array); REQUIRE(classProperty->count == std::nullopt); + uint32_t invokedCallbackCount = 0; view.getPropertyView( "TestClassProperty", - [&values]( + [&values, &invokedCallbackCount]( const std::string& /*propertyName*/, auto propertyValue) mutable { + invokedCallbackCount++; if constexpr (std::is_same_v< MetadataPropertyView, decltype(propertyValue)>) { @@ -2720,6 +2918,8 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") { "type for TestClassProperty."); } }); + + REQUIRE(invokedCallbackCount == 1); } TEST_CASE("Test StructuralMetadata callback for vecN property") { @@ -2774,8 +2974,12 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { propertyTableProperty.values = static_cast(valueBufferViewIndex); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::VEC3); @@ -2785,11 +2989,14 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + uint32_t invokedCallbackCount = 0; + view.getPropertyView( "TestClassProperty", - [&values]( + [&values, &invokedCallbackCount]( const std::string& /*propertyName*/, auto propertyValue) mutable { + invokedCallbackCount++; REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); @@ -2806,6 +3013,8 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { "type for TestClassProperty."); } }); + + REQUIRE(invokedCallbackCount == 1); } TEST_CASE("Test StructuralMetadata callback for matN property") { @@ -2870,8 +3079,12 @@ TEST_CASE("Test StructuralMetadata callback for matN property") { propertyTableProperty.values = static_cast(valueBufferViewIndex); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::MAT2); @@ -2881,9 +3094,10 @@ TEST_CASE("Test StructuralMetadata callback for matN property") { REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + uint32_t invokedCallbackCount = 0; view.getPropertyView( "TestClassProperty", - [&values]( + [&values, &invokedCallbackCount]( const std::string& /*propertyName*/, auto propertyValue) mutable { REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); @@ -2901,7 +3115,10 @@ TEST_CASE("Test StructuralMetadata callback for matN property") { FAIL("getPropertyView returned MetadataPropertyView of incorrect " "type for TestClassProperty."); } + invokedCallbackCount++; }); + + REQUIRE(invokedCallbackCount == 1); } TEST_CASE("Test StructuralMetadata callback for boolean property") { @@ -2964,8 +3181,12 @@ TEST_CASE("Test StructuralMetadata callback for boolean property") { static_cast(model.bufferViews.size() - 1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); @@ -2973,11 +3194,14 @@ TEST_CASE("Test StructuralMetadata callback for boolean property") { REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + uint32_t invokedCallbackCount = 0; view.getPropertyView( "TestClassProperty", - [&expected]( + [&expected, &invokedCallbackCount]( const std::string& /*propertyName*/, auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); @@ -2994,6 +3218,8 @@ TEST_CASE("Test StructuralMetadata callback for boolean property") { "type for TestClassProperty."); } }); + + REQUIRE(invokedCallbackCount == 1); } TEST_CASE("Test StructuralMetadata callback for string property") { @@ -3076,8 +3302,12 @@ TEST_CASE("Test StructuralMetadata callback for string property") { static_cast(offsetBufferViewIndex); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::STRING); @@ -3085,11 +3315,13 @@ TEST_CASE("Test StructuralMetadata callback for string property") { REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + uint32_t invokedCallbackCount = 0; view.getPropertyView( "TestClassProperty", - [&expected]( + [&expected, &invokedCallbackCount]( const std::string& /*propertyName*/, auto propertyValue) mutable { + invokedCallbackCount++; REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); @@ -3106,6 +3338,8 @@ TEST_CASE("Test StructuralMetadata callback for string property") { "type for TestClassProperty."); } }); + + REQUIRE(invokedCallbackCount == 1); } TEST_CASE("Test StructuralMetadata callback for scalar array") { @@ -3156,8 +3390,12 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { static_cast(model.bufferViews.size() - 1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); @@ -3167,9 +3405,13 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { REQUIRE(classProperty->array); REQUIRE(classProperty->count == 3); + uint32_t invokedCallbackCount = 0; view.getPropertyView( "TestClassProperty", - [&values](const std::string& /*propertyName*/, auto propertyValue) { + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); @@ -3187,6 +3429,8 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { "type for TestClassProperty."); } }); + + REQUIRE(invokedCallbackCount == 1); } TEST_CASE("Test StructuralMetadata callback for vecN array") { @@ -3243,8 +3487,12 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { static_cast(model.bufferViews.size() - 1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::VEC3); @@ -3254,9 +3502,13 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); + uint32_t invokedCallbackCount = 0; view.getPropertyView( "TestClassProperty", - [&values](const std::string& /*propertyName*/, auto propertyValue) { + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); @@ -3274,6 +3526,8 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { "type for TestClassProperty."); } }); + + REQUIRE(invokedCallbackCount == 1); } TEST_CASE("Test StructuralMetadata callback for matN array") { @@ -3344,8 +3598,12 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { static_cast(model.bufferViews.size() - 1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::MAT2); @@ -3355,9 +3613,13 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); + uint32_t invokedCallbackCount = 0; view.getPropertyView( "TestClassProperty", - [&values](const std::string& /*propertyName*/, auto propertyValue) { + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); @@ -3376,6 +3638,8 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { "type for TestClassProperty."); } }); + + REQUIRE(invokedCallbackCount == 1); } TEST_CASE("Test StructuralMetadata callback for boolean array") { @@ -3446,17 +3710,25 @@ TEST_CASE("Test StructuralMetadata callback for boolean array") { static_cast(model.bufferViews.size() - 1); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 3); + uint32_t invokedCallbackCount = 0; view.getPropertyView( "TestClassProperty", - [&expected](const std::string& /*propertyName*/, auto propertyValue) { + [&expected, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); @@ -3474,6 +3746,8 @@ TEST_CASE("Test StructuralMetadata callback for boolean array") { "type for TestClassProperty."); } }); + + REQUIRE(invokedCallbackCount == 1); } TEST_CASE("Test StructuralMetadata callback for array of strings") { @@ -3559,25 +3833,32 @@ TEST_CASE("Test StructuralMetadata callback for array of strings") { static_cast(offsetBufferViewIndex); MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); REQUIRE( classProperty->type == ExtensionExtStructuralMetadataClassProperty::Type::STRING); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); + uint32_t invokedCallbackCount = 0; view.getPropertyView( "TestClassProperty", - [](const std::string& /*propertyName*/, auto propertyValue) { + [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.size() == 3); if constexpr (std::is_same_v< MetadataPropertyView< MetadataArrayView>, decltype(propertyValue)>) { - REQUIRE(propertyValue.size() == 3); - MetadataArrayView v0 = propertyValue.get(0); REQUIRE(v0.size() == 2); REQUIRE(v0[0] == "What's up"); @@ -3600,4 +3881,6 @@ TEST_CASE("Test StructuralMetadata callback for array of strings") { "type for TestClassProperty."); } }); + + REQUIRE(invokedCallbackCount == 1); } From 7f2ea4994013d0ca0ecd1c512a7fe5bcc0ac1c82 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 24 May 2023 12:42:07 -0400 Subject: [PATCH 031/121] Minor whitespace nitpicks --- CesiumGltf/src/StructuralMetadataPropertyTableView.cpp | 1 - CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp index d47d48a0c..6e0dfb421 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -115,7 +115,6 @@ MetadataPropertyTableView::MetadataPropertyTableView( _status() { const ExtensionModelExtStructuralMetadata* pMetadata = model.getExtension(); - if (!pMetadata) { _status = MetadataPropertyTableViewStatus::ErrorNoStructuralMetadataExtension; diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp index 4fb419302..95d148e1a 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -2990,7 +2990,6 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { REQUIRE(!classProperty->array); uint32_t invokedCallbackCount = 0; - view.getPropertyView( "TestClassProperty", [&values, &invokedCallbackCount]( From 8ad3f06a96aef72716d58b8de755fcf5155dcc91 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 24 May 2023 14:54:40 -0400 Subject: [PATCH 032/121] Convert batch table to EXT_structural_metadata instead --- .../src/B3dmToGltfConverter.cpp | 2 +- .../BatchTableToGltfStructuralMetadata.cpp | 1479 +++++++++-------- 2 files changed, 816 insertions(+), 665 deletions(-) diff --git a/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp b/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp index dc2689d38..8ee72dc22 100644 --- a/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp +++ b/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp @@ -219,7 +219,7 @@ void convertB3dmMetadataToGltfFeatureMetadata( return; } - // upgrade batch table to glTF feature metadata and append the result + // upgrade batch table to glTF structural metadata and append the result result.errors.merge(BatchTableToGltfStructuralMetadata::convertFromB3dm( featureTableJson, batchTableJson, diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 98ca77a24..aeb71a6d1 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -4,44 +4,230 @@ #include "Cesium3DTilesSelection/spdlog-cesium.h" #include -#include +#include #include -#include -#include +#include +#include #include #include #include +#include #include #include #include using namespace CesiumGltf; +using namespace CesiumGltf::StructuralMetadata; using namespace Cesium3DTilesSelection::CesiumImpl; namespace Cesium3DTilesSelection { namespace { +/** + * Indicates how a JSON value can be interpreted. Does not correspond one-to-one + * with types / component types in EXT_structural_metadata. + */ struct MaskedType { - bool isInt8 = true; - bool isUint8 = true; - bool isInt16 = true; - bool isUint16 = true; - bool isInt32 = true; - bool isUint32 = true; - bool isInt64 = true; - bool isUint64 = true; - bool isFloat32 = true; - bool isFloat64 = true; - bool isBool = true; - bool isArray = true; + bool isInt8; + bool isUint8; + bool isInt16; + bool isUint16; + bool isInt32; + bool isUint32; + bool isInt64; + bool isUint64; + bool isFloat32; + bool isFloat64; + bool isBool; + + MaskedType() : MaskedType(true){}; + + MaskedType(bool defaultValue) + : isInt8(defaultValue), + isUint8(defaultValue), + isInt16(defaultValue), + isUint16(defaultValue), + isInt32(defaultValue), + isUint32(defaultValue), + isInt64(defaultValue), + isUint64(defaultValue), + isFloat32(defaultValue), + isFloat64(defaultValue), + isBool(defaultValue) {} + + /** + * Merges another MaskedType into this one. + */ + void operator&=(const MaskedType& source) { + isInt8 &= source.isInt8; + isUint8 &= source.isUint8; + isInt16 &= source.isInt16; + isUint16 &= source.isUint16; + isInt32 &= source.isInt32; + isUint32 &= source.isUint32; + isInt64 &= source.isInt64; + isUint64 &= source.isUint64; + isFloat32 &= source.isFloat32; + isFloat64 &= source.isFloat64; + isBool &= source.isBool; + } +}; + +/** + * Indicates how the elements of an array JSON value can be interpreted. Does + * not correspond one-to-one with types / component types in + * EXT_structural_metadata. + * + * To avoid complications while parsing, this implementation disallows array + * elements that are also arrays. The nested arrays will be treated as strings. + */ +struct MaskedArrayType { + MaskedType elementType; + uint32_t minArrayCount; + uint32_t maxArrayCount; + + MaskedArrayType() : MaskedArrayType(true){}; + + MaskedArrayType(bool defaultValue) + : elementType(defaultValue), + minArrayCount(std::numeric_limits::max()), + maxArrayCount(std::numeric_limits::min()){}; + + MaskedArrayType( + MaskedType elementType, + uint32_t minArrayCount, + uint32_t maxArrayCount) + : elementType(elementType), + minArrayCount(minArrayCount), + maxArrayCount(maxArrayCount) {} + + /** + * Merges another MaskedArrayType into this one. + */ + void operator&=(const MaskedArrayType& source) { + elementType &= source.elementType; + minArrayCount = glm::min(minArrayCount, source.minArrayCount); + maxArrayCount = glm::max(maxArrayCount, source.maxArrayCount); + } }; +/** + * Indicates a batch table property's compatibility with C++ types. + */ struct CompatibleTypes { - MaskedType type; - std::optional componentType; - std::optional minComponentCount; - std::optional maxComponentCount; + // std::monostate represents "complete" compatibility, in that nothing has + // been determined to be incompatible yet. Once something is either a + // MaskedType or MaskedArrayType, they are considered incompatible with the + // other type. + std::variant maskedType; + + CompatibleTypes() : maskedType(){}; + + CompatibleTypes(const MaskedType& maskedType) : maskedType(maskedType){}; + CompatibleTypes(const MaskedArrayType& maskedArrayType) + : maskedType(maskedArrayType){}; + + /** + * Whether this is only compatible with arrays. + */ + bool isArray() const { return std::get_if(&maskedType); } + + /** + * Marks as incompatible with every type. Fully-incompatible types will be + * treated as strings. + */ + void makeIncompatible() { + MaskedType incompatibleMaskedType(false); + maskedType = incompatibleMaskedType; + } + + /** + * Merges a MaskedType into this CompatibleTypes. + */ + void operator&=(const MaskedType& otherMaskedType) { + if (isArray()) { + makeIncompatible(); + return; + } + + MaskedType* pMaskedType = std::get_if(&maskedType); + if (pMaskedType) { + *pMaskedType &= otherMaskedType; + } else { + maskedType = otherMaskedType; + } + } + + /** + * Merges a MaskedArrayType into this CompatibleTypes. + */ + void operator&=(const MaskedArrayType& maskedArrayType) { + if (!isArray()) { + makeIncompatible(); + return; + } + + MaskedArrayType* pMaskedArrayType = + std::get_if(&maskedType); + if (pMaskedArrayType) { + *pMaskedArrayType &= maskedArrayType; + } else { + maskedType = maskedArrayType; + } + } + + /** + * Merges another CompatibleTypes into this one. + */ + void operator&=(const CompatibleTypes& otherTypes) { + if (otherTypes.isArray()) { + const MaskedArrayType& otherMaskedType = + std::get(otherTypes.maskedType); + operator&=(otherMaskedType); + } else { + const MaskedType& otherMaskedType = + std::get(otherTypes.maskedType); + operator&=(otherMaskedType); + } + } + + /** + * Derives MaskedType info from this CompatibleTypes. If this CompatibleTypes + * is only compatible with arrays, this will return an incompatible + * MaskedType. + */ + MaskedType toMaskedType() const { + if (isArray()) { + return MaskedType(false); + } + + const MaskedType* pMaskedType = std::get_if(&maskedType); + if (pMaskedType) { + return *pMaskedType; + } + + // If maskedType == std::monostate, then this CompatibleTypes is considered + // compatible with everything. + return MaskedType(true); + } + + /** + * Derives MaskedArrayType info from this CompatibleTypes. If this + * CompatibleTypes is not compatible with arrays, this will return an + * incompatible MaskedArrayType. + */ + MaskedArrayType toMaskedArrayType() const { + if (isArray()) { + return std::get(maskedType); + } + + // If maskedType is a MaskedType, it is incompatible. Otherwise, if + // maskedType == std::monostate, then this CompatibleTypes is considered + // compatible with everything. + const MaskedType* pMaskedType = std::get_if(&maskedType); + return MaskedArrayType(pMaskedType == nullptr); + } }; struct BinaryProperty { @@ -50,21 +236,71 @@ struct BinaryProperty { int64_t byteLength; }; -struct GltfFeatureTableType { - std::string typeName; - size_t typeSize; +struct GltfPropertyTableType { + std::string type; + size_t componentCount; }; -const std::map - batchTableComponentTypeToGltfType = { - {"BYTE", GltfFeatureTableType{"INT8", sizeof(int8_t)}}, - {"UNSIGNED_BYTE", GltfFeatureTableType{"UINT8", sizeof(uint8_t)}}, - {"SHORT", GltfFeatureTableType{"INT16", sizeof(int16_t)}}, - {"UNSIGNED_SHORT", GltfFeatureTableType{"UINT16", sizeof(uint16_t)}}, - {"INT", GltfFeatureTableType{"INT32", sizeof(int32_t)}}, - {"UNSIGNED_INT", GltfFeatureTableType{"UINT32", sizeof(uint32_t)}}, - {"FLOAT", GltfFeatureTableType{"FLOAT32", sizeof(float)}}, - {"DOUBLE", GltfFeatureTableType{"FLOAT64", sizeof(double)}}, +const std::map batchTableTypeToGltfType = { + {"SCALAR", + GltfPropertyTableType{ + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + 1}}, + {"VEC2", + GltfPropertyTableType{ + ExtensionExtStructuralMetadataClassProperty::Type::VEC2, + 2}}, + {"VEC3", + GltfPropertyTableType{ + ExtensionExtStructuralMetadataClassProperty::Type::VEC3, + 3}}, + {"VEC4", + GltfPropertyTableType{ + ExtensionExtStructuralMetadataClassProperty::Type::VEC4, + 4}}, +}; + +struct GltfPropertyTableComponentType { + std::string componentType; + size_t componentTypeSize; +}; + +const std::map + batchTableComponentTypeToGltfComponentType = { + {"BYTE", + GltfPropertyTableComponentType{ + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + sizeof(int8_t)}}, + {"UNSIGNED_BYTE", + GltfPropertyTableComponentType{ + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8, + sizeof(uint8_t)}}, + {"SHORT", + GltfPropertyTableComponentType{ + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16, + sizeof(int16_t)}}, + {"UNSIGNED_SHORT", + GltfPropertyTableComponentType{ + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16, + sizeof(uint16_t)}}, + {"INT", + GltfPropertyTableComponentType{ + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32, + sizeof(int32_t)}}, + {"UNSIGNED_INT", + GltfPropertyTableComponentType{ + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32, + sizeof(uint32_t)}}, + {"FLOAT", + GltfPropertyTableComponentType{ + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + FLOAT32, + sizeof(float)}}, + {"DOUBLE", + GltfPropertyTableComponentType{ + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + FLOAT64, + sizeof(double)}}, }; int64_t roundUp(int64_t num, int64_t multiple) noexcept { @@ -149,132 +385,135 @@ class ArrayOfPropertyValues { const rapidjson::Value& _propertyValues; }; +CompatibleTypes findCompatibleTypesForBoolean() { + MaskedType type; + // Don't allow conversion of bools to numeric 0 or 1. + type.isInt8 = type.isUint8 = false; + type.isInt16 = type.isUint16 = false; + type.isInt32 = type.isUint32 = false; + type.isInt64 = type.isUint64 = false; + type.isFloat32 = false; + type.isFloat64 = false; + type.isBool &= true; + + return CompatibleTypes(type); +} + +template +CompatibleTypes findCompatibleTypesForNumber(const TValueIter& it) { + MaskedType type; + type.isBool = false; + + if (it->IsInt64()) { + const int64_t value = it->GetInt64(); + type.isInt8 = isInRangeForSignedInteger(value); + type.isUint8 = isInRangeForSignedInteger(value); + type.isInt16 = isInRangeForSignedInteger(value); + type.isUint16 = isInRangeForSignedInteger(value); + type.isInt32 = isInRangeForSignedInteger(value); + type.isUint32 = isInRangeForSignedInteger(value); + type.isInt64 = true; + type.isUint64 = value >= 0; + type.isFloat32 = it->IsLosslessFloat(); + type.isFloat64 = it->IsLosslessDouble(); + } else if (it->IsUint64()) { + // Only uint64_t can represent a value that fits in a uint64_t but not in + // an int64_t. + type.isInt8 = type.isUint8 = false; + type.isInt16 = type.isUint16 = false; + type.isInt32 = type.isUint32 = false; + type.isInt64 = false; + type.isUint64 = true; + type.isFloat32 = false; + type.isFloat64 = false; + } else if (it->IsLosslessFloat()) { + type.isInt8 = type.isUint8 = false; + type.isInt16 = type.isUint16 = false; + type.isInt32 = type.isUint32 = false; + type.isInt64 = type.isUint64 = false; + type.isFloat32 = true; + type.isFloat64 = true; + } else if (it->IsDouble()) { + type.isInt8 = type.isUint8 = false; + type.isInt16 = type.isUint16 = false; + type.isInt32 = type.isUint32 = false; + type.isInt64 = type.isUint64 = false; + type.isFloat32 = false; + type.isFloat64 = true; + } + + return CompatibleTypes(type); +} + +template +CompatibleTypes findCompatibleTypesForArray(const TValueIter& it) { + // Iterate over all of the elements in the array and determine their + // compatible type. + CompatibleTypes arrayElementCompatibleTypes = + findCompatibleTypes(ArrayOfPropertyValues(*it)); + + if (arrayElementCompatibleTypes.isArray()) { + // Ignore complications with arrays of arrays. The elements will be treated + // like strings. + arrayElementCompatibleTypes.makeIncompatible(); + assert(!arrayElementCompatibleTypes.isArray()); + } + + MaskedType elementType = arrayElementCompatibleTypes.toMaskedType(); + MaskedArrayType arrayType(elementType, it->Size(), it->Size()); + + return CompatibleTypes(arrayType); +} + template CompatibleTypes findCompatibleTypes(const TValueGetter& propertyValue) { - MaskedType type; - std::optional componentType; - std::optional minComponentCount; - std::optional maxComponentCount; + CompatibleTypes compatibleTypes; for (auto it = propertyValue.begin(); it != propertyValue.end(); ++it) { if (it->IsBool()) { - // Should we allow conversion of bools to numeric 0 or 1? Nah. - type.isInt8 = type.isUint8 = false; - type.isInt16 = type.isUint16 = false; - type.isInt32 = type.isUint32 = false; - type.isInt64 = type.isUint64 = false; - type.isFloat32 = false; - type.isFloat64 = false; - type.isBool &= true; - type.isArray = false; - } else if (it->IsInt64()) { - const int64_t value = it->GetInt64(); - type.isInt8 &= isInRangeForSignedInteger(value); - type.isUint8 &= isInRangeForSignedInteger(value); - type.isInt16 &= isInRangeForSignedInteger(value); - type.isUint16 &= isInRangeForSignedInteger(value); - type.isInt32 &= isInRangeForSignedInteger(value); - type.isUint32 &= isInRangeForSignedInteger(value); - type.isInt64 &= true; - type.isUint64 &= value >= 0; - type.isFloat32 &= it->IsLosslessFloat(); - type.isFloat64 &= it->IsLosslessDouble(); - type.isBool = false; - type.isArray = false; - } else if (it->IsUint64()) { - // Only uint64_t can represent a value that fits in a uint64_t but not in - // an int64_t. - type.isInt8 = type.isUint8 = false; - type.isInt16 = type.isUint16 = false; - type.isInt32 = type.isUint32 = false; - type.isInt64 = false; - type.isUint64 &= true; - type.isFloat32 = false; - type.isFloat64 = false; - type.isBool = false; - type.isArray = false; - } else if (it->IsLosslessFloat()) { - type.isInt8 = type.isUint8 = false; - type.isInt16 = type.isUint16 = false; - type.isInt32 = type.isUint32 = false; - type.isInt64 = type.isUint64 = false; - type.isFloat32 &= true; - type.isFloat64 &= true; - type.isBool = false; - type.isArray = false; - } else if (it->IsDouble()) { - type.isInt8 = type.isUint8 = false; - type.isInt16 = type.isUint16 = false; - type.isInt32 = type.isUint32 = false; - type.isInt64 = type.isUint64 = false; - type.isFloat32 = false; - type.isFloat64 &= true; - type.isBool = false; - type.isArray = false; + compatibleTypes &= findCompatibleTypesForBoolean(); + } else if (it->IsNumber()) { + compatibleTypes &= findCompatibleTypesForNumber(it); } else if (it->IsArray()) { - type.isInt8 = type.isUint8 = false; - type.isInt16 = type.isUint16 = false; - type.isInt32 = type.isUint32 = false; - type.isInt64 = type.isUint64 = false; - type.isFloat32 = false; - type.isFloat64 = false; - type.isBool = false; - type.isArray &= true; - CompatibleTypes currentComponentType = - findCompatibleTypes(ArrayOfPropertyValues(*it)); - if (!componentType) { - componentType = currentComponentType.type; - } else { - componentType->isInt8 &= currentComponentType.type.isInt8; - componentType->isUint8 &= currentComponentType.type.isUint8; - componentType->isInt16 &= currentComponentType.type.isInt16; - componentType->isUint16 &= currentComponentType.type.isUint16; - componentType->isInt32 &= currentComponentType.type.isInt32; - componentType->isUint32 &= currentComponentType.type.isUint32; - componentType->isInt64 &= currentComponentType.type.isInt64; - componentType->isUint64 &= currentComponentType.type.isUint64; - componentType->isFloat32 &= currentComponentType.type.isFloat32; - componentType->isFloat64 &= currentComponentType.type.isFloat64; - componentType->isBool &= currentComponentType.type.isBool; - componentType->isArray &= currentComponentType.type.isArray; - } - - maxComponentCount = maxComponentCount - ? glm::max(*maxComponentCount, it->Size()) - : it->Size(); - minComponentCount = minComponentCount - ? glm::min(*minComponentCount, it->Size()) - : it->Size(); + compatibleTypes &= findCompatibleTypesForArray(it); } else { // A string, null, or something else. - type.isInt8 = type.isUint8 = false; - type.isInt16 = type.isUint16 = false; - type.isInt32 = type.isUint32 = false; - type.isInt64 = type.isUint64 = false; - type.isFloat32 = false; - type.isFloat64 = false; - type.isBool = false; - type.isArray = false; + compatibleTypes.makeIncompatible(); } } - return {type, componentType, minComponentCount, maxComponentCount}; + return compatibleTypes; +} + +int32_t addBufferToGltf(Model& gltf, std::vector&& buffer) { + const size_t gltfBufferIndex = gltf.buffers.size(); + Buffer& gltfBuffer = gltf.buffers.emplace_back(); + gltfBuffer.byteLength = static_cast(buffer.size()); + gltfBuffer.cesium.data = std::move(buffer); + + const size_t bufferViewIndex = gltf.bufferViews.size(); + BufferView& bufferView = gltf.bufferViews.emplace_back(); + bufferView.buffer = static_cast(gltfBufferIndex); + bufferView.byteOffset = 0; + bufferView.byteLength = gltfBuffer.byteLength; + + return static_cast(bufferViewIndex); } template void updateExtensionWithJsonStringProperty( Model& gltf, - ClassProperty& classProperty, - const FeatureTable& featureTable, - FeatureTableProperty& featureTableProperty, + ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, const TValueGetter& propertyValue) { rapidjson::StringBuffer rapidjsonStrBuffer; std::vector rapidjsonOffsets; - rapidjsonOffsets.reserve(static_cast(featureTable.count + 1)); + rapidjsonOffsets.reserve(static_cast(propertyTable.count + 1)); rapidjsonOffsets.emplace_back(0); auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { if (it == propertyValue.end()) { rapidjsonOffsets.emplace_back(rapidjsonStrBuffer.GetLength()); continue; @@ -284,9 +523,9 @@ void updateExtensionWithJsonStringProperty( rapidjson::Writer writer(rapidjsonStrBuffer); it->Accept(writer); } else { - // Because serialized string json will add double quotations in the buffer - // which is not needed by us, we will manually add the string to the - // buffer + // Because serialized string json will add double quotations in the + // buffer which is not needed by us, we will manually add the string to + // the buffer const auto& rapidjsonStr = it->GetString(); rapidjsonStrBuffer.Reserve(it->GetStringLength()); for (rapidjson::SizeType j = 0; j < it->GetStringLength(); ++j) { @@ -307,28 +546,36 @@ void updateExtensionWithJsonStringProperty( rapidjsonOffsets, buffer, offsetBuffer); - featureTableProperty.offsetType = "UINT8"; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT8; } else if (isInRangeForUnsignedInteger(totalSize)) { copyStringBuffer( rapidjsonStrBuffer, rapidjsonOffsets, buffer, offsetBuffer); - featureTableProperty.offsetType = "UINT16"; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT16; } else if (isInRangeForUnsignedInteger(totalSize)) { copyStringBuffer( rapidjsonStrBuffer, rapidjsonOffsets, buffer, offsetBuffer); - featureTableProperty.offsetType = "UINT32"; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT32; } else { copyStringBuffer( rapidjsonStrBuffer, rapidjsonOffsets, buffer, offsetBuffer); - featureTableProperty.offsetType = "UINT64"; + propertyTableProperty.stringOffsetType = + ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: + UINT64; } Buffer& gltfBuffer = gltf.buffers.emplace_back(); @@ -354,85 +601,70 @@ void updateExtensionWithJsonStringProperty( const int32_t offsetBufferViewIdx = static_cast(gltf.bufferViews.size() - 1); - classProperty.type = "STRING"; + classProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::STRING; - featureTableProperty.bufferView = valueBufferViewIdx; - featureTableProperty.stringOffsetBufferView = offsetBufferViewIdx; + propertyTableProperty.values = valueBufferViewIdx; + propertyTableProperty.stringOffsets = offsetBufferViewIdx; } template -void updateExtensionWithJsonNumericProperty( +void updateExtensionWithJsonScalarProperty( Model& gltf, - ClassProperty& classProperty, - const FeatureTable& featureTable, - FeatureTableProperty& featureTableProperty, + ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, const TValueGetter& propertyValue, - const std::string& typeName) { - assert(propertyValue.size() >= featureTable.count); + const std::string& componentTypeName) { + assert(propertyValue.size() >= propertyTable.count); - classProperty.type = typeName; + classProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + classProperty.componentType = componentTypeName; // Create a new buffer for this property. - const size_t bufferIndex = gltf.buffers.size(); - Buffer& buffer = gltf.buffers.emplace_back(); - buffer.byteLength = - static_cast(sizeof(T) * static_cast(featureTable.count)); - buffer.cesium.data.resize(static_cast(buffer.byteLength)); - - const size_t bufferViewIndex = gltf.bufferViews.size(); - BufferView& bufferView = gltf.bufferViews.emplace_back(); - bufferView.buffer = int32_t(bufferIndex); - bufferView.byteOffset = 0; - bufferView.byteLength = buffer.byteLength; - - featureTableProperty.bufferView = int32_t(bufferViewIndex); + std::vector buffer; + const size_t byteLength = + sizeof(T) * static_cast(propertyTable.count); + buffer.resize(byteLength); - T* p = reinterpret_cast(buffer.cesium.data.data()); + T* p = reinterpret_cast(buffer.data()); auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { *p = static_cast(it->template Get()); ++p; ++it; } + + propertyTableProperty.values = addBufferToGltf(gltf, std::move(buffer)); } template -void updateExtensionWithJsonBoolProperty( +void updateExtensionWithJsonBooleanProperty( Model& gltf, - ClassProperty& classProperty, - const FeatureTable& featureTable, - FeatureTableProperty& featureTableProperty, + ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, const TValueGetter& propertyValue) { - assert(propertyValue.size() >= featureTable.count); + assert(propertyValue.size() >= propertyTable.count); - std::vector data(static_cast( - glm::ceil(static_cast(featureTable.count) / 8.0))); + std::vector buffer(static_cast( + glm::ceil(static_cast(propertyTable.count) / 8.0))); auto it = propertyValue.begin(); for (rapidjson::SizeType i = 0; - i < static_cast(featureTable.count); + i < static_cast(propertyTable.count); ++i) { const bool value = it->GetBool(); const size_t byteIndex = i / 8; const size_t bitIndex = i % 8; - data[byteIndex] = - static_cast(value << bitIndex) | data[byteIndex]; + buffer[byteIndex] = + static_cast(value << bitIndex) | buffer[byteIndex]; ++it; } - const size_t bufferIndex = gltf.buffers.size(); - Buffer& buffer = gltf.buffers.emplace_back(); - buffer.byteLength = static_cast(data.size()); - buffer.cesium.data = std::move(data); - - BufferView& bufferView = gltf.bufferViews.emplace_back(); - bufferView.buffer = static_cast(bufferIndex); - bufferView.byteOffset = 0; - bufferView.byteLength = buffer.byteLength; - - featureTableProperty.bufferView = - static_cast(gltf.bufferViews.size() - 1); - - classProperty.type = "BOOLEAN"; + classProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + propertyTableProperty.values = addBufferToGltf(gltf, std::move(buffer)); } template < @@ -440,20 +672,20 @@ template < typename ValueType, typename OffsetType, typename TValueGetter> -void copyNumericDynamicArrayBuffers( +void copyVariableLengthScalarArraysToBuffers( std::vector& valueBuffer, std::vector& offsetBuffer, size_t numOfElements, - const FeatureTable& featureTable, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, const TValueGetter& propertyValue) { valueBuffer.resize(sizeof(ValueType) * numOfElements); offsetBuffer.resize( - sizeof(OffsetType) * static_cast(featureTable.count + 1)); + sizeof(OffsetType) * static_cast(propertyTable.count + 1)); ValueType* value = reinterpret_cast(valueBuffer.data()); OffsetType* offsetValue = reinterpret_cast(offsetBuffer.data()); OffsetType prevOffset = 0; auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { const auto& jsonArrayMember = *it; *offsetValue = prevOffset; ++offsetValue; @@ -472,23 +704,31 @@ void copyNumericDynamicArrayBuffers( } template -void updateNumericArrayProperty( +void updateScalarArrayProperty( Model& gltf, - ClassProperty& classProperty, - FeatureTableProperty& featureTableProperty, - const FeatureTable& featureTable, - const CompatibleTypes& compatibleTypes, + ExtensionExtStructuralMetadataClassProperty& classProperty, + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + const MaskedArrayType& arrayType, const TValueGetter& propertyValue) { - assert(propertyValue.size() >= featureTable.count); - - // check if it's a fixed array - if (compatibleTypes.minComponentCount == compatibleTypes.maxComponentCount) { - const size_t numOfValues = static_cast(featureTable.count) * - *compatibleTypes.minComponentCount; + assert(propertyValue.size() >= propertyTable.count); + + classProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + classProperty.componentType = + convertPropertyComponentTypeToString(static_cast( + TypeToPropertyType::component)); + classProperty.array = true; + + // Handle fixed-length arrays. + if (arrayType.minArrayCount == arrayType.maxArrayCount) { + const size_t arrayCount = static_cast(arrayType.minArrayCount); + const size_t numOfValues = + static_cast(propertyTable.count) * arrayCount; std::vector valueBuffer(sizeof(ValueType) * numOfValues); ValueType* value = reinterpret_cast(valueBuffer.data()); auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { const auto& jsonArrayMember = *it; for (const auto& valueJson : jsonArrayMember.GetArray()) { *value = static_cast(valueJson.template Get()); @@ -497,121 +737,82 @@ void updateNumericArrayProperty( ++it; } - Buffer& gltfValueBuffer = gltf.buffers.emplace_back(); - gltfValueBuffer.byteLength = static_cast(valueBuffer.size()); - gltfValueBuffer.cesium.data = std::move(valueBuffer); - - BufferView& gltfValueBufferView = gltf.bufferViews.emplace_back(); - gltfValueBufferView.buffer = static_cast(gltf.buffers.size() - 1); - gltfValueBufferView.byteOffset = 0; - gltfValueBufferView.byteLength = - static_cast(gltfValueBuffer.cesium.data.size()); - - classProperty.type = "ARRAY"; - classProperty.componentType = convertPropertyTypeToString( - static_cast(TypeToPropertyType::value)); - classProperty.componentCount = *compatibleTypes.minComponentCount; - - featureTableProperty.bufferView = - static_cast(gltf.bufferViews.size() - 1); + classProperty.count = arrayCount; + propertyTableProperty.values = + addBufferToGltf(gltf, std::move(valueBuffer)); return; } - // total size of value buffer - size_t numOfElements = 0; + // Handle variable-length arrays. + // Compute total size of the value buffer. + size_t totalNumElements = 0; auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { const auto& jsonArrayMember = *it; - numOfElements += jsonArrayMember.Size(); + totalNumElements += jsonArrayMember.Size(); ++it; } - PropertyType offsetType = PropertyType::None; + PropertyComponentType offsetType = PropertyComponentType::None; std::vector valueBuffer; std::vector offsetBuffer; - const uint64_t maxOffsetValue = numOfElements * sizeof(ValueType); + const uint64_t maxOffsetValue = totalNumElements * sizeof(ValueType); if (isInRangeForUnsignedInteger(maxOffsetValue)) { - copyNumericDynamicArrayBuffers( + copyVariableLengthScalarArraysToBuffers( valueBuffer, offsetBuffer, - numOfElements, - featureTable, + totalNumElements, + propertyTable, propertyValue); - offsetType = PropertyType::Uint8; + offsetType = PropertyComponentType::Uint8; } else if (isInRangeForUnsignedInteger(maxOffsetValue)) { - copyNumericDynamicArrayBuffers( + copyVariableLengthScalarArraysToBuffers( valueBuffer, offsetBuffer, - numOfElements, - featureTable, + totalNumElements, + propertyTable, propertyValue); - offsetType = PropertyType::Uint16; + offsetType = PropertyComponentType::Uint16; } else if (isInRangeForUnsignedInteger(maxOffsetValue)) { - copyNumericDynamicArrayBuffers( + copyVariableLengthScalarArraysToBuffers( valueBuffer, offsetBuffer, - numOfElements, - featureTable, + totalNumElements, + propertyTable, propertyValue); - offsetType = PropertyType::Uint32; + offsetType = PropertyComponentType::Uint32; } else if (isInRangeForUnsignedInteger(maxOffsetValue)) { - copyNumericDynamicArrayBuffers( + copyVariableLengthScalarArraysToBuffers( valueBuffer, offsetBuffer, - numOfElements, - featureTable, + totalNumElements, + propertyTable, propertyValue); - offsetType = PropertyType::Uint64; + offsetType = PropertyComponentType::Uint64; } - Buffer& gltfValueBuffer = gltf.buffers.emplace_back(); - gltfValueBuffer.byteLength = static_cast(valueBuffer.size()); - gltfValueBuffer.cesium.data = std::move(valueBuffer); - - BufferView& gltfValueBufferView = gltf.bufferViews.emplace_back(); - gltfValueBufferView.buffer = static_cast(gltf.buffers.size() - 1); - gltfValueBufferView.byteOffset = 0; - gltfValueBufferView.byteLength = - static_cast(gltfValueBuffer.cesium.data.size()); - const int32_t valueBufferIdx = - static_cast(gltf.bufferViews.size() - 1); - - Buffer& gltfOffsetBuffer = gltf.buffers.emplace_back(); - gltfOffsetBuffer.byteLength = static_cast(offsetBuffer.size()); - gltfOffsetBuffer.cesium.data = std::move(offsetBuffer); - - BufferView& gltfOffsetBufferView = gltf.bufferViews.emplace_back(); - gltfOffsetBufferView.buffer = static_cast(gltf.buffers.size() - 1); - gltfOffsetBufferView.byteOffset = 0; - gltfOffsetBufferView.byteLength = - static_cast(gltfOffsetBuffer.cesium.data.size()); - const int32_t offsetBufferIdx = - static_cast(gltf.bufferViews.size() - 1); - - classProperty.type = "ARRAY"; - classProperty.componentType = convertPropertyTypeToString( - static_cast(TypeToPropertyType::value)); - - featureTableProperty.bufferView = valueBufferIdx; - featureTableProperty.arrayOffsetBufferView = offsetBufferIdx; - featureTableProperty.offsetType = convertPropertyTypeToString(offsetType); + propertyTableProperty.values = addBufferToGltf(gltf, std::move(valueBuffer)); + propertyTableProperty.arrayOffsets = + addBufferToGltf(gltf, std::move(offsetBuffer)); + propertyTableProperty.arrayOffsetType = + convertPropertyComponentTypeToString(offsetType); } template -void copyStringArrayBuffers( +void copyStringsToBuffers( std::vector& valueBuffer, std::vector& offsetBuffer, size_t totalByteLength, size_t numOfString, - const FeatureTable& featureTable, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, const TValueGetter& propertyValue) { valueBuffer.resize(totalByteLength); offsetBuffer.resize((numOfString + 1) * sizeof(OffsetType)); OffsetType offset = 0; size_t offsetIndex = 0; auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { const auto& arrayMember = *it; for (const auto& str : arrayMember.GetArray()) { OffsetType byteLength = static_cast( @@ -634,16 +835,16 @@ void copyStringArrayBuffers( } template -void copyArrayOffsetBufferForStringArrayProperty( +void copyArrayOffsetsForStringArraysToBuffer( std::vector& offsetBuffer, - const FeatureTable& featureTable, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, const TValueGetter& propertyValue) { OffsetType prevOffset = 0; offsetBuffer.resize( - static_cast(featureTable.count + 1) * sizeof(OffsetType)); + static_cast(propertyTable.count + 1) * sizeof(OffsetType)); OffsetType* offset = reinterpret_cast(offsetBuffer.data()); auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { const auto& arrayMember = *it; *offset = prevOffset; prevOffset = static_cast( @@ -658,175 +859,137 @@ void copyArrayOffsetBufferForStringArrayProperty( template void updateStringArrayProperty( Model& gltf, - ClassProperty& classProperty, - FeatureTableProperty& featureTableProperty, - const FeatureTable& featureTable, - const CompatibleTypes& compatibleTypes, + ExtensionExtStructuralMetadataClassProperty& classProperty, + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + const MaskedArrayType& arrayType, const TValueGetter& propertyValue) { - assert(propertyValue.size() >= featureTable.count); + assert(propertyValue.size() >= propertyTable.count); - size_t numOfString = 0; - size_t totalChars = 0; + size_t stringCount = 0; + size_t totalCharCount = 0; auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { const auto& arrayMember = *it; - numOfString += arrayMember.Size(); + stringCount += arrayMember.Size(); for (const auto& str : arrayMember.GetArray()) { - totalChars += str.GetStringLength(); + totalCharCount += str.GetStringLength(); } ++it; } - const uint64_t totalByteLength = totalChars * sizeof(rapidjson::Value::Ch); + const uint64_t totalByteLength = + totalCharCount * sizeof(rapidjson::Value::Ch); std::vector valueBuffer; - std::vector offsetBuffer; - PropertyType offsetType = PropertyType::None; + std::vector stringOffsetBuffer; + PropertyComponentType stringOffsetType = PropertyComponentType::None; if (isInRangeForUnsignedInteger(totalByteLength)) { - copyStringArrayBuffers( + copyStringsToBuffers( valueBuffer, - offsetBuffer, + stringOffsetBuffer, totalByteLength, - numOfString, - featureTable, + stringCount, + propertyTable, propertyValue); - offsetType = PropertyType::Uint8; + stringOffsetType = PropertyComponentType::Uint8; } else if (isInRangeForUnsignedInteger(totalByteLength)) { - copyStringArrayBuffers( + copyStringsToBuffers( valueBuffer, - offsetBuffer, + stringOffsetBuffer, totalByteLength, - numOfString, - featureTable, + stringCount, + propertyTable, propertyValue); - offsetType = PropertyType::Uint16; + stringOffsetType = PropertyComponentType::Uint16; } else if (isInRangeForUnsignedInteger(totalByteLength)) { - copyStringArrayBuffers( + copyStringsToBuffers( valueBuffer, - offsetBuffer, + stringOffsetBuffer, totalByteLength, - numOfString, - featureTable, + stringCount, + propertyTable, propertyValue); - offsetType = PropertyType::Uint32; + stringOffsetType = PropertyComponentType::Uint32; } else if (isInRangeForUnsignedInteger(totalByteLength)) { - copyStringArrayBuffers( + copyStringsToBuffers( valueBuffer, - offsetBuffer, + stringOffsetBuffer, totalByteLength, - numOfString, - featureTable, + stringCount, + propertyTable, propertyValue); - offsetType = PropertyType::Uint64; + stringOffsetType = PropertyComponentType::Uint64; } - // create gltf value buffer view - Buffer& gltfValueBuffer = gltf.buffers.emplace_back(); - gltfValueBuffer.byteLength = static_cast(valueBuffer.size()); - gltfValueBuffer.cesium.data = std::move(valueBuffer); - - BufferView& gltfValueBufferView = gltf.bufferViews.emplace_back(); - gltfValueBufferView.buffer = - static_cast(gltf.buffers.size() - 1); - gltfValueBufferView.byteOffset = 0; - gltfValueBufferView.byteLength = gltfValueBuffer.byteLength; - const int32_t valueBufferViewIdx = - static_cast(gltf.bufferViews.size() - 1); - - // create gltf string offset buffer view - Buffer& gltfOffsetBuffer = gltf.buffers.emplace_back(); - gltfOffsetBuffer.byteLength = static_cast(offsetBuffer.size()); - gltfOffsetBuffer.cesium.data = std::move(offsetBuffer); - - BufferView& gltfOffsetBufferView = gltf.bufferViews.emplace_back(); - gltfOffsetBufferView.buffer = static_cast(gltf.buffers.size() - 1); - gltfOffsetBufferView.byteOffset = 0; - gltfOffsetBufferView.byteLength = gltfOffsetBuffer.byteLength; - const int32_t offsetBufferViewIdx = - static_cast(gltf.bufferViews.size() - 1); - - // fixed array of string - if (compatibleTypes.minComponentCount == compatibleTypes.maxComponentCount) { - classProperty.type = "ARRAY"; - classProperty.componentCount = compatibleTypes.minComponentCount; - classProperty.componentType = "STRING"; - - featureTableProperty.bufferView = valueBufferViewIdx; - featureTableProperty.stringOffsetBufferView = offsetBufferViewIdx; - featureTableProperty.offsetType = convertPropertyTypeToString(offsetType); + classProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::STRING; + classProperty.array = true; + propertyTableProperty.stringOffsetType = + convertPropertyComponentTypeToString(stringOffsetType); + propertyTableProperty.values = addBufferToGltf(gltf, std::move(valueBuffer)); + propertyTableProperty.stringOffsets = + addBufferToGltf(gltf, std::move(stringOffsetBuffer)); + + // Handle fixed-length arrays + if (arrayType.minArrayCount == arrayType.maxArrayCount) { + classProperty.count = arrayType.minArrayCount; return; } - // dynamic array of string needs array offset buffer + // Handle variable-length arrays std::vector arrayOffsetBuffer; - switch (offsetType) { - case PropertyType::Uint8: - copyArrayOffsetBufferForStringArrayProperty( + switch (stringOffsetType) { + case PropertyComponentType::Uint8: + copyArrayOffsetsForStringArraysToBuffer( arrayOffsetBuffer, - featureTable, + propertyTable, propertyValue); break; - case PropertyType::Uint16: - copyArrayOffsetBufferForStringArrayProperty( + case PropertyComponentType::Uint16: + copyArrayOffsetsForStringArraysToBuffer( arrayOffsetBuffer, - featureTable, + propertyTable, propertyValue); break; - case PropertyType::Uint32: - copyArrayOffsetBufferForStringArrayProperty( + case PropertyComponentType::Uint32: + copyArrayOffsetsForStringArraysToBuffer( arrayOffsetBuffer, - featureTable, + propertyTable, propertyValue); break; - case PropertyType::Uint64: - copyArrayOffsetBufferForStringArrayProperty( + case PropertyComponentType::Uint64: + copyArrayOffsetsForStringArraysToBuffer( arrayOffsetBuffer, - featureTable, + propertyTable, propertyValue); break; default: break; } - // create gltf array offset buffer view - Buffer& gltfArrayOffsetBuffer = gltf.buffers.emplace_back(); - gltfArrayOffsetBuffer.byteLength = - static_cast(arrayOffsetBuffer.size()); - gltfArrayOffsetBuffer.cesium.data = std::move(arrayOffsetBuffer); - - BufferView& gltfArrayOffsetBufferView = gltf.bufferViews.emplace_back(); - gltfArrayOffsetBufferView.buffer = - static_cast(gltf.buffers.size() - 1); - gltfArrayOffsetBufferView.byteOffset = 0; - gltfArrayOffsetBufferView.byteLength = gltfArrayOffsetBuffer.byteLength; - const int32_t arrayOffsetBufferViewIdx = - static_cast(gltf.bufferViews.size() - 1); - - classProperty.type = "ARRAY"; - classProperty.componentType = "STRING"; - - featureTableProperty.bufferView = valueBufferViewIdx; - featureTableProperty.arrayOffsetBufferView = arrayOffsetBufferViewIdx; - featureTableProperty.stringOffsetBufferView = offsetBufferViewIdx; - featureTableProperty.offsetType = convertPropertyTypeToString(offsetType); + propertyTableProperty.arrayOffsets = + addBufferToGltf(gltf, std::move(arrayOffsetBuffer)); + propertyTableProperty.arrayOffsetType = + convertPropertyComponentTypeToString(stringOffsetType); } template -void copyBooleanArrayBuffers( +void copyVariableLengthBooleanArraysBuffers( std::vector& valueBuffer, std::vector& offsetBuffer, size_t numOfElements, - const FeatureTable& featureTable, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, const TValueGetter& propertyValue) { size_t currentIndex = 0; const size_t totalByteLength = static_cast(glm::ceil(static_cast(numOfElements) / 8.0)); valueBuffer.resize(totalByteLength); offsetBuffer.resize( - static_cast(featureTable.count + 1) * sizeof(OffsetType)); + static_cast(propertyTable.count + 1) * sizeof(OffsetType)); OffsetType* offset = reinterpret_cast(offsetBuffer.data()); OffsetType prevOffset = 0; auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { const auto& arrayMember = *it; *offset = prevOffset; @@ -850,23 +1013,27 @@ void copyBooleanArrayBuffers( template void updateBooleanArrayProperty( Model& gltf, - ClassProperty& classProperty, - FeatureTableProperty& featureTableProperty, - const FeatureTable& featureTable, - const CompatibleTypes& compatibleTypes, + ExtensionExtStructuralMetadataClassProperty& classProperty, + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + const MaskedArrayType& arrayType, const TValueGetter& propertyValue) { - assert(propertyValue.size() >= featureTable.count); + assert(propertyValue.size() >= propertyTable.count); + + classProperty.type = "BOOLEAN"; + classProperty.array = true; - // fixed array of boolean - if (compatibleTypes.minComponentCount == compatibleTypes.maxComponentCount) { - const size_t numOfElements = static_cast( - featureTable.count * compatibleTypes.minComponentCount.value()); + // Fixed-length array of booleans + if (arrayType.minArrayCount == arrayType.maxArrayCount) { + const size_t arrayCount = static_cast(arrayType.minArrayCount); + const size_t numOfElements = + static_cast(propertyTable.count) * arrayCount; const size_t totalByteLength = static_cast( glm::ceil(static_cast(numOfElements) / 8.0)); std::vector valueBuffer(totalByteLength); size_t currentIndex = 0; auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { const auto& arrayMember = *it; for (const auto& data : arrayMember.GetArray()) { const bool value = data.GetBool(); @@ -879,29 +1046,17 @@ void updateBooleanArrayProperty( ++it; } - Buffer& gltfValueBuffer = gltf.buffers.emplace_back(); - gltfValueBuffer.byteLength = static_cast(valueBuffer.size()); - gltfValueBuffer.cesium.data = std::move(valueBuffer); - - BufferView& gltfValueBufferView = gltf.bufferViews.emplace_back(); - gltfValueBufferView.buffer = static_cast(gltf.buffers.size() - 1); - gltfValueBufferView.byteOffset = 0; - gltfValueBufferView.byteLength = gltfValueBuffer.byteLength; - - classProperty.type = "ARRAY"; - classProperty.componentCount = compatibleTypes.minComponentCount; - classProperty.componentType = "BOOLEAN"; - - featureTableProperty.bufferView = - static_cast(gltf.bufferViews.size() - 1); + propertyTableProperty.values = + addBufferToGltf(gltf, std::move(valueBuffer)); + classProperty.count = static_cast(arrayCount); return; } - // dynamic array of boolean + // Variable-length array of booleans size_t numOfElements = 0; auto it = propertyValue.begin(); - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { const auto& arrayMember = *it; numOfElements += arrayMember.Size(); ++it; @@ -909,197 +1064,175 @@ void updateBooleanArrayProperty( std::vector valueBuffer; std::vector offsetBuffer; - PropertyType offsetType = PropertyType::None; + PropertyComponentType offsetType = PropertyComponentType::None; if (isInRangeForUnsignedInteger(numOfElements)) { - copyBooleanArrayBuffers( + copyVariableLengthBooleanArraysBuffers( valueBuffer, offsetBuffer, numOfElements, - featureTable, + propertyTable, propertyValue); - offsetType = PropertyType::Uint8; + offsetType = PropertyComponentType::Uint8; } else if (isInRangeForUnsignedInteger(numOfElements)) { - copyBooleanArrayBuffers( + copyVariableLengthBooleanArraysBuffers( valueBuffer, offsetBuffer, numOfElements, - featureTable, + propertyTable, propertyValue); - offsetType = PropertyType::Uint16; + offsetType = PropertyComponentType::Uint16; } else if (isInRangeForUnsignedInteger(numOfElements)) { - copyBooleanArrayBuffers( + copyVariableLengthBooleanArraysBuffers( valueBuffer, offsetBuffer, numOfElements, - featureTable, + propertyTable, propertyValue); - offsetType = PropertyType::Uint32; + offsetType = PropertyComponentType::Uint32; } else { - copyBooleanArrayBuffers( + copyVariableLengthBooleanArraysBuffers( valueBuffer, offsetBuffer, numOfElements, - featureTable, + propertyTable, propertyValue); - offsetType = PropertyType::Uint64; + offsetType = PropertyComponentType::Uint64; } - Buffer& gltfValueBuffer = gltf.buffers.emplace_back(); - gltfValueBuffer.byteLength = static_cast(valueBuffer.size()); - gltfValueBuffer.cesium.data = std::move(valueBuffer); - - BufferView& gltfValueBufferView = gltf.bufferViews.emplace_back(); - gltfValueBufferView.buffer = static_cast(gltf.buffers.size() - 1); - gltfValueBufferView.byteOffset = 0; - gltfValueBufferView.byteLength = - static_cast(gltfValueBuffer.cesium.data.size()); - const int32_t valueBufferIdx = - static_cast(gltf.bufferViews.size() - 1); - - Buffer& gltfOffsetBuffer = gltf.buffers.emplace_back(); - gltfOffsetBuffer.byteLength = static_cast(offsetBuffer.size()); - gltfOffsetBuffer.cesium.data = std::move(offsetBuffer); - - BufferView& gltfOffsetBufferView = gltf.bufferViews.emplace_back(); - gltfOffsetBufferView.buffer = static_cast(gltf.buffers.size() - 1); - gltfOffsetBufferView.byteOffset = 0; - gltfOffsetBufferView.byteLength = - static_cast(gltfOffsetBuffer.cesium.data.size()); - const int32_t offsetBufferIdx = - static_cast(gltf.bufferViews.size() - 1); - - classProperty.type = "ARRAY"; - classProperty.componentType = "BOOLEAN"; - - featureTableProperty.bufferView = valueBufferIdx; - featureTableProperty.arrayOffsetBufferView = offsetBufferIdx; - featureTableProperty.offsetType = convertPropertyTypeToString(offsetType); + propertyTableProperty.values = addBufferToGltf(gltf, std::move(valueBuffer)); + propertyTableProperty.arrayOffsets = + addBufferToGltf(gltf, std::move(offsetBuffer)); + propertyTableProperty.arrayOffsetType = + convertPropertyComponentTypeToString(offsetType); } template void updateExtensionWithArrayProperty( Model& gltf, - ClassProperty& classProperty, - const FeatureTable& featureTable, - FeatureTableProperty& featureTableProperty, - const CompatibleTypes& compatibleTypes, + ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, + const MaskedArrayType& arrayType, const TValueGetter& propertyValue) { - assert(propertyValue.size() >= featureTable.count); + assert(propertyValue.size() >= propertyTable.count); - if (compatibleTypes.componentType->isBool) { + const MaskedType& elementType = arrayType.elementType; + if (elementType.isBool) { updateBooleanArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); - } else if (compatibleTypes.componentType->isInt8) { - updateNumericArrayProperty( + } else if (elementType.isInt8) { + updateScalarArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); - } else if (compatibleTypes.componentType->isUint8) { - updateNumericArrayProperty( + } else if (elementType.isUint8) { + updateScalarArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); - } else if (compatibleTypes.componentType->isInt16) { - updateNumericArrayProperty( + } else if (elementType.isInt16) { + updateScalarArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); - } else if (compatibleTypes.componentType->isUint16) { - updateNumericArrayProperty( + } else if (elementType.isUint16) { + updateScalarArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); - } else if (compatibleTypes.componentType->isInt32) { - updateNumericArrayProperty( + } else if (elementType.isInt32) { + updateScalarArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); - } else if (compatibleTypes.componentType->isUint32) { - updateNumericArrayProperty( + } else if (elementType.isUint32) { + updateScalarArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); - } else if (compatibleTypes.componentType->isInt64) { - updateNumericArrayProperty( + } else if (elementType.isInt64) { + updateScalarArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); - } else if (compatibleTypes.componentType->isUint64) { - updateNumericArrayProperty( + } else if (elementType.isUint64) { + updateScalarArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); - } else if (compatibleTypes.componentType->isFloat32) { - updateNumericArrayProperty( + } else if (elementType.isFloat32) { + updateScalarArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); - } else if (compatibleTypes.componentType->isFloat64) { - updateNumericArrayProperty( + } else if (elementType.isFloat64) { + updateScalarArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); } else { updateStringArrayProperty( gltf, classProperty, - featureTableProperty, - featureTable, - compatibleTypes, + propertyTableProperty, + propertyTable, + arrayType, propertyValue); } } +// Updates the extension with a property defined as an array of values in the +// batch table JSON. template void updateExtensionWithJsonProperty( Model& gltf, - ClassProperty& classProperty, - const FeatureTable& featureTable, - FeatureTableProperty& featureTableProperty, + ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, const TValueGetter& propertyValue) { - if (propertyValue.size() == 0 || propertyValue.size() < featureTable.count) { + if (propertyValue.size() == 0 || propertyValue.size() < propertyTable.count) { // No property to infer the type from, so assume string. updateExtensionWithJsonStringProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue); return; } @@ -1107,107 +1240,112 @@ void updateExtensionWithJsonProperty( // Figure out which types we can use for this data. // Use the smallest type we can, and prefer signed to unsigned. const CompatibleTypes compatibleTypes = findCompatibleTypes(propertyValue); - if (compatibleTypes.type.isBool) { - updateExtensionWithJsonBoolProperty( + if (compatibleTypes.isArray()) { + MaskedArrayType arrayType = compatibleTypes.toMaskedArrayType(); + updateExtensionWithArrayProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, + arrayType, propertyValue); - } else if (compatibleTypes.type.isInt8) { - updateExtensionWithJsonNumericProperty( + return; + } + + MaskedType type = compatibleTypes.toMaskedType(); + if (type.isBool) { + updateExtensionWithJsonBooleanProperty( gltf, classProperty, - featureTable, - featureTableProperty, - propertyValue, - "INT8"); - } else if (compatibleTypes.type.isUint8) { - updateExtensionWithJsonNumericProperty( + propertyTable, + propertyTableProperty, + propertyValue); + } else if (type.isInt8) { + updateExtensionWithJsonScalarProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue, - "UINT8"); - } else if (compatibleTypes.type.isInt16) { - updateExtensionWithJsonNumericProperty( + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8); + } else if (type.isUint8) { + updateExtensionWithJsonScalarProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue, - "INT16"); - } else if (compatibleTypes.type.isUint16) { - updateExtensionWithJsonNumericProperty( + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8); + } else if (type.isInt16) { + updateExtensionWithJsonScalarProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue, - "UINT16"); - } else if (compatibleTypes.type.isInt32) { - updateExtensionWithJsonNumericProperty( + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16); + } else if (type.isUint16) { + updateExtensionWithJsonScalarProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue, - "INT32"); - } else if (compatibleTypes.type.isUint32) { - updateExtensionWithJsonNumericProperty( + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); + } else if (type.isInt32) { + updateExtensionWithJsonScalarProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue, - "UINT32"); - } else if (compatibleTypes.type.isInt64) { - updateExtensionWithJsonNumericProperty( + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + } else if (type.isUint32) { + updateExtensionWithJsonScalarProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue, - "INT64"); - } else if (compatibleTypes.type.isUint64) { - updateExtensionWithJsonNumericProperty( + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + } else if (type.isInt64) { + updateExtensionWithJsonScalarProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue, - "UINT64"); - } else if (compatibleTypes.type.isFloat32) { - updateExtensionWithJsonNumericProperty( + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64); + } else if (type.isUint64) { + updateExtensionWithJsonScalarProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue, - "FLOAT32"); - } else if (compatibleTypes.type.isFloat64) { - updateExtensionWithJsonNumericProperty( + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64); + } else if (type.isFloat32) { + updateExtensionWithJsonScalarProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue, - "FLOAT64"); - } else if (compatibleTypes.type.isArray) { - updateExtensionWithArrayProperty( + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); + } else if (type.isFloat64) { + updateExtensionWithJsonScalarProperty( gltf, classProperty, - featureTable, - featureTableProperty, - compatibleTypes, - propertyValue); + propertyTable, + propertyTableProperty, + propertyValue, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); } else { updateExtensionWithJsonStringProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, propertyValue); } } @@ -1217,12 +1355,12 @@ void updateExtensionWithBinaryProperty( int32_t gltfBufferIndex, int64_t gltfBufferOffset, BinaryProperty& binaryProperty, - ClassProperty& classProperty, - FeatureTableProperty& featureTableProperty, - ErrorList& result, - const FeatureTable& featureTable, + ExtensionExtStructuralMetadataClassProperty& classProperty, + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, const std::string& propertyName, - const rapidjson::Value& propertyValue) { + const rapidjson::Value& propertyValue, + ErrorList& result) { assert( gltfBufferIndex >= 0 && "gltfBufferIndex is negative. Need to allocate buffer before " @@ -1232,7 +1370,7 @@ void updateExtensionWithBinaryProperty( if (byteOffsetIt == propertyValue.MemberEnd() || !byteOffsetIt->value.IsInt64()) { result.emplaceWarning(fmt::format( - "Skip converting {}. The binary property doesn't have required " + "Skip converting {}. The binary property doesn't have a valid " "byteOffset.", propertyName)); return; @@ -1242,7 +1380,7 @@ void updateExtensionWithBinaryProperty( if (componentTypeIt == propertyValue.MemberEnd() || !componentTypeIt->value.IsString()) { result.emplaceWarning(fmt::format( - "Skip converting {}. The binary property doesn't have required " + "Skip converting {}. The binary property doesn't have a valid " "componentType.", propertyName)); return; @@ -1251,53 +1389,52 @@ void updateExtensionWithBinaryProperty( const auto& typeIt = propertyValue.FindMember("type"); if (typeIt == propertyValue.MemberEnd() || !typeIt->value.IsString()) { result.emplaceWarning(fmt::format( - "Skip convert {}. The binary property doesn't have required type.", + "Skip converting {}. The binary property doesn't have a valid type.", propertyName)); return; } - // convert class property + // Convert batch table property to glTF property table property const int64_t byteOffset = byteOffsetIt->value.GetInt64(); const std::string& componentType = componentTypeIt->value.GetString(); const std::string& type = typeIt->value.GetString(); - auto convertedTypeIt = batchTableComponentTypeToGltfType.find(componentType); - if (convertedTypeIt == batchTableComponentTypeToGltfType.end()) { + auto convertedTypeIt = batchTableTypeToGltfType.find(type); + if (convertedTypeIt == batchTableTypeToGltfType.end()) { + result.emplaceWarning(fmt::format( + "Skip converting {}. The binary property doesn't have a valid type.", + propertyName)); return; } - const GltfFeatureTableType& gltfType = convertedTypeIt->second; - - size_t componentCount = 1; - if (type == "SCALAR") { - classProperty.type = gltfType.typeName; - } else if (type == "VEC2") { - classProperty.type = "ARRAY"; - classProperty.componentCount = 2; - classProperty.componentType = gltfType.typeName; - componentCount = 2; - } else if (type == "VEC3") { - classProperty.type = "ARRAY"; - classProperty.componentCount = 3; - classProperty.componentType = gltfType.typeName; - componentCount = 3; - } else if (type == "VEC4") { - classProperty.type = "ARRAY"; - classProperty.componentCount = 4; - classProperty.componentType = gltfType.typeName; - componentCount = 4; - } else { + auto convertedComponentTypeIt = + batchTableComponentTypeToGltfComponentType.find(componentType); + if (convertedComponentTypeIt == + batchTableComponentTypeToGltfComponentType.end()) { + result.emplaceWarning(fmt::format( + "Skip converting {}. The binary property doesn't have a valid " + "componentType.", + propertyName)); return; } - // convert feature table - const size_t typeSize = gltfType.typeSize; + const GltfPropertyTableType& gltfType = convertedTypeIt->second; + const GltfPropertyTableComponentType& gltfComponentType = + convertedComponentTypeIt->second; + + classProperty.type = gltfType.type; + classProperty.componentType = gltfComponentType.componentType; + + // Convert to a buffer view + const size_t componentCount = gltfType.componentCount; + const size_t componentTypeSize = gltfComponentType.componentTypeSize; auto& bufferView = gltf.bufferViews.emplace_back(); bufferView.buffer = gltfBufferIndex; bufferView.byteOffset = gltfBufferOffset; bufferView.byteLength = static_cast( - typeSize * componentCount * static_cast(featureTable.count)); + componentTypeSize * componentCount * + static_cast(propertyTable.count)); - featureTableProperty.bufferView = + propertyTableProperty.values = static_cast(gltf.bufferViews.size() - 1); binaryProperty.batchTableByteOffset = byteOffset; @@ -1307,8 +1444,8 @@ void updateExtensionWithBinaryProperty( void updateExtensionWithBatchTableHierarchy( Model& gltf, - Class& classDefinition, - FeatureTable& featureTable, + ExtensionExtStructuralMetadataClass& classDefinition, + ExtensionExtStructuralMetadataPropertyTable& propertyTable, ErrorList& result, const rapidjson::Value& batchTableHierarchy) { // EXT_feature_metadata can't support hierarchy, so we need to flatten it. @@ -1329,7 +1466,8 @@ void updateExtensionWithBatchTableHierarchy( for (const auto& element : parentCountsIt->value.GetArray()) { if (!element.IsInt64() || element.GetInt64() != 1LL) { result.emplaceWarning( - "3DTILES_batch_table_hierarchy with a \"parentCounts\" property is " + "3DTILES_batch_table_hierarchy with a \"parentCounts\" property " + "is " "not currently supported. All instances must have at most one " "parent."); return; @@ -1350,7 +1488,8 @@ void updateExtensionWithBatchTableHierarchy( if (propertyIt->value.IsObject()) { result.emplaceWarning(fmt::format( "Property {} uses binary values. Only JSON-based " - "3DTILES_batch_table_hierarchy properties are currently supported.", + "3DTILES_batch_table_hierarchy properties are currently " + "supported.", propertyIt->name.GetString())); } else { properties.insert(propertyIt->name.GetString()); @@ -1360,15 +1499,20 @@ void updateExtensionWithBatchTableHierarchy( BatchTableHierarchyPropertyValues batchTableHierarchyValues( batchTableHierarchy, - featureTable.count); + propertyTable.count); for (const std::string& name : properties) { - ClassProperty& classProperty = - classDefinition.properties.emplace(name, ClassProperty()).first->second; + ExtensionExtStructuralMetadataClassProperty& classProperty = + classDefinition.properties + .emplace(name, ExtensionExtStructuralMetadataClassProperty()) + .first->second; classProperty.name = name; - FeatureTableProperty& featureTableProperty = - featureTable.properties.emplace(name, FeatureTableProperty()) + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties + .emplace( + name, + ExtensionExtStructuralMetadataPropertyTableProperty()) .first->second; batchTableHierarchyValues.setProperty(name); @@ -1376,8 +1520,8 @@ void updateExtensionWithBatchTableHierarchy( updateExtensionWithJsonProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, batchTableHierarchyValues); } } @@ -1388,8 +1532,8 @@ void convertBatchTableToGltfStructuralMetadataExtension( CesiumGltf::Model& gltf, const int64_t featureCount, ErrorList& result) { - // Add the binary part of the batch table - if any - to the glTF as a buffer. - // We will reallign this buffer later on + // Add the binary part of the batch table - if any - to the glTF as a + // buffer. We will reallign this buffer later on int32_t gltfBufferIndex = -1; int64_t gltfBufferOffset = -1; std::vector binaryProperties; @@ -1399,17 +1543,20 @@ void convertBatchTableToGltfStructuralMetadataExtension( gltf.buffers.emplace_back(); } - ExtensionModelExtFeatureMetadata& modelExtension = - gltf.addExtension(); - Schema& schema = modelExtension.schema.emplace(); - Class& classDefinition = - schema.classes.emplace("default", Class()).first->second; + ExtensionModelExtStructuralMetadata& modelExtension = + gltf.addExtension(); + ExtensionExtStructuralMetadataSchema& schema = + modelExtension.schema.emplace(); + schema.id = "default"; // Required by the spec. - FeatureTable& featureTable = - modelExtension.featureTables.emplace("default", FeatureTable()) + ExtensionExtStructuralMetadataClass& classDefinition = + schema.classes.emplace("default", ExtensionExtStructuralMetadataClass()) .first->second; - featureTable.count = featureCount; - featureTable.classProperty = "default"; + + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + modelExtension.propertyTables.emplace_back(); + propertyTable.count = featureCount; + propertyTable.classProperty = "default"; // Convert each regular property in the batch table for (auto propertyIt = batchTableJson.MemberBegin(); @@ -1422,20 +1569,25 @@ void convertBatchTableToGltfStructuralMetadataExtension( continue; } - ClassProperty& classProperty = - classDefinition.properties.emplace(name, ClassProperty()).first->second; + ExtensionExtStructuralMetadataClassProperty& classProperty = + classDefinition.properties + .emplace(name, ExtensionExtStructuralMetadataClassProperty()) + .first->second; classProperty.name = name; - FeatureTableProperty& featureTableProperty = - featureTable.properties.emplace(name, FeatureTableProperty()) + ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + propertyTable.properties + .emplace( + name, + ExtensionExtStructuralMetadataPropertyTableProperty()) .first->second; const rapidjson::Value& propertyValue = propertyIt->value; if (propertyValue.IsArray()) { updateExtensionWithJsonProperty( gltf, classProperty, - featureTable, - featureTableProperty, + propertyTable, + propertyTableProperty, ArrayOfPropertyValues(propertyValue)); } else { BinaryProperty& binaryProperty = binaryProperties.emplace_back(); @@ -1445,11 +1597,11 @@ void convertBatchTableToGltfStructuralMetadataExtension( gltfBufferOffset, binaryProperty, classProperty, - featureTableProperty, - result, - featureTable, + propertyTableProperty, + propertyTable, name, - propertyValue); + propertyValue, + result); gltfBufferOffset += roundUp(binaryProperty.byteLength, 8); } } @@ -1463,13 +1615,13 @@ void convertBatchTableToGltfStructuralMetadataExtension( updateExtensionWithBatchTableHierarchy( gltf, classDefinition, - featureTable, + propertyTable, result, bthIt->value); } } - // re-arrange binary property buffer + // Re-arrange binary property buffer if (!batchTableBinaryData.empty()) { Buffer& buffer = gltf.buffers[static_cast(gltfBufferIndex)]; buffer.byteLength = gltfBufferOffset; @@ -1521,7 +1673,7 @@ ErrorList BatchTableToGltfStructuralMetadata::convertFromB3dm( batchLength, result); - // Create an EXT_feature_metadata extension for each primitive with a _BATCHID + // Create an EXT_mesh_features extension for each primitive with a _BATCHID // attribute. for (Mesh& mesh : gltf.meshes) { for (MeshPrimitive& primitive : mesh.primitives) { @@ -1535,7 +1687,6 @@ ErrorList BatchTableToGltfStructuralMetadata::convertFromB3dm( primitive.attributes["_FEATURE_ID_0"] = batchIDIt->second; primitive.attributes.erase("_BATCHID"); - // Create an EXT_mesh_features extension with a feature ID attribute. ExtensionExtMeshFeatures& extension = primitive.addExtension(); From 219da88a0af4599271a69a74e363be33581c94b8 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 25 May 2023 10:22:13 -0400 Subject: [PATCH 033/121] Use pointers in MetadataPropertyTableView --- .../StructuralMetadataPropertyTableView.h | 27 +++++++++--------- .../StructuralMetadataPropertyTableView.cpp | 28 +++++++++---------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index 6d8b0cca7..7fcd8fc38 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -83,7 +83,7 @@ class MetadataPropertyTableView { */ int64_t size() const noexcept { return _status == MetadataPropertyTableViewStatus::Valid - ? _propertyTable.count + ? _pPropertyTable->count : 0; } @@ -973,8 +973,8 @@ class MetadataPropertyTableView { const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty) const { auto propertyTablePropertyIter = - _propertyTable.properties.find(propertyName); - if (propertyTablePropertyIter == _propertyTable.properties.end()) { + _pPropertyTable->properties.find(propertyName); + if (propertyTablePropertyIter == _pPropertyTable->properties.end()) { return createInvalidPropertyView( MetadataPropertyViewStatus::ErrorPropertyDoesNotExist); } @@ -1043,9 +1043,9 @@ class MetadataPropertyTableView { size_t maxRequiredBytes = 0; if (IsMetadataBoolean::value) { maxRequiredBytes = static_cast( - glm::ceil(static_cast(_propertyTable.count) / 8.0)); + glm::ceil(static_cast(_pPropertyTable->count) / 8.0)); } else { - maxRequiredBytes = _propertyTable.count * sizeof(T); + maxRequiredBytes = _pPropertyTable->count * sizeof(T); } if (values.size() < maxRequiredBytes) { @@ -1057,7 +1057,7 @@ class MetadataPropertyTableView { return MetadataPropertyView( MetadataPropertyViewStatus::Valid, values, - _propertyTable.count, + _pPropertyTable->count, classProperty.normalized); } @@ -1118,11 +1118,12 @@ class MetadataPropertyTableView { size_t maxRequiredBytes = 0; if constexpr (IsMetadataBoolean::value) { maxRequiredBytes = static_cast(glm::ceil( - static_cast(_propertyTable.count * fixedLengthArrayCount) / + static_cast( + _pPropertyTable->count * fixedLengthArrayCount) / 8.0)); } else { maxRequiredBytes = static_cast( - _propertyTable.count * fixedLengthArrayCount * sizeof(T)); + _pPropertyTable->count * fixedLengthArrayCount * sizeof(T)); } if (values.size() < maxRequiredBytes) { @@ -1139,7 +1140,7 @@ class MetadataPropertyTableView { PropertyComponentType::None, PropertyComponentType::None, static_cast(fixedLengthArrayCount), - static_cast(_propertyTable.count), + static_cast(_pPropertyTable->count), classProperty.normalized); } @@ -1158,7 +1159,7 @@ class MetadataPropertyTableView { propertyTableProperty.arrayOffsets, arrayOffsetType, values.size(), - static_cast(_propertyTable.count), + static_cast(_pPropertyTable->count), checkBitsSize, arrayOffsets); if (status != MetadataPropertyViewStatus::Valid) { @@ -1173,7 +1174,7 @@ class MetadataPropertyTableView { arrayOffsetType, PropertyComponentType::None, 0, - static_cast(_propertyTable.count), + static_cast(_pPropertyTable->count), classProperty.normalized); } @@ -1212,8 +1213,8 @@ class MetadataPropertyTableView { false); } - const Model& _model; - const ExtensionExtStructuralMetadataPropertyTable& _propertyTable; + const Model* _pModel; + const ExtensionExtStructuralMetadataPropertyTable* _pPropertyTable; const ExtensionExtStructuralMetadataClass* _pClass; MetadataPropertyTableViewStatus _status; }; diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp index 6e0dfb421..66f47c2fe 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -109,8 +109,8 @@ static MetadataPropertyViewStatus checkStringAndArrayOffsetsBuffers( MetadataPropertyTableView::MetadataPropertyTableView( const Model& model, const ExtensionExtStructuralMetadataPropertyTable& propertyTable) - : _model{model}, - _propertyTable{propertyTable}, + : _pModel{&model}, + _pPropertyTable{&propertyTable}, _pClass{nullptr}, _status() { const ExtensionModelExtStructuralMetadata* pMetadata = @@ -128,7 +128,7 @@ MetadataPropertyTableView::MetadataPropertyTableView( return; } - auto classIter = schema->classes.find(_propertyTable.classProperty); + auto classIter = schema->classes.find(_pPropertyTable->classProperty); if (classIter != schema->classes.end()) { _pClass = &classIter->second; } @@ -160,12 +160,12 @@ MetadataPropertyViewStatus MetadataPropertyTableView::getBufferSafe( buffer = {}; const BufferView* pBufferView = - _model.getSafe(&_model.bufferViews, bufferViewIdx); + _pModel->getSafe(&_pModel->bufferViews, bufferViewIdx); if (!pBufferView) { return MetadataPropertyViewStatus::ErrorInvalidValueBufferView; } - const Buffer* pBuffer = _model.getSafe(&_model.buffers, pBufferView->buffer); + const Buffer* pBuffer = _pModel->getSafe(&_pModel->buffers, pBufferView->buffer); if (!pBuffer) { return MetadataPropertyViewStatus::ErrorInvalidValueBuffer; } @@ -318,7 +318,7 @@ MetadataPropertyTableView::getStringPropertyValues( propertyTableProperty.stringOffsets, offsetType, values.size(), - static_cast(_propertyTable.count), + static_cast(_pPropertyTable->count), stringOffsets); if (status != MetadataPropertyViewStatus::Valid) { return createInvalidPropertyView(status); @@ -332,7 +332,7 @@ MetadataPropertyTableView::getStringPropertyValues( PropertyComponentType::None, offsetType, 0, - _propertyTable.count, + _pPropertyTable->count, classProperty.normalized); } @@ -392,7 +392,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( propertyTableProperty.stringOffsets, stringOffsetType, values.size(), - static_cast(_propertyTable.count * fixedLengthArrayCount), + static_cast(_pPropertyTable->count * fixedLengthArrayCount), stringOffsets); if (status != MetadataPropertyViewStatus::Valid) { return createInvalidPropertyView>( @@ -407,7 +407,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( PropertyComponentType::None, stringOffsetType, fixedLengthArrayCount, - _propertyTable.count, + _pPropertyTable->count, classProperty.normalized); } @@ -447,7 +447,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( stringOffsets, values.size(), stringOffsetType, - static_cast(_propertyTable.count)); + static_cast(_pPropertyTable->count)); break; case PropertyComponentType::Uint16: status = checkStringAndArrayOffsetsBuffers( @@ -455,7 +455,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( stringOffsets, values.size(), stringOffsetType, - static_cast(_propertyTable.count)); + static_cast(_pPropertyTable->count)); break; case PropertyComponentType::Uint32: status = checkStringAndArrayOffsetsBuffers( @@ -463,7 +463,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( stringOffsets, values.size(), stringOffsetType, - static_cast(_propertyTable.count)); + static_cast(_pPropertyTable->count)); break; case PropertyComponentType::Uint64: status = checkStringAndArrayOffsetsBuffers( @@ -471,7 +471,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( stringOffsets, values.size(), stringOffsetType, - static_cast(_propertyTable.count)); + static_cast(_pPropertyTable->count)); break; default: status = MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType; @@ -491,7 +491,7 @@ MetadataPropertyTableView::getStringArrayPropertyValues( arrayOffsetType, stringOffsetType, 0, - _propertyTable.count, + _pPropertyTable->count, classProperty.normalized); } From d8658e000af0c370a6ca0a6e93e1463da018e6d5 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 25 May 2023 11:49:29 -0400 Subject: [PATCH 034/121] Rewrite tests for EXT_structural_metadata --- .../BatchTableToGltfStructuralMetadata.cpp | 12 +- .../test/TestPntsToGltfConverter.cpp | 20 +- ...radeBatchTableToExtStructuralMetadata.cpp} | 1454 ++++++++++------- 3 files changed, 906 insertions(+), 580 deletions(-) rename Cesium3DTilesSelection/test/{TestUpgradeBatchTableToExtFeatureMetadata.cpp => TestUpgradeBatchTableToExtStructuralMetadata.cpp} (52%) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index aeb71a6d1..bd49e97d5 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -163,15 +163,15 @@ struct CompatibleTypes { * Merges a MaskedArrayType into this CompatibleTypes. */ void operator&=(const MaskedArrayType& maskedArrayType) { - if (!isArray()) { - makeIncompatible(); + if (isArray()) { + MaskedArrayType& arrayType = std::get(maskedType); + arrayType &= maskedArrayType; return; } - MaskedArrayType* pMaskedArrayType = - std::get_if(&maskedType); - if (pMaskedArrayType) { - *pMaskedArrayType &= maskedArrayType; + MaskedType* pMaskedType = std::get_if(&maskedType); + if (pMaskedType) { + makeIncompatible(); } else { maskedType = maskedArrayType; } diff --git a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp index 41da45719..8560ba20c 100644 --- a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp +++ b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include @@ -654,7 +654,7 @@ getUniqueBufferIds(const std::vector& bufferViews) { } TEST_CASE( - "Converts point cloud with batch IDs to glTF with EXT_feature_metadata") { + "Converts point cloud with batch IDs to glTF with EXT_structural_metadata") { std::filesystem::path testFilePath = Cesium3DTilesSelection_TEST_DATA_DIR; testFilePath = testFilePath / "PointCloud" / "pointCloudBatched.pnts"; const int32_t pointsLength = 8; @@ -665,8 +665,8 @@ TEST_CASE( Model& gltf = *result.model; // The correctness of the model extension is thoroughly tested in - // TestUpgradeBatchTableToExtFeatureMetadata - CHECK(gltf.hasExtension()); + // TestUpgradeBatchTableToExtStructuralMetadata + CHECK(gltf.hasExtension()); CHECK(gltf.nodes.size() == 1); REQUIRE(gltf.meshes.size() == 1); @@ -744,8 +744,8 @@ TEST_CASE("Converts point cloud with per-point properties to glTF with " Model& gltf = *result.model; // The correctness of the model extension is thoroughly tested in - // TestUpgradeBatchTableToExtFeatureMetadata - CHECK(gltf.hasExtension()); + // TestUpgradeBatchTableToExtStructuralMetadata + CHECK(gltf.hasExtension()); CHECK(gltf.nodes.size() == 1); REQUIRE(gltf.meshes.size() == 1); @@ -803,8 +803,8 @@ TEST_CASE("Converts point cloud with Draco compression to glTF") { CHECK(gltf.hasExtension()); // The correctness of the model extension is thoroughly tested in - // TestUpgradeBatchTableToExtFeatureMetadata - CHECK(gltf.hasExtension()); + // TestUpgradeBatchTableToExtStructuralMetadata + CHECK(gltf.hasExtension()); CHECK(gltf.nodes.size() == 1); REQUIRE(gltf.meshes.size() == 1); @@ -948,7 +948,7 @@ TEST_CASE("Converts point cloud with partial Draco compression to glTF") { Model& gltf = *result.model; CHECK(gltf.hasExtension()); - CHECK(gltf.hasExtension()); + CHECK(gltf.hasExtension()); CHECK(gltf.nodes.size() == 1); REQUIRE(gltf.meshes.size() == 1); @@ -1087,7 +1087,7 @@ TEST_CASE("Converts batched point cloud with Draco compression to glTF") { // The correctness of the model extension is thoroughly tested in // TestUpgradeBatchTableToExtFeatureMetadata - CHECK(gltf.hasExtension()); + CHECK(gltf.hasExtension()); CHECK(gltf.nodes.size() == 1); REQUIRE(gltf.meshes.size() == 1); diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp similarity index 52% rename from Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp rename to Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 34dfc9267..651af2c5d 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtFeatureMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -4,9 +4,10 @@ #include #include #include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -17,36 +18,49 @@ #include using namespace CesiumGltf; +using namespace CesiumGltf::StructuralMetadata; using namespace Cesium3DTilesSelection; +using namespace CesiumUtility; template -static void checkScalarProperty( +static void checkNonArrayProperty( const Model& model, - const FeatureTable& featureTable, - const Class& metaClass, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + const ExtensionExtStructuralMetadataClass& metaClass, const std::string& propertyName, - const std::string& expectedPropertyType, + const std::string& expectedType, + const std::optional& expectedComponentType, const std::vector& expected, size_t expectedTotalInstances) { - const ClassProperty& property = metaClass.properties.at(propertyName); - REQUIRE(property.type == expectedPropertyType); - REQUIRE(property.componentType == std::nullopt); - REQUIRE(property.componentCount == std::nullopt); - - MetadataFeatureTableView view(&model, &featureTable); - std::optional> propertyView = + const ExtensionExtStructuralMetadataClassProperty& property = + metaClass.properties.at(propertyName); + REQUIRE(property.type == expectedType); + REQUIRE(property.componentType == expectedComponentType); + REQUIRE(!property.array); + REQUIRE(property.count == std::nullopt); + + MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + MetadataPropertyView propertyView = view.getPropertyView(propertyName); - REQUIRE(propertyView != std::nullopt); - REQUIRE(propertyView->size() == featureTable.count); - REQUIRE(propertyView->size() == static_cast(expectedTotalInstances)); - for (int64_t i = 0; i < propertyView->size(); ++i) { - if constexpr ( + REQUIRE(propertyView.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyView.size() == propertyTable.count); + REQUIRE(propertyView.size() == static_cast(expectedTotalInstances)); + for (int64_t i = 0; i < propertyView.size(); ++i) { + if constexpr (std::is_same_v) { + REQUIRE(Math::equalsEpsilon( + static_cast(propertyView.get(i)), + static_cast(expected[static_cast(i)]), + Math::Epsilon6)); + } else if constexpr ( std::is_same_v || std::is_same_v) { - REQUIRE(propertyView->get(i) == Approx(expected[static_cast(i)])); + REQUIRE(propertyView.get(i) == Approx(expected[static_cast(i)])); } else { REQUIRE( - static_cast(propertyView->get(i)) == + static_cast(propertyView.get(i)) == expected[static_cast(i)]); } } @@ -55,52 +69,54 @@ static void checkScalarProperty( template static void checkArrayProperty( const Model& model, - const FeatureTable& featureTable, - const Class& metaClass, + const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + const ExtensionExtStructuralMetadataClass& metaClass, const std::string& propertyName, - int64_t expectedComponentCount, - const std::string& expectedComponentType, + int64_t expectedCount, + const std::string& expectedType, + const std::optional& expectedComponentType, const std::vector>& expected, size_t expectedTotalInstances) { - const ClassProperty& property = metaClass.properties.at(propertyName); - REQUIRE(property.type == "ARRAY"); - REQUIRE(property.componentType.has_value()); - REQUIRE(*property.componentType == expectedComponentType); - if (expectedComponentCount > 0) { - REQUIRE( - property.componentCount.value() == - static_cast(expectedComponentCount)); - } - - MetadataFeatureTableView view(&model, &featureTable); - std::optional>> - propertyView = view.getPropertyView>( - propertyName); - REQUIRE(propertyView->size() == featureTable.count); - REQUIRE(propertyView->size() == static_cast(expectedTotalInstances)); + const ExtensionExtStructuralMetadataClassProperty& property = + metaClass.properties.at(propertyName); + REQUIRE(property.type == expectedType); + REQUIRE(property.componentType == expectedComponentType); + REQUIRE(property.array); + REQUIRE(property.count.value_or(0) == expectedCount); + + MetadataPropertyTableView view(model, propertyTable); + REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + MetadataPropertyView> propertyView = + view.getPropertyView>(propertyName); + REQUIRE(propertyView.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyView.size() == propertyTable.count); + REQUIRE(propertyView.size() == static_cast(expectedTotalInstances)); for (size_t i = 0; i < expectedTotalInstances; ++i) { - MetadataArrayView val = - propertyView->get(static_cast(i)); - if (expectedComponentCount > 0) { - REQUIRE(val.size() == expectedComponentCount); + MetadataArrayView value = + propertyView.get(static_cast(i)); + if (expectedCount > 0) { + REQUIRE(value.size() == expectedCount); } for (size_t j = 0; j < expected[i].size(); ++j) { if constexpr ( std::is_same_v || std::is_same_v) { - REQUIRE(val[static_cast(j)] == Approx(expected[i][j])); + REQUIRE(value[static_cast(j)] == Approx(expected[i][j])); } else { - REQUIRE(val[static_cast(j)] == expected[i][j]); + REQUIRE(value[static_cast(j)] == expected[i][j]); } } } } template -static void createTestForScalarJson( +static void createTestForNonArrayJson( const std::vector& expected, - const std::string& expectedPropertyType, + const std::string& expectedType, + const std::optional& expectedComponentType, size_t totalInstances) { Model model; @@ -132,7 +148,7 @@ static void createTestForScalarJson( } batchTableJson.AddMember( - "scalarProp", + "scalarProperty", scalarProperty, batchTableJson.GetAllocator()); @@ -142,28 +158,37 @@ static void createTestForScalarJson( gsl::span(), model); - ExtensionModelExtFeatureMetadata* metadata = - model.getExtension(); - REQUIRE(metadata != nullptr); + const ExtensionModelExtStructuralMetadata* pMetadata = + model.getExtension(); + REQUIRE(pMetadata); - std::optional schema = metadata->schema; - REQUIRE(schema != std::nullopt); + const std::optional schema = + pMetadata->schema; + REQUIRE(schema); - const std::unordered_map& classes = schema->classes; + const std::unordered_map& + classes = schema->classes; REQUIRE(classes.size() == 1); - const Class& defaultClass = classes.at("default"); - const std::unordered_map& properties = + const ExtensionExtStructuralMetadataClass& defaultClass = + classes.at("default"); + const std::unordered_map< + std::string, + ExtensionExtStructuralMetadataClassProperty>& properties = defaultClass.properties; REQUIRE(properties.size() == 1); - const FeatureTable& featureTable = metadata->featureTables["default"]; - checkScalarProperty( + REQUIRE(pMetadata->propertyTables.size() == 1); + + const ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pMetadata->propertyTables[0]; + checkNonArrayProperty( model, - featureTable, + propertyTable, defaultClass, - "scalarProp", - expectedPropertyType, + "scalarProperty", + expectedType, + expectedComponentType, expected, totalInstances); } @@ -171,8 +196,9 @@ static void createTestForScalarJson( template static void createTestForArrayJson( const std::vector>& expected, - const std::string& expectedComponentType, - int64_t componentCount, + const std::string& expectedType, + const std::optional& expectedComponentType, + int64_t arrayCount, size_t totalInstances) { Model model; @@ -208,7 +234,7 @@ static void createTestForArrayJson( } batchTableJson.AddMember( - "fixedArrayProp", + "fixedLengthArrayProperty", fixedArrayProperties, batchTableJson.GetAllocator()); @@ -218,28 +244,30 @@ static void createTestForArrayJson( gsl::span(), model); - ExtensionModelExtFeatureMetadata* metadata = - model.getExtension(); - REQUIRE(metadata != nullptr); + const ExtensionModelExtStructuralMetadata* pMetadata = + model.getExtension(); + REQUIRE(pMetadata); - std::optional schema = metadata->schema; - REQUIRE(schema != std::nullopt); + const std::optional& schema = + pMetadata->schema; + REQUIRE(schema); + REQUIRE(schema->classes.find("default") != schema->classes.end()); - const std::unordered_map& classes = schema->classes; - REQUIRE(classes.size() == 1); + const ExtensionExtStructuralMetadataClass& defaultClass = + schema->classes.at("default"); + REQUIRE(defaultClass.properties.size() == 1); - const Class& defaultClass = classes.at("default"); - const std::unordered_map& properties = - defaultClass.properties; - REQUIRE(properties.size() == 1); + REQUIRE(pMetadata->propertyTables.size() == 1); + const ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pMetadata->propertyTables[0]; - const FeatureTable& featureTable = metadata->featureTables["default"]; checkArrayProperty( model, - featureTable, + propertyTable, defaultClass, - "fixedArrayProp", - componentCount, + "fixedLengthArrayProperty", + arrayCount, + expectedType, expectedComponentType, expected, totalInstances); @@ -247,21 +275,21 @@ static void createTestForArrayJson( std::set getUniqueBufferViewIds( const std::vector& accessors, - FeatureTable& featureTable) { + const ExtensionExtStructuralMetadataPropertyTable& propertyTable) { std::set result; for (auto it = accessors.begin(); it != accessors.end(); it++) { result.insert(it->bufferView); } - auto& properties = featureTable.properties; + auto& properties = propertyTable.properties; for (auto it = properties.begin(); it != properties.end(); it++) { auto& property = it->second; - result.insert(property.bufferView); - if (property.arrayOffsetBufferView >= 0) { - result.insert(property.arrayOffsetBufferView); + result.insert(property.values); + if (property.arrayOffsets >= 0) { + result.insert(property.arrayOffsets); } - if (property.stringOffsetBufferView >= 0) { - result.insert(property.stringOffsetBufferView); + if (property.stringOffsets >= 0) { + result.insert(property.stringOffsets); } } @@ -278,8 +306,8 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { Model& gltf = *result.model; - ExtensionModelExtFeatureMetadata* pExtension = - gltf.getExtension(); + ExtensionModelExtStructuralMetadata* pExtension = + gltf.getExtension(); REQUIRE(pExtension); // Check the schema @@ -289,7 +317,7 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - CesiumGltf::Class& defaultClass = firstClassIt->second; + ExtensionExtStructuralMetadataClass& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 4); auto idIt = defaultClass.properties.find("id"); @@ -301,50 +329,68 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { auto heightIt = defaultClass.properties.find("Height"); REQUIRE(heightIt != defaultClass.properties.end()); - CHECK(idIt->second.type == "INT8"); - CHECK(longitudeIt->second.type == "FLOAT64"); - CHECK(latitudeIt->second.type == "FLOAT64"); - CHECK(heightIt->second.type == "FLOAT64"); - - // Check the feature table - auto firstFeatureTableIt = pExtension->featureTables.begin(); - REQUIRE(firstFeatureTableIt != pExtension->featureTables.end()); - - FeatureTable& featureTable = firstFeatureTableIt->second; - CHECK(featureTable.classProperty == "default"); - REQUIRE(featureTable.properties.size() == 4); - - auto idIt2 = featureTable.properties.find("id"); - REQUIRE(idIt2 != featureTable.properties.end()); - auto longitudeIt2 = featureTable.properties.find("Longitude"); - REQUIRE(longitudeIt2 != featureTable.properties.end()); - auto latitudeIt2 = featureTable.properties.find("Latitude"); - REQUIRE(latitudeIt2 != featureTable.properties.end()); - auto heightIt2 = featureTable.properties.find("Height"); - REQUIRE(heightIt2 != featureTable.properties.end()); - - CHECK(idIt2->second.bufferView >= 0); CHECK( - idIt2->second.bufferView < static_cast(gltf.bufferViews.size())); - CHECK(longitudeIt2->second.bufferView >= 0); + idIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); CHECK( - longitudeIt2->second.bufferView < - static_cast(gltf.bufferViews.size())); - CHECK(latitudeIt2->second.bufferView >= 0); + longitudeIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); CHECK( - latitudeIt2->second.bufferView < - static_cast(gltf.bufferViews.size())); - CHECK(heightIt2->second.bufferView >= 0); + latitudeIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + CHECK( + heightIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + CHECK( - heightIt2->second.bufferView < + idIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8); + CHECK( + longitudeIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); + CHECK( + latitudeIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); + CHECK( + heightIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); + + // Check the property table + REQUIRE(pExtension->propertyTables.size() == 1); + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pExtension->propertyTables[0]; + CHECK(propertyTable.classProperty == "default"); + REQUIRE(propertyTable.properties.size() == 4); + + auto idIt2 = propertyTable.properties.find("id"); + REQUIRE(idIt2 != propertyTable.properties.end()); + auto longitudeIt2 = propertyTable.properties.find("Longitude"); + REQUIRE(longitudeIt2 != propertyTable.properties.end()); + auto latitudeIt2 = propertyTable.properties.find("Latitude"); + REQUIRE(latitudeIt2 != propertyTable.properties.end()); + auto heightIt2 = propertyTable.properties.find("Height"); + REQUIRE(heightIt2 != propertyTable.properties.end()); + + REQUIRE(idIt2->second.values >= 0); + REQUIRE(idIt2->second.values < static_cast(gltf.bufferViews.size())); + REQUIRE(longitudeIt2->second.values >= 0); + REQUIRE( + longitudeIt2->second.values < + static_cast(gltf.bufferViews.size())); + REQUIRE(latitudeIt2->second.values >= 0); + REQUIRE( + latitudeIt2->second.values < static_cast(gltf.bufferViews.size())); + REQUIRE(heightIt2->second.values >= 0); + REQUIRE( + heightIt2->second.values < static_cast(gltf.bufferViews.size())); // Make sure all property bufferViews are unique std::set bufferViews{ - idIt2->second.bufferView, - longitudeIt2->second.bufferView, - latitudeIt2->second.bufferView, - heightIt2->second.bufferView}; + idIt2->second.values, + longitudeIt2->second.values, + latitudeIt2->second.values, + heightIt2->second.values}; CHECK(bufferViews.size() == 4); // Check the mesh primitives @@ -359,6 +405,8 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { CHECK( primitive.attributes.find("_FEATURE_ID_1") == primitive.attributes.end()); + CHECK( + primitive.attributes.find("_BATCH_ID") == primitive.attributes.end()); ExtensionExtMeshFeatures* pPrimitiveExtension = primitive.getExtension(); @@ -375,12 +423,13 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { // Check metadata values { std::vector expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "id", - "INT8", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, expected, expected.size()); } @@ -397,12 +446,13 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { 13.513022359460592, 13.74609257467091, 10.145220385864377}; - checkScalarProperty( + checkNonArrayProperty( *result.model, - featureTable, + propertyTable, defaultClass, "Height", - "FLOAT64", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -419,12 +469,13 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { -1.3196718857616954, -1.3196471198757775, -1.319644104024109}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "Longitude", - "FLOAT64", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -441,18 +492,19 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { 0.6988670019309562, 0.6988523191715889, 0.6988697375823105}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "Latitude", - "FLOAT64", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, expected, expected.size()); } } -TEST_CASE("Convert binary B3DM batch table to EXT_feature_metadata") { +TEST_CASE("Convert binary B3DM batch table to EXT_structural_metadata") { std::filesystem::path testFilePath = Cesium3DTilesSelection_TEST_DATA_DIR; testFilePath = testFilePath / "BatchTables" / "batchedWithBatchTableBinary.b3dm"; @@ -460,33 +512,69 @@ TEST_CASE("Convert binary B3DM batch table to EXT_feature_metadata") { GltfConverterResult result = ConvertTileToGltf::fromB3dm(testFilePath); REQUIRE(!result.errors); - REQUIRE(result.model != std::nullopt); + REQUIRE(result.model); + + const Model& model = *result.model; - ExtensionModelExtFeatureMetadata* metadata = - result.model->getExtension(); - REQUIRE(metadata != nullptr); + const ExtensionModelExtStructuralMetadata* metadata = + model.getExtension(); + REQUIRE(metadata); - std::optional schema = metadata->schema; - REQUIRE(schema != std::nullopt); + std::optional schema = metadata->schema; + REQUIRE(schema); - const std::unordered_map& classes = schema->classes; + const std::unordered_map& + classes = schema->classes; REQUIRE(classes.size() == 1); - const Class& defaultClass = classes.at("default"); - const std::unordered_map& properties = + const ExtensionExtStructuralMetadataClass& defaultClass = + classes.at("default"); + const std::unordered_map< + std::string, + ExtensionExtStructuralMetadataClassProperty>& properties = defaultClass.properties; REQUIRE(properties.size() == 6); - const FeatureTable& featureTable = metadata->featureTables["default"]; + REQUIRE(metadata->propertyTables.size() == 1); + const ExtensionExtStructuralMetadataPropertyTable& propertyTable = + metadata->propertyTables[0]; + + // Check that batch IDs were converted to EXT_mesh_features + CHECK(!model.meshes.empty()); + + for (const Mesh& mesh : model.meshes) { + CHECK(!mesh.primitives.empty()); + for (const MeshPrimitive& primitive : mesh.primitives) { + CHECK( + primitive.attributes.find("_FEATURE_ID_0") != + primitive.attributes.end()); + CHECK( + primitive.attributes.find("_FEATURE_ID_1") == + primitive.attributes.end()); + CHECK( + primitive.attributes.find("_BATCH_ID") == primitive.attributes.end()); + + const ExtensionExtMeshFeatures* pPrimitiveExtension = + primitive.getExtension(); + REQUIRE(pPrimitiveExtension); + REQUIRE(pPrimitiveExtension->featureIds.size() == 1); + const ExtensionExtMeshFeaturesFeatureId& featureId = + pPrimitiveExtension->featureIds[0]; + CHECK(featureId.featureCount == 10); + CHECK(featureId.attribute == 0); + CHECK(featureId.propertyTable == 0); + } + } { std::vector expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + model, + propertyTable, defaultClass, "id", - "INT8", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, expected, expected.size()); } @@ -503,12 +591,13 @@ TEST_CASE("Convert binary B3DM batch table to EXT_feature_metadata") { 12.224825594574213, 12.546202838420868, 7.632075032219291}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + model, + propertyTable, defaultClass, "Height", - "FLOAT64", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -525,12 +614,13 @@ TEST_CASE("Convert binary B3DM batch table to EXT_feature_metadata") { -1.3196940116311096, -1.319683648959897, -1.3196959060375169}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + model, + propertyTable, defaultClass, "Longitude", - "FLOAT64", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -547,31 +637,33 @@ TEST_CASE("Convert binary B3DM batch table to EXT_feature_metadata") { 0.6988590050687061, 0.6988690935212543, 0.6988854945986224}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + model, + propertyTable, defaultClass, "Latitude", - "FLOAT64", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, expected, expected.size()); } { std::vector expected(10, 255); - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + model, + propertyTable, defaultClass, "code", - "UINT8", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8, expected, expected.size()); } { // clang-format off - std::vector> expected{ + std::vector expected{ {-1.31968, 0.698874, 6.155801922082901}, {-1.3196832683949145, 0.6988615321420496, 13.410263679921627}, {-1.3196637662080655, 0.6988736012180136, 6.1022464875131845}, @@ -584,29 +676,29 @@ TEST_CASE("Convert binary B3DM batch table to EXT_feature_metadata") { {-1.3196959060375169, 0.6988854945986224, 7.632075032219291} }; // clang-format on - checkArrayProperty( - *result.model, - featureTable, + checkNonArrayProperty( + model, + propertyTable, defaultClass, "cartographic", - 3, - "FLOAT64", + ExtensionExtStructuralMetadataClassProperty::Type::VEC3, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, expected, expected.size()); } } -TEST_CASE("Converts batched PNTS batch table to EXT_feature_metadata") { +TEST_CASE("Converts batched PNTS batch table to EXT_structural_metadata") { std::filesystem::path testFilePath = Cesium3DTilesSelection_TEST_DATA_DIR; testFilePath = testFilePath / "PointCloud" / "pointCloudBatched.pnts"; GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); - Model& gltf = *result.model; + const Model& gltf = *result.model; - ExtensionModelExtFeatureMetadata* pExtension = - gltf.getExtension(); + const ExtensionModelExtStructuralMetadata* pExtension = + gltf.getExtension(); REQUIRE(pExtension); // Check the schema @@ -616,7 +708,8 @@ TEST_CASE("Converts batched PNTS batch table to EXT_feature_metadata") { auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - CesiumGltf::Class& defaultClass = firstClassIt->second; + const ExtensionExtStructuralMetadataClass& defaultClass = + firstClassIt->second; REQUIRE(defaultClass.properties.size() == 3); { @@ -627,61 +720,68 @@ TEST_CASE("Converts batched PNTS batch table to EXT_feature_metadata") { auto idIt = defaultClass.properties.find("id"); REQUIRE(idIt != defaultClass.properties.end()); - CHECK(nameIt->second.type == "STRING"); - CHECK(dimensionsIt->second.type == "ARRAY"); - REQUIRE(dimensionsIt->second.componentType); - CHECK(dimensionsIt->second.componentType.value() == "FLOAT32"); - CHECK(idIt->second.type == "UINT32"); + CHECK( + nameIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::STRING); + CHECK( + dimensionsIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + CHECK( + dimensionsIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); + CHECK( + idIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + CHECK( + idIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); } - // Check the feature table - auto firstFeatureTableIt = pExtension->featureTables.begin(); - REQUIRE(firstFeatureTableIt != pExtension->featureTables.end()); - - FeatureTable& featureTable = firstFeatureTableIt->second; - CHECK(featureTable.classProperty == "default"); - REQUIRE(featureTable.properties.size() == 3); + // Check the property table + REQUIRE(pExtension->propertyTables.size() == 1); + const ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pExtension->propertyTables[0]; + CHECK(propertyTable.classProperty == "default"); + REQUIRE(propertyTable.properties.size() == 3); { - auto nameIt = featureTable.properties.find("name"); - REQUIRE(nameIt != featureTable.properties.end()); - auto dimensionsIt = featureTable.properties.find("dimensions"); - REQUIRE(dimensionsIt != featureTable.properties.end()); - auto idIt = featureTable.properties.find("id"); - REQUIRE(idIt != featureTable.properties.end()); - - CHECK(nameIt->second.bufferView >= 0); - CHECK( - nameIt->second.bufferView < - static_cast(gltf.bufferViews.size())); - CHECK(dimensionsIt->second.bufferView >= 0); - CHECK( - dimensionsIt->second.bufferView < - static_cast(gltf.bufferViews.size())); - CHECK(idIt->second.bufferView >= 0); - CHECK( - idIt->second.bufferView < + auto nameIt = propertyTable.properties.find("name"); + REQUIRE(nameIt != propertyTable.properties.end()); + auto dimensionsIt = propertyTable.properties.find("dimensions"); + REQUIRE(dimensionsIt != propertyTable.properties.end()); + auto idIt = propertyTable.properties.find("id"); + REQUIRE(idIt != propertyTable.properties.end()); + + REQUIRE(nameIt->second.values >= 0); + REQUIRE( + nameIt->second.values < static_cast(gltf.bufferViews.size())); + REQUIRE(dimensionsIt->second.values >= 0); + REQUIRE( + dimensionsIt->second.values < static_cast(gltf.bufferViews.size())); + REQUIRE(idIt->second.values >= 0); + REQUIRE( + idIt->second.values < static_cast(gltf.bufferViews.size())); } std::set bufferViewSet = - getUniqueBufferViewIds(gltf.accessors, featureTable); + getUniqueBufferViewIds(gltf.accessors, propertyTable); CHECK(bufferViewSet.size() == gltf.bufferViews.size()); // Check the mesh primitive REQUIRE(gltf.meshes.size() == 1); - Mesh& mesh = gltf.meshes[0]; + const Mesh& mesh = gltf.meshes[0]; REQUIRE(mesh.primitives.size() == 1); - MeshPrimitive& primitive = mesh.primitives[0]; + const MeshPrimitive& primitive = mesh.primitives[0]; CHECK( primitive.attributes.find("_FEATURE_ID_0") != primitive.attributes.end()); - ExtensionExtMeshFeatures* pPrimitiveExtension = + const ExtensionExtMeshFeatures* pPrimitiveExtension = primitive.getExtension(); REQUIRE(pPrimitiveExtension); REQUIRE(pPrimitiveExtension->featureIds.size() == 1); - ExtensionExtMeshFeaturesFeatureId& featureId = + const ExtensionExtMeshFeaturesFeatureId& featureId = pPrimitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 8); CHECK(featureId.attribute == 0); @@ -698,18 +798,19 @@ TEST_CASE("Converts batched PNTS batch table to EXT_feature_metadata") { "section5", "section6", "section7"}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "name", - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, expected, expected.size()); } { - std::vector> expected = { + std::vector expected = { {0.1182744f, 0.7206326f, 0.6399210f}, {0.5820198f, 0.1433532f, 0.5373732f}, {0.9446688f, 0.7586156f, 0.5218483f}, @@ -718,32 +819,32 @@ TEST_CASE("Converts batched PNTS batch table to EXT_feature_metadata") { {0.7369181f, 0.4561503f, 0.2165503f}, {0.5684339f, 0.1352181f, 0.0187897f}, {0.3241409f, 0.6176354f, 0.1496748f}}; - - checkArrayProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "dimensions", - 3, - "FLOAT32", + ExtensionExtStructuralMetadataClassProperty::Type::VEC3, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, expected, expected.size()); } { std::vector expected = {0, 1, 2, 3, 4, 5, 6, 7}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "id", - "UINT32", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32, expected, expected.size()); } } -TEST_CASE("Converts per-point PNTS batch table to EXT_feature_metadata") { +TEST_CASE("Converts per-point PNTS batch table to EXT_structural_metadata") { std::filesystem::path testFilePath = Cesium3DTilesSelection_TEST_DATA_DIR; testFilePath = testFilePath / "PointCloud" / "pointCloudWithPerPointProperties.pnts"; @@ -751,10 +852,10 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_feature_metadata") { GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); - Model& gltf = *result.model; + const Model& gltf = *result.model; - ExtensionModelExtFeatureMetadata* pExtension = - gltf.getExtension(); + const ExtensionModelExtStructuralMetadata* pExtension = + gltf.getExtension(); REQUIRE(pExtension); // Check the schema @@ -764,7 +865,8 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_feature_metadata") { auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - CesiumGltf::Class& defaultClass = firstClassIt->second; + const ExtensionExtStructuralMetadataClass& defaultClass = + firstClassIt->second; REQUIRE(defaultClass.properties.size() == 3); { @@ -775,61 +877,73 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_feature_metadata") { auto idIt = defaultClass.properties.find("id"); REQUIRE(idIt != defaultClass.properties.end()); - CHECK(temperatureIt->second.type == "FLOAT32"); - CHECK(secondaryColorIt->second.type == "ARRAY"); + CHECK( + temperatureIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + CHECK( + temperatureIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); + CHECK( + secondaryColorIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3); REQUIRE(secondaryColorIt->second.componentType); - CHECK(secondaryColorIt->second.componentType.value() == "FLOAT32"); - CHECK(idIt->second.type == "UINT16"); + CHECK( + secondaryColorIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); + CHECK( + idIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + CHECK( + idIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); } - // Check the feature table - auto firstFeatureTableIt = pExtension->featureTables.begin(); - REQUIRE(firstFeatureTableIt != pExtension->featureTables.end()); - - FeatureTable& featureTable = firstFeatureTableIt->second; - CHECK(featureTable.classProperty == "default"); - REQUIRE(featureTable.properties.size() == 3); + // Check the property table + REQUIRE(pExtension->propertyTables.size() == 1); + const ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pExtension->propertyTables[0]; + CHECK(propertyTable.classProperty == "default"); + REQUIRE(propertyTable.properties.size() == 3); { - auto temperatureIt = featureTable.properties.find("temperature"); - REQUIRE(temperatureIt != featureTable.properties.end()); - auto secondaryColorIt = featureTable.properties.find("secondaryColor"); - REQUIRE(secondaryColorIt != featureTable.properties.end()); - auto idIt = featureTable.properties.find("id"); - REQUIRE(idIt != featureTable.properties.end()); - - CHECK(temperatureIt->second.bufferView >= 0); - CHECK( - temperatureIt->second.bufferView < - static_cast(gltf.bufferViews.size())); - CHECK(secondaryColorIt->second.bufferView >= 0); - CHECK( - secondaryColorIt->second.bufferView < + auto temperatureIt = propertyTable.properties.find("temperature"); + REQUIRE(temperatureIt != propertyTable.properties.end()); + auto secondaryColorIt = propertyTable.properties.find("secondaryColor"); + REQUIRE(secondaryColorIt != propertyTable.properties.end()); + auto idIt = propertyTable.properties.find("id"); + REQUIRE(idIt != propertyTable.properties.end()); + + REQUIRE(temperatureIt->second.values >= 0); + REQUIRE( + temperatureIt->second.values < static_cast(gltf.bufferViews.size())); - CHECK(idIt->second.bufferView >= 0); - CHECK( - idIt->second.bufferView < + REQUIRE(secondaryColorIt->second.values >= 0); + REQUIRE( + secondaryColorIt->second.values < static_cast(gltf.bufferViews.size())); + REQUIRE(idIt->second.values >= 0); + REQUIRE( + idIt->second.values < static_cast(gltf.bufferViews.size())); } std::set bufferViewSet = - getUniqueBufferViewIds(gltf.accessors, featureTable); + getUniqueBufferViewIds(gltf.accessors, propertyTable); CHECK(bufferViewSet.size() == gltf.bufferViews.size()); // Check the mesh primitive REQUIRE(gltf.meshes.size() == 1); - Mesh& mesh = gltf.meshes[0]; + const Mesh& mesh = gltf.meshes[0]; REQUIRE(mesh.primitives.size() == 1); - MeshPrimitive& primitive = mesh.primitives[0]; + const MeshPrimitive& primitive = mesh.primitives[0]; CHECK( primitive.attributes.find("_FEATURE_ID_0") == primitive.attributes.end()); - ExtensionExtMeshFeatures* pPrimitiveExtension = + const ExtensionExtMeshFeatures* pPrimitiveExtension = primitive.getExtension(); REQUIRE(pPrimitiveExtension); REQUIRE(pPrimitiveExtension->featureIds.size() == 1); - ExtensionExtMeshFeaturesFeatureId& featureId = + const ExtensionExtMeshFeaturesFeatureId& featureId = pPrimitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 8); CHECK(!featureId.attribute); @@ -846,18 +960,19 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_feature_metadata") { 0.3274261f, 0.1337213f, 0.0207673f}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "temperature", - "FLOAT32", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, expected, expected.size()); } { - std::vector> expected = { + std::vector expected = { {0.0202183f, 0, 0}, {0.3682415f, 0, 0}, {0.8326198f, 0, 0}, @@ -866,43 +981,43 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_feature_metadata") { {0.1403507f, 0, 0}, {0.8700121f, 0, 0}, {0.8700872f, 0, 0}}; - - checkArrayProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "secondaryColor", - 3, - "FLOAT32", + ExtensionExtStructuralMetadataClassProperty::Type::VEC3, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, expected, expected.size()); } { std::vector expected = {0, 1, 2, 3, 4, 5, 6, 7}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "id", - "UINT16", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16, expected, expected.size()); } } TEST_CASE("Converts Draco per-point PNTS batch table to " - "EXT_feature_metadata") { + "EXT_structural_metadata") { std::filesystem::path testFilePath = Cesium3DTilesSelection_TEST_DATA_DIR; testFilePath = testFilePath / "PointCloud" / "pointCloudDraco.pnts"; GltfConverterResult result = ConvertTileToGltf::fromPnts(testFilePath); REQUIRE(result.model); - Model& gltf = *result.model; + const Model& gltf = *result.model; - ExtensionModelExtFeatureMetadata* pExtension = - gltf.getExtension(); + const ExtensionModelExtStructuralMetadata* pExtension = + gltf.getExtension(); REQUIRE(pExtension); // Check the schema @@ -912,7 +1027,8 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - CesiumGltf::Class& defaultClass = firstClassIt->second; + const ExtensionExtStructuralMetadataClass& defaultClass = + firstClassIt->second; REQUIRE(defaultClass.properties.size() == 3); { @@ -923,61 +1039,73 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " auto idIt = defaultClass.properties.find("id"); REQUIRE(idIt != defaultClass.properties.end()); - CHECK(temperatureIt->second.type == "FLOAT32"); - CHECK(secondaryColorIt->second.type == "ARRAY"); + CHECK( + temperatureIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + CHECK( + temperatureIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); + CHECK( + secondaryColorIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3); REQUIRE(secondaryColorIt->second.componentType); - CHECK(secondaryColorIt->second.componentType.value() == "FLOAT32"); - CHECK(idIt->second.type == "UINT16"); + CHECK( + secondaryColorIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); + CHECK( + idIt->second.type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + CHECK( + idIt->second.componentType == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); } - // Check the feature table - auto firstFeatureTableIt = pExtension->featureTables.begin(); - REQUIRE(firstFeatureTableIt != pExtension->featureTables.end()); - - FeatureTable& featureTable = firstFeatureTableIt->second; - CHECK(featureTable.classProperty == "default"); - REQUIRE(featureTable.properties.size() == 3); + // Check the property table + REQUIRE(pExtension->propertyTables.size() == 1); + const ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pExtension->propertyTables[0]; + CHECK(propertyTable.classProperty == "default"); + REQUIRE(propertyTable.properties.size() == 3); { - auto temperatureIt = featureTable.properties.find("temperature"); - REQUIRE(temperatureIt != featureTable.properties.end()); - auto secondaryColorIt = featureTable.properties.find("secondaryColor"); - REQUIRE(secondaryColorIt != featureTable.properties.end()); - auto idIt = featureTable.properties.find("id"); - REQUIRE(idIt != featureTable.properties.end()); - - CHECK(temperatureIt->second.bufferView >= 0); - CHECK( - temperatureIt->second.bufferView < - static_cast(gltf.bufferViews.size())); - CHECK(secondaryColorIt->second.bufferView >= 0); - CHECK( - secondaryColorIt->second.bufferView < + auto temperatureIt = propertyTable.properties.find("temperature"); + REQUIRE(temperatureIt != propertyTable.properties.end()); + auto secondaryColorIt = propertyTable.properties.find("secondaryColor"); + REQUIRE(secondaryColorIt != propertyTable.properties.end()); + auto idIt = propertyTable.properties.find("id"); + REQUIRE(idIt != propertyTable.properties.end()); + + REQUIRE(temperatureIt->second.values >= 0); + REQUIRE( + temperatureIt->second.values < static_cast(gltf.bufferViews.size())); - CHECK(idIt->second.bufferView >= 0); - CHECK( - idIt->second.bufferView < + REQUIRE(secondaryColorIt->second.values >= 0); + REQUIRE( + secondaryColorIt->second.values < static_cast(gltf.bufferViews.size())); + REQUIRE(idIt->second.values >= 0); + REQUIRE( + idIt->second.values < static_cast(gltf.bufferViews.size())); } std::set bufferViewSet = - getUniqueBufferViewIds(gltf.accessors, featureTable); + getUniqueBufferViewIds(gltf.accessors, propertyTable); CHECK(bufferViewSet.size() == gltf.bufferViews.size()); // Check the mesh primitive REQUIRE(gltf.meshes.size() == 1); - Mesh& mesh = gltf.meshes[0]; + const Mesh& mesh = gltf.meshes[0]; REQUIRE(mesh.primitives.size() == 1); - MeshPrimitive& primitive = mesh.primitives[0]; + const MeshPrimitive& primitive = mesh.primitives[0]; CHECK( primitive.attributes.find("_FEATURE_ID_0") == primitive.attributes.end()); - ExtensionExtMeshFeatures* pPrimitiveExtension = + const ExtensionExtMeshFeatures* pPrimitiveExtension = primitive.getExtension(); REQUIRE(pPrimitiveExtension); REQUIRE(pPrimitiveExtension->featureIds.size() == 1); - ExtensionExtMeshFeaturesFeatureId& featureId = + const ExtensionExtMeshFeaturesFeatureId& featureId = pPrimitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 8); CHECK(!featureId.attribute); @@ -994,18 +1122,19 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " 0.3274441f, 0.1337535f, 0.0207673f}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "temperature", - "FLOAT32", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, expected, expected.size()); } { - std::vector> expected = { + std::vector expected = { {0.1182744f, 0, 0}, {0.7206645f, 0, 0}, {0.6399421f, 0, 0}, @@ -1014,32 +1143,32 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " {0.5374249f, 0, 0}, {0.9446688f, 0, 0}, {0.7586040f, 0, 0}}; - - checkArrayProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "secondaryColor", - 3, - "FLOAT32", + ExtensionExtStructuralMetadataClassProperty::Type::VEC3, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, expected, expected.size()); } { std::vector expected = {0, 1, 2, 3, 4, 5, 6, 7}; - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + gltf, + propertyTable, defaultClass, "id", - "UINT16", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16, expected, expected.size()); } } -TEST_CASE("Upgrade json nested json metadata to string") { +TEST_CASE("Upgrade nested JSON metadata to string") { std::filesystem::path testFilePath = Cesium3DTilesSelection_TEST_DATA_DIR; testFilePath = testFilePath / "BatchTables" / "batchedWithStringAndNestedJson.b3dm"; @@ -1047,46 +1176,55 @@ TEST_CASE("Upgrade json nested json metadata to string") { GltfConverterResult result = ConvertTileToGltf::fromB3dm(testFilePath); REQUIRE(!result.errors); - REQUIRE(result.model != std::nullopt); + REQUIRE(result.model); - ExtensionModelExtFeatureMetadata* metadata = - result.model->getExtension(); - REQUIRE(metadata != nullptr); + const Model& model = *result.model; + const ExtensionModelExtStructuralMetadata* pMetadata = + result.model->getExtension(); + REQUIRE(pMetadata); - std::optional schema = metadata->schema; - REQUIRE(schema != std::nullopt); + const std::optional& schema = + pMetadata->schema; + REQUIRE(schema); - const std::unordered_map& classes = schema->classes; + const std::unordered_map& + classes = schema->classes; REQUIRE(classes.size() == 1); - const Class& defaultClass = classes.at("default"); - const std::unordered_map& properties = + const ExtensionExtStructuralMetadataClass& defaultClass = + classes.at("default"); + const std::unordered_map< + std::string, + ExtensionExtStructuralMetadataClassProperty>& properties = defaultClass.properties; REQUIRE(properties.size() == 6); - const FeatureTable& featureTable = metadata->featureTables["default"]; - REQUIRE(featureTable.count == 10); + REQUIRE(pMetadata->propertyTables.size() == 1); + const ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pMetadata->propertyTables[0]; + REQUIRE(propertyTable.count == 10); { std::vector expected; - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { std::string v = std::string("{\"name\":\"building") + std::to_string(i) + "\",\"year\":" + std::to_string(i) + "}"; expected.push_back(v); } - checkScalarProperty( - *result.model, - featureTable, + checkNonArrayProperty( + model, + propertyTable, defaultClass, "info", - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, expected, expected.size()); } { std::vector> expected; - for (int64_t i = 0; i < featureTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i) { std::vector expectedVal; expectedVal.emplace_back("room" + std::to_string(i) + "_a"); expectedVal.emplace_back("room" + std::to_string(i) + "_b"); @@ -1094,18 +1232,19 @@ TEST_CASE("Upgrade json nested json metadata to string") { expected.emplace_back(std::move(expectedVal)); } checkArrayProperty( - *result.model, - featureTable, + model, + propertyTable, defaultClass, "rooms", 3, - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, expected, expected.size()); } } -TEST_CASE("Upgrade bool json to boolean binary") { +TEST_CASE("Upgrade JSON booleans to binary") { Model model; rapidjson::Document featureTableJson; @@ -1138,36 +1277,45 @@ TEST_CASE("Upgrade bool json to boolean binary") { gsl::span(), model); - ExtensionModelExtFeatureMetadata* metadata = - model.getExtension(); - REQUIRE(metadata != nullptr); + const ExtensionModelExtStructuralMetadata* pMetadata = + model.getExtension(); + REQUIRE(pMetadata); - std::optional schema = metadata->schema; - REQUIRE(schema != std::nullopt); + const std::optional& schema = + pMetadata->schema; + REQUIRE(schema); - const std::unordered_map& classes = schema->classes; + const std::unordered_map& + classes = schema->classes; REQUIRE(classes.size() == 1); - const Class& defaultClass = classes.at("default"); - const std::unordered_map& properties = + const ExtensionExtStructuralMetadataClass& defaultClass = + classes.at("default"); + const std::unordered_map< + std::string, + ExtensionExtStructuralMetadataClassProperty>& properties = defaultClass.properties; REQUIRE(properties.size() == 1); - const ClassProperty& propertyClass = properties.at("boolProp"); + const ExtensionExtStructuralMetadataClassProperty& propertyClass = + properties.at("boolProp"); REQUIRE(propertyClass.type == "BOOLEAN"); - const FeatureTable& featureTable = metadata->featureTables["default"]; - checkScalarProperty( + REQUIRE(pMetadata->propertyTables.size() == 1); + const ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pMetadata->propertyTables[0]; + checkNonArrayProperty( model, - featureTable, + propertyTable, defaultClass, "boolProp", - "BOOLEAN", + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + std::nullopt, expected, expected.size()); } -TEST_CASE("Upgrade fixed json number array") { +TEST_CASE("Upgrade fixed-length JSON arrays") { SECTION("int8_t") { // clang-format off std::vector> expected { @@ -1178,8 +1326,12 @@ TEST_CASE("Upgrade fixed json number array") { {11, 22, 3, 5}}; // clang-format on - std::string expectedComponentType = "INT8"; - createTestForArrayJson(expected, expectedComponentType, 4, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + 4, + expected.size()); } SECTION("uint8_t") { @@ -1192,13 +1344,17 @@ TEST_CASE("Upgrade fixed json number array") { {119, 112, 156, 5, 35}}; // clang-format on - std::string expectedComponentType = "UINT8"; - createTestForArrayJson(expected, expectedComponentType, 5, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8, + 5, + expected.size()); } SECTION("int16_t") { // clang-format off - std::vector> expected { + std::vector> expected { {0, 1, 4, 4445}, {12, 50, -12, -1}, {123, 10, 3333, 3}, @@ -1206,13 +1362,17 @@ TEST_CASE("Upgrade fixed json number array") { {11, 22, 3, 50}}; // clang-format on - std::string expectedComponentType = "INT16"; - createTestForArrayJson(expected, expectedComponentType, 4, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16, + 4, + expected.size()); } SECTION("uint16_t") { // clang-format off - std::vector> expected { + std::vector> expected { {0, 1, 4, 65000}, {12, 50, 12, 1}, {123, 10, 33330, 3}, @@ -1220,13 +1380,17 @@ TEST_CASE("Upgrade fixed json number array") { {11, 22, 3, 50000}}; // clang-format on - std::string expectedComponentType = "UINT16"; - createTestForArrayJson(expected, expectedComponentType, 4, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16, + 4, + expected.size()); } SECTION("int32_t") { // clang-format off - std::vector> expected { + std::vector> expected { {0, 1, 4, 1}, {1244, -500000, 1222, 544662}, {123, -10, 122, 334}, @@ -1234,13 +1398,17 @@ TEST_CASE("Upgrade fixed json number array") { {11, 22, 3, 2147483647}}; // clang-format on - std::string expectedComponentType = "INT32"; - createTestForArrayJson(expected, expectedComponentType, 4, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32, + 4, + expected.size()); } SECTION("uint32_t") { // clang-format off - std::vector> expected { + std::vector> expected { {0, 1, 4, 1}, {1244, 12200000, 1222, 544662}, {123, 10, 122, 334}, @@ -1248,15 +1416,19 @@ TEST_CASE("Upgrade fixed json number array") { {11, 22, 3, (uint32_t)4294967295}}; // clang-format on - std::string expectedComponentType = "UINT32"; - createTestForArrayJson(expected, expectedComponentType, 4, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32, + 4, + expected.size()); } SECTION("int64_t") { - // though the max positive number is only uint32_t. However, due to negative - // number, it is upgraded to int64_t + // The max positive number only requires uint32_t, but due to + // the negative number, it is upgraded to int64_t. // clang-format off - std::vector> expected { + std::vector> expected { {0, 1, 4, 1}, {1244, -922, 1222, 54}, {123, 10, 122, 334}, @@ -1264,13 +1436,17 @@ TEST_CASE("Upgrade fixed json number array") { {11, 22, 3, 3147483647}}; // clang-format on - std::string expectedComponentType = "INT64"; - createTestForArrayJson(expected, expectedComponentType, 4, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64, + 4, + expected.size()); } SECTION("uint64_t") { // clang-format off - std::vector> expected { + std::vector> expected { {0, 1, 4, 1}, {1244, 13223302036854775807u, 1222, 544662}, {123, 10, 122, 334}, @@ -1278,13 +1454,35 @@ TEST_CASE("Upgrade fixed json number array") { {11, 22, 3, 13223302036854775807u}}; // clang-format on - std::string expectedComponentType = "UINT64"; - createTestForArrayJson(expected, expectedComponentType, 4, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64, + 4, + expected.size()); + } + + SECTION("float") { + // clang-format off + std::vector> expected { + {0.122f, 1.1233f, 4.113f, 1.11f}, + {1.244f, 122.3f, 1.222f, 544.66f}, + {12.003f, 1.21f, 2.123f, 33.12f}, + {1.333f, 4.232f, 1.422f, 9.4f}, + {1.1221f, 2.2f, 3.0f, 122.31f}}; + // clang-format on + + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, + 4, + expected.size()); } SECTION("double") { // clang-format off - std::vector> expected { + std::vector> expected { {0.122, 1.1233, 4.113, 1.11}, {1.244, 122.3, 1.222, 544.66}, {12.003, 1.21, 2.123, 33.12}, @@ -1292,13 +1490,17 @@ TEST_CASE("Upgrade fixed json number array") { {1.1221, 2.2, 3.0, 122.31}}; // clang-format on - std::string expectedComponentType = "FLOAT64"; - createTestForArrayJson(expected, expectedComponentType, 4, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + 4, + expected.size()); } SECTION("string") { // clang-format off - std::vector> expected{ + std::vector> expected{ {"Test0", "Test1", "Test2", "Test4"}, {"Test5", "Test6", "Test7", "Test8"}, {"Test9", "Test10", "Test11", "Test12"}, @@ -1308,14 +1510,15 @@ TEST_CASE("Upgrade fixed json number array") { createTestForArrayJson( expected, - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, 4, expected.size()); } SECTION("Boolean") { // clang-format off - std::vector> expected{ + std::vector> expected{ {true, true, false, true, false, true}, {true, false, true, false, true, true}, {false, true, true, false, false, true}, @@ -1323,11 +1526,16 @@ TEST_CASE("Upgrade fixed json number array") { }; // clang-format on - createTestForArrayJson(expected, "BOOLEAN", 6, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + std::nullopt, + 6, + expected.size()); } } -TEST_CASE("Upgrade dynamic json number array") { +TEST_CASE("Upgrade variable-length JSON arrays") { SECTION("int8_t") { // clang-format off std::vector> expected { @@ -1338,8 +1546,12 @@ TEST_CASE("Upgrade dynamic json number array") { {11, 22, 3, 5, 33, 12, -122}}; // clang-format on - std::string expectedComponentType = "INT8"; - createTestForArrayJson(expected, expectedComponentType, 0, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + 0, + expected.size()); } SECTION("uint8_t") { @@ -1352,8 +1564,12 @@ TEST_CASE("Upgrade dynamic json number array") { {119, 112, 156, 5, 35, 244, 122}}; // clang-format on - std::string expectedComponentType = "UINT8"; - createTestForArrayJson(expected, expectedComponentType, 0, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8, + 0, + expected.size()); } SECTION("int16_t") { @@ -1366,8 +1582,12 @@ TEST_CASE("Upgrade dynamic json number array") { {11, 22, 3, 50, 455, 122, 3333, 5555, 12233}}; // clang-format on - std::string expectedComponentType = "INT16"; - createTestForArrayJson(expected, expectedComponentType, 0, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16, + 0, + expected.size()); } SECTION("uint16_t") { @@ -1380,8 +1600,12 @@ TEST_CASE("Upgrade dynamic json number array") { {11, 22, 3, 50000, 333}}; // clang-format on - std::string expectedComponentType = "UINT16"; - createTestForArrayJson(expected, expectedComponentType, 0, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16, + 0, + expected.size()); } SECTION("int32_t") { @@ -1394,8 +1618,12 @@ TEST_CASE("Upgrade dynamic json number array") { {11, 22, 3, 2147483647, 12233}}; // clang-format on - std::string expectedComponentType = "INT32"; - createTestForArrayJson(expected, expectedComponentType, 0, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32, + 0, + expected.size()); } SECTION("uint32_t") { @@ -1408,8 +1636,12 @@ TEST_CASE("Upgrade dynamic json number array") { {11, 22, 3, (uint32_t)4294967295}}; // clang-format on - std::string expectedComponentType = "UINT32"; - createTestForArrayJson(expected, expectedComponentType, 0, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32, + 0, + expected.size()); } SECTION("int64_t") { @@ -1422,8 +1654,12 @@ TEST_CASE("Upgrade dynamic json number array") { {11, 22, 3, 9223372036854775807, 12333}}; // clang-format on - std::string expectedComponentType = "INT64"; - createTestForArrayJson(expected, expectedComponentType, 0, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64, + 0, + expected.size()); } SECTION("uint64_t") { @@ -1436,8 +1672,30 @@ TEST_CASE("Upgrade dynamic json number array") { {11, 22, 3, 13223302036854775807u, 32323}}; // clang-format on - std::string expectedComponentType = "UINT64"; - createTestForArrayJson(expected, expectedComponentType, 0, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64, + 0, + expected.size()); + } + + SECTION("float") { + // clang-format off + std::vector> expected { + {0.122f, 1.1233f}, + {1.244f, 122.3f, 1.222f, 544.66f, 323.122f}, + {12.003f, 1.21f, 2.123f, 33.12f, 122.2f}, + {1.333f}, + {1.1221f, 2.2f}}; + // clang-format on + + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, + 0, + expected.size()); } SECTION("double") { @@ -1450,8 +1708,12 @@ TEST_CASE("Upgrade dynamic json number array") { {1.1221, 2.2}}; // clang-format on - std::string expectedComponentType = "FLOAT64"; - createTestForArrayJson(expected, expectedComponentType, 0, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + 0, + expected.size()); } SECTION("string") { @@ -1466,7 +1728,8 @@ TEST_CASE("Upgrade dynamic json number array") { createTestForArrayJson( expected, - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, 0, expected.size()); } @@ -1482,54 +1745,76 @@ TEST_CASE("Upgrade dynamic json number array") { }; // clang-format on - createTestForArrayJson(expected, "BOOLEAN", 0, expected.size()); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + std::nullopt, + 0, + expected.size()); } } -TEST_CASE("Upgrade scalar json") { +TEST_CASE("Upgrade JSON values") { SECTION("Uint32") { + // Even though the values are typed uint32, they are small enough to be + // stored as int8s. Signed types are preferred over unsigned. std::vector expected{32, 45, 21, 65, 78}; - createTestForScalarJson( + createTestForNonArrayJson( expected, - "INT8", + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, expected.size()); } SECTION("Boolean") { std::vector expected{true, false, true, false, true, true, false}; - createTestForScalarJson(expected, "BOOLEAN", expected.size()); + createTestForNonArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + std::nullopt, + expected.size()); } SECTION("String") { std::vector expected{"Test 0", "Test 1", "Test 2", "Test 3"}; - createTestForScalarJson( + createTestForNonArrayJson( expected, - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, expected.size()); } } -TEST_CASE("Cannot write pass batch length table") { - SECTION("Numeric") { +TEST_CASE("Cannot write past batch table length") { + SECTION("Uint32") { std::vector expected{32, 45, 21, 65, 78, 20, 33, 12}; - createTestForScalarJson(expected, "INT8", 4); + createTestForNonArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + 4); } SECTION("Boolean") { std::vector expected{true, false, true, false, true, true, false}; - createTestForScalarJson(expected, "BOOLEAN", 4); + createTestForNonArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + std::nullopt, + 4); } SECTION("String") { std::vector expected{"Test 0", "Test 1", "Test 2", "Test 3", "Test 4"}; - createTestForScalarJson( + createTestForNonArrayJson( expected, - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, 3); } - SECTION("Fixed number array") { + SECTION("Fixed-length scalar array") { // clang-format off std::vector> expected { {0, 1, 4, 1}, @@ -1539,11 +1824,15 @@ TEST_CASE("Cannot write pass batch length table") { {11, 22, 3, 13223302036854775807u}}; // clang-format on - std::string expectedComponentType = "UINT64"; - createTestForArrayJson(expected, expectedComponentType, 4, 2); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64, + 4, + 2); } - SECTION("Fixed boolean array") { + SECTION("Fixed-length boolean array") { // clang-format off std::vector> expected{ {true, true, false}, @@ -1553,10 +1842,15 @@ TEST_CASE("Cannot write pass batch length table") { }; // clang-format on - createTestForArrayJson(expected, "BOOLEAN", 3, 2); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + std::nullopt, + 3, + 2); } - SECTION("Fixed string array") { + SECTION("Fixed-length string array") { // clang-format off std::vector> expected{ {"Test0", "Test1", "Test2", "Test4"}, @@ -1568,59 +1862,70 @@ TEST_CASE("Cannot write pass batch length table") { createTestForArrayJson( expected, - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, 4, 2); } - SECTION("Dynamic number array") { + SECTION("Variable-length number array") { // clang-format off - std::vector> expected { - {0, 1}, - {1244, -500000, 1222, 544662}, - {123, -10}, - {13}, - {11, 22, 3, 2147483647, 12233}}; + std::vector> expected { + {0, 1}, + {1244, -500000, 1222, 544662}, + {123, -10}, + {13}, + {11, 22, 3, 2147483647, 12233}}; // clang-format on - std::string expectedComponentType = "INT32"; - createTestForArrayJson(expected, expectedComponentType, 0, 3); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32, + 0, + 3); } - SECTION("Dynamic boolean array") { + SECTION("Variable-length boolean array") { // clang-format off - std::vector> expected{ - {true, true, false, true, false, false, true}, - {true, false}, - {false, true, true, false}, - {false, true, true}, - {true, true, false, false} - }; + std::vector> expected{ + {true, true, false, true, false, false, true}, + {true, false}, + {false, true, true, false}, + {false, true, true}, + {true, true, false, false} + }; // clang-format on - createTestForArrayJson(expected, "BOOLEAN", 0, 2); + createTestForArrayJson( + expected, + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + std::nullopt, + 0, + 2); } - SECTION("Dynamic string array") { + SECTION("Variable-length string array") { // clang-format off - std::vector> expected{ - {"This is Test", "Another Test"}, - {"Good morning", "How you doing?", "The book in the freezer", "Batman beats superman", ""}, - {"Test9", "Test10", "", "Test12", ""}, - {"Test13", ""}, - }; + std::vector> expected{ + {"This is Test", "Another Test"}, + {"Good morning", "How you doing?", "The book in the freezer", "Batman beats superman", ""}, + {"Test9", "Test10", "", "Test12", ""}, + {"Test13", ""}, + }; // clang-format on createTestForArrayJson( expected, - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, 0, 2); } } -TEST_CASE("Converts Feature Classes 3DTILES_batch_table_hierarchy example to " - "EXT_feature_metadata") { +TEST_CASE("Converts \"Feature Classes\" 3DTILES_batch_table_hierarchy example " + "to EXT_structural_metadata") { Model gltf; std::string featureTableJson = R"( @@ -1680,8 +1985,8 @@ TEST_CASE("Converts Feature Classes 3DTILES_batch_table_hierarchy example to " gsl::span(), gltf); - ExtensionModelExtFeatureMetadata* pExtension = - gltf.getExtension(); + ExtensionModelExtStructuralMetadata* pExtension = + gltf.getExtension(); REQUIRE(pExtension); // Check the schema @@ -1691,44 +1996,50 @@ TEST_CASE("Converts Feature Classes 3DTILES_batch_table_hierarchy example to " auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - CesiumGltf::Class& defaultClass = firstClassIt->second; + ExtensionExtStructuralMetadataClass& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 6); - // Check the feature table - auto firstFeatureTableIt = pExtension->featureTables.begin(); - REQUIRE(firstFeatureTableIt != pExtension->featureTables.end()); - - FeatureTable& featureTable = firstFeatureTableIt->second; - CHECK(featureTable.classProperty == "default"); - REQUIRE(featureTable.properties.size() == 6); + // Check the property table + REQUIRE(pExtension->propertyTables.size() == 1); + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pExtension->propertyTables[0]; + CHECK(propertyTable.classProperty == "default"); + REQUIRE(propertyTable.properties.size() == 6); - // Even though some of these properties are numeric, they become STRING - // because not every feature has every property, and only STRING can - // represent null. + // Even though some of these properties are scalars, they become strings + // because not every feature has every property, and only strings can + // represent "null". struct Expected { std::string name; std::string type; + std::optional componentType; std::vector values; }; std::vector expectedProperties{ {"lampStrength", - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, {"10", "5", "7", "null", "null", "null", "null", "null"}}, {"lampColor", - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, {"yellow", "white", "white", "null", "null", "null", "null", "null"}}, {"carType", - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, {"null", "null", "null", "truck", "bus", "sedan", "null", "null"}}, {"carColor", - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, {"null", "null", "null", "green", "blue", "red", "null", "null"}}, {"treeHeight", - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, {"null", "null", "null", "null", "null", "null", "10", "15"}}, {"treeAge", - "STRING", + ExtensionExtStructuralMetadataClassProperty::Type::STRING, + std::nullopt, {"null", "null", "null", "null", "null", "null", "5", "8"}}}; for (const auto& expected : expectedProperties) { @@ -1736,19 +2047,21 @@ TEST_CASE("Converts Feature Classes 3DTILES_batch_table_hierarchy example to " REQUIRE(it != defaultClass.properties.end()); CHECK(it->second.type == expected.type); - checkScalarProperty( + checkNonArrayProperty( gltf, - featureTable, + propertyTable, defaultClass, expected.name, expected.type, + expected.componentType, expected.values, expected.values.size()); } } -TEST_CASE("Converts Feature Hierarchy 3DTILES_batch_table_hierarchy example to " - "EXT_feature_metadata") { +TEST_CASE( + "Converts \"Feature Hierarchy\" 3DTILES_batch_table_hierarchy example to " + "EXT_structural_metadata") { Model gltf; std::string featureTableJson = R"( @@ -1768,17 +2081,17 @@ TEST_CASE("Converts Feature Hierarchy 3DTILES_batch_table_hierarchy example to " "name" : "Wall", "length" : 6, "instances" : { - "wall_color" : ["blue", "pink", "green", "lime", "black", "brown"], - "wall_windows" : [2, 4, 4, 2, 0, 3] + "wall_color" : ["blue", "pink", "green", "lime", "black", + "brown"], "wall_windows" : [2, 4, 4, 2, 0, 3] } }, { "name" : "Building", "length" : 3, "instances" : { - "building_name" : ["building_0", "building_1", "building_2"], - "building_id" : [0, 1, 2], - "building_address" : ["10 Main St", "12 Main St", "14 Main St"] + "building_name" : ["building_0", "building_1", + "building_2"], "building_id" : [0, 1, 2], "building_address" + : ["10 Main St", "12 Main St", "14 Main St"] } }, { @@ -1810,8 +2123,8 @@ TEST_CASE("Converts Feature Hierarchy 3DTILES_batch_table_hierarchy example to " gsl::span(), gltf); - ExtensionModelExtFeatureMetadata* pExtension = - gltf.getExtension(); + ExtensionModelExtStructuralMetadata* pExtension = + gltf.getExtension(); REQUIRE(pExtension); // Check the schema @@ -1821,29 +2134,28 @@ TEST_CASE("Converts Feature Hierarchy 3DTILES_batch_table_hierarchy example to " auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - CesiumGltf::Class& defaultClass = firstClassIt->second; + ExtensionExtStructuralMetadataClass& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 7); - // Check the feature table - auto firstFeatureTableIt = pExtension->featureTables.begin(); - REQUIRE(firstFeatureTableIt != pExtension->featureTables.end()); - - FeatureTable& featureTable = firstFeatureTableIt->second; - CHECK(featureTable.classProperty == "default"); - REQUIRE(featureTable.properties.size() == 7); + // Check the property table + REQUIRE(pExtension->propertyTables.size() == 1); + ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pExtension->propertyTables[0]; + CHECK(propertyTable.classProperty == "default"); + REQUIRE(propertyTable.properties.size() == 7); struct ExpectedString { std::string name; - std::string type; std::vector values; + std::string type() const { + return ExtensionExtStructuralMetadataClassProperty::Type::STRING; + } + std::optional componentType() const { return std::nullopt; } }; std::vector expectedStringProperties{ - {"wall_color", - "STRING", - {"blue", "pink", "green", "lime", "black", "brown"}}, + {"wall_color", {"blue", "pink", "green", "lime", "black", "brown"}}, {"building_name", - "STRING", {"building_0", "building_0", "building_1", @@ -1851,7 +2163,6 @@ TEST_CASE("Converts Feature Hierarchy 3DTILES_batch_table_hierarchy example to " "building_2", "building_2"}}, {"building_address", - "STRING", {"10 Main St", "10 Main St", "12 Main St", @@ -1859,62 +2170,73 @@ TEST_CASE("Converts Feature Hierarchy 3DTILES_batch_table_hierarchy example to " "14 Main St", "14 Main St"}}, {"block_district", - "STRING", {"central", "central", "central", "central", "central", "central"}}}; for (const auto& expected : expectedStringProperties) { auto it = defaultClass.properties.find(expected.name); REQUIRE(it != defaultClass.properties.end()); - CHECK(it->second.type == expected.type); + CHECK(it->second.type == expected.type()); + CHECK(it->second.componentType == expected.componentType()); - checkScalarProperty( + checkNonArrayProperty( gltf, - featureTable, + propertyTable, defaultClass, expected.name, - expected.type, + expected.type(), + expected.componentType(), expected.values, expected.values.size()); } struct ExpectedInt8Properties { std::string name; - std::string type; std::vector values; + std::string type() const { + return ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + } + std::optional componentType() const { + return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8; + } }; std::vector expectedInt8Properties{ - {"wall_windows", "INT8", {2, 4, 4, 2, 0, 3}}, - {"building_id", "INT8", {0, 0, 1, 1, 2, 2}}, + {"wall_windows", {2, 4, 4, 2, 0, 3}}, + {"building_id", {0, 0, 1, 1, 2, 2}}, }; for (const auto& expected : expectedInt8Properties) { auto it = defaultClass.properties.find(expected.name); REQUIRE(it != defaultClass.properties.end()); - CHECK(it->second.type == expected.type); + CHECK(it->second.type == expected.type()); + CHECK(it->second.componentType == expected.componentType()); - checkScalarProperty( + checkNonArrayProperty( gltf, - featureTable, + propertyTable, defaultClass, expected.name, - expected.type, + expected.type(), + expected.componentType(), expected.values, expected.values.size()); } struct ExpectedDoubleArrayProperties { std::string name; - std::string type; - std::string componentType; - int64_t componentCount; + int64_t count; std::vector> values; + std::string type() const { + return ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + } + std::optional componentType() const { + return ExtensionExtStructuralMetadataClassProperty::ComponentType:: + FLOAT64; + } }; std::vector expectedDoubleArrayProperties{ {"block_lat_long", - "ARRAY", - "FLOAT64", 2, {{0.12, 0.543}, {0.12, 0.543}, @@ -1926,23 +2248,26 @@ TEST_CASE("Converts Feature Hierarchy 3DTILES_batch_table_hierarchy example to " for (const auto& expected : expectedDoubleArrayProperties) { auto it = defaultClass.properties.find(expected.name); REQUIRE(it != defaultClass.properties.end()); - CHECK(it->second.type == expected.type); - CHECK(it->second.componentType == expected.componentType); + CHECK(it->second.type == expected.type()); + CHECK(it->second.componentType == expected.componentType()); + CHECK(it->second.array); + CHECK(it->second.count == expected.count); checkArrayProperty( gltf, - featureTable, + propertyTable, defaultClass, expected.name, - expected.componentCount, - expected.componentType, + expected.count, + expected.type(), + expected.componentType(), expected.values, expected.values.size()); } } -TEST_CASE( - "3DTILES_batch_table_hierarchy with parentCounts is ok if all are 1") { +TEST_CASE("3DTILES_batch_table_hierarchy with parentCounts is okay if all " + "values are 1") { Model gltf; std::string featureTableJson = R"( @@ -2010,8 +2335,8 @@ TEST_CASE( REQUIRE(logMessages.size() == 0); // There should actually be metadata properties as normal. - ExtensionModelExtFeatureMetadata* pExtension = - gltf.getExtension(); + const ExtensionModelExtStructuralMetadata* pExtension = + gltf.getExtension(); REQUIRE(pExtension); // Check the schema @@ -2021,20 +2346,20 @@ TEST_CASE( auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - CesiumGltf::Class& defaultClass = firstClassIt->second; + const ExtensionExtStructuralMetadataClass& defaultClass = + firstClassIt->second; REQUIRE(defaultClass.properties.size() == 3); - // Check the feature table - auto firstFeatureTableIt = pExtension->featureTables.begin(); - REQUIRE(firstFeatureTableIt != pExtension->featureTables.end()); - - FeatureTable& featureTable = firstFeatureTableIt->second; - CHECK(featureTable.classProperty == "default"); - REQUIRE(featureTable.properties.size() == 3); + // Check the property table + REQUIRE(pExtension->propertyTables.size() == 1); + const ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pExtension->propertyTables[0]; + CHECK(propertyTable.classProperty == "default"); + REQUIRE(propertyTable.properties.size() == 3); } -TEST_CASE( - "3DTILES_batch_table_hierarchy with parentCounts != 1 is not supported") { +TEST_CASE("3DTILES_batch_table_hierarchy with parentCounts values != 1 is " + "unsupported") { Model gltf; std::string featureTableJson = R"( @@ -2101,8 +2426,8 @@ TEST_CASE( REQUIRE(logMessages.size() == 1); CHECK(logMessages[0].find("parentCounts") != std::string::npos); - ExtensionModelExtFeatureMetadata* pExtension = - gltf.getExtension(); + const ExtensionModelExtStructuralMetadata* pExtension = + gltf.getExtension(); REQUIRE(pExtension); // Check the schema @@ -2112,14 +2437,15 @@ TEST_CASE( auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - CesiumGltf::Class& defaultClass = firstClassIt->second; + const ExtensionExtStructuralMetadataClass& defaultClass = + firstClassIt->second; REQUIRE(defaultClass.properties.size() == 0); - // Check the feature table - auto firstFeatureTableIt = pExtension->featureTables.begin(); - REQUIRE(firstFeatureTableIt != pExtension->featureTables.end()); + // Check the property table + REQUIRE(pExtension->propertyTables.size() == 1); + const ExtensionExtStructuralMetadataPropertyTable& propertyTable = + pExtension->propertyTables[0]; - FeatureTable& featureTable = firstFeatureTableIt->second; - CHECK(featureTable.classProperty == "default"); - REQUIRE(featureTable.properties.size() == 0); + CHECK(propertyTable.classProperty == "default"); + REQUIRE(propertyTable.properties.size() == 0); } From dec58d660e445563bf1b050a5b62794cdaa4cbcb Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 25 May 2023 11:55:24 -0400 Subject: [PATCH 035/121] Rewrite names / comments for EXT_structural_metadata --- Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp | 4 ++-- .../src/BatchTableToGltfStructuralMetadata.cpp | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp b/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp index 8ee72dc22..c4c9bf5c7 100644 --- a/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp +++ b/Cesium3DTilesSelection/src/B3dmToGltfConverter.cpp @@ -176,7 +176,7 @@ rapidjson::Document parseFeatureTableJsonData( return document; } -void convertB3dmMetadataToGltfFeatureMetadata( +void convertB3dmMetadataToGltfStructuralMetadata( const gsl::span& b3dmBinary, const B3dmHeader& header, uint32_t headerLength, @@ -246,7 +246,7 @@ GltfConverterResult B3dmToGltfConverter::convert( return result; } - convertB3dmMetadataToGltfFeatureMetadata( + convertB3dmMetadataToGltfStructuralMetadata( b3dmBinary, header, headerLength, diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index bd49e97d5..23a5fc98d 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -1448,10 +1448,11 @@ void updateExtensionWithBatchTableHierarchy( ExtensionExtStructuralMetadataPropertyTable& propertyTable, ErrorList& result, const rapidjson::Value& batchTableHierarchy) { - // EXT_feature_metadata can't support hierarchy, so we need to flatten it. + // EXT_structural_metadata can't support hierarchy, so we need to flatten it. // It also can't support multiple classes with a single set of feature IDs. - // So essentially every property of every class gets added to the one class - // definition. + // (Feature IDs can only specify one property table, which only supports one class.) + // So essentially every property of every class gets added to + // the one class definition. auto classesIt = batchTableHierarchy.FindMember("classes"); if (classesIt == batchTableHierarchy.MemberEnd()) { result.emplaceWarning( @@ -1649,7 +1650,7 @@ ErrorList BatchTableToGltfStructuralMetadata::convertFromB3dm( ErrorList result; - // Parse the b3dm batch table and convert it to the EXT_feature_metadata + // Parse the b3dm batch table and convert it to the EXT_structural_metadata // extension. // If the feature table is missing the BATCH_LENGTH semantic, ignore the batch @@ -1716,7 +1717,7 @@ ErrorList BatchTableToGltfStructuralMetadata::convertFromPnts( ErrorList result; - // Parse the pnts batch table and convert it to the EXT_feature_metadata + // Parse the pnts batch table and convert it to the EXT_structural_metadata // extension. const auto pointsLengthIt = featureTableJson.FindMember("POINTS_LENGTH"); From d7f9c98c330b5c83456c132dec807dfc21a34866 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 25 May 2023 13:13:35 -0400 Subject: [PATCH 036/121] Initial self-review --- .../BatchTableToGltfStructuralMetadata.cpp | 205 ++++++++---------- .../src/PntsToGltfConverter.cpp | 1 - .../test/TestPntsToGltfConverter.cpp | 2 +- 3 files changed, 89 insertions(+), 119 deletions(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 23a5fc98d..815983282 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -95,12 +95,12 @@ struct MaskedArrayType { maxArrayCount(std::numeric_limits::min()){}; MaskedArrayType( - MaskedType elementType, - uint32_t minArrayCount, - uint32_t maxArrayCount) - : elementType(elementType), - minArrayCount(minArrayCount), - maxArrayCount(maxArrayCount) {} + MaskedType inElementType, + uint32_t inMinArrayCount, + uint32_t inMaxArrayCount) + : elementType(inElementType), + minArrayCount(inMinArrayCount), + maxArrayCount(inMaxArrayCount) {} /** * Merges another MaskedArrayType into this one. @@ -120,76 +120,101 @@ struct CompatibleTypes { // been determined to be incompatible yet. Once something is either a // MaskedType or MaskedArrayType, they are considered incompatible with the // other type. - std::variant maskedType; +private: + std::variant type; - CompatibleTypes() : maskedType(){}; +public: + CompatibleTypes() : type(){}; - CompatibleTypes(const MaskedType& maskedType) : maskedType(maskedType){}; + CompatibleTypes(const MaskedType& maskedType) : type(maskedType){}; CompatibleTypes(const MaskedArrayType& maskedArrayType) - : maskedType(maskedArrayType){}; + : type(maskedArrayType){}; /** - * Whether this is only compatible with arrays. + * Whether this is compatible with array types. */ - bool isArray() const { return std::get_if(&maskedType); } + bool supportsArray() const { + return !std::holds_alternative(type); + } /** * Marks as incompatible with every type. Fully-incompatible types will be * treated as strings. */ - void makeIncompatible() { - MaskedType incompatibleMaskedType(false); - maskedType = incompatibleMaskedType; + void makeIncompatible() { type = MaskedType(false); } + + /** + * Marks as incompatible with array types. + */ + void makeIncompatibleWithArray() { + if (std::holds_alternative(type)) { + return; + } + + if (std::holds_alternative(type)) { + makeIncompatible(); + return; + } + + // If std::monostate, retain potential compatibility with non-array types + type = MaskedType(true); } /** * Merges a MaskedType into this CompatibleTypes. */ - void operator&=(const MaskedType& otherMaskedType) { - if (isArray()) { - makeIncompatible(); + void operator&=(const MaskedType& inMaskedType) { + if (std::holds_alternative(type)) { + MaskedType& maskedType = std::get(type); + maskedType &= inMaskedType; return; } - MaskedType* pMaskedType = std::get_if(&maskedType); - if (pMaskedType) { - *pMaskedType &= otherMaskedType; - } else { - maskedType = otherMaskedType; + if (std::holds_alternative(type)) { + makeIncompatible(); + return; } + + type = inMaskedType; } /** * Merges a MaskedArrayType into this CompatibleTypes. */ - void operator&=(const MaskedArrayType& maskedArrayType) { - if (isArray()) { - MaskedArrayType& arrayType = std::get(maskedType); - arrayType &= maskedArrayType; + void operator&=(const MaskedArrayType& inArrayType) { + if (std::holds_alternative(type)) { + MaskedArrayType& arrayType = std::get(type); + arrayType &= inArrayType; return; } - MaskedType* pMaskedType = std::get_if(&maskedType); - if (pMaskedType) { + if (std::holds_alternative(type)) { makeIncompatible(); - } else { - maskedType = maskedArrayType; + return; } + + type = inArrayType; } /** * Merges another CompatibleTypes into this one. */ - void operator&=(const CompatibleTypes& otherTypes) { - if (otherTypes.isArray()) { - const MaskedArrayType& otherMaskedType = - std::get(otherTypes.maskedType); - operator&=(otherMaskedType); - } else { - const MaskedType& otherMaskedType = - std::get(otherTypes.maskedType); - operator&=(otherMaskedType); + void operator&=(const CompatibleTypes& inCompatibleTypes) { + if (std::holds_alternative(inCompatibleTypes.type)) { + // The other CompatibleTypes is compatible with everything, so it does not + // change this one. + return; + } + + if (std::holds_alternative(inCompatibleTypes.type)) { + const MaskedArrayType& arrayType = + std::get(inCompatibleTypes.type); + operator&=(arrayType); + return; } + + const MaskedType& maskedType = std::get(inCompatibleTypes.type); + operator&=(maskedType); } /** @@ -198,18 +223,12 @@ struct CompatibleTypes { * MaskedType. */ MaskedType toMaskedType() const { - if (isArray()) { - return MaskedType(false); + if (std::holds_alternative(type)) { + return std::get(type); } - const MaskedType* pMaskedType = std::get_if(&maskedType); - if (pMaskedType) { - return *pMaskedType; - } - - // If maskedType == std::monostate, then this CompatibleTypes is considered - // compatible with everything. - return MaskedType(true); + bool isArray = std::holds_alternative(type); + return MaskedType(!isArray); } /** @@ -218,15 +237,12 @@ struct CompatibleTypes { * incompatible MaskedArrayType. */ MaskedArrayType toMaskedArrayType() const { - if (isArray()) { - return std::get(maskedType); + if (std::holds_alternative(type)) { + return std::get(type); } - // If maskedType is a MaskedType, it is incompatible. Otherwise, if - // maskedType == std::monostate, then this CompatibleTypes is considered - // compatible with everything. - const MaskedType* pMaskedType = std::get_if(&maskedType); - return MaskedArrayType(pMaskedType == nullptr); + bool isNonArray = std::holds_alternative(type); + return MaskedArrayType(!isNonArray); } }; @@ -386,23 +402,16 @@ class ArrayOfPropertyValues { }; CompatibleTypes findCompatibleTypesForBoolean() { - MaskedType type; // Don't allow conversion of bools to numeric 0 or 1. - type.isInt8 = type.isUint8 = false; - type.isInt16 = type.isUint16 = false; - type.isInt32 = type.isUint32 = false; - type.isInt64 = type.isUint64 = false; - type.isFloat32 = false; - type.isFloat64 = false; - type.isBool &= true; + MaskedType type(false); + type.isBool = true; return CompatibleTypes(type); } template CompatibleTypes findCompatibleTypesForNumber(const TValueIter& it) { - MaskedType type; - type.isBool = false; + MaskedType type(false); if (it->IsInt64()) { const int64_t value = it->GetInt64(); @@ -419,26 +428,11 @@ CompatibleTypes findCompatibleTypesForNumber(const TValueIter& it) { } else if (it->IsUint64()) { // Only uint64_t can represent a value that fits in a uint64_t but not in // an int64_t. - type.isInt8 = type.isUint8 = false; - type.isInt16 = type.isUint16 = false; - type.isInt32 = type.isUint32 = false; - type.isInt64 = false; type.isUint64 = true; - type.isFloat32 = false; - type.isFloat64 = false; } else if (it->IsLosslessFloat()) { - type.isInt8 = type.isUint8 = false; - type.isInt16 = type.isUint16 = false; - type.isInt32 = type.isUint32 = false; - type.isInt64 = type.isUint64 = false; type.isFloat32 = true; type.isFloat64 = true; } else if (it->IsDouble()) { - type.isInt8 = type.isUint8 = false; - type.isInt16 = type.isUint16 = false; - type.isInt32 = type.isUint32 = false; - type.isInt64 = type.isUint64 = false; - type.isFloat32 = false; type.isFloat64 = true; } @@ -450,13 +444,13 @@ CompatibleTypes findCompatibleTypesForArray(const TValueIter& it) { // Iterate over all of the elements in the array and determine their // compatible type. CompatibleTypes arrayElementCompatibleTypes = - findCompatibleTypes(ArrayOfPropertyValues(*it)); + findCompatibleTypes(ArrayOfPropertyValues(*it)); - if (arrayElementCompatibleTypes.isArray()) { + if (arrayElementCompatibleTypes.supportsArray()) { // Ignore complications with arrays of arrays. The elements will be treated // like strings. - arrayElementCompatibleTypes.makeIncompatible(); - assert(!arrayElementCompatibleTypes.isArray()); + arrayElementCompatibleTypes.makeIncompatibleWithArray(); + assert(!arrayElementCompatibleTypes.supportsArray()); } MaskedType elementType = arrayElementCompatibleTypes.toMaskedType(); @@ -578,34 +572,12 @@ void updateExtensionWithJsonStringProperty( UINT64; } - Buffer& gltfBuffer = gltf.buffers.emplace_back(); - gltfBuffer.byteLength = static_cast(buffer.size()); - gltfBuffer.cesium.data = std::move(buffer); - - BufferView& gltfBufferView = gltf.bufferViews.emplace_back(); - gltfBufferView.buffer = static_cast(gltf.buffers.size() - 1); - gltfBufferView.byteOffset = 0; - gltfBufferView.byteLength = static_cast(totalSize); - const int32_t valueBufferViewIdx = - static_cast(gltf.bufferViews.size() - 1); - - Buffer& gltfOffsetBuffer = gltf.buffers.emplace_back(); - gltfOffsetBuffer.byteLength = static_cast(offsetBuffer.size()); - gltfOffsetBuffer.cesium.data = std::move(offsetBuffer); - - BufferView& gltfOffsetBufferView = gltf.bufferViews.emplace_back(); - gltfOffsetBufferView.buffer = static_cast(gltf.buffers.size() - 1); - gltfOffsetBufferView.byteOffset = 0; - gltfOffsetBufferView.byteLength = - static_cast(gltfOffsetBuffer.cesium.data.size()); - const int32_t offsetBufferViewIdx = - static_cast(gltf.bufferViews.size() - 1); - classProperty.type = ExtensionExtStructuralMetadataClassProperty::Type::STRING; - propertyTableProperty.values = valueBufferViewIdx; - propertyTableProperty.stringOffsets = offsetBufferViewIdx; + propertyTableProperty.values = addBufferToGltf(gltf, std::move(buffer)); + propertyTableProperty.stringOffsets = + addBufferToGltf(gltf, std::move(offsetBuffer)); } template @@ -623,10 +595,9 @@ void updateExtensionWithJsonScalarProperty( classProperty.componentType = componentTypeName; // Create a new buffer for this property. - std::vector buffer; const size_t byteLength = sizeof(T) * static_cast(propertyTable.count); - buffer.resize(byteLength); + std::vector buffer(byteLength); T* p = reinterpret_cast(buffer.data()); auto it = propertyValue.begin(); @@ -1240,7 +1211,7 @@ void updateExtensionWithJsonProperty( // Figure out which types we can use for this data. // Use the smallest type we can, and prefer signed to unsigned. const CompatibleTypes compatibleTypes = findCompatibleTypes(propertyValue); - if (compatibleTypes.isArray()) { + if (compatibleTypes.supportsArray()) { MaskedArrayType arrayType = compatibleTypes.toMaskedArrayType(); updateExtensionWithArrayProperty( gltf, @@ -1450,9 +1421,9 @@ void updateExtensionWithBatchTableHierarchy( const rapidjson::Value& batchTableHierarchy) { // EXT_structural_metadata can't support hierarchy, so we need to flatten it. // It also can't support multiple classes with a single set of feature IDs. - // (Feature IDs can only specify one property table, which only supports one class.) - // So essentially every property of every class gets added to - // the one class definition. + // (Feature IDs can only specify one property table, which only supports one + // class.) So essentially every property of every class gets added to the one + // class definition. auto classesIt = batchTableHierarchy.FindMember("classes"); if (classesIt == batchTableHierarchy.MemberEnd()) { result.emplaceWarning( diff --git a/Cesium3DTilesSelection/src/PntsToGltfConverter.cpp b/Cesium3DTilesSelection/src/PntsToGltfConverter.cpp index ca49693b2..d732fc7da 100644 --- a/Cesium3DTilesSelection/src/PntsToGltfConverter.cpp +++ b/Cesium3DTilesSelection/src/PntsToGltfConverter.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp index 8560ba20c..f647fc64f 100644 --- a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp +++ b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp @@ -1086,7 +1086,7 @@ TEST_CASE("Converts batched point cloud with Draco compression to glTF") { Model& gltf = *result.model; // The correctness of the model extension is thoroughly tested in - // TestUpgradeBatchTableToExtFeatureMetadata + // TestUpgradeBatchTableToExtStructuralMetadata CHECK(gltf.hasExtension()); CHECK(gltf.nodes.size() == 1); From f2bee8531ec307849e21748054ea052debda0b77 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 25 May 2023 14:11:49 -0400 Subject: [PATCH 037/121] Try to resolve CI errors --- .../BatchTableToGltfStructuralMetadata.cpp | 100 +++++++----------- .../test/TestPntsToGltfConverter.cpp | 4 +- 2 files changed, 40 insertions(+), 64 deletions(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 815983282..f05ce2bd3 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -131,10 +131,10 @@ struct CompatibleTypes { : type(maskedArrayType){}; /** - * Whether this is compatible with array types. + * Whether this is exclusively compatible with array types. */ - bool supportsArray() const { - return !std::holds_alternative(type); + bool isExclusivelyArray() const { + return std::holds_alternative(type); } /** @@ -143,23 +143,6 @@ struct CompatibleTypes { */ void makeIncompatible() { type = MaskedType(false); } - /** - * Marks as incompatible with array types. - */ - void makeIncompatibleWithArray() { - if (std::holds_alternative(type)) { - return; - } - - if (std::holds_alternative(type)) { - makeIncompatible(); - return; - } - - // If std::monostate, retain potential compatibility with non-array types - type = MaskedType(true); - } - /** * Merges a MaskedType into this CompatibleTypes. */ @@ -439,20 +422,16 @@ CompatibleTypes findCompatibleTypesForNumber(const TValueIter& it) { return CompatibleTypes(type); } -template +template CompatibleTypes findCompatibleTypesForArray(const TValueIter& it) { // Iterate over all of the elements in the array and determine their // compatible type. CompatibleTypes arrayElementCompatibleTypes = - findCompatibleTypes(ArrayOfPropertyValues(*it)); - - if (arrayElementCompatibleTypes.supportsArray()) { - // Ignore complications with arrays of arrays. The elements will be treated - // like strings. - arrayElementCompatibleTypes.makeIncompatibleWithArray(); - assert(!arrayElementCompatibleTypes.supportsArray()); - } + findCompatibleTypes(ArrayOfPropertyValues(*it)); + // If the elements inside the array are also arrays, this will return a + // completely incompatible MaskedType, which means the elements will be + // treated like strings. MaskedType elementType = arrayElementCompatibleTypes.toMaskedType(); MaskedArrayType arrayType(elementType, it->Size(), it->Size()); @@ -468,7 +447,7 @@ CompatibleTypes findCompatibleTypes(const TValueGetter& propertyValue) { } else if (it->IsNumber()) { compatibleTypes &= findCompatibleTypesForNumber(it); } else if (it->IsArray()) { - compatibleTypes &= findCompatibleTypesForArray(it); + compatibleTypes &= findCompatibleTypesForArray(it); } else { // A string, null, or something else. compatibleTypes.makeIncompatible(); @@ -601,10 +580,8 @@ void updateExtensionWithJsonScalarProperty( T* p = reinterpret_cast(buffer.data()); auto it = propertyValue.begin(); - for (int64_t i = 0; i < propertyTable.count; ++i) { + for (int64_t i = 0; i < propertyTable.count; ++i, ++p, ++it) { *p = static_cast(it->template Get()); - ++p; - ++it; } propertyTableProperty.values = addBufferToGltf(gltf, std::move(buffer)); @@ -881,7 +858,7 @@ void updateStringArrayProperty( propertyTable, propertyValue); stringOffsetType = PropertyComponentType::Uint32; - } else if (isInRangeForUnsignedInteger(totalByteLength)) { + } else { copyStringsToBuffers( valueBuffer, stringOffsetBuffer, @@ -907,45 +884,46 @@ void updateStringArrayProperty( return; } - // Handle variable-length arrays + // Handle variable-length arrays. + // For string arrays, arrayOffsets indexes into the stringOffsets buffer, + // the size of which is the number of stringElements + 1. This determines the + // component type of the array offsets. std::vector arrayOffsetBuffer; - switch (stringOffsetType) { - case PropertyComponentType::Uint8: + PropertyComponentType arrayOffsetType = PropertyComponentType::None; + if (isInRangeForUnsignedInteger(stringCount + 1)) { copyArrayOffsetsForStringArraysToBuffer( arrayOffsetBuffer, propertyTable, propertyValue); - break; - case PropertyComponentType::Uint16: + arrayOffsetType = PropertyComponentType::Uint8; + } else if (isInRangeForUnsignedInteger(stringCount + 1)) { copyArrayOffsetsForStringArraysToBuffer( arrayOffsetBuffer, propertyTable, propertyValue); - break; - case PropertyComponentType::Uint32: + arrayOffsetType = PropertyComponentType::Uint16; + } else if (isInRangeForUnsignedInteger(stringCount + 1)) { copyArrayOffsetsForStringArraysToBuffer( arrayOffsetBuffer, propertyTable, propertyValue); - break; - case PropertyComponentType::Uint64: + arrayOffsetType = PropertyComponentType::Uint32; + } else { copyArrayOffsetsForStringArraysToBuffer( arrayOffsetBuffer, propertyTable, propertyValue); - break; - default: - break; + arrayOffsetType = PropertyComponentType::Uint64; } propertyTableProperty.arrayOffsets = addBufferToGltf(gltf, std::move(arrayOffsetBuffer)); propertyTableProperty.arrayOffsetType = - convertPropertyComponentTypeToString(stringOffsetType); + convertPropertyComponentTypeToString(arrayOffsetType); } template -void copyVariableLengthBooleanArraysBuffers( +void copyVariableLengthBooleanArraysToBuffers( std::vector& valueBuffer, std::vector& offsetBuffer, size_t numOfElements, @@ -1036,24 +1014,24 @@ void updateBooleanArrayProperty( std::vector valueBuffer; std::vector offsetBuffer; PropertyComponentType offsetType = PropertyComponentType::None; - if (isInRangeForUnsignedInteger(numOfElements)) { - copyVariableLengthBooleanArraysBuffers( + if (isInRangeForUnsignedInteger(numOfElements + 1)) { + copyVariableLengthBooleanArraysToBuffers( valueBuffer, offsetBuffer, numOfElements, propertyTable, propertyValue); offsetType = PropertyComponentType::Uint8; - } else if (isInRangeForUnsignedInteger(numOfElements)) { - copyVariableLengthBooleanArraysBuffers( + } else if (isInRangeForUnsignedInteger(numOfElements + 1)) { + copyVariableLengthBooleanArraysToBuffers( valueBuffer, offsetBuffer, numOfElements, propertyTable, propertyValue); offsetType = PropertyComponentType::Uint16; - } else if (isInRangeForUnsignedInteger(numOfElements)) { - copyVariableLengthBooleanArraysBuffers( + } else if (isInRangeForUnsignedInteger(numOfElements + 1)) { + copyVariableLengthBooleanArraysToBuffers( valueBuffer, offsetBuffer, numOfElements, @@ -1061,7 +1039,7 @@ void updateBooleanArrayProperty( propertyValue); offsetType = PropertyComponentType::Uint32; } else { - copyVariableLengthBooleanArraysBuffers( + copyVariableLengthBooleanArraysToBuffers( valueBuffer, offsetBuffer, numOfElements, @@ -1211,7 +1189,7 @@ void updateExtensionWithJsonProperty( // Figure out which types we can use for this data. // Use the smallest type we can, and prefer signed to unsigned. const CompatibleTypes compatibleTypes = findCompatibleTypes(propertyValue); - if (compatibleTypes.supportsArray()) { + if (compatibleTypes.isExclusivelyArray()) { MaskedArrayType arrayType = compatibleTypes.toMaskedArrayType(); updateExtensionWithArrayProperty( gltf, @@ -1420,10 +1398,9 @@ void updateExtensionWithBatchTableHierarchy( ErrorList& result, const rapidjson::Value& batchTableHierarchy) { // EXT_structural_metadata can't support hierarchy, so we need to flatten it. - // It also can't support multiple classes with a single set of feature IDs. - // (Feature IDs can only specify one property table, which only supports one - // class.) So essentially every property of every class gets added to the one - // class definition. + // It also can't support multiple classes with a single set of feature IDs, + // because IDs can only specify one property table. So essentially every + // property of every class gets added to the one class definition. auto classesIt = batchTableHierarchy.FindMember("classes"); if (classesIt == batchTableHierarchy.MemberEnd()) { result.emplaceWarning( @@ -1439,8 +1416,7 @@ void updateExtensionWithBatchTableHierarchy( if (!element.IsInt64() || element.GetInt64() != 1LL) { result.emplaceWarning( "3DTILES_batch_table_hierarchy with a \"parentCounts\" property " - "is " - "not currently supported. All instances must have at most one " + "is not currently supported. All instances must have at most one " "parent."); return; } diff --git a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp index f647fc64f..ca7bdca5a 100644 --- a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp +++ b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp @@ -653,8 +653,8 @@ getUniqueBufferIds(const std::vector& bufferViews) { return result; } -TEST_CASE( - "Converts point cloud with batch IDs to glTF with EXT_structural_metadata") { +TEST_CASE("Converts point cloud with batch IDs to glTF with " + "EXT_structural_metadata") { std::filesystem::path testFilePath = Cesium3DTilesSelection_TEST_DATA_DIR; testFilePath = testFilePath / "PointCloud" / "pointCloudBatched.pnts"; const int32_t pointsLength = 8; From b5fb7302e34b1d5b7a2159e4a57403925acdf64c Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 25 May 2023 14:43:43 -0400 Subject: [PATCH 038/121] Fold helper functions into findCompatibleTypes, fix formatting --- .../BatchTableToGltfStructuralMetadata.cpp | 49 ++++++++----------- .../StructuralMetadataPropertyTableView.cpp | 3 +- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index f05ce2bd3..1262edbc8 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -384,16 +384,8 @@ class ArrayOfPropertyValues { const rapidjson::Value& _propertyValues; }; -CompatibleTypes findCompatibleTypesForBoolean() { - // Don't allow conversion of bools to numeric 0 or 1. - MaskedType type(false); - type.isBool = true; - - return CompatibleTypes(type); -} - template -CompatibleTypes findCompatibleTypesForNumber(const TValueIter& it) { +MaskedType getCompatibleTypesForNumber(const TValueIter& it) { MaskedType type(false); if (it->IsInt64()) { @@ -419,23 +411,7 @@ CompatibleTypes findCompatibleTypesForNumber(const TValueIter& it) { type.isFloat64 = true; } - return CompatibleTypes(type); -} - -template -CompatibleTypes findCompatibleTypesForArray(const TValueIter& it) { - // Iterate over all of the elements in the array and determine their - // compatible type. - CompatibleTypes arrayElementCompatibleTypes = - findCompatibleTypes(ArrayOfPropertyValues(*it)); - - // If the elements inside the array are also arrays, this will return a - // completely incompatible MaskedType, which means the elements will be - // treated like strings. - MaskedType elementType = arrayElementCompatibleTypes.toMaskedType(); - MaskedArrayType arrayType(elementType, it->Size(), it->Size()); - - return CompatibleTypes(arrayType); + return type; } template @@ -443,11 +419,26 @@ CompatibleTypes findCompatibleTypes(const TValueGetter& propertyValue) { CompatibleTypes compatibleTypes; for (auto it = propertyValue.begin(); it != propertyValue.end(); ++it) { if (it->IsBool()) { - compatibleTypes &= findCompatibleTypesForBoolean(); + // Don't allow booleans to be converted to numeric 0 or 1. + MaskedType booleanType(false); + booleanType.isBool = true; + + compatibleTypes &= booleanType; } else if (it->IsNumber()) { - compatibleTypes &= findCompatibleTypesForNumber(it); + compatibleTypes &= getCompatibleTypesForNumber(it); } else if (it->IsArray()) { - compatibleTypes &= findCompatibleTypesForArray(it); + // Iterate over all of the elements in the array + // and determine their compatible type. + CompatibleTypes arrayElementCompatibleTypes = + findCompatibleTypes(ArrayOfPropertyValues(*it)); + + // If the elements inside the array are also arrays, this will return a + // completely incompatible MaskedType, which means the elements will be + // treated like strings. + MaskedType elementType = arrayElementCompatibleTypes.toMaskedType(); + MaskedArrayType arrayType(elementType, it->Size(), it->Size()); + + compatibleTypes &= arrayType; } else { // A string, null, or something else. compatibleTypes.makeIncompatible(); diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp index 66f47c2fe..bf6bdfd18 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -165,7 +165,8 @@ MetadataPropertyViewStatus MetadataPropertyTableView::getBufferSafe( return MetadataPropertyViewStatus::ErrorInvalidValueBufferView; } - const Buffer* pBuffer = _pModel->getSafe(&_pModel->buffers, pBufferView->buffer); + const Buffer* pBuffer = + _pModel->getSafe(&_pModel->buffers, pBufferView->buffer); if (!pBuffer) { return MetadataPropertyViewStatus::ErrorInvalidValueBuffer; } From 619faea5b7e50315009a6adb58e2a3ad26679916 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 30 May 2023 10:27:21 -0400 Subject: [PATCH 039/121] Add PropertyTextureView and rename PropertyTable classes --- ...gradeBatchTableToExtStructuralMetadata.cpp | 18 +- ...cturalMetadataPropertyTablePropertyView.h} | 78 +- .../StructuralMetadataPropertyTableView.h | 171 ++-- ...turalMetadataPropertyTexturePropertyView.h | 245 ++++++ .../StructuralMetadataPropertyTextureView.h | 124 +++ .../StructuralMetadataPropertyTableView.cpp | 172 ++-- ...ralMetadataPropertyTexturePropertyView.cpp | 102 +++ .../StructuralMetadataPropertyTextureView.cpp | 84 ++ ...uralMetadataPropertyTablePropertyView.cpp} | 38 +- ...estStructuralMetadataPropertyTableView.cpp | 808 +++++++++--------- ...tStructuralMetadataPropertyTextureView.cpp | 169 ++++ 11 files changed, 1388 insertions(+), 621 deletions(-) rename CesiumGltf/include/CesiumGltf/{StructuralMetadataPropertyView.h => StructuralMetadataPropertyTablePropertyView.h} (87%) create mode 100644 CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h create mode 100644 CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTextureView.h create mode 100644 CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp create mode 100644 CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp rename CesiumGltf/test/{TestStructuralMetadataPropertyView.cpp => TestStructuralMetadataPropertyTablePropertyView.cpp} (96%) create mode 100644 CesiumGltf/test/TestStructuralMetadataPropertyTextureView.cpp diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 651af2c5d..f6d232138 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -39,13 +39,13 @@ static void checkNonArrayProperty( REQUIRE(!property.array); REQUIRE(property.count == std::nullopt); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - MetadataPropertyView propertyView = + PropertyTablePropertyView propertyView = view.getPropertyView(propertyName); - REQUIRE(propertyView.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() == propertyTable.count); REQUIRE(propertyView.size() == static_cast(expectedTotalInstances)); for (int64_t i = 0; i < propertyView.size(); ++i) { @@ -84,13 +84,13 @@ static void checkArrayProperty( REQUIRE(property.array); REQUIRE(property.count.value_or(0) == expectedCount); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - MetadataPropertyView> propertyView = + PropertyTablePropertyView> propertyView = view.getPropertyView>(propertyName); - REQUIRE(propertyView.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() == propertyTable.count); REQUIRE(propertyView.size() == static_cast(expectedTotalInstances)); for (size_t i = 0; i < expectedTotalInstances; ++i) { diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTablePropertyView.h similarity index 87% rename from CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h rename to CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTablePropertyView.h index 4ad34057b..320beb349 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTablePropertyView.h @@ -15,15 +15,15 @@ namespace CesiumGltf { namespace StructuralMetadata { /** - * @brief Indicates the status of a property view. + * @brief Indicates the status of a property table property view. * - * The {@link MetadataPropertyView} constructor always completes successfully. + * The {@link PropertyTablePropertyView} constructor always completes successfully. * However, it may not always reflect the actual content of the * {@link ExtensionExtStructuralMetadataPropertyTableProperty}, but instead - * indicate that its {@link MetadataPropertyView::size} is 0. This enumeration + * indicate that its {@link PropertyTablePropertyView::size} is 0. This enumeration * provides the reason. */ -enum class MetadataPropertyViewStatus { +enum class PropertyTablePropertyViewStatus { /** * @brief This property view is valid and ready to use. */ @@ -36,7 +36,8 @@ enum class MetadataPropertyViewStatus { ErrorInvalidPropertyTable, /** - * @brief This property view does not exist in the + * @brief This property view is trying to view a property that does not exist + * in the * {@link ExtensionExtStructuralMetadataPropertyTable}. */ ErrorPropertyDoesNotExist, @@ -172,15 +173,15 @@ enum class MetadataPropertyViewStatus { * the scalar types, bool, std::string_view, or MetadataArrayView with T as * one of the aforementioned types. */ -template class MetadataPropertyView { +template class PropertyTablePropertyView { public: /** * @brief Constructs a new instance with a non-existent property. */ - MetadataPropertyView() - : _status{MetadataPropertyViewStatus::ErrorPropertyDoesNotExist}, + PropertyTablePropertyView() + : _status{PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist}, _values{}, - _fixedLengthArrayCount{}, + _arrayCount{}, _size{}, _normalized{} {} @@ -191,8 +192,8 @@ template class MetadataPropertyView { * @param size The number of elements in the property table specified by {@link ExtensionExtStructuralMetadataPropertyTable::count} * @param normalized Whether this property has a normalized integer type. */ - MetadataPropertyView( - MetadataPropertyViewStatus status, + PropertyTablePropertyView( + PropertyTablePropertyViewStatus status, gsl::span values, int64_t size, bool normalized) noexcept @@ -204,7 +205,7 @@ template class MetadataPropertyView { _stringOffsets{}, _stringOffsetType{PropertyComponentType::None}, _stringOffsetTypeSize{0}, - _fixedLengthArrayCount{0}, + _arrayCount{0}, _size{size}, _normalized{normalized} {} @@ -216,18 +217,18 @@ template class MetadataPropertyView { * @param stringOffsets The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::stringOffsets} * @param offsetType The offset type of arrayOffsets specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::arrayOffsetType} * @param offsetType The offset type of stringOffsets specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::stringOffsetType} - * @param fixedLengthArrayCount The number of elements in each array value specified by {@link ExtensionExtStructuralMetadataClassProperty::count} + * @param arrayCount The number of elements in each array value specified by {@link ExtensionExtStructuralMetadataClassProperty::count} * @param size The number of elements in the property table specified by {@link ExtensionExtStructuralMetadataPropertyTable::count} * @param normalized Whether this property has a normalized integer type. */ - MetadataPropertyView( - MetadataPropertyViewStatus status, + PropertyTablePropertyView( + PropertyTablePropertyViewStatus status, gsl::span values, gsl::span arrayOffsets, gsl::span stringOffsets, StructuralMetadata::PropertyComponentType arrayOffsetType, StructuralMetadata::PropertyComponentType stringOffsetType, - int64_t fixedLengthArrayCount, + int64_t arrayCount, int64_t size, bool normalized) noexcept : _status{status}, @@ -238,19 +239,19 @@ template class MetadataPropertyView { _stringOffsets{stringOffsets}, _stringOffsetType{stringOffsetType}, _stringOffsetTypeSize{getOffsetTypeSize(stringOffsetType)}, - _fixedLengthArrayCount{fixedLengthArrayCount}, + _arrayCount{arrayCount}, _size{size}, _normalized{normalized} {} /** - * @brief Gets the status of this property view. + * @brief Gets the status of this property table property view. * * Indicates whether the view accurately reflects the property's data, or * whether an error occurred. * * @return The status of this property view. */ - MetadataPropertyViewStatus status() const noexcept { return _status; } + PropertyTablePropertyViewStatus status() const noexcept { return _status; } /** * @brief Get the value of an element of the {@link ExtensionExtStructuralMetadataPropertyTable}. @@ -259,7 +260,7 @@ template class MetadataPropertyView { */ ElementType get(int64_t index) const noexcept { assert( - _status == MetadataPropertyViewStatus::Valid && + _status == PropertyTablePropertyViewStatus::Valid && "Check the status() first to make sure view is valid"); assert( size() > 0 && @@ -294,14 +295,14 @@ template class MetadataPropertyView { } /** - * @brief Get the number of elements in this MetadataPropertyView. If the view - * is valid, this returns + * @brief Get the number of elements in this + * PropertyTablePropertyView. If the view is valid, this returns * {@link ExtensionExtStructuralMetadataPropertyTable::count}. Otherwise, this returns 0. * - * @return The number of elements in this MetadataPropertyView. + * @return The number of elements in this PropertyTablePropertyView. */ int64_t size() const noexcept { - return status() == MetadataPropertyViewStatus::Valid ? _size : 0; + return status() == PropertyTablePropertyViewStatus::Valid ? _size : 0; } /** @@ -310,9 +311,7 @@ template class MetadataPropertyView { * * @return The count of this property. */ - int64_t getFixedLengthArrayCount() const noexcept { - return _fixedLengthArrayCount; - } + int64_t getArrayCount() const noexcept { return _arrayCount; } /** * @brief Whether this property has a normalized integer type. @@ -348,8 +347,8 @@ template class MetadataPropertyView { template MetadataArrayView getNumericArrayValues(int64_t index) const noexcept { // Handle fixed-length arrays - if (_fixedLengthArrayCount > 0) { - size_t arraySize = _fixedLengthArrayCount * sizeof(T); + if (_arrayCount > 0) { + size_t arraySize = _arrayCount * sizeof(T); const gsl::span values( _values.data() + index * arraySize, arraySize); @@ -370,9 +369,9 @@ template class MetadataPropertyView { MetadataArrayView getStringArrayValues(int64_t index) const noexcept { // Handle fixed-length arrays - if (_fixedLengthArrayCount > 0) { + if (_arrayCount > 0) { // Copy the corresponding string offsets to pass to the MetadataArrayView. - const size_t arraySize = _fixedLengthArrayCount * _stringOffsetTypeSize; + const size_t arraySize = _arrayCount * _stringOffsetTypeSize; const gsl::span stringOffsetValues( _stringOffsets.data() + index * arraySize, arraySize + _stringOffsetTypeSize); @@ -380,7 +379,7 @@ template class MetadataPropertyView { _values, stringOffsetValues, _stringOffsetType, - _fixedLengthArrayCount); + _arrayCount); } // Handle variable-length arrays @@ -401,16 +400,13 @@ template class MetadataPropertyView { MetadataArrayView getBooleanArrayValues(int64_t index) const noexcept { // Handle fixed-length arrays - if (_fixedLengthArrayCount > 0) { - const size_t offsetBits = _fixedLengthArrayCount * index; - const size_t nextOffsetBits = _fixedLengthArrayCount * (index + 1); + if (_arrayCount > 0) { + const size_t offsetBits = _arrayCount * index; + const size_t nextOffsetBits = _arrayCount * (index + 1); const gsl::span buffer( _values.data() + offsetBits / 8, (nextOffsetBits / 8 - offsetBits / 8 + 1)); - return MetadataArrayView( - buffer, - offsetBits % 8, - _fixedLengthArrayCount); + return MetadataArrayView(buffer, offsetBits % 8, _arrayCount); } // Handle variable-length arrays @@ -440,7 +436,7 @@ template class MetadataPropertyView { } } - MetadataPropertyViewStatus _status; + PropertyTablePropertyViewStatus _status; gsl::span _values; gsl::span _arrayOffsets; @@ -451,7 +447,7 @@ template class MetadataPropertyView { PropertyComponentType _stringOffsetType; int64_t _stringOffsetTypeSize; - int64_t _fixedLengthArrayCount; + int64_t _arrayCount; int64_t _size; bool _normalized; }; diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h index 7fcd8fc38..e3c55db2d 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h @@ -2,8 +2,8 @@ #include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" #include "CesiumGltf/Model.h" +#include "CesiumGltf/StructuralMetadataPropertyTablePropertyView.h" #include "CesiumGltf/StructuralMetadataPropertyType.h" -#include "CesiumGltf/StructuralMetadataPropertyView.h" #include @@ -15,12 +15,12 @@ namespace StructuralMetadata { /** * @brief Indicates the status of a property table view. * - * The {@link MetadataPropertyTableView} constructor always completes successfully. + * The {@link PropertyTableView} constructor always completes successfully. * However, it may not always reflect the actual content of the * {@link ExtensionExtStructuralMetadataPropertyTable}, but instead indicate that its - * {@link MetadataPropertyTableView::size} is 0. This enumeration provides the reason. + * {@link PropertyTableView::size} is 0. This enumeration provides the reason. */ -enum class MetadataPropertyTableViewStatus { +enum class PropertyTableViewStatus { /** * @brief This property table view is valid and ready to use. */ @@ -30,37 +30,38 @@ enum class MetadataPropertyTableViewStatus { * @brief The property table view's model does not contain an * EXT_structural_metadata extension. */ - ErrorNoStructuralMetadataExtension, + ErrorMissingMetadataExtension, /** * @brief The property table view's model does not have a schema in its * EXT_structural_metadata extension. */ - ErrorNoSchema, + ErrorMissingSchema, /** - * @brief The class of the property table does not exist in the schema. + * @brief The property table's specified class could not be found in the + * extension. */ - ErrorPropertyTableClassDoesNotExist + ErrorClassNotFound }; /** * @brief Utility to retrieve the data of * {@link ExtensionExtStructuralMetadataPropertyTable}. * - * This should be used to get a {@link MetadataPropertyView} of a property in the property table. - * It will validate the EXT_structural_metadata format and ensure {@link MetadataPropertyView} + * This should be used to get a {@link PropertyTablePropertyView} of a property in the property table. + * It will validate the EXT_structural_metadata format and ensure {@link PropertyTablePropertyView} * does not access out of bounds. */ -class MetadataPropertyTableView { +class PropertyTableView { public: /** - * @brief Creates an instance of MetadataPropertyTableView. + * @brief Creates an instance of PropertyTableView. * @param model The Gltf Model that contains property table data. * @param propertyTable The {@link ExtensionExtStructuralMetadataPropertyTable} * from which the view will retrieve data. */ - MetadataPropertyTableView( + PropertyTableView( const Model& model, const ExtensionExtStructuralMetadataPropertyTable& propertyTable); @@ -72,19 +73,18 @@ class MetadataPropertyTableView { * * @return The status of this property table view. */ - MetadataPropertyTableViewStatus status() const noexcept { return _status; } + PropertyTableViewStatus status() const noexcept { return _status; } /** - * @brief Get the number of elements in this MetadataPropertyTableView. If the + * @brief Get the number of elements in this PropertyTableView. If the * view is valid, this returns * {@link ExtensionExtStructuralMetadataPropertyTable::count}. Otherwise, this returns 0. * - * @return The number of elements in this MetadataPropertyTableView. + * @return The number of elements in this PropertyTableView. */ int64_t size() const noexcept { - return _status == MetadataPropertyTableViewStatus::Valid - ? _pPropertyTable->count - : 0; + return _status == PropertyTableViewStatus::Valid ? _pPropertyTable->count + : 0; } /** @@ -92,18 +92,18 @@ class MetadataPropertyTableView { * describes the type information of the property with the specified name. * @param propertyName The name of the property to retrieve the class for. * @return A pointer to the {@link ExtensionExtStructuralMetadataClassProperty}. - * Return nullptr if the MetadataPropertyTableView is invalid or if no class + * Return nullptr if the PropertyTableView is invalid or if no class * property was found. */ const ExtensionExtStructuralMetadataClassProperty* getClassProperty(const std::string& propertyName) const; /** - * @brief Gets a {@link MetadataPropertyView} that views the data of a property stored + * @brief Gets a {@link PropertyTablePropertyView} that views the data of a property stored * in the {@link ExtensionExtStructuralMetadataPropertyTable}. * * This method will validate the EXT_structural_metadata format to ensure - * {@link MetadataPropertyView} retrieves the correct data. T must be one of the + * {@link PropertyTablePropertyView} retrieves the correct data. T must be one of the * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, @@ -111,15 +111,15 @@ class MetadataPropertyTableView { * aforementioned types. * * @param propertyName The name of the property to retrieve data from - * @return A {@link MetadataPropertyView} of the property. If no valid property is + * @return A {@link PropertyTablePropertyView} of the property. If no valid property is * found, the property view will be invalid. */ template - MetadataPropertyView + PropertyTablePropertyView getPropertyView(const std::string& propertyName) const { if (this->size() <= 0) { return createInvalidPropertyView( - StructuralMetadata::MetadataPropertyViewStatus:: + StructuralMetadata::PropertyTablePropertyViewStatus:: ErrorInvalidPropertyTable); } @@ -127,7 +127,7 @@ class MetadataPropertyTableView { getClassProperty(propertyName); if (!pClassProperty) { return createInvalidPropertyView( - StructuralMetadata::MetadataPropertyViewStatus:: + StructuralMetadata::PropertyTablePropertyViewStatus:: ErrorPropertyDoesNotExist); } @@ -135,23 +135,23 @@ class MetadataPropertyTableView { } /** - * @brief Gets a {@link MetadataPropertyView} through a callback that accepts a - * property name and a {@link MetadataPropertyView} that views the data + * @brief Gets a {@link PropertyTablePropertyView} through a callback that accepts a + * property name and a {@link PropertyTablePropertyView} that views the data * of the property with the specified name. * * This method will validate the EXT_structural_metadata format to ensure - * {@link MetadataPropertyView} retrieves the correct data. T must be one of the + * {@link PropertyTablePropertyView} retrieves the correct data. T must be one of the * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, * std::string_view, or {@link MetadataArrayView} with T as one of the * aforementioned types. If the property is invalid, an empty - * {@link MetadataPropertyView} with an error status will be passed to the + * {@link PropertyTablePropertyView} 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 MetadataPropertyView} + * {@link PropertyTablePropertyView} */ template void @@ -160,7 +160,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - StructuralMetadata::MetadataPropertyViewStatus:: + StructuralMetadata::PropertyTablePropertyViewStatus:: ErrorInvalidPropertyTable)); return; } @@ -171,7 +171,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorPropertyDoesNotExist)); + PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist)); return; } @@ -221,30 +221,30 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorTypeMismatch)); } } /** * @brief Iterates over each property in the * {@link ExtensionExtStructuralMetadataPropertyTable} with a callback that accepts a - * property name and a {@link MetadataPropertyView} to view the data + * property name and a {@link PropertyTablePropertyView} to view the data * stored in the {@link ExtensionExtStructuralMetadataPropertyTableProperty}. * * This method will validate the EXT_structural_metadata format to ensure - * {@link MetadataPropertyView} retrieves the correct data. T must be one of the + * {@link PropertyTablePropertyView} retrieves the correct data. T must be one of the * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, * std::string_view, or {@link MetadataArrayView} with T as one of the * aforementioned types. If the property is invalid, an empty - * {@link MetadataPropertyView} with an error status code will be passed to the + * {@link PropertyTablePropertyView} with an error status code 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 MetadataPropertyView} + * {@link PropertyTablePropertyView} */ template void forEachProperty(Callback&& callback) const { for (const auto& property : this->_pClass->properties) { @@ -350,7 +350,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } } @@ -436,7 +436,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } } @@ -475,7 +475,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorTypeMismatch)); break; } } @@ -561,7 +561,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } } @@ -600,7 +600,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorTypeMismatch)); break; } } @@ -649,7 +649,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorTypeMismatch)); } } @@ -733,7 +733,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } } @@ -772,7 +772,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorTypeMismatch)); break; } } @@ -858,7 +858,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } } @@ -897,7 +897,7 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorTypeMismatch)); break; } } @@ -963,20 +963,20 @@ class MetadataPropertyTableView { callback( propertyName, createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorComponentTypeMismatch)); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } } template - MetadataPropertyView getPropertyViewImpl( + PropertyTablePropertyView getPropertyViewImpl( const std::string& propertyName, const ExtensionExtStructuralMetadataClassProperty& classProperty) const { auto propertyTablePropertyIter = _pPropertyTable->properties.find(propertyName); if (propertyTablePropertyIter == _pPropertyTable->properties.end()) { return createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorPropertyDoesNotExist); + PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist); } const ExtensionExtStructuralMetadataPropertyTableProperty& @@ -1006,37 +1006,37 @@ class MetadataPropertyTableView { } template - MetadataPropertyView getNumericOrBooleanPropertyValues( + PropertyTablePropertyView getNumericOrBooleanPropertyValues( const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty) const { if (classProperty.array) { return createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { return createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } const PropertyComponentType componentType = convertStringToPropertyComponentType( classProperty.componentType.value_or("")); if (TypeToPropertyType::component != componentType) { return createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } gsl::span values; const auto status = getBufferSafe(propertyTableProperty.values, values); - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return createInvalidPropertyView(status); } if (values.size() % sizeof(T) != 0) { return createInvalidPropertyView( - StructuralMetadata::MetadataPropertyViewStatus:: + StructuralMetadata::PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize); } @@ -1050,36 +1050,37 @@ class MetadataPropertyTableView { if (values.size() < maxRequiredBytes) { return createInvalidPropertyView( - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } - return MetadataPropertyView( - MetadataPropertyViewStatus::Valid, + return PropertyTablePropertyView( + PropertyTablePropertyViewStatus::Valid, values, _pPropertyTable->count, classProperty.normalized); } - MetadataPropertyView getStringPropertyValues( + PropertyTablePropertyView getStringPropertyValues( const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty) const; template - MetadataPropertyView> getPrimitiveArrayPropertyValues( + PropertyTablePropertyView> + getPrimitiveArrayPropertyValues( const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty) const { if (!classProperty.array) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } const PropertyComponentType componentType = @@ -1087,30 +1088,32 @@ class MetadataPropertyTableView { classProperty.componentType.value_or("")); if (TypeToPropertyType::component != componentType) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } gsl::span values; auto status = getBufferSafe(propertyTableProperty.values, values); - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return createInvalidPropertyView>(status); } if (values.size() % sizeof(T) != 0) { return createInvalidPropertyView>( - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize); } const int64_t fixedLengthArrayCount = classProperty.count.value_or(0); if (fixedLengthArrayCount > 0 && propertyTableProperty.arrayOffsets >= 0) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferCoexist); } if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); } // Handle fixed-length arrays @@ -1128,12 +1131,12 @@ class MetadataPropertyTableView { if (values.size() < maxRequiredBytes) { return createInvalidPropertyView>( - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } - return MetadataPropertyView>( - MetadataPropertyViewStatus::Valid, + return PropertyTablePropertyView>( + PropertyTablePropertyViewStatus::Valid, values, gsl::span(), gsl::span(), @@ -1150,7 +1153,7 @@ class MetadataPropertyTableView { propertyTableProperty.arrayOffsetType); if (arrayOffsetType == PropertyComponentType::None) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } constexpr bool checkBitsSize = IsMetadataBoolean::value; @@ -1162,12 +1165,12 @@ class MetadataPropertyTableView { static_cast(_pPropertyTable->count), checkBitsSize, arrayOffsets); - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return createInvalidPropertyView>(status); } - return MetadataPropertyView>( - MetadataPropertyViewStatus::Valid, + return PropertyTablePropertyView>( + PropertyTablePropertyViewStatus::Valid, values, arrayOffsets, gsl::span(), @@ -1178,17 +1181,17 @@ class MetadataPropertyTableView { classProperty.normalized); } - MetadataPropertyView> + PropertyTablePropertyView> getStringArrayPropertyValues( const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty) const; - MetadataPropertyViewStatus getBufferSafe( + PropertyTablePropertyViewStatus getBufferSafe( int32_t bufferView, gsl::span& buffer) const noexcept; - MetadataPropertyViewStatus getArrayOffsetsBufferSafe( + PropertyTablePropertyViewStatus getArrayOffsetsBufferSafe( int32_t arrayOffsetsBufferView, PropertyComponentType arrayOffsetType, size_t valuesBufferSize, @@ -1196,7 +1199,7 @@ class MetadataPropertyTableView { bool checkBitsSize, gsl::span& arrayOffsetsBuffer) const noexcept; - MetadataPropertyViewStatus getStringOffsetsBufferSafe( + PropertyTablePropertyViewStatus getStringOffsetsBufferSafe( int32_t stringOffsetsBufferView, PropertyComponentType stringOffsetType, size_t valuesBufferSize, @@ -1204,9 +1207,9 @@ class MetadataPropertyTableView { gsl::span& stringOffsetsBuffer) const noexcept; template - static MetadataPropertyView - createInvalidPropertyView(MetadataPropertyViewStatus invalidStatus) noexcept { - return MetadataPropertyView( + static PropertyTablePropertyView createInvalidPropertyView( + PropertyTablePropertyViewStatus invalidStatus) noexcept { + return PropertyTablePropertyView( invalidStatus, gsl::span(), 0, @@ -1216,7 +1219,7 @@ class MetadataPropertyTableView { const Model* _pModel; const ExtensionExtStructuralMetadataPropertyTable* _pPropertyTable; const ExtensionExtStructuralMetadataClass* _pClass; - MetadataPropertyTableViewStatus _status; + PropertyTableViewStatus _status; }; } // namespace StructuralMetadata diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h new file mode 100644 index 000000000..7cd609a13 --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h @@ -0,0 +1,245 @@ +#pragma once + +#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" +#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTexture.h" +#include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" +#include "CesiumGltf/Image.h" +#include "CesiumGltf/ImageCesium.h" +#include "CesiumGltf/Model.h" +#include "CesiumGltf/Sampler.h" +#include "CesiumGltf/Texture.h" + +#include +#include +#include + +namespace CesiumGltf { +namespace StructuralMetadata { +/** + * @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. + */ +enum class PropertyTexturePropertyViewStatus { + /** + * @brief This view is valid and ready to use. + */ + Valid, + + /** + * @brief This view has not been initialized. + */ + ErrorUninitialized, + + /** + * @brief This property texture property has a texture index that does not + * exist in the glTF. + */ + ErrorInvalidTexture, + + /** + * @brief This property texture property has a texture sampler index that does + * not exist in the glTF. + */ + ErrorInvalidTextureSampler, + + /** + * @brief This property texture property has an image index that does not + * exist in the glTF. + */ + ErrorInvalidImage, + + /** + * @brief This property texture property points to an empty image. + */ + ErrorEmptyImage, + + /** + * @brief The channels of this property texture property are invalid. + * Channels must be in the range 0-3, with a minimum of one channel and a + * maximum of four. + */ + ErrorInvalidChannels +}; + +/** + * @brief The supported component types that can exist in property id textures. + */ +enum class PropertyTexturePropertyComponentType { + Uint8 + // TODO: add more types. Currently this is the only one outputted by stb, + // so change stb call to output more of the original types. +}; + +/** + * @brief The property texture property value for a pixel. This will contain + * four channels of the specified type. + * + * Only the first n components will be valid, where n is the number of channels + * in this property texture property. + * + * @tparam T The component type, must correspond to a valid + * {@link PropertyTexturePropertyComponentType}. + */ +template struct PropertyTexturePropertyValue { + T components[4]; +}; + +/** + * @brief A view of the data specified by a + * {@link ExtensionExtStructuralMetadataPropertyTextureProperty}. + * + * Provides utilities to sample the property texture property using texture + * coordinates. + */ +class PropertyTexturePropertyView { +public: + /** + * @brief Construct an uninitialized, invalid view. + */ + PropertyTexturePropertyView() noexcept; + + /** + * @brief Construct a view of the data specified by the given property texture + * property. Assumes the model has already been validated by + * PropertyTextureView. + * + * @param model The glTF in which to look for the data specified by the + * property texture property. + * @param classProperty The property description. + * @param propertyTextureProperty The property texture property + */ + PropertyTexturePropertyView( + const Model& model, + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty) noexcept; + + /** + * @brief Gets the unswizzled property for the given texture coordinates. + * + * Will return -1s when the status is not Valid or when the templated + * component type doesn't match the image's channel byte-size. + * + * @tparam T The component type to use when interpreting the channels of the + * property's pixel value. + * @param u The u-component of the texture coordinates. Must be within + * [0.0, 1.0]. + * @param v The v-component of the texture coordinates. Must be within + * [0.0, 1.0]. + * @return The property at the nearest pixel to the texture coordinates. + */ + template + PropertyTexturePropertyValue + getProperty(double u, double v) const noexcept { + PropertyTexturePropertyValue property; + property.components[0] = -1; + property.components[1] = -1; + property.components[2] = -1; + property.components[3] = -1; + + if (this->_status != PropertyTexturePropertyViewStatus::Valid || + sizeof(T) != this->_pImage->bytesPerChannel) { + return property; + } + + // TODO: actually use the sampler?? + int64_t x = std::clamp( + std::llround(u * this->_pImage->width), + 0LL, + (long long)this->_pImage->width); + int64_t y = std::clamp( + std::llround(v * this->_pImage->height), + 0LL, + (long long)this->_pImage->height); + + int64_t pixelOffset = this->_pImage->bytesPerChannel * + this->_pImage->channels * + (y * this->_pImage->width + x); + const T* pRedChannel = reinterpret_cast( + this->_pImage->pixelData.data() + pixelOffset); + + for (size_t i = 0; i < this->_channels.size(); i++) { + const size_t channel = static_cast(this->_channels[i]); + property.components[channel] = *(pRedChannel + channel); + } + + return property; + } + + /** + * @brief Get the status of this view. + * + * If invalid, it will not be safe to sample from this view. + */ + PropertyTexturePropertyViewStatus status() const noexcept { + return this->_status; + } + + /** + * @brief Get the component type for this property. + */ + PropertyTexturePropertyComponentType getPropertyType() const noexcept { + return this->_type; + } + + /** + * @brief Get the count for this property. + * + * This is also how many channels a pixel value for this property will use. + */ + int64_t getCount() const noexcept { return this->_count; } + + /** + * @brief Get the texture coordinate set index for this property. + */ + int64_t getTextureCoordinateSetIndex() const noexcept { + return this->_textureCoordinateSetIndex; + } + + /** + * @brief Whether the component type for this property should be normalized. + */ + bool isNormalized() const noexcept { return this->_normalized; } + + /** + * @brief Get the image containing this property's data. + * + * This will be nullptr if the property texture property view runs into + * problems during construction. + */ + const ImageCesium* getImage() const noexcept { return this->_pImage; } + + /** + * @brief Gets the channels of this property texture property. + */ + const std::vector& 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: + PropertyTexturePropertyViewStatus _status; + const ExtensionExtStructuralMetadataClassProperty* _pClassProperty; + const ExtensionExtStructuralMetadataPropertyTextureProperty* + _pPropertyTextureProperty; + + const Sampler* _pSampler; + const ImageCesium* _pImage; + int64_t _textureCoordinateSetIndex; + std::vector _channels; + std::string _swizzle; + PropertyTexturePropertyComponentType _type; + int64_t _count; + bool _normalized; +}; + +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTextureView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTextureView.h new file mode 100644 index 000000000..9d053357e --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTextureView.h @@ -0,0 +1,124 @@ +#pragma once + +#include "CesiumGltf/ExtensionExtStructuralMetadataClass.h" +#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" +#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTexture.h" +#include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" +#include "CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h" +#include "CesiumGltf/Texture.h" +#include "CesiumGltf/TextureAccessor.h" +#include "Image.h" +#include "ImageCesium.h" +#include "Model.h" + +namespace CesiumGltf { +namespace StructuralMetadata { + +/** + * @brief Indicates the status of a property texture view. + * + * The {@link PropertyTextureView} constructor always completes successfully. + * However it may not always reflect the actual content of the + * {@link ExtensionExtStructuralMetadataPropertyTexture}. This enumeration provides the reason. + */ +enum class PropertyTextureViewStatus { + /** + * @brief This property texture view is valid and ready to use. + */ + Valid, + + /** + * @brief This property texture view is not initialized. + */ + ErrorUninitialized, + + /** + * @brief The glTF is missing the EXT_structural_metadata extension. + */ + ErrorMissingMetadataExtension, + + /** + * @brief The glTF EXT_structural_metadata extension doesn't contain a schema. + */ + ErrorMissingSchema, + + /** + * @brief The property texture's specified class could not be found in the + * extension. + */ + ErrorClassNotFound, + + /** + * @brief A property name specified in the property texture could not be found + * in the class. + */ + ErrorClassPropertyNotFound, + + /** + * @brief A property view for one of this property texture's properties failed + * to initialize successfully. Look for the invalid property view's status to + * find why it failed. + */ + ErrorInvalidPropertyView +}; + +/** + * @brief A view on the {@link ExtensionExtStructuralMetadataPropertyTexture}. + * + * Provides access to views on the property texture properties. + */ +class PropertyTextureView { +public: + /** + * @brief Construct an uninitialized, invalid property texture view. + */ + PropertyTextureView() noexcept; + + /** + * @brief Construct a view for the property texture. + * + * @param model The glTF in which to look for the property texture's data. + * @param propertyTexture The property texture to create a view for. + */ + PropertyTextureView( + const Model& model, + const ExtensionExtStructuralMetadataPropertyTexture& + propertyTexture) noexcept; + + /** + * @brief Gets the status of this property texture view. + * + * Indicates whether the view accurately reflects the property texture's data, + * or whether an error occurred. + */ + PropertyTextureViewStatus status() const noexcept { return this->_status; } + + /** + * @brief Finds the {@link ExtensionExtStructuralMetadataClassProperty} that + * describes the type information of the property with the specified name. + * @param propertyName The name of the property to retrieve the class for. + * @return A pointer to the {@link ExtensionExtStructuralMetadataClassProperty}. + * Return nullptr if the PropertyTextureView is invalid or if no class + * property was found. + */ + const ExtensionExtStructuralMetadataClassProperty* + getClassProperty(const std::string& propertyName) const; + + /** + * @brief Get the views for this property texture's properties. + */ + const std::unordered_map& + getProperties() const noexcept { + return this->_propertyViews; + } + +private: + const Model* _pModel; + const ExtensionExtStructuralMetadataPropertyTexture* _pPropertyTexture; + const ExtensionExtStructuralMetadataClass* _pClass; + std::unordered_map _propertyViews; + PropertyTextureViewStatus _status; +}; + +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp index bf6bdfd18..c1012e1e5 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -4,21 +4,21 @@ namespace CesiumGltf { namespace StructuralMetadata { template -static MetadataPropertyViewStatus checkOffsetsBuffer( +static PropertyTablePropertyViewStatus checkOffsetsBuffer( const gsl::span& offsetBuffer, size_t valueBufferSize, size_t instanceCount, bool checkBitSize, - MetadataPropertyViewStatus offsetsNotSortedError, - MetadataPropertyViewStatus offsetOutOfBoundsError) noexcept { + PropertyTablePropertyViewStatus offsetsNotSortedError, + PropertyTablePropertyViewStatus offsetOutOfBoundsError) noexcept { if (offsetBuffer.size() % sizeof(T) != 0) { - return MetadataPropertyViewStatus:: + return PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize; } const size_t size = offsetBuffer.size() / sizeof(T); if (size != instanceCount + 1) { - return MetadataPropertyViewStatus:: + return PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount; } @@ -34,21 +34,21 @@ static MetadataPropertyViewStatus checkOffsetsBuffer( if (checkBitSize) { if (offsetValues.back() / 8 <= valueBufferSize) { - return MetadataPropertyViewStatus::Valid; + return PropertyTablePropertyViewStatus::Valid; } return offsetOutOfBoundsError; } if (offsetValues.back() <= valueBufferSize) { - return MetadataPropertyViewStatus::Valid; + return PropertyTablePropertyViewStatus::Valid; } return offsetOutOfBoundsError; } template -static MetadataPropertyViewStatus checkStringAndArrayOffsetsBuffers( +static PropertyTablePropertyViewStatus checkStringAndArrayOffsetsBuffers( const gsl::span& arrayOffsets, const gsl::span& stringOffsets, size_t valueBufferSize, @@ -59,10 +59,10 @@ static MetadataPropertyViewStatus checkStringAndArrayOffsetsBuffers( stringOffsets.size(), propertyTableCount, false, - MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return status; } @@ -75,38 +75,38 @@ static MetadataPropertyViewStatus checkStringAndArrayOffsetsBuffers( valueBufferSize, pValue[propertyTableCount] / sizeof(T), false, - MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); case PropertyComponentType::Uint16: return checkOffsetsBuffer( stringOffsets, valueBufferSize, pValue[propertyTableCount] / sizeof(T), false, - MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); case PropertyComponentType::Uint32: return checkOffsetsBuffer( stringOffsets, valueBufferSize, pValue[propertyTableCount] / sizeof(T), false, - MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); case PropertyComponentType::Uint64: return checkOffsetsBuffer( stringOffsets, valueBufferSize, pValue[propertyTableCount] / sizeof(T), false, - MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); default: - return MetadataPropertyViewStatus::ErrorInvalidStringOffsetType; + return PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType; } } -MetadataPropertyTableView::MetadataPropertyTableView( +PropertyTableView::PropertyTableView( const Model& model, const ExtensionExtStructuralMetadataPropertyTable& propertyTable) : _pModel{&model}, @@ -116,15 +116,14 @@ MetadataPropertyTableView::MetadataPropertyTableView( const ExtensionModelExtStructuralMetadata* pMetadata = model.getExtension(); if (!pMetadata) { - _status = - MetadataPropertyTableViewStatus::ErrorNoStructuralMetadataExtension; + _status = PropertyTableViewStatus::ErrorMissingMetadataExtension; return; } const std::optional& schema = pMetadata->schema; if (!schema) { - _status = MetadataPropertyTableViewStatus::ErrorNoSchema; + _status = PropertyTableViewStatus::ErrorMissingSchema; return; } @@ -134,15 +133,14 @@ MetadataPropertyTableView::MetadataPropertyTableView( } if (!_pClass) { - _status = - MetadataPropertyTableViewStatus::ErrorPropertyTableClassDoesNotExist; + _status = PropertyTableViewStatus::ErrorClassNotFound; } } const ExtensionExtStructuralMetadataClassProperty* -MetadataPropertyTableView::getClassProperty( +PropertyTableView::getClassProperty( const std::string& propertyName) const { - if (_status != MetadataPropertyTableViewStatus::Valid) { + if (_status != PropertyTableViewStatus::Valid) { return nullptr; } @@ -154,7 +152,7 @@ MetadataPropertyTableView::getClassProperty( return &propertyIter->second; } -MetadataPropertyViewStatus MetadataPropertyTableView::getBufferSafe( +PropertyTablePropertyViewStatus PropertyTableView::getBufferSafe( int32_t bufferViewIdx, gsl::span& buffer) const noexcept { buffer = {}; @@ -162,36 +160,36 @@ MetadataPropertyViewStatus MetadataPropertyTableView::getBufferSafe( const BufferView* pBufferView = _pModel->getSafe(&_pModel->bufferViews, bufferViewIdx); if (!pBufferView) { - return MetadataPropertyViewStatus::ErrorInvalidValueBufferView; + return PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView; } const Buffer* pBuffer = _pModel->getSafe(&_pModel->buffers, pBufferView->buffer); if (!pBuffer) { - return MetadataPropertyViewStatus::ErrorInvalidValueBuffer; + return PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer; } if (pBufferView->byteOffset + pBufferView->byteLength > static_cast(pBuffer->cesium.data.size())) { - return MetadataPropertyViewStatus::ErrorBufferViewOutOfBounds; + return PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds; } buffer = gsl::span( pBuffer->cesium.data.data() + pBufferView->byteOffset, static_cast(pBufferView->byteLength)); - return MetadataPropertyViewStatus::Valid; + return PropertyTablePropertyViewStatus::Valid; } -MetadataPropertyViewStatus MetadataPropertyTableView::getArrayOffsetsBufferSafe( +PropertyTablePropertyViewStatus PropertyTableView::getArrayOffsetsBufferSafe( int32_t arrayOffsetsBufferView, PropertyComponentType arrayOffsetType, size_t valueBufferSize, size_t propertyTableCount, bool checkBitsSize, gsl::span& arrayOffsetsBuffer) const noexcept { - const MetadataPropertyViewStatus bufferStatus = + const PropertyTablePropertyViewStatus bufferStatus = getBufferSafe(arrayOffsetsBufferView, arrayOffsetsBuffer); - if (bufferStatus != MetadataPropertyViewStatus::Valid) { + if (bufferStatus != PropertyTablePropertyViewStatus::Valid) { return bufferStatus; } @@ -202,47 +200,47 @@ MetadataPropertyViewStatus MetadataPropertyTableView::getArrayOffsetsBufferSafe( valueBufferSize, propertyTableCount, checkBitsSize, - MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); case PropertyComponentType::Uint16: return checkOffsetsBuffer( arrayOffsetsBuffer, valueBufferSize, propertyTableCount, checkBitsSize, - MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); case PropertyComponentType::Uint32: return checkOffsetsBuffer( arrayOffsetsBuffer, valueBufferSize, propertyTableCount, checkBitsSize, - MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); case PropertyComponentType::Uint64: return checkOffsetsBuffer( arrayOffsetsBuffer, valueBufferSize, propertyTableCount, checkBitsSize, - MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); default: - return MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType; + return PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType; } } -MetadataPropertyViewStatus -MetadataPropertyTableView::getStringOffsetsBufferSafe( +PropertyTablePropertyViewStatus +PropertyTableView::getStringOffsetsBufferSafe( int32_t stringOffsetsBufferView, PropertyComponentType stringOffsetType, size_t valueBufferSize, size_t propertyTableCount, gsl::span& stringOffsetsBuffer) const noexcept { - const MetadataPropertyViewStatus bufferStatus = + const PropertyTablePropertyViewStatus bufferStatus = getBufferSafe(stringOffsetsBufferView, stringOffsetsBuffer); - if (bufferStatus != MetadataPropertyViewStatus::Valid) { + if (bufferStatus != PropertyTablePropertyViewStatus::Valid) { return bufferStatus; } @@ -253,56 +251,56 @@ MetadataPropertyTableView::getStringOffsetsBufferSafe( valueBufferSize, propertyTableCount, false, - MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); case PropertyComponentType::Uint16: return checkOffsetsBuffer( stringOffsetsBuffer, valueBufferSize, propertyTableCount, false, - MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); case PropertyComponentType::Uint32: return checkOffsetsBuffer( stringOffsetsBuffer, valueBufferSize, propertyTableCount, false, - MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); case PropertyComponentType::Uint64: return checkOffsetsBuffer( stringOffsetsBuffer, valueBufferSize, propertyTableCount, false, - MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted, - MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted, + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); default: - return MetadataPropertyViewStatus::ErrorInvalidStringOffsetType; + return PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType; } } -MetadataPropertyView -MetadataPropertyTableView::getStringPropertyValues( +PropertyTablePropertyView +PropertyTableView::getStringPropertyValues( const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty) const { if (classProperty.array) { return createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } if (classProperty.type != ExtensionExtStructuralMetadataClassProperty::Type::STRING) { return createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } gsl::span values; auto status = getBufferSafe(propertyTableProperty.values, values); - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return createInvalidPropertyView(status); } @@ -311,7 +309,7 @@ MetadataPropertyTableView::getStringPropertyValues( propertyTableProperty.stringOffsetType); if (offsetType == PropertyComponentType::None) { return createInvalidPropertyView( - MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); } gsl::span stringOffsets; @@ -321,12 +319,12 @@ MetadataPropertyTableView::getStringPropertyValues( values.size(), static_cast(_pPropertyTable->count), stringOffsets); - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return createInvalidPropertyView(status); } - return MetadataPropertyView( - MetadataPropertyViewStatus::Valid, + return PropertyTablePropertyView( + PropertyTablePropertyViewStatus::Valid, values, gsl::span(), stringOffsets, @@ -337,25 +335,25 @@ MetadataPropertyTableView::getStringPropertyValues( classProperty.normalized); } -MetadataPropertyView> -MetadataPropertyTableView::getStringArrayPropertyValues( +PropertyTablePropertyView> +PropertyTableView::getStringArrayPropertyValues( const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty) const { if (!classProperty.array) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } if (classProperty.type != ExtensionExtStructuralMetadataClassProperty::Type::STRING) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } gsl::span values; auto status = getBufferSafe(propertyTableProperty.values, values); - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return createInvalidPropertyView>( status); } @@ -364,12 +362,12 @@ MetadataPropertyTableView::getStringArrayPropertyValues( const int64_t fixedLengthArrayCount = classProperty.count.value_or(0); if (fixedLengthArrayCount > 0 && propertyTableProperty.arrayOffsets >= 0) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); } // Get string offset type @@ -378,12 +376,12 @@ MetadataPropertyTableView::getStringArrayPropertyValues( propertyTableProperty.stringOffsetType); if (stringOffsetType == PropertyComponentType::None) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); } if (propertyTableProperty.stringOffsets < 0) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorInvalidStringOffsetBufferView); + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetBufferView); } // Handle fixed-length arrays @@ -395,13 +393,13 @@ MetadataPropertyTableView::getStringArrayPropertyValues( values.size(), static_cast(_pPropertyTable->count * fixedLengthArrayCount), stringOffsets); - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return createInvalidPropertyView>( status); } - return MetadataPropertyView>( - MetadataPropertyViewStatus::Valid, + return PropertyTablePropertyView>( + PropertyTablePropertyViewStatus::Valid, values, gsl::span(), stringOffsets, @@ -418,25 +416,25 @@ MetadataPropertyTableView::getStringArrayPropertyValues( propertyTableProperty.arrayOffsetType); if (arrayOffsetType == PropertyComponentType::None) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } if (propertyTableProperty.arrayOffsets < 0) { return createInvalidPropertyView>( - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetBufferView); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetBufferView); } // Handle variable-length arrays gsl::span stringOffsets; status = getBufferSafe(propertyTableProperty.stringOffsets, stringOffsets); - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return createInvalidPropertyView>( status); } gsl::span arrayOffsets; status = getBufferSafe(propertyTableProperty.arrayOffsets, arrayOffsets); - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return createInvalidPropertyView>( status); } @@ -475,17 +473,17 @@ MetadataPropertyTableView::getStringArrayPropertyValues( static_cast(_pPropertyTable->count)); break; default: - status = MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType; + status = PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType; break; } - if (status != MetadataPropertyViewStatus::Valid) { + if (status != PropertyTablePropertyViewStatus::Valid) { return createInvalidPropertyView>( status); } - return MetadataPropertyView>( - MetadataPropertyViewStatus::Valid, + return PropertyTablePropertyView>( + PropertyTablePropertyViewStatus::Valid, values, arrayOffsets, stringOffsets, diff --git a/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp new file mode 100644 index 000000000..316341124 --- /dev/null +++ b/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp @@ -0,0 +1,102 @@ + +#include "CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h" + +namespace CesiumGltf { +namespace StructuralMetadata { + +PropertyTexturePropertyView::PropertyTexturePropertyView() noexcept + : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), + _pClassProperty(nullptr), + _pPropertyTextureProperty(nullptr), + _pSampler(nullptr), + _pImage(nullptr), + _textureCoordinateSetIndex(-1), + _channels(), + _swizzle(""), + _type(PropertyTexturePropertyComponentType::Uint8), + _count(0), + _normalized(false) {} + +PropertyTexturePropertyView::PropertyTexturePropertyView( + const Model& model, + const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty) noexcept + : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), + _pClassProperty(&classProperty), + _pPropertyTextureProperty(&propertyTextureProperty), + _pSampler(nullptr), + _pImage(nullptr), + _textureCoordinateSetIndex(propertyTextureProperty.texCoord), + _channels(), + _swizzle(""), + _type(PropertyTexturePropertyComponentType::Uint8), + _count(0), + _normalized(false) { + const int64_t index = _pPropertyTextureProperty->index; + if (index < 0 || static_cast(index) >= model.textures.size()) { + this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidTexture; + return; + } + + const Texture& texture = model.textures[static_cast(index)]; + if (texture.sampler < 0 || + static_cast(texture.sampler) >= model.samplers.size()) { + this->_status = + PropertyTexturePropertyViewStatus::ErrorInvalidTextureSampler; + return; + } + + this->_pSampler = &model.samplers[static_cast(texture.sampler)]; + + if (texture.source < 0 || + static_cast(texture.source) >= model.images.size()) { + this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidImage; + return; + } + + this->_pImage = &model.images[static_cast(texture.source)].cesium; + if (this->_pImage->width < 1 || this->_pImage->height < 1) { + this->_status = PropertyTexturePropertyViewStatus::ErrorEmptyImage; + return; + } + + // TODO: support more types + // this->_type = ... + + this->_count = + this->_pClassProperty->count ? *this->_pClassProperty->count : 1; + this->_normalized = this->_pClassProperty->normalized; + + const std::vector& channels = _pPropertyTextureProperty->channels; + if (channels.size() == 0 || channels.size() > 4 || + channels.size() > static_cast(this->_pImage->channels) || + channels.size() != static_cast(this->_count)) { + this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidChannels; + return; + } + + for (size_t i = 0; i < channels.size(); ++i) { + switch (channels[i]) { + case 0: + this->_swizzle += "r"; + break; + case 1: + this->_swizzle += "g"; + break; + case 2: + this->_swizzle += "b"; + break; + case 3: + this->_swizzle += "a"; + break; + default: + this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidChannels; + return; + } + } + + this->_status = PropertyTexturePropertyViewStatus::Valid; +} +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp new file mode 100644 index 000000000..507aa9e0c --- /dev/null +++ b/CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp @@ -0,0 +1,84 @@ +#include "CesiumGltf/StructuralMetadataPropertyTextureView.h" + +namespace CesiumGltf { +namespace StructuralMetadata { +PropertyTextureView::PropertyTextureView() noexcept + : _pModel(nullptr), + _pPropertyTexture(nullptr), + _pClass(nullptr), + _propertyViews(), + _status(PropertyTextureViewStatus::ErrorUninitialized) {} + +PropertyTextureView::PropertyTextureView( + const Model& model, + const ExtensionExtStructuralMetadataPropertyTexture& propertyTexture) noexcept + : _pModel(&model), + _pPropertyTexture(&propertyTexture), + _pClass(nullptr), + _propertyViews(), + _status(PropertyTextureViewStatus::ErrorUninitialized) { + + const ExtensionModelExtStructuralMetadata* pMetadata = + model.getExtension(); + + if (!pMetadata) { + this->_status = PropertyTextureViewStatus::ErrorMissingMetadataExtension; + return; + } + + if (!pMetadata->schema) { + this->_status = PropertyTextureViewStatus::ErrorMissingSchema; + return; + } + + const auto& classIt = + pMetadata->schema->classes.find(propertyTexture.classProperty); + if (classIt == pMetadata->schema->classes.end()) { + this->_status = PropertyTextureViewStatus::ErrorClassNotFound; + return; + } + + this->_pClass = &classIt->second; + + this->_propertyViews.reserve(propertyTexture.properties.size()); + for (const auto& property : propertyTexture.properties) { + auto classPropertyIt = this->_pClass->properties.find(property.first); + + if (classPropertyIt == this->_pClass->properties.end()) { + this->_status = PropertyTextureViewStatus::ErrorClassPropertyNotFound; + return; + } + + this->_propertyViews[property.first] = PropertyTexturePropertyView( + model, + classPropertyIt->second, + property.second); + } + + for (const auto& propertyView : this->_propertyViews) { + if (propertyView.second.status() != + PropertyTexturePropertyViewStatus::Valid) { + this->_status = PropertyTextureViewStatus::ErrorInvalidPropertyView; + return; + } + } + + this->_status = PropertyTextureViewStatus::Valid; +} + +const ExtensionExtStructuralMetadataClassProperty* +PropertyTextureView::getClassProperty(const std::string& propertyName) const { + if (_status != PropertyTextureViewStatus::Valid) { + return nullptr; + } + + auto propertyIter = _pClass->properties.find(propertyName); + if (propertyIter == _pClass->properties.end()) { + return nullptr; + } + + return &propertyIter->second; +} + +} // namespace StructuralMetadata +} // namespace CesiumGltf diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTablePropertyView.cpp similarity index 96% rename from CesiumGltf/test/TestStructuralMetadataPropertyView.cpp rename to CesiumGltf/test/TestStructuralMetadataPropertyTablePropertyView.cpp index 4c8103b08..d77e0a2a6 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTablePropertyView.cpp @@ -1,4 +1,4 @@ -#include "CesiumGltf/StructuralMetadataPropertyView.h" +#include "CesiumGltf/StructuralMetadataPropertyTablePropertyView.h" #include #include @@ -16,8 +16,8 @@ template static void checkNumeric(const std::vector& expected) { data.resize(expected.size() * sizeof(T)); std::memcpy(data.data(), expected.data(), data.size()); - MetadataPropertyView property( - MetadataPropertyViewStatus::Valid, + PropertyTablePropertyView property( + PropertyTablePropertyViewStatus::Valid, gsl::span(data.data(), data.size()), static_cast(expected.size()), false); @@ -46,8 +46,8 @@ static void checkVariableLengthArray( offsets.data(), offsets.size() * sizeof(OffsetType)); - MetadataPropertyView> property( - MetadataPropertyViewStatus::Valid, + PropertyTablePropertyView> property( + PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(offsetBuffer.data(), offsetBuffer.size()), gsl::span(), @@ -78,8 +78,8 @@ static void checkFixedLengthArray( buffer.resize(data.size() * sizeof(T)); std::memcpy(buffer.data(), data.data(), data.size() * sizeof(T)); - MetadataPropertyView> property( - MetadataPropertyViewStatus::Valid, + PropertyTablePropertyView> property( + PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(), @@ -225,8 +225,8 @@ TEST_CASE("Check StructuralMetadata boolean property") { std::memcpy(data.data(), &val, sizeof(val)); size_t instanceCount = sizeof(unsigned long) * CHAR_BIT; - MetadataPropertyView property( - MetadataPropertyViewStatus::Valid, + PropertyTablePropertyView property( + PropertyTablePropertyViewStatus::Valid, gsl::span(data.data(), data.size()), static_cast(instanceCount), false); @@ -272,8 +272,8 @@ TEST_CASE("Check StructuralMetadata string property") { ¤tOffset, sizeof(uint32_t)); - MetadataPropertyView property( - MetadataPropertyViewStatus::Valid, + PropertyTablePropertyView property( + PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(offsetBuffer.data(), offsetBuffer.size()), @@ -831,8 +831,8 @@ TEST_CASE("Check StructuralMetadata fixed-length array of string") { ¤tStringOffset, sizeof(uint32_t)); - MetadataPropertyView> property( - MetadataPropertyViewStatus::Valid, + PropertyTablePropertyView> property( + PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(stringOffsets.data(), stringOffsets.size()), @@ -904,8 +904,8 @@ TEST_CASE( ¤tOffset, sizeof(uint32_t)); - MetadataPropertyView> property( - MetadataPropertyViewStatus::Valid, + PropertyTablePropertyView> property( + PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span( reinterpret_cast(arrayOffsets.data()), @@ -936,8 +936,8 @@ TEST_CASE("Check StructuralMetadata fixed-length boolean array property") { static_cast(0b11111010), static_cast(0b11100111)}; - MetadataPropertyView> property( - MetadataPropertyViewStatus::Valid, + PropertyTablePropertyView> property( + PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(), @@ -988,8 +988,8 @@ TEST_CASE("Check StructuralMetadata variable-length boolean array property") { std::vector offsetBuffer{0, 3, 12, 28}; - MetadataPropertyView> property( - MetadataPropertyViewStatus::Valid, + PropertyTablePropertyView> property( + PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span( reinterpret_cast(offsetBuffer.data()), diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp index 95d148e1a..952f6d4cd 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp @@ -7,7 +7,8 @@ using namespace CesiumGltf; using namespace CesiumGltf::StructuralMetadata; -TEST_CASE("Test model without EXT_structural_metadata extension") { +TEST_CASE("Test PropertyTableView on model without EXT_structural_metadata " + "extension") { Model model; // Create an erroneously isolated property table. @@ -19,10 +20,9 @@ TEST_CASE("Test model without EXT_structural_metadata extension") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(0); - MetadataPropertyTableView view(model, propertyTable); + PropertyTableView view(model, propertyTable); REQUIRE( - view.status() == - MetadataPropertyTableViewStatus::ErrorNoStructuralMetadataExtension); + view.status() == PropertyTableViewStatus::ErrorMissingMetadataExtension); REQUIRE(view.size() == 0); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -30,7 +30,7 @@ TEST_CASE("Test model without EXT_structural_metadata extension") { REQUIRE(!classProperty); } -TEST_CASE("Test model without metadata schema") { +TEST_CASE("Test PropertyTableView on model without metadata schema") { Model model; ExtensionModelExtStructuralMetadata& metadata = @@ -45,8 +45,8 @@ TEST_CASE("Test model without metadata schema") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(0); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::ErrorNoSchema); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::ErrorMissingSchema); REQUIRE(view.size() == 0); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -78,10 +78,8 @@ TEST_CASE("Test property table with nonexistent class") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(0); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE( - view.status() == - MetadataPropertyTableViewStatus::ErrorPropertyTableClassDoesNotExist); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); REQUIRE(view.size() == 0); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -138,8 +136,8 @@ TEST_CASE("Test StructuralMetadata scalar property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -155,9 +153,9 @@ TEST_CASE("Test StructuralMetadata scalar property") { REQUIRE(!classProperty->array); SECTION("Access correct type") { - MetadataPropertyView uint32Property = + PropertyTablePropertyView uint32Property = view.getPropertyView("TestClassProperty"); - REQUIRE(uint32Property.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(uint32Property.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(uint32Property.size() > 0); for (int64_t i = 0; i < uint32Property.size(); ++i) { @@ -166,100 +164,103 @@ TEST_CASE("Test StructuralMetadata scalar property") { } SECTION("Access wrong type") { - MetadataPropertyView uvec3Invalid = + PropertyTablePropertyView uvec3Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( - uvec3Invalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + uvec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView u32mat3x3Invalid = + PropertyTablePropertyView u32mat3x3Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( u32mat3x3Invalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView boolInvalid = + PropertyTablePropertyView boolInvalid = view.getPropertyView("TestClassProperty"); REQUIRE( - boolInvalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + boolInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView stringInvalid = + PropertyTablePropertyView stringInvalid = view.getPropertyView("TestClassProperty"); REQUIRE( stringInvalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } SECTION("Access wrong component type") { - MetadataPropertyView uint8Invalid = + PropertyTablePropertyView uint8Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( uint8Invalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - MetadataPropertyView int32Invalid = + PropertyTablePropertyView int32Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( int32Invalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - MetadataPropertyView uint64Invalid = + PropertyTablePropertyView uint64Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( uint64Invalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Access incorrectly as array") { - MetadataPropertyView> uint32ArrayInvalid = + PropertyTablePropertyView> uint32ArrayInvalid = view.getPropertyView>("TestClassProperty"); REQUIRE( uint32ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Wrong buffer index") { model.bufferViews[valueBufferViewIndex].buffer = 2; - MetadataPropertyView uint32Property = + PropertyTablePropertyView uint32Property = view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == - MetadataPropertyViewStatus::ErrorInvalidValueBuffer); + PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); } SECTION("Wrong buffer view index") { propertyTableProperty.values = -1; - MetadataPropertyView uint32Property = + PropertyTablePropertyView uint32Property = view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == - MetadataPropertyViewStatus::ErrorInvalidValueBufferView); + PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); } SECTION("Buffer view points outside of the real buffer length") { model.buffers[valueBufferIndex].cesium.data.resize(12); - MetadataPropertyView uint32Property = + PropertyTablePropertyView uint32Property = view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == - MetadataPropertyViewStatus::ErrorBufferViewOutOfBounds); + PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); } SECTION("Buffer view length isn't multiple of sizeof(T)") { model.bufferViews[valueBufferViewIndex].byteLength = 13; - MetadataPropertyView uint32Property = + PropertyTablePropertyView uint32Property = view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == - MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); } SECTION("Buffer view length doesn't match with propertyTableCount") { model.bufferViews[valueBufferViewIndex].byteLength = 12; - MetadataPropertyView uint32Property = + PropertyTablePropertyView uint32Property = view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } } @@ -317,8 +318,8 @@ TEST_CASE("Test StructuralMetadata vecN property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -334,9 +335,9 @@ TEST_CASE("Test StructuralMetadata vecN property") { REQUIRE(!classProperty->array); SECTION("Access correct type") { - MetadataPropertyView ivec3Property = + PropertyTablePropertyView ivec3Property = view.getPropertyView("TestClassProperty"); - REQUIRE(ivec3Property.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(ivec3Property.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(ivec3Property.size() > 0); for (int64_t i = 0; i < ivec3Property.size(); ++i) { @@ -345,106 +346,110 @@ TEST_CASE("Test StructuralMetadata vecN property") { } SECTION("Access wrong type") { - MetadataPropertyView int32Invalid = + PropertyTablePropertyView int32Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( - int32Invalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + int32Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView ivec2Invalid = + PropertyTablePropertyView ivec2Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( - ivec2Invalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + ivec2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView i32mat3x3Invalid = + PropertyTablePropertyView i32mat3x3Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( i32mat3x3Invalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView boolInvalid = + PropertyTablePropertyView boolInvalid = view.getPropertyView("TestClassProperty"); REQUIRE( - boolInvalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + boolInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView stringInvalid = + PropertyTablePropertyView stringInvalid = view.getPropertyView("TestClassProperty"); REQUIRE( stringInvalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } SECTION("Access wrong component type") { - MetadataPropertyView u8vec3Invalid = + PropertyTablePropertyView u8vec3Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( u8vec3Invalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - MetadataPropertyView i16vec3Invalid = + PropertyTablePropertyView i16vec3Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( i16vec3Invalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - MetadataPropertyView vec3Invalid = + PropertyTablePropertyView vec3Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( vec3Invalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Access incorrectly as array") { - MetadataPropertyView> ivec3ArrayInvalid = + PropertyTablePropertyView> ivec3ArrayInvalid = view.getPropertyView>( "TestClassProperty"); REQUIRE( ivec3ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Wrong buffer index") { model.bufferViews[valueBufferViewIndex].buffer = 2; - MetadataPropertyView ivec3Property = + PropertyTablePropertyView ivec3Property = view.getPropertyView("TestClassProperty"); REQUIRE( ivec3Property.status() == - MetadataPropertyViewStatus::ErrorInvalidValueBuffer); + PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); } SECTION("Wrong buffer view index") { propertyTableProperty.values = -1; - MetadataPropertyView ivec3Property = + PropertyTablePropertyView ivec3Property = view.getPropertyView("TestClassProperty"); REQUIRE( ivec3Property.status() == - MetadataPropertyViewStatus::ErrorInvalidValueBufferView); + PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); } SECTION("Buffer view points outside of the real buffer length") { model.buffers[valueBufferIndex].cesium.data.resize(12); - MetadataPropertyView ivec3Property = + PropertyTablePropertyView ivec3Property = view.getPropertyView("TestClassProperty"); REQUIRE( ivec3Property.status() == - MetadataPropertyViewStatus::ErrorBufferViewOutOfBounds); + PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); } SECTION("Buffer view length isn't multiple of sizeof(T)") { model.bufferViews[valueBufferViewIndex].byteLength = 11; - MetadataPropertyView ivec3Property = + PropertyTablePropertyView ivec3Property = view.getPropertyView("TestClassProperty"); REQUIRE( ivec3Property.status() == - MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); } SECTION("Buffer view length doesn't match with propertyTableCount") { model.bufferViews[valueBufferViewIndex].byteLength = 12; - MetadataPropertyView ivec3Property = + PropertyTablePropertyView ivec3Property = view.getPropertyView("TestClassProperty"); REQUIRE( ivec3Property.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } } @@ -512,8 +517,8 @@ TEST_CASE("Test StructuralMetadata matN property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -529,9 +534,10 @@ TEST_CASE("Test StructuralMetadata matN property") { REQUIRE(!classProperty->array); SECTION("Access correct type") { - MetadataPropertyView u32mat2x2Property = + PropertyTablePropertyView u32mat2x2Property = view.getPropertyView("TestClassProperty"); - REQUIRE(u32mat2x2Property.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + u32mat2x2Property.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(u32mat2x2Property.size() > 0); for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { @@ -540,110 +546,113 @@ TEST_CASE("Test StructuralMetadata matN property") { } SECTION("Access wrong type") { - MetadataPropertyView uint32Invalid = + PropertyTablePropertyView uint32Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( uint32Invalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView uvec2Invalid = + PropertyTablePropertyView uvec2Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( - uvec2Invalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + uvec2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView u32mat4x4Invalid = + PropertyTablePropertyView u32mat4x4Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( u32mat4x4Invalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView boolInvalid = + PropertyTablePropertyView boolInvalid = view.getPropertyView("TestClassProperty"); REQUIRE( - boolInvalid.status() == MetadataPropertyViewStatus::ErrorTypeMismatch); + boolInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView stringInvalid = + PropertyTablePropertyView stringInvalid = view.getPropertyView("TestClassProperty"); REQUIRE( stringInvalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } SECTION("Access wrong component type") { - MetadataPropertyView u8mat2x2Invalid = + PropertyTablePropertyView u8mat2x2Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( u8mat2x2Invalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - MetadataPropertyView i32mat2x2Invalid = + PropertyTablePropertyView i32mat2x2Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( i32mat2x2Invalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - MetadataPropertyView mat2Invalid = + PropertyTablePropertyView mat2Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( mat2Invalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Access incorrectly as array") { - MetadataPropertyView> + PropertyTablePropertyView> u32mat2x2ArrayInvalid = view.getPropertyView>( "TestClassProperty"); REQUIRE( u32mat2x2ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Wrong buffer index") { model.bufferViews[valueBufferViewIndex].buffer = 2; - MetadataPropertyView u32mat2x2Property = + PropertyTablePropertyView u32mat2x2Property = view.getPropertyView("TestClassProperty"); REQUIRE( u32mat2x2Property.status() == - MetadataPropertyViewStatus::ErrorInvalidValueBuffer); + PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); } SECTION("Wrong buffer view index") { propertyTableProperty.values = -1; - MetadataPropertyView u32mat2x2Property = + PropertyTablePropertyView u32mat2x2Property = view.getPropertyView("TestClassProperty"); REQUIRE( u32mat2x2Property.status() == - MetadataPropertyViewStatus::ErrorInvalidValueBufferView); + PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); } SECTION("Buffer view points outside of the real buffer length") { model.buffers[valueBufferIndex].cesium.data.resize(sizeof(glm::u32mat2x2)); - MetadataPropertyView u32mat2x2Property = + PropertyTablePropertyView u32mat2x2Property = view.getPropertyView("TestClassProperty"); REQUIRE( u32mat2x2Property.status() == - MetadataPropertyViewStatus::ErrorBufferViewOutOfBounds); + PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); } SECTION("Buffer view length isn't multiple of sizeof(T)") { model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::u32mat2x2) * 4 - 1; - MetadataPropertyView u32mat2x2Property = + PropertyTablePropertyView u32mat2x2Property = view.getPropertyView("TestClassProperty"); REQUIRE( u32mat2x2Property.status() == - MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); } SECTION("Buffer view length doesn't match with propertyTableCount") { model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::u32mat2x2); - MetadataPropertyView u32mat2x2Property = + PropertyTablePropertyView u32mat2x2Property = view.getPropertyView("TestClassProperty"); REQUIRE( u32mat2x2Property.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } } @@ -707,8 +716,8 @@ TEST_CASE("Test StructuralMetadata boolean property") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -722,9 +731,9 @@ TEST_CASE("Test StructuralMetadata boolean property") { REQUIRE(!classProperty->array); SECTION("Access correct type") { - MetadataPropertyView boolProperty = + PropertyTablePropertyView boolProperty = view.getPropertyView("TestClassProperty"); - REQUIRE(boolProperty.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(boolProperty.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(boolProperty.size() == instanceCount); for (int64_t i = 0; i < boolProperty.size(); ++i) { bool expectedValue = expected[static_cast(i)]; @@ -734,11 +743,11 @@ TEST_CASE("Test StructuralMetadata boolean property") { SECTION("Buffer size doesn't match with propertyTableCount") { propertyTable.count = 66; - MetadataPropertyView boolProperty = + PropertyTablePropertyView boolProperty = view.getPropertyView("TestClassProperty"); REQUIRE( boolProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } } @@ -822,8 +831,8 @@ TEST_CASE("Test StructuralMetadata string property") { propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -837,33 +846,33 @@ TEST_CASE("Test StructuralMetadata string property") { REQUIRE(!classProperty->array); SECTION("Access correct type") { - MetadataPropertyView stringProperty = + PropertyTablePropertyView stringProperty = view.getPropertyView("TestClassProperty"); - REQUIRE(stringProperty.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { REQUIRE(stringProperty.get(static_cast(i)) == expected[i]); } } SECTION("Wrong array type") { - MetadataPropertyView> + PropertyTablePropertyView> stringArrayInvalid = view.getPropertyView>( "TestClassProperty"); REQUIRE( stringArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Wrong offset type") { propertyTableProperty.stringOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: UINT8; - MetadataPropertyView stringProperty = + PropertyTablePropertyView stringProperty = view.getPropertyView("TestClassProperty"); REQUIRE( stringProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.stringOffsetType = @@ -873,7 +882,7 @@ TEST_CASE("Test StructuralMetadata string property") { view.getPropertyView("TestClassProperty"); REQUIRE( stringProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.stringOffsetType = "NONSENSE"; @@ -881,7 +890,7 @@ TEST_CASE("Test StructuralMetadata string property") { view.getPropertyView("TestClassProperty"); REQUIRE( stringProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); propertyTableProperty.stringOffsetType = ""; propertyTableProperty.arrayOffsetType = @@ -891,7 +900,7 @@ TEST_CASE("Test StructuralMetadata string property") { view.getPropertyView("TestClassProperty"); REQUIRE( stringProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); } SECTION("Offset values are not sorted ascending") { @@ -899,11 +908,11 @@ TEST_CASE("Test StructuralMetadata string property") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[2] = static_cast(model.buffers[valueBufferIndex].byteLength + 4); - MetadataPropertyView stringProperty = + PropertyTablePropertyView stringProperty = view.getPropertyView("TestClassProperty"); REQUIRE( stringProperty.status() == - MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted); + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); } SECTION("Offset value points outside of value buffer") { @@ -911,11 +920,11 @@ TEST_CASE("Test StructuralMetadata string property") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast(model.buffers[valueBufferIndex].byteLength + 4); - MetadataPropertyView stringProperty = + PropertyTablePropertyView stringProperty = view.getPropertyView("TestClassProperty"); REQUIRE( stringProperty.status() == - MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); } } @@ -968,8 +977,8 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -985,9 +994,9 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { REQUIRE(classProperty->count == 3); SECTION("Access the right type") { - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); - REQUIRE(arrayProperty.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { MetadataArrayView member = arrayProperty.get(i); @@ -998,61 +1007,62 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { } SECTION("Wrong type") { - MetadataPropertyView> boolArrayInvalid = + PropertyTablePropertyView> boolArrayInvalid = view.getPropertyView>("TestClassProperty"); REQUIRE( boolArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView> uvec2ArrayInvalid = + PropertyTablePropertyView> uvec2ArrayInvalid = view.getPropertyView>( "TestClassProperty"); REQUIRE( uvec2ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } SECTION("Wrong component type") { - MetadataPropertyView> int32ArrayInvalid = + PropertyTablePropertyView> int32ArrayInvalid = view.getPropertyView>("TestClassProperty"); REQUIRE( int32ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Not an array type") { - MetadataPropertyView uint32Invalid = + PropertyTablePropertyView uint32Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( uint32Invalid.status() == - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Buffer size is not a multiple of type size") { model.bufferViews[valueBufferViewIndex].byteLength = 13; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); } SECTION("Negative component count") { testClassProperty.count = -1; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( - arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + arrayProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); } SECTION("Value buffer doesn't fit into property table count") { testClassProperty.count = 55; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } } @@ -1142,8 +1152,8 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT64; - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -1159,9 +1169,9 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { REQUIRE(!classProperty->count); SECTION("Access the correct type") { - MetadataPropertyView> property = + PropertyTablePropertyView> property = view.getPropertyView>("TestClassProperty"); - REQUIRE(property.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { MetadataArrayView valueMember = property.get(static_cast(i)); @@ -1175,11 +1185,11 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT8; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = @@ -1189,7 +1199,7 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; @@ -1197,7 +1207,7 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = @@ -1207,7 +1217,7 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } SECTION("Offset values are not sorted ascending") { @@ -1217,11 +1227,11 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted); + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); } SECTION("Offset value points outside of value buffer") { @@ -1229,20 +1239,20 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast(model.buffers[valueBufferIndex].byteLength + 4); - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); } SECTION("Count and offset buffer are both present") { testClassProperty.count = 3; - MetadataPropertyView> property = + PropertyTablePropertyView> property = view.getPropertyView>("TestClassProperty"); REQUIRE( property.status() == - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } } @@ -1301,8 +1311,8 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -1318,10 +1328,10 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { REQUIRE(classProperty->count == 2); SECTION("Access the right type") { - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); - REQUIRE(arrayProperty.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { MetadataArrayView member = arrayProperty.get(i); @@ -1332,65 +1342,66 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { } SECTION("Wrong type") { - MetadataPropertyView> int32ArrayInvalid = + PropertyTablePropertyView> int32ArrayInvalid = view.getPropertyView>("TestClassProperty"); REQUIRE( int32ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView> ivec2ArrayInvalid = + PropertyTablePropertyView> ivec2ArrayInvalid = view.getPropertyView>( "TestClassProperty"); REQUIRE( ivec2ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } SECTION("Wrong component type") { - MetadataPropertyView> uvec3ArrayInvalid = + PropertyTablePropertyView> uvec3ArrayInvalid = view.getPropertyView>( "TestClassProperty"); REQUIRE( uvec3ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Not an array type") { - MetadataPropertyView ivec3Invalid = + PropertyTablePropertyView ivec3Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( ivec3Invalid.status() == - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Buffer size is not a multiple of type size") { model.bufferViews[valueBufferViewIndex].byteLength = 13; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); } SECTION("Negative component count") { testClassProperty.count = -1; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( - arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + arrayProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); } SECTION("Value buffer doesn't fit into property table count") { testClassProperty.count = 55; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } } @@ -1482,8 +1493,8 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT64; - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -1499,10 +1510,10 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { REQUIRE(!classProperty->count); SECTION("Access the correct type") { - MetadataPropertyView> property = + PropertyTablePropertyView> property = view.getPropertyView>( "TestClassProperty"); - REQUIRE(property.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { MetadataArrayView valueMember = property.get(static_cast(i)); @@ -1517,12 +1528,12 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT8; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = @@ -1532,7 +1543,7 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; @@ -1540,7 +1551,7 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = @@ -1550,7 +1561,7 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } SECTION("Offset values are not sorted ascending") { @@ -1560,12 +1571,12 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted); + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); } SECTION("Offset value points outside of value buffer") { @@ -1573,22 +1584,22 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast(model.buffers[valueBufferIndex].byteLength + 4); - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); } SECTION("Count and offset buffer are both present") { testClassProperty.count = 3; - MetadataPropertyView> property = + PropertyTablePropertyView> property = view.getPropertyView>( "TestClassProperty"); REQUIRE( property.status() == - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } } @@ -1661,8 +1672,8 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -1678,10 +1689,10 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { REQUIRE(classProperty->count == 2); SECTION("Access the right type") { - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); - REQUIRE(arrayProperty.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { MetadataArrayView member = arrayProperty.get(i); @@ -1692,66 +1703,67 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { } SECTION("Wrong type") { - MetadataPropertyView> int32ArrayInvalid = + PropertyTablePropertyView> int32ArrayInvalid = view.getPropertyView>("TestClassProperty"); REQUIRE( int32ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); - MetadataPropertyView> ivec2ArrayInvalid = + PropertyTablePropertyView> ivec2ArrayInvalid = view.getPropertyView>( "TestClassProperty"); REQUIRE( ivec2ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } SECTION("Wrong component type") { - MetadataPropertyView> + PropertyTablePropertyView> u32mat2x2ArrayInvalid = view.getPropertyView>( "TestClassProperty"); REQUIRE( u32mat2x2ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorComponentTypeMismatch); + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Not an array type") { - MetadataPropertyView ivec3Invalid = + PropertyTablePropertyView ivec3Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( ivec3Invalid.status() == - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Buffer size is not a multiple of type size") { model.bufferViews[valueBufferViewIndex].byteLength = 13; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize); + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); } SECTION("Negative component count") { testClassProperty.count = -1; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( - arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + arrayProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); } SECTION("Value buffer doesn't fit into property table count") { testClassProperty.count = 55; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } } @@ -1863,8 +1875,8 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT64; - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -1880,10 +1892,10 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { REQUIRE(!classProperty->count); SECTION("Access the correct type") { - MetadataPropertyView> property = + PropertyTablePropertyView> property = view.getPropertyView>( "TestClassProperty"); - REQUIRE(property.status() == MetadataPropertyViewStatus::Valid); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { MetadataArrayView valueMember = property.get(static_cast(i)); @@ -1898,12 +1910,12 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT8; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = @@ -1913,7 +1925,7 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; @@ -1921,7 +1933,7 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = @@ -1931,7 +1943,7 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } SECTION("Offset values are not sorted ascending") { @@ -1941,12 +1953,12 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted); + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); } SECTION("Offset value points outside of value buffer") { @@ -1954,22 +1966,22 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast(model.buffers[valueBufferIndex].byteLength + 4); - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); } SECTION("Count and offset buffer are both present") { testClassProperty.count = 3; - MetadataPropertyView> property = + PropertyTablePropertyView> property = view.getPropertyView>( "TestClassProperty"); REQUIRE( property.status() == - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } } @@ -2040,8 +2052,8 @@ TEST_CASE("Test StructuralMetadata fixed-length boolean array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -2054,9 +2066,10 @@ TEST_CASE("Test StructuralMetadata fixed-length boolean array") { REQUIRE(classProperty->count == 3); SECTION("Access correct type") { - MetadataPropertyView> boolArrayProperty = + PropertyTablePropertyView> boolArrayProperty = view.getPropertyView>("TestClassProperty"); - REQUIRE(boolArrayProperty.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(boolArrayProperty.size() == propertyTable.count); REQUIRE(boolArrayProperty.size() > 0); for (int64_t i = 0; i < boolArrayProperty.size(); ++i) { @@ -2068,38 +2081,39 @@ TEST_CASE("Test StructuralMetadata fixed-length boolean array") { } SECTION("Wrong type") { - MetadataPropertyView> uint8ArrayInvalid = + PropertyTablePropertyView> uint8ArrayInvalid = view.getPropertyView>("TestClassProperty"); REQUIRE( uint8ArrayInvalid.status() == - MetadataPropertyViewStatus::ErrorTypeMismatch); + PropertyTablePropertyViewStatus::ErrorTypeMismatch); } SECTION("View is not array type") { - MetadataPropertyView boolInvalid = + PropertyTablePropertyView boolInvalid = view.getPropertyView("TestClassProperty"); REQUIRE( boolInvalid.status() == - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Value buffer doesn't have enough required bytes") { testClassProperty.count = 11; - MetadataPropertyView> boolArrayProperty = + PropertyTablePropertyView> boolArrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( boolArrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } SECTION("Count is negative") { testClassProperty.count = -1; - MetadataPropertyView> boolArrayProperty = + PropertyTablePropertyView> boolArrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( boolArrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); } } @@ -2193,8 +2207,8 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT64; - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -2207,9 +2221,10 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { REQUIRE(!classProperty->count); SECTION("Access correct type") { - MetadataPropertyView> boolArrayProperty = + PropertyTablePropertyView> boolArrayProperty = view.getPropertyView>("TestClassProperty"); - REQUIRE(boolArrayProperty.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { MetadataArrayView arrayMember = boolArrayProperty.get(static_cast(i)); @@ -2224,11 +2239,11 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT8; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = @@ -2238,7 +2253,7 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; @@ -2246,7 +2261,7 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = @@ -2256,7 +2271,7 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } SECTION("Offset values are not sorted ascending") { @@ -2266,11 +2281,11 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted); + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); } SECTION("Offset value points outside of value buffer") { @@ -2278,20 +2293,20 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast( model.buffers[valueBufferIndex].byteLength * 8 + 20); - MetadataPropertyView> arrayProperty = + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); } SECTION("Count and offset buffer both present") { testClassProperty.count = 3; - MetadataPropertyView> boolArrayProperty = + PropertyTablePropertyView> boolArrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( boolArrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } } @@ -2377,8 +2392,8 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -2391,10 +2406,11 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { REQUIRE(classProperty->count == 2); SECTION("Access correct type") { - MetadataPropertyView> stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(stringProperty.status() == MetadataPropertyViewStatus::Valid); + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(stringProperty.size() == 3); MetadataArrayView v0 = stringProperty.get(0); @@ -2414,31 +2430,33 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { } SECTION("Array type mismatch") { - MetadataPropertyView stringProperty = + PropertyTablePropertyView stringProperty = view.getPropertyView("TestClassProperty"); REQUIRE( stringProperty.status() == - MetadataPropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Count is negative") { testClassProperty.count = -1; - MetadataPropertyView> stringProperty = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( - stringProperty.status() == - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + stringProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); } SECTION("Offset type is unknown") { propertyTableProperty.stringOffsetType = "NONSENSE"; - MetadataPropertyView> stringProperty = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( stringProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); propertyTableProperty.stringOffsetType = ""; propertyTableProperty.arrayOffsetType = @@ -2448,17 +2466,18 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { "TestClassProperty"); REQUIRE( stringProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); } SECTION("String offsets don't exist") { propertyTableProperty.stringOffsets = -1; - MetadataPropertyView> stringProperty = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( stringProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidStringOffsetBufferView); + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetBufferView); } } @@ -2582,8 +2601,8 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { propertyTableProperty.stringOffsets = static_cast(stringOffsetBufferView); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -2597,10 +2616,11 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { REQUIRE(!classProperty->count); SECTION("Access correct type") { - MetadataPropertyView> stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(stringProperty.status() == MetadataPropertyViewStatus::Valid); + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { MetadataArrayView stringArray = stringProperty.get(static_cast(i)); @@ -2614,12 +2634,13 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT8; - MetadataPropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = @@ -2629,7 +2650,7 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; @@ -2637,7 +2658,7 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidArrayOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT32; @@ -2647,12 +2668,13 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { propertyTableProperty.stringOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: UINT8; - MetadataPropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.stringOffsetType = @@ -2662,7 +2684,7 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.stringOffsetType = "NONSENSE"; @@ -2670,7 +2692,7 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorInvalidStringOffsetType); + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); propertyTableProperty.stringOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: UINT32; @@ -2680,12 +2702,13 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { uint32_t* offset = reinterpret_cast( model.buffers[arrayOffsetBuffer].cesium.data.data()); offset[0] = static_cast(1000); - MetadataPropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayOffsetsNotSorted); + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); offset[0] = 0; } @@ -2693,12 +2716,13 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { uint32_t* offset = reinterpret_cast( model.buffers[stringOffsetBuffer].cesium.data.data()); offset[0] = static_cast(1000); - MetadataPropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorStringOffsetsNotSorted); + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); offset[0] = 0; } @@ -2707,12 +2731,13 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { model.buffers[arrayOffsetBuffer].cesium.data.data()); uint32_t previousValue = offset[propertyTable.count]; offset[propertyTable.count] = static_cast(100000); - MetadataPropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); offset[propertyTable.count] = previousValue; } @@ -2721,24 +2746,25 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { model.buffers[stringOffsetBuffer].cesium.data.data()); uint32_t previousValue = offset[6]; offset[6] = static_cast(100000); - MetadataPropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == - MetadataPropertyViewStatus::ErrorStringOffsetOutOfBounds); + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); offset[6] = previousValue; } SECTION("Count and offset buffer both present") { testClassProperty.count = 3; - MetadataPropertyView> + PropertyTablePropertyView> boolArrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( boolArrayProperty.status() == - MetadataPropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } } @@ -2758,10 +2784,8 @@ TEST_CASE("Test StructuralMetadata callback on invalid property table view") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(-1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE( - view.status() == - MetadataPropertyTableViewStatus::ErrorPropertyTableClassDoesNotExist); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); REQUIRE(view.size() == 0); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -2777,7 +2801,7 @@ TEST_CASE("Test StructuralMetadata callback on invalid property table view") { invokedCallbackCount++; REQUIRE( propertyValue.status() == - MetadataPropertyViewStatus::ErrorInvalidPropertyTable); + PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); REQUIRE(propertyValue.size() == 0); }); @@ -2807,8 +2831,8 @@ TEST_CASE("Test StructuralMetadata callback for invalid property") { propertyTable.properties["InvalidProperty"]; propertyTableProperty.values = static_cast(-1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -2823,7 +2847,7 @@ TEST_CASE("Test StructuralMetadata callback for invalid property") { const std::string& /*propertyName*/, auto propertyValue) mutable { invokedCallbackCount++; - REQUIRE(propertyValue.status() != MetadataPropertyViewStatus::Valid); + REQUIRE(propertyValue.status() != PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() == 0); }; @@ -2879,8 +2903,8 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -2903,9 +2927,10 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") { auto propertyValue) mutable { invokedCallbackCount++; if constexpr (std::is_same_v< - MetadataPropertyView, + PropertyTablePropertyView, decltype(propertyValue)>) { - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); for (int64_t i = 0; i < propertyValue.size(); ++i) { @@ -2914,8 +2939,9 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") { values[static_cast(i)]); } } else { - FAIL("getPropertyView returned MetadataPropertyView of incorrect " - "type for TestClassProperty."); + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); } }); @@ -2973,8 +2999,8 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -2996,11 +3022,12 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { const std::string& /*propertyName*/, auto propertyValue) mutable { invokedCallbackCount++; - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - MetadataPropertyView, + PropertyTablePropertyView, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { REQUIRE( @@ -3008,8 +3035,9 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { values[static_cast(i)]); } } else { - FAIL("getPropertyView returned MetadataPropertyView of incorrect " - "type for TestClassProperty."); + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); } }); @@ -3077,8 +3105,8 @@ TEST_CASE("Test StructuralMetadata callback for matN property") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -3099,11 +3127,12 @@ TEST_CASE("Test StructuralMetadata callback for matN property") { [&values, &invokedCallbackCount]( const std::string& /*propertyName*/, auto propertyValue) mutable { - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - MetadataPropertyView, + PropertyTablePropertyView, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { REQUIRE( @@ -3111,8 +3140,9 @@ TEST_CASE("Test StructuralMetadata callback for matN property") { values[static_cast(i)]); } } else { - FAIL("getPropertyView returned MetadataPropertyView of incorrect " - "type for TestClassProperty."); + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); } invokedCallbackCount++; }); @@ -3179,8 +3209,8 @@ TEST_CASE("Test StructuralMetadata callback for boolean property") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -3201,11 +3231,12 @@ TEST_CASE("Test StructuralMetadata callback for boolean property") { auto propertyValue) mutable { invokedCallbackCount++; - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - MetadataPropertyView, + PropertyTablePropertyView, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { REQUIRE( @@ -3213,8 +3244,9 @@ TEST_CASE("Test StructuralMetadata callback for boolean property") { expected[static_cast(i)]); } } else { - FAIL("getPropertyView returned MetadataPropertyView of incorrect " - "type for TestClassProperty."); + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); } }); @@ -3300,8 +3332,8 @@ TEST_CASE("Test StructuralMetadata callback for string property") { propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -3321,11 +3353,12 @@ TEST_CASE("Test StructuralMetadata callback for string property") { const std::string& /*propertyName*/, auto propertyValue) mutable { invokedCallbackCount++; - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - MetadataPropertyView, + PropertyTablePropertyView, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { REQUIRE( @@ -3333,8 +3366,9 @@ TEST_CASE("Test StructuralMetadata callback for string property") { expected[static_cast(i)]); } } else { - FAIL("getPropertyView returned MetadataPropertyView of incorrect " - "type for TestClassProperty."); + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); } }); @@ -3388,8 +3422,8 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -3411,11 +3445,13 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { const std::string& /*propertyName*/, auto propertyValue) { invokedCallbackCount++; - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - MetadataPropertyView>, + PropertyTablePropertyView< + MetadataArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { MetadataArrayView member = propertyValue.get(i); @@ -3424,8 +3460,9 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { } } } else { - FAIL("getPropertyView returned MetadataPropertyView of incorrect " - "type for TestClassProperty."); + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); } }); @@ -3485,8 +3522,8 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -3508,11 +3545,13 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { const std::string& /*propertyName*/, auto propertyValue) { invokedCallbackCount++; - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - MetadataPropertyView>, + PropertyTablePropertyView< + MetadataArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { MetadataArrayView member = propertyValue.get(i); @@ -3521,8 +3560,9 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { } } } else { - FAIL("getPropertyView returned MetadataPropertyView of incorrect " - "type for TestClassProperty."); + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); } }); @@ -3596,8 +3636,8 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -3619,11 +3659,12 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { const std::string& /*propertyName*/, auto propertyValue) { invokedCallbackCount++; - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - MetadataPropertyView< + PropertyTablePropertyView< MetadataArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { @@ -3633,8 +3674,9 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { } } } else { - FAIL("getPropertyView returned MetadataPropertyView of incorrect " - "type for TestClassProperty."); + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); } }); @@ -3708,8 +3750,8 @@ TEST_CASE("Test StructuralMetadata callback for boolean array") { propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -3728,11 +3770,12 @@ TEST_CASE("Test StructuralMetadata callback for boolean array") { const std::string& /*propertyName*/, auto propertyValue) { invokedCallbackCount++; - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - MetadataPropertyView>, + PropertyTablePropertyView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { MetadataArrayView member = propertyValue.get(i); @@ -3741,8 +3784,9 @@ TEST_CASE("Test StructuralMetadata callback for boolean array") { } } } else { - FAIL("getPropertyView returned MetadataPropertyView of incorrect " - "type for TestClassProperty."); + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); } }); @@ -3831,8 +3875,8 @@ TEST_CASE("Test StructuralMetadata callback for array of strings") { propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); - MetadataPropertyTableView view(model, propertyTable); - REQUIRE(view.status() == MetadataPropertyTableViewStatus::Valid); + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); const ExtensionExtStructuralMetadataClassProperty* classProperty = @@ -3851,11 +3895,12 @@ TEST_CASE("Test StructuralMetadata callback for array of strings") { const std::string& /*propertyName*/, auto propertyValue) { invokedCallbackCount++; - REQUIRE(propertyValue.status() == MetadataPropertyViewStatus::Valid); + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyValue.size() == 3); if constexpr (std::is_same_v< - MetadataPropertyView< + PropertyTablePropertyView< MetadataArrayView>, decltype(propertyValue)>) { MetadataArrayView v0 = propertyValue.get(0); @@ -3876,8 +3921,9 @@ TEST_CASE("Test StructuralMetadata callback for array of strings") { REQUIRE(v2[0] == "I love you, meat bags! ❤️"); REQUIRE(v2[1] == "Book in the freezer"); } else { - FAIL("getPropertyView returned MetadataPropertyView of incorrect " - "type for TestClassProperty."); + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); } }); diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTextureView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTextureView.cpp new file mode 100644 index 000000000..01cfed051 --- /dev/null +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTextureView.cpp @@ -0,0 +1,169 @@ +#include "CesiumGltf/StructuralMetadataPropertyTextureView.h" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace CesiumGltf; +using namespace CesiumGltf::StructuralMetadata; + +TEST_CASE("Test PropertyTextureView on model without EXT_structural_metadata " + "extension") { + Model model; + + // Create an erroneously isolated property texture. + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTextureView view(model, propertyTexture); + REQUIRE( + view.status() == + PropertyTextureViewStatus::ErrorMissingMetadataExtension); + REQUIRE(view.getProperties().empty()); + + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test PropertyTextureView on model without metadata schema") { + Model model; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataPropertyTexture& propertyTexture = + metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTextureView view(model, propertyTexture); + REQUIRE(view.status() == PropertyTextureViewStatus::ErrorMissingSchema); + REQUIRE(view.getProperties().empty()); + + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test property texture with nonexistent class") { + Model model; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + ExtensionExtStructuralMetadataPropertyTexture& propertyTexture = + metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "I Don't Exist"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTextureView view(model, propertyTexture); + REQUIRE(view.status() == PropertyTextureViewStatus::ErrorClassNotFound); + REQUIRE(view.getProperties().empty()); + + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test property texture with nonexistent class property") { + Model model; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + ExtensionExtStructuralMetadataPropertyTexture& propertyTexture = + metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["I Don't Exist"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTextureView view(model, propertyTexture); + REQUIRE( + view.status() == PropertyTextureViewStatus::ErrorClassPropertyNotFound); + REQUIRE(view.getProperties().empty()); + + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test property texture with invalid property") { + Model model; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + ExtensionExtStructuralMetadataPropertyTexture& propertyTexture = + metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = -1; + + PropertyTextureView view(model, propertyTexture); + REQUIRE(view.status() == PropertyTextureViewStatus::ErrorInvalidPropertyView); + + auto properties = view.getProperties(); + REQUIRE(properties.size() == 1); + + PropertyTexturePropertyView& propertyView = properties["TestClassProperty"]; + REQUIRE(propertyView.status() != PropertyTexturePropertyViewStatus::Valid); + + const ExtensionExtStructuralMetadataClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} From 44b829a081a0ff56cf8a9bd14c3bf3d3d065aa82 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 30 May 2023 11:11:06 -0400 Subject: [PATCH 040/121] Add PropertyTextureProperty tests, fix formatting --- ...gradeBatchTableToExtStructuralMetadata.cpp | 2 +- ...turalMetadataPropertyTexturePropertyView.h | 16 +- ...ralMetadataPropertyTexturePropertyView.cpp | 10 +- ...ralMetadataPropertyTexturePropertyView.cpp | 290 ++++++++++++++++++ 4 files changed, 309 insertions(+), 9 deletions(-) create mode 100644 CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index f6d232138..712098bff 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -5,8 +5,8 @@ #include #include #include -#include #include +#include #include #include diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h index 7cd609a13..09e427aaf 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h @@ -57,6 +57,11 @@ enum class PropertyTexturePropertyViewStatus { */ ErrorEmptyImage, + /** + * @brief This property texture property has a negative TEXCOORD set index. + */ + ErrorInvalidTexCoordSetIndex, + /** * @brief The channels of this property texture property are invalid. * Channels must be in the range 0-3, with a minimum of one channel and a @@ -187,17 +192,16 @@ class PropertyTexturePropertyView { } /** - * @brief Get the count for this property. - * - * This is also how many channels a pixel value for this property will use. + * @brief Get the count for this property. This is equivalent to how many + * channels a pixel value for this property will use. */ int64_t getCount() const noexcept { return this->_count; } /** * @brief Get the texture coordinate set index for this property. */ - int64_t getTextureCoordinateSetIndex() const noexcept { - return this->_textureCoordinateSetIndex; + int64_t getTexCoordSetIndex() const noexcept { + return this->_texCoordSetIndex; } /** @@ -233,7 +237,7 @@ class PropertyTexturePropertyView { const Sampler* _pSampler; const ImageCesium* _pImage; - int64_t _textureCoordinateSetIndex; + int64_t _texCoordSetIndex; std::vector _channels; std::string _swizzle; PropertyTexturePropertyComponentType _type; diff --git a/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp index 316341124..d43e5bdfd 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp @@ -10,7 +10,7 @@ PropertyTexturePropertyView::PropertyTexturePropertyView() noexcept _pPropertyTextureProperty(nullptr), _pSampler(nullptr), _pImage(nullptr), - _textureCoordinateSetIndex(-1), + _texCoordSetIndex(-1), _channels(), _swizzle(""), _type(PropertyTexturePropertyComponentType::Uint8), @@ -27,7 +27,7 @@ PropertyTexturePropertyView::PropertyTexturePropertyView( _pPropertyTextureProperty(&propertyTextureProperty), _pSampler(nullptr), _pImage(nullptr), - _textureCoordinateSetIndex(propertyTextureProperty.texCoord), + _texCoordSetIndex(propertyTextureProperty.texCoord), _channels(), _swizzle(""), _type(PropertyTexturePropertyComponentType::Uint8), @@ -61,6 +61,12 @@ PropertyTexturePropertyView::PropertyTexturePropertyView( return; } + if (this->_texCoordSetIndex < 0) { + this->_status = + PropertyTexturePropertyViewStatus::ErrorInvalidTexCoordSetIndex; + return; + } + // TODO: support more types // this->_type = ... diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp new file mode 100644 index 000000000..234b68d89 --- /dev/null +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp @@ -0,0 +1,290 @@ +#include "CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace CesiumGltf; +using namespace CesiumGltf::StructuralMetadata; + +TEST_CASE( + "Test PropertyTexturePropertyView on property with invalid texture index") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = -1; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE( + view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidTexture); +} + +TEST_CASE( + "Test PropertyTexturePropertyView on property with invalid sampler index") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + Texture& texture = model.textures.emplace_back(); + texture.sampler = -1; + texture.source = 0; + + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE( + view.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidTextureSampler); +} + +TEST_CASE( + "Test PropertyTexturePropertyView on property with invalid image index") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + model.samplers.emplace_back(); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = -1; + + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE( + view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidImage); +} + +TEST_CASE("Test PropertyTexturePropertyView on property with empty image") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + Image& image = model.images.emplace_back(); + image.cesium.width = 0; + image.cesium.height = 0; + + model.samplers.emplace_back(); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE(view.status() == PropertyTexturePropertyViewStatus::ErrorEmptyImage); +} + +TEST_CASE("Test PropertyTextureView on model with negative texture coordinate " + "set index") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + + model.samplers.emplace_back(); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = -1; + propertyTextureProperty.channels = {0}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE( + view.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidTexCoordSetIndex); +} + +TEST_CASE("Test PropertyTextureView on model with zero channels") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + image.cesium.channels = 1; + + model.samplers.emplace_back(); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE( + view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidChannels); +} + +TEST_CASE("Test PropertyTextureView on model with too many channels") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + image.cesium.channels = 1; + + model.samplers.emplace_back(); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0, 1}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE( + view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidChannels); +} From db0f1734d163feda66247c2b61576fb549fb3711 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 30 May 2023 20:26:14 -0400 Subject: [PATCH 041/121] Fix formatting --- .../StructuralMetadataPropertyTexturePropertyView.h | 4 +--- CesiumGltf/src/StructuralMetadataPropertyTableView.cpp | 9 ++++----- .../StructuralMetadataPropertyTexturePropertyView.cpp | 1 - 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h index 09e427aaf..ca2e3eda7 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h @@ -89,9 +89,7 @@ enum class PropertyTexturePropertyComponentType { * @tparam T The component type, must correspond to a valid * {@link PropertyTexturePropertyComponentType}. */ -template struct PropertyTexturePropertyValue { - T components[4]; -}; +template struct PropertyTexturePropertyValue { T components[4]; }; /** * @brief A view of the data specified by a diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp index c1012e1e5..b6e58fa87 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp @@ -138,8 +138,7 @@ PropertyTableView::PropertyTableView( } const ExtensionExtStructuralMetadataClassProperty* -PropertyTableView::getClassProperty( - const std::string& propertyName) const { +PropertyTableView::getClassProperty(const std::string& propertyName) const { if (_status != PropertyTableViewStatus::Valid) { return nullptr; } @@ -231,8 +230,7 @@ PropertyTablePropertyViewStatus PropertyTableView::getArrayOffsetsBufferSafe( } } -PropertyTablePropertyViewStatus -PropertyTableView::getStringOffsetsBufferSafe( +PropertyTablePropertyViewStatus PropertyTableView::getStringOffsetsBufferSafe( int32_t stringOffsetsBufferView, PropertyComponentType stringOffsetType, size_t valueBufferSize, @@ -367,7 +365,8 @@ PropertyTableView::getStringArrayPropertyValues( if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { return createInvalidPropertyView>( - PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist); + PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); } // Get string offset type diff --git a/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp index d43e5bdfd..aaebff6d6 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp @@ -3,7 +3,6 @@ namespace CesiumGltf { namespace StructuralMetadata { - PropertyTexturePropertyView::PropertyTexturePropertyView() noexcept : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), _pClassProperty(nullptr), From 60a528a19b71f7857a81ca70f3f26bf386be281f Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 30 May 2023 20:28:42 -0400 Subject: [PATCH 042/121] Last formatting fix --- CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp index 507aa9e0c..7ebcdab2a 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp @@ -11,7 +11,8 @@ PropertyTextureView::PropertyTextureView() noexcept PropertyTextureView::PropertyTextureView( const Model& model, - const ExtensionExtStructuralMetadataPropertyTexture& propertyTexture) noexcept + const ExtensionExtStructuralMetadataPropertyTexture& + propertyTexture) noexcept : _pModel(&model), _pPropertyTexture(&propertyTexture), _pClass(nullptr), From 4644086f65e474272630a024cd1610bf635fccea Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 2 Jun 2023 14:00:54 -0400 Subject: [PATCH 043/121] Create feature ID texture views for EXT_mesh_features --- .../MeshFeaturesFeatureIDTextureView.h | 150 ++++++++++++++++++ ...turalMetadataPropertyTexturePropertyView.h | 11 +- .../src/MeshFeaturesFeatureIDTextureView.cpp | 92 +++++++++++ ...ralMetadataPropertyTexturePropertyView.cpp | 8 +- 4 files changed, 252 insertions(+), 9 deletions(-) create mode 100644 CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIDTextureView.h create mode 100644 CesiumGltf/src/MeshFeaturesFeatureIDTextureView.cpp diff --git a/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIDTextureView.h b/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIDTextureView.h new file mode 100644 index 000000000..e97343edf --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIDTextureView.h @@ -0,0 +1,150 @@ +#pragma once + +#include "CesiumGltf/ExtensionExtMeshFeaturesFeatureIdTexture.h" +#include "CesiumGltf/Texture.h" +#include "CesiumGltf/TextureAccessor.h" +#include "Image.h" +#include "ImageCesium.h" +#include "Model.h" + +#include +#include +#include +#include +#include +#include + +namespace CesiumGltf { +namespace MeshFeatures { + +/** + * @brief The status of a feature ID texture view. + * + * The {@link FeatureIdTextureView} constructor always completes successfully, + * but it may not always reflect the actual content of the + * {@link ExtensionExtMeshFeaturesFeatureIdTexture}. This enumeration provides the reason. + */ +enum class FeatureIdTextureViewStatus { + /** + * @brief This view is valid and ready to use. + */ + Valid, + + /** + * @brief This view has not yet been initialized. + */ + ErrorUninitialized, + + /** + * @brief This feature ID texture has a texture index that doesn't exist in + * the glTF. + */ + ErrorInvalidTexture, + + /** + * @brief This feature ID texture has an image index that doesn't exist in + * the glTF. + */ + ErrorInvalidImage, + + /** + * @brief This feature ID texture has an empty image. + */ + ErrorEmptyImage, + + /** + * @brief The image for this feature ID texture has channels that take up more + * than a byte. The feature ID texture's channels should represent the bytes + * of the actual feature ID. + */ + ErrorInvalidImageChannelSize, + + /** + * @brief This feature ID texture has a negative TEXCOORD set index. + */ + ErrorInvalidTexCoordSetIndex, + + /** + * @brief The channels of this feature ID texture property are invalid. + * Channels must be in the range 0-3, with a minimum of one channel. Although + * more than four channels can be defined for specialized texture + * formats, this view only supports a maximum of four channels. + */ + ErrorInvalidChannels +}; + +/** + * @brief A view on the image data of {@link ExtensionExtMeshFeaturesFeatureIdTexture}. + * + * It provides the ability to sample the feature IDs from the + * {@link ExtensionExtMeshFeaturesFeatureIdTexture} using texture coordinates. + */ +class FeatureIdTextureView { +public: + /** + * @brief Constructs an uninitialized and invalid view. + */ + FeatureIdTextureView() noexcept; + + /** + * @brief Construct a view of the data specified by a + * {@link ExtensionExtMeshFeaturesFeatureIdTexture}. + * + * @param model The glTF in which to look for the feature id texture's data. + * @param featureIDTexture The feature id texture to create a view for. + */ + FeatureIdTextureView( + const Model& model, + const ExtensionExtMeshFeaturesFeatureIdTexture& + featureIdTexture) noexcept; + + /** + * @brief Get the Feature ID for the given texture coordinates. + * + * Will return -1 when the status is not Valid. + * + * @param u The u-component of the texture coordinates. Must be within + * [0.0, 1.0]. + * @param v The v-component of the texture coordinates. Must be within + * [0.0, 1.0]. + * @return The feature ID at the nearest pixel to the texture coordinates. + */ + int64_t getFeatureId(double u, double v) const noexcept; + + /** + * @brief Get the status of this view. + * + * If invalid, it will not be safe to sample feature IDs from this view. + */ + FeatureIdTextureViewStatus status() const { return _status; } + + /** + * @brief Get the actual feature ID texture. + * + * This will be nullptr if the feature ID texture view runs into problems + * during construction. + */ + const ImageCesium* getImage() const { return _pImage; } + + /** + * @brief Get the channels of this feature ID texture. The channels represent + * the bytes of the actual feature ID, in little-endian order. + */ + std::vector getChannels() const { return _channels; } + + /** + * @brief Get the texture coordinate set index for this feature ID + * texture. + */ + int64_t getTexCoordSetIndex() const { return this->_texCoordSetIndex; } + +private: + FeatureIdTextureViewStatus _status; + std::vector _channels; + int64_t _texCoordSetIndex; + + const ImageCesium* _pImage; +}; + +} // namespace MeshFeatures +} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h index ca2e3eda7..c65140147 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h @@ -64,8 +64,9 @@ enum class PropertyTexturePropertyViewStatus { /** * @brief The channels of this property texture property are invalid. - * Channels must be in the range 0-3, with a minimum of one channel and a - * maximum of four. + * Channels must be in the range 0-3, with a minimum of one channel. Although + * more than four channels can be defined for specialized texture + * formats, this view only supports a maximum of four channels. */ ErrorInvalidChannels }; @@ -89,7 +90,9 @@ enum class PropertyTexturePropertyComponentType { * @tparam T The component type, must correspond to a valid * {@link PropertyTexturePropertyComponentType}. */ -template struct PropertyTexturePropertyValue { T components[4]; }; +template struct PropertyTexturePropertyValue { + T components[4]; +}; /** * @brief A view of the data specified by a @@ -230,8 +233,6 @@ class PropertyTexturePropertyView { private: PropertyTexturePropertyViewStatus _status; const ExtensionExtStructuralMetadataClassProperty* _pClassProperty; - const ExtensionExtStructuralMetadataPropertyTextureProperty* - _pPropertyTextureProperty; const Sampler* _pSampler; const ImageCesium* _pImage; diff --git a/CesiumGltf/src/MeshFeaturesFeatureIDTextureView.cpp b/CesiumGltf/src/MeshFeaturesFeatureIDTextureView.cpp new file mode 100644 index 000000000..dd4b0691a --- /dev/null +++ b/CesiumGltf/src/MeshFeaturesFeatureIDTextureView.cpp @@ -0,0 +1,92 @@ +#include "CesiumGltf/MeshFeaturesFeatureIdTextureView.h" + +namespace CesiumGltf { +namespace MeshFeatures { +FeatureIdTextureView::FeatureIdTextureView() noexcept + : _status(FeatureIdTextureViewStatus::ErrorUninitialized), + _texCoordSetIndex(-1), + _channels(), + _pImage(nullptr) {} + +FeatureIdTextureView::FeatureIdTextureView( + const Model& model, + const ExtensionExtMeshFeaturesFeatureIdTexture& featureIdTexture) noexcept + : _status(FeatureIdTextureViewStatus::ErrorUninitialized), + _texCoordSetIndex(featureIdTexture.texCoord), + _channels(featureIdTexture.channels), + _pImage(nullptr) { + int32_t textureIndex = featureIdTexture.index; + if (textureIndex < 0 || + static_cast(textureIndex) >= model.textures.size()) { + this->_status = FeatureIdTextureViewStatus::ErrorInvalidTexture; + return; + } + + const Texture& texture = model.textures[static_cast(textureIndex)]; + if (texture.source < 0 || + static_cast(texture.source) >= model.images.size()) { + this->_status = FeatureIdTextureViewStatus::ErrorInvalidImage; + return; + } + + // Ignore the texture's sampler, we will always use nearest pixel sampling. + + this->_pImage = &model.images[static_cast(texture.source)].cesium; + if (this->_pImage->width < 1 || this->_pImage->height < 1) { + this->_status = FeatureIdTextureViewStatus::ErrorEmptyImage; + return; + } + + // TODO: once compressed texture support is merged, check that the image is + // decompressed here. + + if (this->_pImage->bytesPerChannel > 1) { + this->_status = FeatureIdTextureViewStatus::ErrorInvalidImageChannelSize; + return; + } + + const std::vector& channels = featureIdTexture.channels; + if (channels.size() == 0 || channels.size() > 4 || + channels.size() > static_cast(this->_pImage->channels)) { + this->_status = FeatureIdTextureViewStatus::ErrorInvalidChannels; + return; + } + this->_channels = channels; + + this->_status = FeatureIdTextureViewStatus::Valid; +} + +int64_t FeatureIdTextureView::getFeatureId(double u, double v) const noexcept { + if (this->_status != FeatureIdTextureViewStatus::Valid) { + return -1; + } + + int64_t x = std::clamp( + std::llround(u * this->_pImage->width), + 0LL, + (long long)this->_pImage->width); + int64_t y = std::clamp( + std::llround(v * this->_pImage->height), + 0LL, + (long long)this->_pImage->height); + + int64_t pixelOffset = this->_pImage->bytesPerChannel * + this->_pImage->channels * + (y * this->_pImage->width + x); + + int64_t value = 0; + // As stated in the spec: values from the selected channels are treated as + // unsigned 8 bit integers, and represent the bytes of the actual feature ID, + // in little-endian order. + for (int i = 0, offset = 0; i < this->_channels.size(); i++, offset += 8) { + int64_t channelValue = static_cast( + this->_pImage + ->pixelData[static_cast(pixelOffset + this->_channels[i])]); + value |= channelValue << offset; + } + + return value; +} + +} // namespace MeshFeatures +} // namespace CesiumGltf diff --git a/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp b/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp index aaebff6d6..409c29166 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp +++ b/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp @@ -6,7 +6,6 @@ namespace StructuralMetadata { PropertyTexturePropertyView::PropertyTexturePropertyView() noexcept : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), _pClassProperty(nullptr), - _pPropertyTextureProperty(nullptr), _pSampler(nullptr), _pImage(nullptr), _texCoordSetIndex(-1), @@ -23,7 +22,6 @@ PropertyTexturePropertyView::PropertyTexturePropertyView( propertyTextureProperty) noexcept : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), _pClassProperty(&classProperty), - _pPropertyTextureProperty(&propertyTextureProperty), _pSampler(nullptr), _pImage(nullptr), _texCoordSetIndex(propertyTextureProperty.texCoord), @@ -32,7 +30,7 @@ PropertyTexturePropertyView::PropertyTexturePropertyView( _type(PropertyTexturePropertyComponentType::Uint8), _count(0), _normalized(false) { - const int64_t index = _pPropertyTextureProperty->index; + const int64_t index = propertyTextureProperty.index; if (index < 0 || static_cast(index) >= model.textures.size()) { this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidTexture; return; @@ -73,7 +71,7 @@ PropertyTexturePropertyView::PropertyTexturePropertyView( this->_pClassProperty->count ? *this->_pClassProperty->count : 1; this->_normalized = this->_pClassProperty->normalized; - const std::vector& channels = _pPropertyTextureProperty->channels; + const std::vector& channels = propertyTextureProperty.channels; if (channels.size() == 0 || channels.size() > 4 || channels.size() > static_cast(this->_pImage->channels) || channels.size() != static_cast(this->_count)) { @@ -101,6 +99,8 @@ PropertyTexturePropertyView::PropertyTexturePropertyView( } } + this->_channels = channels; + this->_status = PropertyTexturePropertyViewStatus::Valid; } } // namespace StructuralMetadata From 7e0cd8a055a73c4303e602cbdfe9dd68fae5498c Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 2 Jun 2023 14:23:15 -0400 Subject: [PATCH 044/121] Add tests for feature ID texture view --- .../MeshFeaturesFeatureIDTextureView.h | 2 +- .../src/MeshFeaturesFeatureIDTextureView.cpp | 19 +- .../TestMeshFeaturesFeatureIdTextureView.cpp | 247 ++++++++++++++++++ ...ralMetadataPropertyTexturePropertyView.cpp | 10 +- 4 files changed, 271 insertions(+), 7 deletions(-) create mode 100644 CesiumGltf/test/TestMeshFeaturesFeatureIdTextureView.cpp diff --git a/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIDTextureView.h b/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIDTextureView.h index e97343edf..0962bc07b 100644 --- a/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIDTextureView.h +++ b/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIDTextureView.h @@ -57,7 +57,7 @@ enum class FeatureIdTextureViewStatus { * than a byte. The feature ID texture's channels should represent the bytes * of the actual feature ID. */ - ErrorInvalidImageChannelSize, + ErrorInvalidImageBytesPerChannel, /** * @brief This feature ID texture has a negative TEXCOORD set index. diff --git a/CesiumGltf/src/MeshFeaturesFeatureIDTextureView.cpp b/CesiumGltf/src/MeshFeaturesFeatureIDTextureView.cpp index dd4b0691a..c147fdcdb 100644 --- a/CesiumGltf/src/MeshFeaturesFeatureIDTextureView.cpp +++ b/CesiumGltf/src/MeshFeaturesFeatureIDTextureView.cpp @@ -12,7 +12,7 @@ FeatureIdTextureView::FeatureIdTextureView( const Model& model, const ExtensionExtMeshFeaturesFeatureIdTexture& featureIdTexture) noexcept : _status(FeatureIdTextureViewStatus::ErrorUninitialized), - _texCoordSetIndex(featureIdTexture.texCoord), + _texCoordSetIndex(-1), _channels(featureIdTexture.channels), _pImage(nullptr) { int32_t textureIndex = featureIdTexture.index; @@ -41,9 +41,16 @@ FeatureIdTextureView::FeatureIdTextureView( // decompressed here. if (this->_pImage->bytesPerChannel > 1) { - this->_status = FeatureIdTextureViewStatus::ErrorInvalidImageChannelSize; + this->_status = + FeatureIdTextureViewStatus::ErrorInvalidImageBytesPerChannel; + return; + } + + if (featureIdTexture.texCoord < 0) { + this->_status = FeatureIdTextureViewStatus::ErrorInvalidTexCoordSetIndex; return; } + this->_texCoordSetIndex = featureIdTexture.texCoord; const std::vector& channels = featureIdTexture.channels; if (channels.size() == 0 || channels.size() > 4 || @@ -51,6 +58,14 @@ FeatureIdTextureView::FeatureIdTextureView( this->_status = FeatureIdTextureViewStatus::ErrorInvalidChannels; return; } + + // Only channel values 0-3 are supported. + for (int i = 0; i < channels.size(); i++) { + if (channels[i] < 0 || channels[i] > 3) { + this->_status = FeatureIdTextureViewStatus::ErrorInvalidChannels; + return; + } + } this->_channels = channels; this->_status = FeatureIdTextureViewStatus::Valid; diff --git a/CesiumGltf/test/TestMeshFeaturesFeatureIdTextureView.cpp b/CesiumGltf/test/TestMeshFeaturesFeatureIdTextureView.cpp new file mode 100644 index 000000000..cde38cd03 --- /dev/null +++ b/CesiumGltf/test/TestMeshFeaturesFeatureIdTextureView.cpp @@ -0,0 +1,247 @@ +#include "CesiumGltf/ExtensionExtMeshFeatures.h" +#include "CesiumGltf/MeshFeaturesFeatureIdTextureView.h" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace CesiumGltf; +using namespace CesiumGltf::MeshFeatures; + +TEST_CASE("Test FeatureIdTextureView on feature ID texture with invalid " + "texture index") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = -1; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {0}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::ErrorInvalidTexture); +} + +TEST_CASE("Test FeatureIdTextureView on feature ID texture with invalid image " + "index") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = -1; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {0}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::ErrorInvalidImage); +} + +TEST_CASE("Test FeatureIdTextureView on feature ID texture with empty image") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + Image& image = model.images.emplace_back(); + image.cesium.width = 0; + image.cesium.height = 0; + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {0}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::ErrorEmptyImage); +} + +TEST_CASE("Test FeatureIdTextureView on feature ID texture with too many bytes " + "per channel") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + image.cesium.bytesPerChannel = 2; + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {0}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE( + view.status() == + FeatureIdTextureViewStatus::ErrorInvalidImageBytesPerChannel); +} + +TEST_CASE( + "Test FeatureIdTextureView on feature ID texture with negative texcoord " + "set index") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = -1; + featureIdTexture.channels = {0}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE( + view.status() == + FeatureIdTextureViewStatus::ErrorInvalidTexCoordSetIndex); +} + +TEST_CASE( + "Test FeatureIdTextureView on feature ID texture with zero channels") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::ErrorInvalidChannels); +} + +TEST_CASE( + "Test FeatureIdTextureView on feature ID texture with too many channels") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {0, 1, 2, 3, 3}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::ErrorInvalidChannels); +} + +TEST_CASE("Test FeatureIdTextureView on feature ID texture with out of range " + "channel") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {4}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::ErrorInvalidChannels); +} diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp index 234b68d89..e697ceafc 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp @@ -162,8 +162,8 @@ TEST_CASE("Test PropertyTexturePropertyView on property with empty image") { REQUIRE(view.status() == PropertyTexturePropertyViewStatus::ErrorEmptyImage); } -TEST_CASE("Test PropertyTextureView on model with negative texture coordinate " - "set index") { +TEST_CASE("Test PropertyTextureView on property table property with negative " + "texcoord set index") { Model model; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -205,7 +205,8 @@ TEST_CASE("Test PropertyTextureView on model with negative texture coordinate " PropertyTexturePropertyViewStatus::ErrorInvalidTexCoordSetIndex); } -TEST_CASE("Test PropertyTextureView on model with zero channels") { +TEST_CASE("Test PropertyTextureView on property texture property with zero " + "channels") { Model model; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -247,7 +248,8 @@ TEST_CASE("Test PropertyTextureView on model with zero channels") { view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidChannels); } -TEST_CASE("Test PropertyTextureView on model with too many channels") { +TEST_CASE("Test PropertyTextureView on property texture property with too many " + "channels") { Model model; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); From d9f330c3ef06430046bc048d427aaa33f35b6bc3 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 2 Jun 2023 14:43:14 -0400 Subject: [PATCH 045/121] Fix formatting and wrong file names --- ...tureIDTextureView.h => MeshFeaturesFeatureIdTextureView.h} | 0 .../StructuralMetadataPropertyTexturePropertyView.h | 4 +--- ...IDTextureView.cpp => MeshFeaturesFeatureIdTextureView.cpp} | 0 3 files changed, 1 insertion(+), 3 deletions(-) rename CesiumGltf/include/CesiumGltf/{MeshFeaturesFeatureIDTextureView.h => MeshFeaturesFeatureIdTextureView.h} (100%) rename CesiumGltf/src/{MeshFeaturesFeatureIDTextureView.cpp => MeshFeaturesFeatureIdTextureView.cpp} (100%) diff --git a/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIDTextureView.h b/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIdTextureView.h similarity index 100% rename from CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIDTextureView.h rename to CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIdTextureView.h diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h index c65140147..e8f858732 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h @@ -90,9 +90,7 @@ enum class PropertyTexturePropertyComponentType { * @tparam T The component type, must correspond to a valid * {@link PropertyTexturePropertyComponentType}. */ -template struct PropertyTexturePropertyValue { - T components[4]; -}; +template struct PropertyTexturePropertyValue { T components[4]; }; /** * @brief A view of the data specified by a diff --git a/CesiumGltf/src/MeshFeaturesFeatureIDTextureView.cpp b/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp similarity index 100% rename from CesiumGltf/src/MeshFeaturesFeatureIDTextureView.cpp rename to CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp From 2744abd7fe8aea1ddf320604a9e6330876436538 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 5 Jun 2023 10:04:28 -0400 Subject: [PATCH 046/121] Fix CI errors --- .../CesiumGltf/MeshFeaturesFeatureIdTextureView.h | 2 +- CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIdTextureView.h b/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIdTextureView.h index 0962bc07b..c7df25c12 100644 --- a/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIdTextureView.h +++ b/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIdTextureView.h @@ -140,8 +140,8 @@ class FeatureIdTextureView { private: FeatureIdTextureViewStatus _status; - std::vector _channels; int64_t _texCoordSetIndex; + std::vector _channels; const ImageCesium* _pImage; }; diff --git a/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp b/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp index c147fdcdb..9dcf68a38 100644 --- a/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp +++ b/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp @@ -60,7 +60,7 @@ FeatureIdTextureView::FeatureIdTextureView( } // Only channel values 0-3 are supported. - for (int i = 0; i < channels.size(); i++) { + for (size_t i = 0; i < channels.size(); i++) { if (channels[i] < 0 || channels[i] > 3) { this->_status = FeatureIdTextureViewStatus::ErrorInvalidChannels; return; @@ -90,14 +90,16 @@ int64_t FeatureIdTextureView::getFeatureId(double u, double v) const noexcept { (y * this->_pImage->width + x); int64_t value = 0; + int64_t bitOffset = 0; // As stated in the spec: values from the selected channels are treated as // unsigned 8 bit integers, and represent the bytes of the actual feature ID, // in little-endian order. - for (int i = 0, offset = 0; i < this->_channels.size(); i++, offset += 8) { + for (size_t i = 0; i < this->_channels.size(); i++) { int64_t channelValue = static_cast( this->_pImage - ->pixelData[static_cast(pixelOffset + this->_channels[i])]); - value |= channelValue << offset; + ->pixelData[static_cast(pixelOffset) + this->_channels[i]]); + value |= channelValue << bitOffset; + bitOffset += 8; } return value; From bf8033d2ba8564f26521737240446f84a3139ccc Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 5 Jun 2023 10:09:47 -0400 Subject: [PATCH 047/121] Fix last CI error --- CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp b/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp index 9dcf68a38..0727e091f 100644 --- a/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp +++ b/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp @@ -97,7 +97,7 @@ int64_t FeatureIdTextureView::getFeatureId(double u, double v) const noexcept { for (size_t i = 0; i < this->_channels.size(); i++) { int64_t channelValue = static_cast( this->_pImage - ->pixelData[static_cast(pixelOffset) + this->_channels[i]]); + ->pixelData[static_cast(pixelOffset + this->_channels[i])]); value |= channelValue << bitOffset; bitOffset += 8; } From a50093c460050ab5d9ec364138d4a78559c23e27 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 6 Jun 2023 11:28:24 -0400 Subject: [PATCH 048/121] Rename files and take classes out of separate namespaces --- .../include/CesiumGltf/FeatureIDTextureView.h | 141 -- ...IdTextureView.h => FeatureIdTextureView.h} | 4 - .../include/CesiumGltf/MetadataArrayView.h | 129 -- .../CesiumGltf/MetadataFeatureTableView.h | 536 -------- .../include/CesiumGltf/MetadataPropertyView.h | 411 ------ ...etadataArrayView.h => PropertyArrayView.h} | 30 +- ...ertyView.h => PropertyTablePropertyView.h} | 36 +- ...ropertyTableView.h => PropertyTableView.h} | 117 +- ...tyView.h => PropertyTexturePropertyView.h} | 3 - ...rtyTextureView.h => PropertyTextureView.h} | 6 +- CesiumGltf/include/CesiumGltf/PropertyType.h | 36 +- .../include/CesiumGltf/PropertyTypeTraits.h | 197 ++- .../StructuralMetadataPropertyType.h | 59 - .../StructuralMetadataPropertyTypeTraits.h | 271 ---- .../CesiumGltf/getOffsetFromOffsetsBuffer.h | 6 +- CesiumGltf/src/FeatureIDTextureView.cpp | 91 -- ...xtureView.cpp => FeatureIdTextureView.cpp} | 5 +- CesiumGltf/src/FeatureTexturePropertyView.cpp | 101 -- CesiumGltf/src/FeatureTextureView.cpp | 68 - CesiumGltf/src/MetadataFeatureTableView.cpp | 386 ------ ...rtyTableView.cpp => PropertyTableView.cpp} | 38 +- ...ew.cpp => PropertyTexturePropertyView.cpp} | 4 +- ...extureView.cpp => PropertyTextureView.cpp} | 5 +- CesiumGltf/src/PropertyType.cpp | 237 +++- .../src/StructuralMetadataPropertyType.cpp | 224 ---- ...eView.cpp => TestFeatureIdTextureView.cpp} | 3 +- .../test/TestMetadataFeatureTableView.cpp | 1164 ----------------- ....cpp => TestPropertyTablePropertyView.cpp} | 64 +- ...ableView.cpp => TestPropertyTableView.cpp} | 383 +++--- ...pp => TestPropertyTexturePropertyView.cpp} | 3 +- ...reView.cpp => TestPropertyTextureView.cpp} | 3 +- CesiumGltf/test/TestPropertyType.cpp | 244 +++- CesiumGltf/test/TestPropertyTypeTrait.cpp | 82 -- ...eTraits.cpp => TestPropertyTypeTraits.cpp} | 26 +- CesiumGltf/test/TestPropertyView.cpp | 589 --------- .../TestStructuralMetadataPropertyType.cpp | 253 ---- 36 files changed, 862 insertions(+), 5093 deletions(-) delete mode 100644 CesiumGltf/include/CesiumGltf/FeatureIDTextureView.h rename CesiumGltf/include/CesiumGltf/{MeshFeaturesFeatureIdTextureView.h => FeatureIdTextureView.h} (98%) delete mode 100644 CesiumGltf/include/CesiumGltf/MetadataArrayView.h delete mode 100644 CesiumGltf/include/CesiumGltf/MetadataFeatureTableView.h delete mode 100644 CesiumGltf/include/CesiumGltf/MetadataPropertyView.h rename CesiumGltf/include/CesiumGltf/{StructuralMetadataArrayView.h => PropertyArrayView.h} (76%) rename CesiumGltf/include/CesiumGltf/{StructuralMetadataPropertyTablePropertyView.h => PropertyTablePropertyView.h} (93%) rename CesiumGltf/include/CesiumGltf/{StructuralMetadataPropertyTableView.h => PropertyTableView.h} (91%) rename CesiumGltf/include/CesiumGltf/{StructuralMetadataPropertyTexturePropertyView.h => PropertyTexturePropertyView.h} (99%) rename CesiumGltf/include/CesiumGltf/{StructuralMetadataPropertyTextureView.h => PropertyTextureView.h} (96%) delete mode 100644 CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h delete mode 100644 CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h delete mode 100644 CesiumGltf/src/FeatureIDTextureView.cpp rename CesiumGltf/src/{MeshFeaturesFeatureIdTextureView.cpp => FeatureIdTextureView.cpp} (96%) delete mode 100644 CesiumGltf/src/FeatureTexturePropertyView.cpp delete mode 100644 CesiumGltf/src/FeatureTextureView.cpp delete mode 100644 CesiumGltf/src/MetadataFeatureTableView.cpp rename CesiumGltf/src/{StructuralMetadataPropertyTableView.cpp => PropertyTableView.cpp} (93%) rename CesiumGltf/src/{StructuralMetadataPropertyTexturePropertyView.cpp => PropertyTexturePropertyView.cpp} (96%) rename CesiumGltf/src/{StructuralMetadataPropertyTextureView.cpp => PropertyTextureView.cpp} (94%) delete mode 100644 CesiumGltf/src/StructuralMetadataPropertyType.cpp rename CesiumGltf/test/{TestMeshFeaturesFeatureIdTextureView.cpp => TestFeatureIdTextureView.cpp} (98%) delete mode 100644 CesiumGltf/test/TestMetadataFeatureTableView.cpp rename CesiumGltf/test/{TestStructuralMetadataPropertyTablePropertyView.cpp => TestPropertyTablePropertyView.cpp} (93%) rename CesiumGltf/test/{TestStructuralMetadataPropertyTableView.cpp => TestPropertyTableView.cpp} (91%) rename CesiumGltf/test/{TestStructuralMetadataPropertyTexturePropertyView.cpp => TestPropertyTexturePropertyView.cpp} (98%) rename CesiumGltf/test/{TestStructuralMetadataPropertyTextureView.cpp => TestPropertyTextureView.cpp} (98%) delete mode 100644 CesiumGltf/test/TestPropertyTypeTrait.cpp rename CesiumGltf/test/{TestStructuralMetadataPropertyTypeTraits.cpp => TestPropertyTypeTraits.cpp} (95%) delete mode 100644 CesiumGltf/test/TestPropertyView.cpp delete mode 100644 CesiumGltf/test/TestStructuralMetadataPropertyType.cpp diff --git a/CesiumGltf/include/CesiumGltf/FeatureIDTextureView.h b/CesiumGltf/include/CesiumGltf/FeatureIDTextureView.h deleted file mode 100644 index c3a29c02f..000000000 --- a/CesiumGltf/include/CesiumGltf/FeatureIDTextureView.h +++ /dev/null @@ -1,141 +0,0 @@ -#pragma once - -#include "CesiumGltf/FeatureIDTexture.h" -#include "CesiumGltf/Texture.h" -#include "CesiumGltf/TextureAccessor.h" -#include "Image.h" -#include "ImageCesium.h" -#include "Model.h" - -#include -#include -#include -#include -#include -#include - -namespace CesiumGltf { - -/** - * @brief The status of a feature id texture view. - * - * The {@link FeatureIDTextureView} constructor always completes successfully, - * but it may not always reflect the actual content of the - * {@link FeatureIDTexture}. This enumeration provides the reason. - */ -enum class FeatureIDTextureViewStatus { - /** - * @brief This view is valid and ready to use. - */ - Valid, - - /** - * @brief This view has not yet been initialized. - */ - InvalidUninitialized, - - /** - * @brief This feature id texture has a texture index that doesn't exist in - * the glTF. - */ - InvalidTextureIndex, - - /** - * @brief This feature id texture has an image index that doesn't exist in - * the glTF. - */ - InvalidImageIndex, - - /** - * @brief This feature id texture has an unknown image channel. - */ - InvalidChannel, - - /** - * @brief This feature id texture has an empty image. - */ - InvalidEmptyImage -}; - -/** - * @brief A view on the image data of {@link FeatureIDTexture}. - * - * It provides the ability to sample the feature IDs from the - * {@link FeatureIDTexture} using texture coordinates. - */ -class FeatureIDTextureView { -public: - /** - * @brief Constructs an uninitialized and invalid view. - */ - FeatureIDTextureView() noexcept; - - /** - * @brief Construct a view of the data specified by a - * {@link FeatureIDTexture}. - * - * @param model The glTF in which to look for the feature id texture's data. - * @param featureIDTexture The feature id texture to create a view for. - */ - FeatureIDTextureView( - const Model& model, - const FeatureIDTexture& featureIDTexture) noexcept; - - /** - * @brief Get the Feature ID for the given texture coordinates. - * - * Will return -1 when the status is not Valid. - * - * @param u The u-component of the texture coordinates. Must be within - * [0.0, 1.0]. - * @param v The v-component of the texture coordinates. Must be within - * [0.0, 1.0]. - * @return The feature ID at the nearest pixel to the texture coordinates. - */ - int64_t getFeatureID(double u, double v) const noexcept; - - /** - * @brief Get the status of this view. - * - * If invalid, it will not be safe to sample feature ids from this view. - */ - FeatureIDTextureViewStatus status() const { return _status; } - - /** - * @brief Get the actual feature ID texture. - * - * This will be nullptr if the feature id texture view runs into problems - * during construction. - */ - const ImageCesium* getImage() const { return _pImage; } - - /** - * @brief Get the channel index that this feature ID texture uses. - */ - int32_t getChannel() const { return _channel; } - - /** - * @brief Get the name of the feature table associated with this feature ID - * texture. - */ - const std::string& getFeatureTableName() const { - return this->_featureTableName; - } - - /** - * @brief Get the texture coordinate attribute index for this feature id - * texture. - */ - int64_t getTextureCoordinateAttributeId() const { - return this->_textureCoordinateAttributeId; - } - -private: - const ImageCesium* _pImage; - int32_t _channel; - int64_t _textureCoordinateAttributeId; - std::string _featureTableName; - FeatureIDTextureViewStatus _status; -}; - -} // namespace CesiumGltf \ No newline at end of file diff --git a/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIdTextureView.h b/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h similarity index 98% rename from CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIdTextureView.h rename to CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h index c7df25c12..c579ca836 100644 --- a/CesiumGltf/include/CesiumGltf/MeshFeaturesFeatureIdTextureView.h +++ b/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h @@ -15,8 +15,6 @@ #include namespace CesiumGltf { -namespace MeshFeatures { - /** * @brief The status of a feature ID texture view. * @@ -145,6 +143,4 @@ class FeatureIdTextureView { const ImageCesium* _pImage; }; - -} // namespace MeshFeatures } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/MetadataArrayView.h b/CesiumGltf/include/CesiumGltf/MetadataArrayView.h deleted file mode 100644 index fe6b94b0c..000000000 --- a/CesiumGltf/include/CesiumGltf/MetadataArrayView.h +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include "CesiumGltf/PropertyType.h" - -#include - -#include - -#include -#include - -namespace CesiumGltf { -template class MetadataArrayView { -public: - MetadataArrayView() : _valueBuffer{} {} - - MetadataArrayView(const gsl::span& buffer) noexcept - : _valueBuffer{ - CesiumUtility::reintepretCastSpan(buffer)} {} - - const ElementType& operator[](int64_t index) const noexcept { - return _valueBuffer[index]; - } - - int64_t size() const noexcept { - return static_cast(_valueBuffer.size()); - } - -private: - gsl::span _valueBuffer; -}; - -template <> class MetadataArrayView { -public: - MetadataArrayView() : _valueBuffer{}, _bitOffset{0}, _instanceCount{0} {} - - MetadataArrayView( - const gsl::span& buffer, - int64_t bitOffset, - int64_t instanceCount) noexcept - : _valueBuffer{buffer}, - _bitOffset{bitOffset}, - _instanceCount{instanceCount} {} - - bool operator[](int64_t index) const noexcept { - index += _bitOffset; - const int64_t byteIndex = index / 8; - const int64_t bitIndex = index % 8; - const int bitValue = - static_cast(_valueBuffer[byteIndex] >> bitIndex) & 1; - return bitValue == 1; - } - - int64_t size() const noexcept { return _instanceCount; } - -private: - gsl::span _valueBuffer; - int64_t _bitOffset; - int64_t _instanceCount; -}; - -template <> class MetadataArrayView { -public: - MetadataArrayView() - : _valueBuffer{}, _offsetBuffer{}, _offsetType{}, _size{0} {} - - MetadataArrayView( - const gsl::span& buffer, - const gsl::span& offsetBuffer, - PropertyType offsetType, - int64_t size) noexcept - : _valueBuffer{buffer}, - _offsetBuffer{offsetBuffer}, - _offsetType{offsetType}, - _size{size} {} - - std::string_view operator[](int64_t index) const noexcept { - const size_t currentOffset = - getOffsetFromOffsetBuffer(index, _offsetBuffer, _offsetType); - const size_t nextOffset = - getOffsetFromOffsetBuffer(index + 1, _offsetBuffer, _offsetType); - return std::string_view( - reinterpret_cast(_valueBuffer.data() + currentOffset), - (nextOffset - currentOffset)); - } - - int64_t size() const noexcept { return _size; } - -private: - static size_t getOffsetFromOffsetBuffer( - size_t instance, - const gsl::span& offsetBuffer, - PropertyType offsetType) noexcept { - switch (offsetType) { - case PropertyType::Uint8: { - assert(instance < offsetBuffer.size() / sizeof(uint8_t)); - const uint8_t offset = *reinterpret_cast( - offsetBuffer.data() + instance * sizeof(uint8_t)); - return static_cast(offset); - } - case PropertyType::Uint16: { - assert(instance < offsetBuffer.size() / sizeof(uint16_t)); - const uint16_t offset = *reinterpret_cast( - offsetBuffer.data() + instance * sizeof(uint16_t)); - return static_cast(offset); - } - case PropertyType::Uint32: { - assert(instance < offsetBuffer.size() / sizeof(uint32_t)); - const uint32_t offset = *reinterpret_cast( - offsetBuffer.data() + instance * sizeof(uint32_t)); - return static_cast(offset); - } - case PropertyType::Uint64: { - assert(instance < offsetBuffer.size() / sizeof(uint64_t)); - const uint64_t offset = *reinterpret_cast( - offsetBuffer.data() + instance * sizeof(uint64_t)); - return static_cast(offset); - } - default: - assert(false && "Offset type has unknown type"); - return 0; - } - } - gsl::span _valueBuffer; - gsl::span _offsetBuffer; - PropertyType _offsetType; - int64_t _size; -}; -} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/MetadataFeatureTableView.h b/CesiumGltf/include/CesiumGltf/MetadataFeatureTableView.h deleted file mode 100644 index cae3deb92..000000000 --- a/CesiumGltf/include/CesiumGltf/MetadataFeatureTableView.h +++ /dev/null @@ -1,536 +0,0 @@ -#pragma once - -#include "CesiumGltf/ExtensionModelExtFeatureMetadata.h" -#include "CesiumGltf/MetadataPropertyView.h" -#include "CesiumGltf/Model.h" -#include "CesiumGltf/PropertyType.h" - -#include - -#include - -namespace CesiumGltf { -/** - * @brief Utility to retrieve the data of FeatureTable - * - * This should be used to get {@link MetadataPropertyView} of a property since - * it will validate the EXT_Feature_Metadata format to make sure {@link MetadataPropertyView} - * not access out of bound - */ -class MetadataFeatureTableView { -public: - /** - * @brief Create an instance of MetadataFeatureTableView - * @param model The Gltf Model that stores featureTable data - * @param featureTable The FeatureTable that will be used to retrieve the data - * from - */ - MetadataFeatureTableView( - const Model* pModel, - const FeatureTable* pFeatureTable); - - /** - * @brief Find the {@link ClassProperty} which stores the type information of a property based on the property name - * @param propertyName The name of the property to retrieve type info - * @return ClassProperty of a property. Return nullptr if no property is found - */ - const ClassProperty* getClassProperty(const std::string& propertyName) const; - - /** - * @brief Get MetadataPropertyView to view the data of a property stored in - * the FeatureTable. - * - * This method will validate the EXT_Feature_Metadata format to ensure - * MetadataPropertyView retrieve the correct data. T must be uin8_t, int8_t, - * uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, - * bool, std::string_view, and MetadataArrayView with T must be one of the - * types mentioned above - * - * @param propertyName The name of the property to retrieve data from - * @return ClassProperty of a property. Return nullptr if no property is found - */ - template - MetadataPropertyView - getPropertyView(const std::string& propertyName) const { - if (_pFeatureTable->count < 0) { - return createInvalidPropertyView( - MetadataPropertyViewStatus::InvalidPropertyNotExist); - } - - const ClassProperty* pClassProperty = getClassProperty(propertyName); - if (!pClassProperty) { - return createInvalidPropertyView( - MetadataPropertyViewStatus::InvalidPropertyNotExist); - } - - return getPropertyViewImpl(propertyName, *pClassProperty); - } - - /** - * @brief Get MetadataPropertyView through a callback that accepts property - * name and std::optional> to view the data of a - * property stored in the FeatureTable. - * - * This method will validate the EXT_Feature_Metadata format to ensure - * MetadataPropertyView retrieve the correct data. T must be uin8_t, int8_t, - * uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, - * bool, std::string_view, and MetadataArrayView with T must be one of the - * types mentioned above. If the property is invalid, std::nullopt 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 - * std::optional> - */ - template - void - getPropertyView(const std::string& propertyName, Callback&& callback) const { - const ClassProperty* pClassProperty = getClassProperty(propertyName); - if (!pClassProperty) { - return; - } - - PropertyType type = convertStringToPropertyType(pClassProperty->type); - PropertyType componentType = PropertyType::None; - if (pClassProperty->componentType.has_value()) { - componentType = - convertStringToPropertyType(pClassProperty->componentType.value()); - } - - if (type != PropertyType::Array) { - getScalarPropertyViewImpl( - propertyName, - *pClassProperty, - type, - std::forward(callback)); - } else { - getArrayPropertyViewImpl( - propertyName, - *pClassProperty, - componentType, - std::forward(callback)); - } - } - - /** - * @brief Get MetadataPropertyView for each property in the FeatureTable - * through a callback that accepts property name and - * std::optional> to view the data stored in the - * FeatureTableProperty. - * - * This method will validate the EXT_Feature_Metadata format to ensure - * MetadataPropertyView retrieve the correct data. T must be uin8_t, int8_t, - * uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, - * bool, std::string_view, and MetadataArrayView with T must be one of the - * types mentioned above. If the property is invalid, std::nullopt 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 - * std::optional> - */ - template void forEachProperty(Callback&& callback) const { - for (const auto& property : this->_pClass->properties) { - getPropertyView(property.first, std::forward(callback)); - } - } - -private: - template - void getArrayPropertyViewImpl( - const std::string& propertyName, - const ClassProperty& classProperty, - PropertyType type, - Callback&& callback) const { - switch (type) { - case PropertyType::Int8: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::Uint8: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::Int16: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::Uint16: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::Int32: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::Uint32: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::Int64: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::Uint64: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::Float32: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::Float64: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::Boolean: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - case PropertyType::String: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; - default: - break; - } - } - - template - void getScalarPropertyViewImpl( - const std::string& propertyName, - const ClassProperty& classProperty, - PropertyType type, - Callback&& callback) const { - switch (type) { - case PropertyType::Int8: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Uint8: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Int16: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Uint16: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Int32: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Uint32: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Int64: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Uint64: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Float32: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Float64: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::Boolean: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - case PropertyType::String: - callback( - propertyName, - getPropertyViewImpl(propertyName, classProperty)); - break; - default: - break; - } - } - - template - MetadataPropertyView getPropertyViewImpl( - const std::string& propertyName, - const ClassProperty& classProperty) const { - auto featureTablePropertyIter = - _pFeatureTable->properties.find(propertyName); - if (featureTablePropertyIter == _pFeatureTable->properties.end()) { - return createInvalidPropertyView( - MetadataPropertyViewStatus::InvalidPropertyNotExist); - } - - const FeatureTableProperty& featureTableProperty = - featureTablePropertyIter->second; - - if constexpr (IsMetadataNumeric::value || IsMetadataBoolean::value) { - return getPrimitivePropertyValues(classProperty, featureTableProperty); - } - - if constexpr (IsMetadataString::value) { - return getStringPropertyValues(classProperty, featureTableProperty); - } - - if constexpr ( - IsMetadataNumericArray::value || IsMetadataBooleanArray::value) { - return getPrimitiveArrayPropertyValues< - typename MetadataArrayType::type>( - classProperty, - featureTableProperty); - } - - if constexpr (IsMetadataStringArray::value) { - return getStringArrayPropertyValues(classProperty, featureTableProperty); - } - } - - template - MetadataPropertyView getPrimitivePropertyValues( - const ClassProperty& classProperty, - const FeatureTableProperty& featureTableProperty) const { - const PropertyType type = convertStringToPropertyType(classProperty.type); - if (TypeToPropertyType::value != type) { - return createInvalidPropertyView( - MetadataPropertyViewStatus::InvalidTypeMismatch); - } - - gsl::span valueBuffer; - const auto status = - getBufferSafe(featureTableProperty.bufferView, valueBuffer); - if (status != MetadataPropertyViewStatus::Valid) { - return createInvalidPropertyView(status); - } - - if (valueBuffer.size() % sizeof(T) != 0) { - return createInvalidPropertyView( - MetadataPropertyViewStatus:: - InvalidBufferViewSizeNotDivisibleByTypeSize); - } - - size_t maxRequiredBytes = 0; - if (IsMetadataBoolean::value) { - maxRequiredBytes = static_cast( - glm::ceil(static_cast(_pFeatureTable->count) / 8.0)); - } else { - maxRequiredBytes = _pFeatureTable->count * sizeof(T); - } - - if (valueBuffer.size() < maxRequiredBytes) { - return createInvalidPropertyView( - MetadataPropertyViewStatus::InvalidBufferViewSizeNotFitInstanceCount); - } - - return MetadataPropertyView( - MetadataPropertyViewStatus::Valid, - valueBuffer, - gsl::span(), - gsl::span(), - PropertyType::None, - 0, - _pFeatureTable->count, - classProperty.normalized); - } - - MetadataPropertyView getStringPropertyValues( - const ClassProperty& classProperty, - const FeatureTableProperty& featureTableProperty) const; - - template - MetadataPropertyView> getPrimitiveArrayPropertyValues( - const ClassProperty& classProperty, - const FeatureTableProperty& featureTableProperty) const { - if (classProperty.type != ClassProperty::Type::ARRAY) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus::InvalidTypeMismatch); - } - - if (!classProperty.componentType.has_value()) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus::InvalidTypeMismatch); - } - - const PropertyType componentType = - convertStringToPropertyType(classProperty.componentType.value()); - if (TypeToPropertyType::value != componentType) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus::InvalidTypeMismatch); - } - - gsl::span valueBuffer; - auto status = getBufferSafe(featureTableProperty.bufferView, valueBuffer); - if (status != MetadataPropertyViewStatus::Valid) { - return createInvalidPropertyView>(status); - } - - if (valueBuffer.size() % sizeof(T) != 0) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus:: - InvalidBufferViewSizeNotDivisibleByTypeSize); - } - - const int64_t componentCount = classProperty.componentCount.value_or(0); - if (componentCount > 0 && featureTableProperty.arrayOffsetBufferView >= 0) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus:: - InvalidArrayComponentCountAndOffsetBufferCoexist); - } - - if (componentCount <= 0 && featureTableProperty.arrayOffsetBufferView < 0) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus:: - InvalidArrayComponentCountOrOffsetBufferNotExist); - } - - // fixed array - if (componentCount > 0) { - size_t maxRequiredBytes = 0; - if constexpr (IsMetadataBoolean::value) { - maxRequiredBytes = static_cast(glm::ceil( - static_cast(_pFeatureTable->count * componentCount) / 8.0)); - } else { - maxRequiredBytes = static_cast( - _pFeatureTable->count * componentCount * sizeof(T)); - } - - if (valueBuffer.size() < maxRequiredBytes) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus:: - InvalidBufferViewSizeNotFitInstanceCount); - } - - return MetadataPropertyView>( - MetadataPropertyViewStatus::Valid, - valueBuffer, - gsl::span(), - gsl::span(), - PropertyType::None, - static_cast(componentCount), - static_cast(_pFeatureTable->count), - classProperty.normalized); - } - - // dynamic array - const PropertyType offsetType = - convertOffsetStringToPropertyType(featureTableProperty.offsetType); - if (offsetType == PropertyType::None) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus::InvalidOffsetType); - } - - constexpr bool checkBitsSize = IsMetadataBoolean::value; - gsl::span offsetBuffer; - status = getOffsetBufferSafe( - featureTableProperty.arrayOffsetBufferView, - offsetType, - valueBuffer.size(), - static_cast(_pFeatureTable->count), - checkBitsSize, - offsetBuffer); - if (status != MetadataPropertyViewStatus::Valid) { - return createInvalidPropertyView>(status); - } - - return MetadataPropertyView>( - MetadataPropertyViewStatus::Valid, - valueBuffer, - offsetBuffer, - gsl::span(), - offsetType, - 0, - static_cast(_pFeatureTable->count), - classProperty.normalized); - } - - MetadataPropertyView> - getStringArrayPropertyValues( - const ClassProperty& classProperty, - const FeatureTableProperty& featureTableProperty) const; - - MetadataPropertyViewStatus getBufferSafe( - int32_t bufferViewIdx, - gsl::span& buffer) const noexcept; - - MetadataPropertyViewStatus getOffsetBufferSafe( - int32_t bufferViewIdx, - PropertyType offsetType, - size_t valueBufferSize, - size_t instanceCount, - bool checkBitsSize, - gsl::span& offsetBuffer) const noexcept; - - template - static MetadataPropertyView - createInvalidPropertyView(MetadataPropertyViewStatus invalidStatus) noexcept { - return MetadataPropertyView( - invalidStatus, - gsl::span(), - gsl::span(), - gsl::span(), - PropertyType::None, - 0, - 0, - false); - } - - const Model* _pModel; - const FeatureTable* _pFeatureTable; - const Class* _pClass; -}; -} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/MetadataPropertyView.h b/CesiumGltf/include/CesiumGltf/MetadataPropertyView.h deleted file mode 100644 index 6b535d27d..000000000 --- a/CesiumGltf/include/CesiumGltf/MetadataPropertyView.h +++ /dev/null @@ -1,411 +0,0 @@ -#pragma once - -#include "CesiumGltf/MetadataArrayView.h" -#include "CesiumGltf/PropertyType.h" -#include "CesiumGltf/PropertyTypeTraits.h" - -#include - -#include -#include -#include -#include -#include - -namespace CesiumGltf { -/** - * @brief Indicates the status of a property view. - * - * The {@link MetadataPropertyView} constructor always completes successfully. However, - * it may not always reflect the actual content of the {@link FeatureTableProperty}, but - * instead indicate that its {@link MetadataPropertyView::size} is 0. This enumeration - * provides the reason. - */ -enum class MetadataPropertyViewStatus { - /** - * @brief This property view is valid and ready to use. - */ - Valid, - - /** - * @brief This property view does not exist in the FeatureTable. - */ - InvalidPropertyNotExist, - - /** - * @brief This property view does not have a correct type with what is - * specified in {@link ClassProperty::type}. - */ - InvalidTypeMismatch, - - /** - * @brief This property view does not have a valid value buffer view index. - */ - InvalidValueBufferViewIndex, - - /** - * @brief This array property view does not have a valid array offset buffer - * view index. - */ - InvalidArrayOffsetBufferViewIndex, - - /** - * @brief This string property view does not have a valid string offset buffer - * view index. - */ - InvalidStringOffsetBufferViewIndex, - - /** - * @brief This property view has a valid value buffer view index, but buffer - * view specifies an invalid buffer index - */ - InvalidValueBufferIndex, - - /** - * @brief This property view has a valid array string buffer view index, but - * buffer view specifies an invalid buffer index - */ - InvalidArrayOffsetBufferIndex, - - /** - * @brief This property view has a valid string offset buffer view index, but - * buffer view specifies an invalid buffer index - */ - InvalidStringOffsetBufferIndex, - - /** - * @brief This property view has buffer view's offset not aligned by 8 bytes - */ - InvalidBufferViewNotAligned8Bytes, - - /** - * @brief This property view has an out-of-bound buffer view - */ - InvalidBufferViewOutOfBound, - - /** - * @brief This property view has an invalid buffer view's length which is not - * a multiple of the size of its type or offset type - */ - InvalidBufferViewSizeNotDivisibleByTypeSize, - - /** - * @brief This property view has an invalid buffer view's length which cannot - * fit all the instances of the feature table - */ - InvalidBufferViewSizeNotFitInstanceCount, - - /** - * @brief This array property view has both component count and offset buffer - * view - */ - InvalidArrayComponentCountAndOffsetBufferCoexist, - - /** - * @brief This array property view doesn't have either component count or - * offset buffer view - */ - InvalidArrayComponentCountOrOffsetBufferNotExist, - - /** - * @brief This property view have an unknown offset type - */ - InvalidOffsetType, - - /** - * @brief This property view has offset values not sorted ascendingly - */ - InvalidOffsetValuesNotSortedAscending, - - /** - * @brief This property view has an offset point to an out of bound value - */ - InvalidOffsetValuePointsToOutOfBoundBuffer -}; - -/** - * @brief A view on the data of the FeatureTableProperty - * - * It provides utility to retrieve the actual data stored in the - * {@link FeatureTableProperty::bufferView} like an array of elements. - * Data of each instance can be accessed through the {@link get(int64_t instance)} method - * - * @param ElementType must be uin8_t, int8_t, uint16_t, int16_t, - * uint32_t, int32_t, uint64_t, int64_t, float, double, bool, std::string_view, - * and MetadataArrayView with T must be one of the types mentioned above - */ -template class MetadataPropertyView { -public: - /** - * @brief Constructs a new instance viewing a non-existent property. - */ - MetadataPropertyView() - : _status{MetadataPropertyViewStatus::InvalidPropertyNotExist}, - _valueBuffer{}, - _arrayOffsetBuffer{}, - _stringOffsetBuffer{}, - _offsetType{}, - _offsetSize{}, - _componentCount{}, - _instanceCount{}, - _normalized{} {} - - /** - * @brief Construct a new instance pointing to the data specified by - * FeatureTableProperty - * @param valueBuffer The raw buffer specified by {@link FeatureTableProperty::bufferView} - * @param arrayOffsetBuffer The raw buffer specified by {@link FeatureTableProperty::arrayOffsetBufferView} - * @param stringOffsetBuffer The raw buffer specified by {@link FeatureTableProperty::stringOffsetBufferView} - * @param offsetType The offset type of the arrayOffsetBuffer and stringOffsetBuffer that is specified by {@link FeatureTableProperty::offsetType} - * @param componentCount The number of elements for fixed array value which is specified by {@link FeatureTableProperty::componentCount} - * @param instanceCount The number of instances specified by {@link FeatureTable::count} - * @param normalized Whether this property has a normalized integer type. - */ - MetadataPropertyView( - MetadataPropertyViewStatus status, - gsl::span valueBuffer, - gsl::span arrayOffsetBuffer, - gsl::span stringOffsetBuffer, - PropertyType offsetType, - int64_t componentCount, - int64_t instanceCount, - bool normalized) noexcept - : _status{status}, - _valueBuffer{valueBuffer}, - _arrayOffsetBuffer{arrayOffsetBuffer}, - _stringOffsetBuffer{stringOffsetBuffer}, - _offsetType{offsetType}, - _offsetSize{getOffsetSize(offsetType)}, - _componentCount{componentCount}, - _instanceCount{instanceCount}, - _normalized{normalized} {} - - /** - * @brief Gets the status of this property view. - * - * Indicates whether the view accurately reflects the property's data, or - * whether an error occurred. - */ - MetadataPropertyViewStatus status() const noexcept { return _status; } - - /** - * @brief Get the value of an instance of the FeatureTable. - * @param instance The instance index - * @return The value of the instance - */ - ElementType get(int64_t instance) const noexcept { - assert( - _status == MetadataPropertyViewStatus::Valid && - "Check the status() first to make sure view is valid"); - assert( - size() > 0 && - "Check the size() of the view to make sure it's not empty"); - assert(instance >= 0 && "instance index must be positive"); - - if constexpr (IsMetadataNumeric::value) { - return getNumeric(instance); - } - - if constexpr (IsMetadataBoolean::value) { - return getBoolean(instance); - } - - if constexpr (IsMetadataString::value) { - return getString(instance); - } - - if constexpr (IsMetadataNumericArray::value) { - return getNumericArray::type>( - instance); - } - - if constexpr (IsMetadataBooleanArray::value) { - return getBooleanArray(instance); - } - - if constexpr (IsMetadataStringArray::value) { - return getStringArray(instance); - } - } - - /** - * @brief Get the number of instances in the FeatureTable - * @return The number of instances in the FeatureTable - */ - int64_t size() const noexcept { return _instanceCount; } - - /** - * @brief Get the component count of this property. Only applicable when the - * property is an array type. - * - * @return The component count of this property. - */ - int64_t getComponentCount() const noexcept { return _componentCount; } - - /** - * @brief Whether this property has a normalized integer type. - * - * @return Whether this property has a normalized integer type. - */ - bool isNormalized() const noexcept { return _normalized; } - -private: - ElementType getNumeric(int64_t instance) const noexcept { - return reinterpret_cast(_valueBuffer.data())[instance]; - } - - bool getBoolean(int64_t instance) const noexcept { - const int64_t byteIndex = instance / 8; - const int64_t bitIndex = instance % 8; - const int bitValue = - static_cast(_valueBuffer[byteIndex] >> bitIndex) & 1; - return bitValue == 1; - } - - std::string_view getString(int64_t instance) const noexcept { - const size_t currentOffset = - getOffsetFromOffsetBuffer(instance, _stringOffsetBuffer, _offsetType); - const size_t nextOffset = getOffsetFromOffsetBuffer( - instance + 1, - _stringOffsetBuffer, - _offsetType); - return std::string_view( - reinterpret_cast(_valueBuffer.data() + currentOffset), - (nextOffset - currentOffset)); - } - - template - MetadataArrayView getNumericArray(int64_t instance) const noexcept { - if (_componentCount > 0) { - const gsl::span vals( - _valueBuffer.data() + instance * _componentCount * sizeof(T), - _componentCount * sizeof(T)); - return MetadataArrayView{vals}; - } - - const size_t currentOffset = - getOffsetFromOffsetBuffer(instance, _arrayOffsetBuffer, _offsetType); - const size_t nextOffset = getOffsetFromOffsetBuffer( - instance + 1, - _arrayOffsetBuffer, - _offsetType); - const gsl::span vals( - _valueBuffer.data() + currentOffset, - (nextOffset - currentOffset)); - return MetadataArrayView{vals}; - } - - MetadataArrayView - getStringArray(int64_t instance) const noexcept { - if (_componentCount > 0) { - const gsl::span offsetVals( - _stringOffsetBuffer.data() + instance * _componentCount * _offsetSize, - (_componentCount + 1) * _offsetSize); - return MetadataArrayView( - _valueBuffer, - offsetVals, - _offsetType, - _componentCount); - } - - const size_t currentOffset = - getOffsetFromOffsetBuffer(instance, _arrayOffsetBuffer, _offsetType); - const size_t nextOffset = getOffsetFromOffsetBuffer( - instance + 1, - _arrayOffsetBuffer, - _offsetType); - const gsl::span offsetVals( - _stringOffsetBuffer.data() + currentOffset, - (nextOffset - currentOffset + _offsetSize)); - return MetadataArrayView( - _valueBuffer, - offsetVals, - _offsetType, - (nextOffset - currentOffset) / _offsetSize); - } - - MetadataArrayView getBooleanArray(int64_t instance) const noexcept { - if (_componentCount > 0) { - const size_t offsetBits = _componentCount * instance; - const size_t nextOffsetBits = _componentCount * (instance + 1); - const gsl::span buffer( - _valueBuffer.data() + offsetBits / 8, - (nextOffsetBits / 8 - offsetBits / 8 + 1)); - return MetadataArrayView(buffer, offsetBits % 8, _componentCount); - } - - const size_t currentOffset = - getOffsetFromOffsetBuffer(instance, _arrayOffsetBuffer, _offsetType); - const size_t nextOffset = getOffsetFromOffsetBuffer( - instance + 1, - _arrayOffsetBuffer, - _offsetType); - - const size_t totalBits = nextOffset - currentOffset; - const gsl::span buffer( - _valueBuffer.data() + currentOffset / 8, - (nextOffset / 8 - currentOffset / 8 + 1)); - return MetadataArrayView(buffer, currentOffset % 8, totalBits); - } - - static int64_t getOffsetSize(PropertyType offsetType) noexcept { - switch (offsetType) { - case CesiumGltf::PropertyType::Uint8: - return sizeof(uint8_t); - case CesiumGltf::PropertyType::Uint16: - return sizeof(uint16_t); - case CesiumGltf::PropertyType::Uint32: - return sizeof(uint32_t); - case CesiumGltf::PropertyType::Uint64: - return sizeof(uint64_t); - default: - return 0; - } - } - - static size_t getOffsetFromOffsetBuffer( - size_t instance, - const gsl::span& offsetBuffer, - PropertyType offsetType) noexcept { - switch (offsetType) { - case PropertyType::Uint8: { - assert(instance < offsetBuffer.size() / sizeof(uint8_t)); - const uint8_t offset = *reinterpret_cast( - offsetBuffer.data() + instance * sizeof(uint8_t)); - return static_cast(offset); - } - case PropertyType::Uint16: { - assert(instance < offsetBuffer.size() / sizeof(uint16_t)); - const uint16_t offset = *reinterpret_cast( - offsetBuffer.data() + instance * sizeof(uint16_t)); - return static_cast(offset); - } - case PropertyType::Uint32: { - assert(instance < offsetBuffer.size() / sizeof(uint32_t)); - const uint32_t offset = *reinterpret_cast( - offsetBuffer.data() + instance * sizeof(uint32_t)); - return static_cast(offset); - } - case PropertyType::Uint64: { - assert(instance < offsetBuffer.size() / sizeof(uint64_t)); - const uint64_t offset = *reinterpret_cast( - offsetBuffer.data() + instance * sizeof(uint64_t)); - return static_cast(offset); - } - default: - assert(false && "Offset type has unknown type"); - return 0; - } - } - - MetadataPropertyViewStatus _status; - gsl::span _valueBuffer; - gsl::span _arrayOffsetBuffer; - gsl::span _stringOffsetBuffer; - PropertyType _offsetType; - int64_t _offsetSize; - int64_t _componentCount; - int64_t _instanceCount; - bool _normalized; -}; -} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h similarity index 76% rename from CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h rename to CesiumGltf/include/CesiumGltf/PropertyArrayView.h index e315584f4..9f3ea6d2f 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -1,6 +1,6 @@ #pragma once -#include "CesiumGltf/StructuralMetadataPropertyType.h" +#include "CesiumGltf/PropertyType.h" #include "getOffsetFromOffsetsBuffer.h" #include @@ -11,8 +11,6 @@ #include namespace CesiumGltf { -namespace StructuralMetadata { - /** * @brief A view on an array element of a * {@link ExtensionExtStructuralMetadataPropertyTableProperty}. @@ -20,11 +18,11 @@ namespace StructuralMetadata { * Provides utility to retrieve the data stored in the array of * elements via the array index operator. */ -template class MetadataArrayView { +template class PropertyArrayView { public: - MetadataArrayView() : _values{} {} + PropertyArrayView() : _values{} {} - MetadataArrayView(const gsl::span& buffer) noexcept + PropertyArrayView(const gsl::span& buffer) noexcept : _values{CesiumUtility::reintepretCastSpan(buffer)} {} const ElementType& operator[](int64_t index) const noexcept { @@ -34,14 +32,14 @@ template class MetadataArrayView { int64_t size() const noexcept { return static_cast(_values.size()); } private: - const gsl::span _values; + gsl::span _values; }; -template <> class MetadataArrayView { +template <> class PropertyArrayView { public: - MetadataArrayView() : _values{}, _bitOffset{0}, _size{0} {} + PropertyArrayView() : _values{}, _bitOffset{0}, _size{0} {} - MetadataArrayView( + PropertyArrayView( const gsl::span& buffer, int64_t bitOffset, int64_t size) noexcept @@ -63,15 +61,15 @@ template <> class MetadataArrayView { int64_t _size; }; -template <> class MetadataArrayView { +template <> class PropertyArrayView { public: - MetadataArrayView() + PropertyArrayView() : _values{}, _stringOffsets{}, _stringOffsetType{}, _size{0} {} - MetadataArrayView( + PropertyArrayView( const gsl::span& values, const gsl::span& stringOffsets, - StructuralMetadata::PropertyComponentType stringOffsetType, + PropertyComponentType stringOffsetType, int64_t size) noexcept : _values{values}, _stringOffsets{stringOffsets}, @@ -95,9 +93,7 @@ template <> class MetadataArrayView { private: gsl::span _values; gsl::span _stringOffsets; - StructuralMetadata::PropertyComponentType _stringOffsetType; + PropertyComponentType _stringOffsetType; int64_t _size; }; - -} // namespace StructuralMetadata } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h similarity index 93% rename from CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTablePropertyView.h rename to CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 320beb349..451c5f14d 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -1,7 +1,7 @@ #pragma once -#include "CesiumGltf/StructuralMetadataArrayView.h" -#include "CesiumGltf/StructuralMetadataPropertyTypeTraits.h" +#include "CesiumGltf/PropertyArrayView.h" +#include "CesiumGltf/PropertyTypeTraits.h" #include @@ -12,8 +12,6 @@ #include namespace CesiumGltf { -namespace StructuralMetadata { - /** * @brief Indicates the status of a property table property view. * @@ -161,7 +159,7 @@ enum class PropertyTablePropertyViewStatus { /** * @brief A view on the data of the * {@link ExtensionExtStructuralMetadataPropertyTableProperty that is created by - * a {@link MetadataPropertyTableView}. + * a {@link PropertyTableView}. * * It provides utility to retrieve the actual data stored in the * {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} like an array of elements. @@ -170,7 +168,7 @@ enum class PropertyTablePropertyViewStatus { * @param ElementType must be one of the following: a scalar (uint8_t, int8_t, * uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double), a * glm vecN composed of one of the scalar types, a glm matN composed of one of - * the scalar types, bool, std::string_view, or MetadataArrayView with T as + * the scalar types, bool, std::string_view, or PropertyArrayView with T as * one of the aforementioned types. */ template class PropertyTablePropertyView { @@ -226,8 +224,8 @@ template class PropertyTablePropertyView { gsl::span values, gsl::span arrayOffsets, gsl::span stringOffsets, - StructuralMetadata::PropertyComponentType arrayOffsetType, - StructuralMetadata::PropertyComponentType stringOffsetType, + PropertyComponentType arrayOffsetType, + PropertyComponentType stringOffsetType, int64_t arrayCount, int64_t size, bool normalized) noexcept @@ -345,14 +343,14 @@ template class PropertyTablePropertyView { } template - MetadataArrayView getNumericArrayValues(int64_t index) const noexcept { + PropertyArrayView getNumericArrayValues(int64_t index) const noexcept { // Handle fixed-length arrays if (_arrayCount > 0) { size_t arraySize = _arrayCount * sizeof(T); const gsl::span values( _values.data() + index * arraySize, arraySize); - return MetadataArrayView{values}; + return PropertyArrayView{values}; } // Handle variable-length arrays @@ -363,19 +361,19 @@ template class PropertyTablePropertyView { const gsl::span values( _values.data() + currentOffset, nextOffset - currentOffset); - return MetadataArrayView{values}; + return PropertyArrayView{values}; } - MetadataArrayView + PropertyArrayView getStringArrayValues(int64_t index) const noexcept { // Handle fixed-length arrays if (_arrayCount > 0) { - // Copy the corresponding string offsets to pass to the MetadataArrayView. + // Copy the corresponding string offsets to pass to the PropertyArrayView. const size_t arraySize = _arrayCount * _stringOffsetTypeSize; const gsl::span stringOffsetValues( _stringOffsets.data() + index * arraySize, arraySize + _stringOffsetTypeSize); - return MetadataArrayView( + return PropertyArrayView( _values, stringOffsetValues, _stringOffsetType, @@ -391,14 +389,14 @@ template class PropertyTablePropertyView { const gsl::span stringOffsetValues( _stringOffsets.data() + currentArrayOffset, arraySize + _arrayOffsetTypeSize); - return MetadataArrayView( + return PropertyArrayView( _values, stringOffsetValues, _stringOffsetType, arraySize / _arrayOffsetTypeSize); } - MetadataArrayView getBooleanArrayValues(int64_t index) const noexcept { + PropertyArrayView getBooleanArrayValues(int64_t index) const noexcept { // Handle fixed-length arrays if (_arrayCount > 0) { const size_t offsetBits = _arrayCount * index; @@ -406,7 +404,7 @@ template class PropertyTablePropertyView { const gsl::span buffer( _values.data() + offsetBits / 8, (nextOffsetBits / 8 - offsetBits / 8 + 1)); - return MetadataArrayView(buffer, offsetBits % 8, _arrayCount); + return PropertyArrayView(buffer, offsetBits % 8, _arrayCount); } // Handle variable-length arrays @@ -418,7 +416,7 @@ template class PropertyTablePropertyView { const gsl::span buffer( _values.data() + currentOffset / 8, (nextOffset / 8 - currentOffset / 8 + 1)); - return MetadataArrayView(buffer, currentOffset % 8, totalBits); + return PropertyArrayView(buffer, currentOffset % 8, totalBits); } static int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { @@ -451,6 +449,4 @@ template class PropertyTablePropertyView { int64_t _size; bool _normalized; }; - -} // namespace StructuralMetadata } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h similarity index 91% rename from CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h rename to CesiumGltf/include/CesiumGltf/PropertyTableView.h index e3c55db2d..84757d07f 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -2,16 +2,14 @@ #include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" #include "CesiumGltf/Model.h" -#include "CesiumGltf/StructuralMetadataPropertyTablePropertyView.h" -#include "CesiumGltf/StructuralMetadataPropertyType.h" +#include "CesiumGltf/PropertyTablePropertyView.h" +#include "CesiumGltf/PropertyType.h" #include #include namespace CesiumGltf { -namespace StructuralMetadata { - /** * @brief Indicates the status of a property table view. * @@ -107,7 +105,7 @@ class PropertyTableView { * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, - * std::string_view, or {@link MetadataArrayView} with T as one of the + * std::string_view, or {@link PropertyArrayView} with T as one of the * aforementioned types. * * @param propertyName The name of the property to retrieve data from @@ -119,16 +117,14 @@ class PropertyTableView { getPropertyView(const std::string& propertyName) const { if (this->size() <= 0) { return createInvalidPropertyView( - StructuralMetadata::PropertyTablePropertyViewStatus:: - ErrorInvalidPropertyTable); + PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); } const ExtensionExtStructuralMetadataClassProperty* pClassProperty = getClassProperty(propertyName); if (!pClassProperty) { return createInvalidPropertyView( - StructuralMetadata::PropertyTablePropertyViewStatus:: - ErrorPropertyDoesNotExist); + PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist); } return getPropertyViewImpl(propertyName, *pClassProperty); @@ -144,7 +140,7 @@ class PropertyTableView { * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, - * std::string_view, or {@link MetadataArrayView} with T as one of the + * std::string_view, or {@link PropertyArrayView} with T as one of the * aforementioned types. If the property is invalid, an empty * {@link PropertyTablePropertyView} with an error status will be passed to the * callback. Otherwise, a valid property view will be passed to the callback. @@ -160,8 +156,7 @@ class PropertyTableView { callback( propertyName, createInvalidPropertyView( - StructuralMetadata::PropertyTablePropertyViewStatus:: - ErrorInvalidPropertyTable)); + PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable)); return; } @@ -236,7 +231,7 @@ class PropertyTableView { * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, - * std::string_view, or {@link MetadataArrayView} with T as one of the + * std::string_view, or {@link PropertyArrayView} with T as one of the * aforementioned types. If the property is invalid, an empty * {@link PropertyTablePropertyView} with an error status code will be passed to the * callback. Otherwise, a valid property view will be passed to @@ -279,70 +274,70 @@ class PropertyTableView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); break; case PropertyComponentType::Int32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); break; case PropertyComponentType::Int64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); break; case PropertyComponentType::Uint64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); break; case PropertyComponentType::Float64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); break; @@ -365,70 +360,70 @@ class PropertyTableView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Int32: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Int64: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Uint64: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Float64: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; @@ -490,70 +485,70 @@ class PropertyTableView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Int32: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Int64: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Uint64: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; case PropertyComponentType::Float64: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>>( propertyName, classProperty)); break; @@ -635,14 +630,14 @@ class PropertyTableView { } else if (type == PropertyType::Boolean) { callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); } else if (type == PropertyType::String) { callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl>( propertyName, classProperty)); } else { @@ -1036,7 +1031,7 @@ class PropertyTableView { if (values.size() % sizeof(T) != 0) { return createInvalidPropertyView( - StructuralMetadata::PropertyTablePropertyViewStatus:: + PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize); } @@ -1067,19 +1062,19 @@ class PropertyTableView { propertyTableProperty) const; template - PropertyTablePropertyView> + PropertyTablePropertyView> getPrimitiveArrayPropertyValues( const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty) const { if (!classProperty.array) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorTypeMismatch); } @@ -1087,31 +1082,31 @@ class PropertyTableView { convertStringToPropertyComponentType( classProperty.componentType.value_or("")); if (TypeToPropertyType::component != componentType) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } gsl::span values; auto status = getBufferSafe(propertyTableProperty.values, values); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>(status); + return createInvalidPropertyView>(status); } if (values.size() % sizeof(T) != 0) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize); } const int64_t fixedLengthArrayCount = classProperty.count.value_or(0); if (fixedLengthArrayCount > 0 && propertyTableProperty.arrayOffsets >= 0) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus:: ErrorArrayCountAndOffsetBufferCoexist); } if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus:: ErrorArrayCountAndOffsetBufferDontExist); } @@ -1130,12 +1125,12 @@ class PropertyTableView { } if (values.size() < maxRequiredBytes) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } - return PropertyTablePropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::Valid, values, gsl::span(), @@ -1152,7 +1147,7 @@ class PropertyTableView { convertArrayOffsetTypeStringToPropertyComponentType( propertyTableProperty.arrayOffsetType); if (arrayOffsetType == PropertyComponentType::None) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } @@ -1166,10 +1161,10 @@ class PropertyTableView { checkBitsSize, arrayOffsets); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>(status); + return createInvalidPropertyView>(status); } - return PropertyTablePropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::Valid, values, arrayOffsets, @@ -1181,7 +1176,7 @@ class PropertyTableView { classProperty.normalized); } - PropertyTablePropertyView> + PropertyTablePropertyView> getStringArrayPropertyValues( const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& @@ -1221,6 +1216,4 @@ class PropertyTableView { const ExtensionExtStructuralMetadataClass* _pClass; PropertyTableViewStatus _status; }; - -} // namespace StructuralMetadata } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h similarity index 99% rename from CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h rename to CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index e8f858732..a6b97ccd1 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -14,7 +14,6 @@ #include namespace CesiumGltf { -namespace StructuralMetadata { /** * @brief Indicates the status of a property texture property view. * @@ -241,6 +240,4 @@ class PropertyTexturePropertyView { int64_t _count; bool _normalized; }; - -} // namespace StructuralMetadata } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h similarity index 96% rename from CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTextureView.h rename to CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 9d053357e..69c0f70e2 100644 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -4,7 +4,7 @@ #include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" #include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTexture.h" #include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" -#include "CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h" +#include "CesiumGltf/PropertyTexturePropertyView.h" #include "CesiumGltf/Texture.h" #include "CesiumGltf/TextureAccessor.h" #include "Image.h" @@ -12,8 +12,6 @@ #include "Model.h" namespace CesiumGltf { -namespace StructuralMetadata { - /** * @brief Indicates the status of a property texture view. * @@ -119,6 +117,4 @@ class PropertyTextureView { std::unordered_map _propertyViews; PropertyTextureViewStatus _status; }; - -} // namespace StructuralMetadata } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyType.h b/CesiumGltf/include/CesiumGltf/PropertyType.h index 130d37fad..e5771a015 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyType.h +++ b/CesiumGltf/include/CesiumGltf/PropertyType.h @@ -6,6 +6,20 @@ namespace CesiumGltf { enum class PropertyType { + Invalid, + Scalar, + Vec2, + Vec3, + Vec4, + Mat2, + Mat3, + Mat4, + String, + Boolean, + Enum +}; + +enum class PropertyComponentType { None, Int8, Uint8, @@ -17,15 +31,25 @@ enum class PropertyType { Uint64, Float32, Float64, - Boolean, - Enum, - String, - Array, }; -std::string convertPropertyTypeToString(CesiumGltf::PropertyType type); +std::string convertPropertyTypeToString(PropertyType type); PropertyType convertStringToPropertyType(const std::string& str); -PropertyType convertOffsetStringToPropertyType(const std::string& str); +std::string +convertPropertyComponentTypeToString(PropertyComponentType componentType); + +PropertyComponentType +convertStringToPropertyComponentType(const std::string& str); + +PropertyComponentType +convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str); + +PropertyComponentType +convertStringOffsetTypeStringToPropertyComponentType(const std::string& str); + +bool isPropertyTypeVecN(PropertyType type); + +bool isPropertyTypeMatN(PropertyType type); } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h index 144365665..999947f54 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h @@ -1,27 +1,29 @@ #pragma once -#include "CesiumGltf/MetadataArrayView.h" +#include "CesiumGltf/PropertyArrayView.h" #include "CesiumGltf/PropertyType.h" +#include + #include #include namespace CesiumGltf { /** - * @brief Check if a C++ type can be represented as a numeric property type + * @brief Check if a C++ type can be represented as a scalar property type */ -template struct IsMetadataNumeric; -template struct IsMetadataNumeric : std::false_type {}; -template <> struct IsMetadataNumeric : std::true_type {}; -template <> struct IsMetadataNumeric : std::true_type {}; -template <> struct IsMetadataNumeric : std::true_type {}; -template <> struct IsMetadataNumeric : std::true_type {}; -template <> struct IsMetadataNumeric : std::true_type {}; -template <> struct IsMetadataNumeric : std::true_type {}; -template <> struct IsMetadataNumeric : std::true_type {}; -template <> struct IsMetadataNumeric : std::true_type {}; -template <> struct IsMetadataNumeric : std::true_type {}; -template <> struct IsMetadataNumeric : std::true_type {}; +template struct IsMetadataScalar; +template struct IsMetadataScalar : std::false_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; +template <> struct IsMetadataScalar : std::true_type {}; /** * @brief Check if a C++ type can be represented as an integer property type @@ -39,13 +41,40 @@ template <> struct IsMetadataInteger : std::true_type {}; /** * @brief Check if a C++ type can be represented as a floating-point property - * type + * type. */ template struct IsMetadataFloating; template struct IsMetadataFloating : std::false_type {}; template <> struct IsMetadataFloating : std::true_type {}; template <> struct IsMetadataFloating : std::true_type {}; +/** + * @brief Check if a C++ type can be represented as a vecN type. + */ +template struct IsMetadataVecN; +template struct IsMetadataVecN : std::false_type {}; +template +struct IsMetadataVecN> : IsMetadataScalar {}; + +/** + * @brief Check if a C++ type can be represented as a matN type. + */ +template struct IsMetadataMatN; +template struct IsMetadataMatN : std::false_type {}; +template +struct IsMetadataMatN> : IsMetadataScalar {}; + +/** + * @brief Check if a C++ type can be represented as a numeric property, i.e. + * a scalar / vecN / matN type. + */ +template struct IsMetadataNumeric; +template struct IsMetadataNumeric { + static constexpr bool value = IsMetadataScalar::value || + IsMetadataVecN::value || + IsMetadataMatN::value; +}; + /** * @brief Check if a C++ type can be represented as a boolean property type */ @@ -66,35 +95,35 @@ template <> struct IsMetadataString : std::true_type {}; template struct IsMetadataArray; template struct IsMetadataArray : std::false_type {}; template -struct IsMetadataArray> : std::true_type {}; +struct IsMetadataArray> : std::true_type {}; /** - * @brief Check if a C++ type can be represented as an array of number property - * type + * @brief Check if a C++ type can be represented as an array of numeric elements + * property type */ template struct IsMetadataNumericArray; template struct IsMetadataNumericArray : std::false_type {}; -template struct IsMetadataNumericArray> { +template struct IsMetadataNumericArray> { static constexpr bool value = IsMetadataNumeric::value; }; /** - * @brief Check if a C++ type can be represented as an array of boolean property - * type + * @brief Check if a C++ type can be represented as an array of booleans + * property type */ template struct IsMetadataBooleanArray; template struct IsMetadataBooleanArray : std::false_type {}; template <> -struct IsMetadataBooleanArray> : std::true_type {}; +struct IsMetadataBooleanArray> : std::true_type {}; /** - * @brief Check if a C++ type can be represented as an array of string property + * @brief Check if a C++ type can be represented as an array of strings property * type */ template struct IsMetadataStringArray; template struct IsMetadataStringArray : std::false_type {}; template <> -struct IsMetadataStringArray> +struct IsMetadataStringArray> : std::true_type {}; /** @@ -102,79 +131,137 @@ struct IsMetadataStringArray> */ template struct MetadataArrayType; template -struct MetadataArrayType> { +struct MetadataArrayType> { using type = T; }; /** - * @brief Convert a C++ type to PropertyType + * @brief Convert a C++ type to PropertyType and PropertyComponentType */ template struct TypeToPropertyType; +#pragma region Scalar Property Types + template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; - static constexpr PropertyType value = PropertyType::Uint8; + static constexpr PropertyComponentType component = + PropertyComponentType::Uint8; + static constexpr PropertyType value = PropertyType::Scalar; }; template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; - static constexpr PropertyType value = PropertyType::Int8; + static constexpr PropertyComponentType component = + PropertyComponentType::Int8; + static constexpr PropertyType value = PropertyType::Scalar; }; template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; - static constexpr PropertyType value = PropertyType::Uint16; + static constexpr PropertyComponentType component = + PropertyComponentType::Uint16; + static constexpr PropertyType value = PropertyType::Scalar; }; template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; - static constexpr PropertyType value = PropertyType::Int16; + static constexpr PropertyComponentType component = + PropertyComponentType::Int16; + static constexpr PropertyType value = PropertyType::Scalar; }; template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; - static constexpr PropertyType value = PropertyType::Uint32; + static constexpr PropertyComponentType component = + PropertyComponentType::Uint32; + static constexpr PropertyType value = PropertyType::Scalar; }; template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; - static constexpr PropertyType value = PropertyType::Int32; + static constexpr PropertyComponentType component = + PropertyComponentType::Int32; + static constexpr PropertyType value = PropertyType::Scalar; }; template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; - static constexpr PropertyType value = PropertyType::Uint64; + static constexpr PropertyComponentType component = + PropertyComponentType::Uint64; + static constexpr PropertyType value = PropertyType::Scalar; }; template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; - static constexpr PropertyType value = PropertyType::Int64; + static constexpr PropertyComponentType component = + PropertyComponentType::Int64; + static constexpr PropertyType value = PropertyType::Scalar; }; template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; - static constexpr PropertyType value = PropertyType::Float32; + static constexpr PropertyComponentType component = + PropertyComponentType::Float32; + static constexpr PropertyType value = PropertyType::Scalar; }; template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; - static constexpr PropertyType value = PropertyType::Float64; + static constexpr PropertyComponentType component = + PropertyComponentType::Float64; + static constexpr PropertyType value = PropertyType::Scalar; }; +#pragma endregion + +#pragma region Vector Property Types + +template +struct TypeToPropertyType> { + static constexpr PropertyComponentType component = + TypeToPropertyType::component; + static constexpr PropertyType value = PropertyType::Vec2; +}; + +template +struct TypeToPropertyType> { + static constexpr PropertyComponentType component = + TypeToPropertyType::component; + static constexpr PropertyType value = PropertyType::Vec3; +}; + +template +struct TypeToPropertyType> { + static constexpr PropertyComponentType component = + TypeToPropertyType::component; + static constexpr PropertyType value = PropertyType::Vec4; +}; + +#pragma endregion + +#pragma region Matrix Property Types + +template +struct TypeToPropertyType> { + static constexpr PropertyComponentType component = + TypeToPropertyType::component; + static constexpr PropertyType value = PropertyType::Mat2; +}; + +template +struct TypeToPropertyType> { + static constexpr PropertyComponentType component = + TypeToPropertyType::component; + static constexpr PropertyType value = PropertyType::Mat3; +}; + +template +struct TypeToPropertyType> { + static constexpr PropertyComponentType component = + TypeToPropertyType::component; + static constexpr PropertyType value = PropertyType::Mat4; +}; + +#pragma endregion template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; + static constexpr PropertyComponentType component = + PropertyComponentType::None; static constexpr PropertyType value = PropertyType::Boolean; }; template <> struct TypeToPropertyType { - static constexpr PropertyType component = PropertyType::None; + static constexpr PropertyComponentType component = + PropertyComponentType::None; static constexpr PropertyType value = PropertyType::String; }; - -template -struct TypeToPropertyType> { - static constexpr PropertyType component = TypeToPropertyType::value; - static constexpr PropertyType value = PropertyType::Array; -}; - } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h deleted file mode 100644 index 4648c7c12..000000000 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyType.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace CesiumGltf { -namespace StructuralMetadata { - -enum class PropertyType { - Invalid, - Scalar, - Vec2, - Vec3, - Vec4, - Mat2, - Mat3, - Mat4, - String, - Boolean, - Enum -}; - -enum class PropertyComponentType { - None, - Int8, - Uint8, - Int16, - Uint16, - Int32, - Uint32, - Int64, - Uint64, - Float32, - Float64, -}; - -std::string convertPropertyTypeToString(PropertyType type); - -PropertyType convertStringToPropertyType(const std::string& str); - -std::string -convertPropertyComponentTypeToString(PropertyComponentType componentType); - -PropertyComponentType -convertStringToPropertyComponentType(const std::string& str); - -PropertyComponentType -convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str); - -PropertyComponentType -convertStringOffsetTypeStringToPropertyComponentType(const std::string& str); - -bool isPropertyTypeVecN(PropertyType type); - -bool isPropertyTypeMatN(PropertyType type); - -} // namespace StructuralMetadata -} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h deleted file mode 100644 index 535667d9a..000000000 --- a/CesiumGltf/include/CesiumGltf/StructuralMetadataPropertyTypeTraits.h +++ /dev/null @@ -1,271 +0,0 @@ -#pragma once - -#include "CesiumGltf/StructuralMetadataArrayView.h" -#include "CesiumGltf/StructuralMetadataPropertyType.h" - -#include - -#include -#include - -namespace CesiumGltf { -namespace StructuralMetadata { - -/** - * @brief Check if a C++ type can be represented as a scalar property type - */ -template struct IsMetadataScalar; -template struct IsMetadataScalar : std::false_type {}; -template <> struct IsMetadataScalar : std::true_type {}; -template <> struct IsMetadataScalar : std::true_type {}; -template <> struct IsMetadataScalar : std::true_type {}; -template <> struct IsMetadataScalar : std::true_type {}; -template <> struct IsMetadataScalar : std::true_type {}; -template <> struct IsMetadataScalar : std::true_type {}; -template <> struct IsMetadataScalar : std::true_type {}; -template <> struct IsMetadataScalar : std::true_type {}; -template <> struct IsMetadataScalar : std::true_type {}; -template <> struct IsMetadataScalar : std::true_type {}; - -/** - * @brief Check if a C++ type can be represented as an integer property type - */ -template struct IsMetadataInteger; -template struct IsMetadataInteger : std::false_type {}; -template <> struct IsMetadataInteger : std::true_type {}; -template <> struct IsMetadataInteger : std::true_type {}; -template <> struct IsMetadataInteger : std::true_type {}; -template <> struct IsMetadataInteger : std::true_type {}; -template <> struct IsMetadataInteger : std::true_type {}; -template <> struct IsMetadataInteger : std::true_type {}; -template <> struct IsMetadataInteger : std::true_type {}; -template <> struct IsMetadataInteger : std::true_type {}; - -/** - * @brief Check if a C++ type can be represented as a floating-point property - * type. - */ -template struct IsMetadataFloating; -template struct IsMetadataFloating : std::false_type {}; -template <> struct IsMetadataFloating : std::true_type {}; -template <> struct IsMetadataFloating : std::true_type {}; - -/** - * @brief Check if a C++ type can be represented as a vecN type. - */ -template struct IsMetadataVecN; -template struct IsMetadataVecN : std::false_type {}; -template -struct IsMetadataVecN> : IsMetadataScalar {}; - -/** - * @brief Check if a C++ type can be represented as a matN type. - */ -template struct IsMetadataMatN; -template struct IsMetadataMatN : std::false_type {}; -template -struct IsMetadataMatN> : IsMetadataScalar {}; - -/** - * @brief Check if a C++ type can be represented as a numeric property, i.e. - * a scalar / vecN / matN type. - */ -template struct IsMetadataNumeric; -template struct IsMetadataNumeric { - static constexpr bool value = IsMetadataScalar::value || - IsMetadataVecN::value || - IsMetadataMatN::value; -}; - -/** - * @brief Check if a C++ type can be represented as a boolean property type - */ -template struct IsMetadataBoolean; -template struct IsMetadataBoolean : std::false_type {}; -template <> struct IsMetadataBoolean : std::true_type {}; - -/** - * @brief Check if a C++ type can be represented as a string property type - */ -template struct IsMetadataString; -template struct IsMetadataString : std::false_type {}; -template <> struct IsMetadataString : std::true_type {}; - -/** - * @brief Check if a C++ type can be represented as an array. - */ -template struct IsMetadataArray; -template struct IsMetadataArray : std::false_type {}; -template -struct IsMetadataArray> : std::true_type {}; - -/** - * @brief Check if a C++ type can be represented as an array of numeric elements - * property type - */ -template struct IsMetadataNumericArray; -template struct IsMetadataNumericArray : std::false_type {}; -template struct IsMetadataNumericArray> { - static constexpr bool value = IsMetadataNumeric::value; -}; - -/** - * @brief Check if a C++ type can be represented as an array of booleans - * property type - */ -template struct IsMetadataBooleanArray; -template struct IsMetadataBooleanArray : std::false_type {}; -template <> -struct IsMetadataBooleanArray> : std::true_type {}; - -/** - * @brief Check if a C++ type can be represented as an array of strings property - * type - */ -template struct IsMetadataStringArray; -template struct IsMetadataStringArray : std::false_type {}; -template <> -struct IsMetadataStringArray> - : std::true_type {}; - -/** - * @brief Retrieve the component type of a metadata array - */ -template struct MetadataArrayType; -template -struct MetadataArrayType> { - using type = T; -}; - -/** - * @brief Convert a C++ type to PropertyType and PropertyComponentType - */ -template struct TypeToPropertyType; - -#pragma region Scalar Property Types - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint8; - static constexpr PropertyType value = PropertyType::Scalar; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int8; - static constexpr PropertyType value = PropertyType::Scalar; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint16; - static constexpr PropertyType value = PropertyType::Scalar; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int16; - static constexpr PropertyType value = PropertyType::Scalar; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint32; - static constexpr PropertyType value = PropertyType::Scalar; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int32; - static constexpr PropertyType value = PropertyType::Scalar; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Uint64; - static constexpr PropertyType value = PropertyType::Scalar; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Int64; - static constexpr PropertyType value = PropertyType::Scalar; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float32; - static constexpr PropertyType value = PropertyType::Scalar; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::Float64; - static constexpr PropertyType value = PropertyType::Scalar; -}; -#pragma endregion - -#pragma region Vector Property Types - -template -struct TypeToPropertyType> { - static constexpr PropertyComponentType component = - TypeToPropertyType::component; - static constexpr PropertyType value = PropertyType::Vec2; -}; - -template -struct TypeToPropertyType> { - static constexpr PropertyComponentType component = - TypeToPropertyType::component; - static constexpr PropertyType value = PropertyType::Vec3; -}; - -template -struct TypeToPropertyType> { - static constexpr PropertyComponentType component = - TypeToPropertyType::component; - static constexpr PropertyType value = PropertyType::Vec4; -}; - -#pragma endregion - -#pragma region Matrix Property Types - -template -struct TypeToPropertyType> { - static constexpr PropertyComponentType component = - TypeToPropertyType::component; - static constexpr PropertyType value = PropertyType::Mat2; -}; - -template -struct TypeToPropertyType> { - static constexpr PropertyComponentType component = - TypeToPropertyType::component; - static constexpr PropertyType value = PropertyType::Mat3; -}; - -template -struct TypeToPropertyType> { - static constexpr PropertyComponentType component = - TypeToPropertyType::component; - static constexpr PropertyType value = PropertyType::Mat4; -}; - -#pragma endregion - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::None; - static constexpr PropertyType value = PropertyType::Boolean; -}; - -template <> struct TypeToPropertyType { - static constexpr PropertyComponentType component = - PropertyComponentType::None; - static constexpr PropertyType value = PropertyType::String; -}; - -} // namespace StructuralMetadata -} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h b/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h index 431430bf4..762f698cc 100644 --- a/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h +++ b/CesiumGltf/include/CesiumGltf/getOffsetFromOffsetsBuffer.h @@ -1,6 +1,6 @@ #pragma once -#include "CesiumGltf/StructuralMetadataPropertyType.h" +#include "CesiumGltf/PropertyType.h" #include @@ -10,8 +10,6 @@ #include namespace CesiumGltf { -namespace StructuralMetadata { - static size_t getOffsetFromOffsetsBuffer( size_t index, const gsl::span& offsetBuffer, @@ -46,6 +44,4 @@ static size_t getOffsetFromOffsetsBuffer( return 0; } } - -} // namespace StructuralMetadata } // namespace CesiumGltf diff --git a/CesiumGltf/src/FeatureIDTextureView.cpp b/CesiumGltf/src/FeatureIDTextureView.cpp deleted file mode 100644 index 2847314c3..000000000 --- a/CesiumGltf/src/FeatureIDTextureView.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "CesiumGltf/FeatureIDTextureView.h" - -namespace CesiumGltf { - -FeatureIDTextureView::FeatureIDTextureView() noexcept - : _pImage(nullptr), - _channel(0), - _textureCoordinateAttributeId(-1), - _featureTableName(), - _status(FeatureIDTextureViewStatus::InvalidUninitialized) {} - -FeatureIDTextureView::FeatureIDTextureView( - const Model& model, - const FeatureIDTexture& featureIDTexture) noexcept - : _pImage(nullptr), - _channel(0), - _textureCoordinateAttributeId(-1), - _featureTableName(featureIDTexture.featureTable), - _status(FeatureIDTextureViewStatus::InvalidUninitialized) { - - this->_textureCoordinateAttributeId = - featureIDTexture.featureIds.texture.texCoord; - - int32_t textureIndex = featureIDTexture.featureIds.texture.index; - if (textureIndex < 0 || - static_cast(textureIndex) >= model.textures.size()) { - this->_status = FeatureIDTextureViewStatus::InvalidTextureIndex; - return; - } - - const Texture& texture = model.textures[static_cast(textureIndex)]; - - // Ignore sampler, we will always use nearest pixel sampling. - if (texture.source < 0 || - static_cast(texture.source) >= model.images.size()) { - this->_status = FeatureIDTextureViewStatus::InvalidImageIndex; - return; - } - - this->_pImage = &model.images[static_cast(texture.source)].cesium; - - // This assumes that if the channel is g, there must be at least two - // channels (r and g). If it is b there must be r, g, and b. If there is a, - // then there must be r, g, b, and a. - if (featureIDTexture.featureIds.channels == "r") { - this->_channel = 0; - } else if (featureIDTexture.featureIds.channels == "g") { - this->_channel = 1; - } else if (featureIDTexture.featureIds.channels == "b") { - this->_channel = 2; - } else if (featureIDTexture.featureIds.channels == "a") { - this->_channel = 3; - } else { - this->_status = FeatureIDTextureViewStatus::InvalidChannel; - return; - } - - if (this->_pImage->width < 1 || this->_pImage->height < 1) { - this->_status = FeatureIDTextureViewStatus::InvalidEmptyImage; - return; - } - - // TODO: once compressed texture support is merged, check that the image is - // decompressed here. - - this->_status = FeatureIDTextureViewStatus::Valid; -} - -int64_t FeatureIDTextureView::getFeatureID(double u, double v) const noexcept { - if (this->_status != FeatureIDTextureViewStatus::Valid) { - return -1; - } - - int64_t x = std::clamp( - std::llround(u * this->_pImage->width), - 0LL, - (long long)this->_pImage->width); - int64_t y = std::clamp( - std::llround(v * this->_pImage->height), - 0LL, - (long long)this->_pImage->height); - - int64_t pixelOffset = this->_pImage->bytesPerChannel * - this->_pImage->channels * - (y * this->_pImage->width + x); - - return static_cast( - this->_pImage - ->pixelData[static_cast(pixelOffset + this->_channel)]); -} -} // namespace CesiumGltf \ No newline at end of file diff --git a/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp b/CesiumGltf/src/FeatureIdTextureView.cpp similarity index 96% rename from CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp rename to CesiumGltf/src/FeatureIdTextureView.cpp index 0727e091f..589f98ac2 100644 --- a/CesiumGltf/src/MeshFeaturesFeatureIdTextureView.cpp +++ b/CesiumGltf/src/FeatureIdTextureView.cpp @@ -1,7 +1,6 @@ -#include "CesiumGltf/MeshFeaturesFeatureIdTextureView.h" +#include "CesiumGltf/FeatureIdTextureView.h" namespace CesiumGltf { -namespace MeshFeatures { FeatureIdTextureView::FeatureIdTextureView() noexcept : _status(FeatureIdTextureViewStatus::ErrorUninitialized), _texCoordSetIndex(-1), @@ -104,6 +103,4 @@ int64_t FeatureIdTextureView::getFeatureId(double u, double v) const noexcept { return value; } - -} // namespace MeshFeatures } // namespace CesiumGltf diff --git a/CesiumGltf/src/FeatureTexturePropertyView.cpp b/CesiumGltf/src/FeatureTexturePropertyView.cpp deleted file mode 100644 index 0fe9d7e3c..000000000 --- a/CesiumGltf/src/FeatureTexturePropertyView.cpp +++ /dev/null @@ -1,101 +0,0 @@ - -#include "CesiumGltf/FeatureTexturePropertyView.h" - -namespace CesiumGltf { - -FeatureTexturePropertyView::FeatureTexturePropertyView() noexcept - : _pSampler(nullptr), - _pImage(nullptr), - _pClassProperty(nullptr), - _pSwizzle(nullptr), - _textureCoordinateAttributeId(-1), - _status(FeatureTexturePropertyViewStatus::InvalidUninitialized), - _channelOffsets(), - _type(FeatureTexturePropertyComponentType::Uint8), - _componentCount(0), - _normalized(false) {} - -FeatureTexturePropertyView::FeatureTexturePropertyView( - const Model& model, - const ClassProperty& classProperty, - const TextureAccessor& textureAccessor) noexcept - : _pSampler(nullptr), - _pImage(nullptr), - _pClassProperty(&classProperty), - _pSwizzle(&textureAccessor.channels), - _textureCoordinateAttributeId(textureAccessor.texture.texCoord), - _status(FeatureTexturePropertyViewStatus::InvalidUninitialized), - _channelOffsets(), - _type(FeatureTexturePropertyComponentType::Uint8), - _componentCount(0), - _normalized(false) { - - if (textureAccessor.texture.index < 0 || - static_cast(textureAccessor.texture.index) >= - model.textures.size()) { - this->_status = FeatureTexturePropertyViewStatus::InvalidTextureIndex; - return; - } - - const Texture& texture = - model.textures[static_cast(textureAccessor.texture.index)]; - if (texture.sampler < 0 || - static_cast(texture.sampler) >= model.samplers.size()) { - this->_status = - FeatureTexturePropertyViewStatus::InvalidTextureSamplerIndex; - return; - } - - this->_pSampler = &model.samplers[static_cast(texture.sampler)]; - - if (texture.source < 0 || - static_cast(texture.source) >= model.images.size()) { - this->_status = FeatureTexturePropertyViewStatus::InvalidImageIndex; - return; - } - - this->_pImage = &model.images[static_cast(texture.source)].cesium; - - if (this->_pImage->width < 1 || this->_pImage->height < 1) { - this->_status = FeatureTexturePropertyViewStatus::InvalidEmptyImage; - return; - } - - // TODO: support more types - // this->_type = ... - this->_componentCount = this->_pClassProperty->componentCount - ? *this->_pClassProperty->componentCount - : 1; - this->_normalized = this->_pClassProperty->normalized; - if (textureAccessor.channels.length() > 4 || - textureAccessor.channels.length() > - static_cast(this->_pImage->channels) || - textureAccessor.channels.length() != - static_cast(this->_componentCount)) { - this->_status = FeatureTexturePropertyViewStatus::InvalidChannelsString; - return; - } - - for (size_t i = 0; i < textureAccessor.channels.length(); ++i) { - switch (textureAccessor.channels[i]) { - case 'r': - this->_channelOffsets.r = 0; - break; - case 'g': - this->_channelOffsets.g = 1; - break; - case 'b': - this->_channelOffsets.b = 2; - break; - case 'a': - this->_channelOffsets.a = 3; - break; - default: - this->_status = FeatureTexturePropertyViewStatus::InvalidChannelsString; - return; - } - } - - this->_status = FeatureTexturePropertyViewStatus::Valid; -} -} // namespace CesiumGltf \ No newline at end of file diff --git a/CesiumGltf/src/FeatureTextureView.cpp b/CesiumGltf/src/FeatureTextureView.cpp deleted file mode 100644 index 3ef0bfb55..000000000 --- a/CesiumGltf/src/FeatureTextureView.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "CesiumGltf/FeatureTextureView.h" - -namespace CesiumGltf { - -FeatureTextureView::FeatureTextureView() noexcept - : _pModel(nullptr), - _pFeatureTexture(nullptr), - _pClass(nullptr), - _propertyViews(), - _status(FeatureTextureViewStatus::InvalidUninitialized) {} - -FeatureTextureView::FeatureTextureView( - const Model& model, - const FeatureTexture& featureTexture) noexcept - : _pModel(&model), - _pFeatureTexture(&featureTexture), - _pClass(nullptr), - _propertyViews(), - _status(FeatureTextureViewStatus::InvalidUninitialized) { - - const ExtensionModelExtFeatureMetadata* pMetadata = - model.getExtension(); - - if (!pMetadata) { - this->_status = FeatureTextureViewStatus::InvalidMissingMetadataExtension; - return; - } - - if (!pMetadata->schema) { - this->_status = FeatureTextureViewStatus::InvalidMissingSchema; - return; - } - - const auto& classIt = - pMetadata->schema->classes.find(featureTexture.classProperty); - if (classIt == pMetadata->schema->classes.end()) { - this->_status = FeatureTextureViewStatus::InvalidClassNotFound; - return; - } - - this->_pClass = &classIt->second; - - this->_propertyViews.reserve(featureTexture.properties.size()); - for (const auto& property : featureTexture.properties) { - auto classPropertyIt = this->_pClass->properties.find(property.first); - - if (classPropertyIt == this->_pClass->properties.end()) { - this->_status = FeatureTextureViewStatus::InvalidClassPropertyNotFound; - return; - } - - this->_propertyViews[property.first] = FeatureTexturePropertyView( - model, - classPropertyIt->second, - property.second); - } - - for (const auto& propertyView : this->_propertyViews) { - if (propertyView.second.status() != - FeatureTexturePropertyViewStatus::Valid) { - this->_status = FeatureTextureViewStatus::InvalidPropertyViewStatus; - return; - } - } - - this->_status = FeatureTextureViewStatus::Valid; -} -} // namespace CesiumGltf \ No newline at end of file diff --git a/CesiumGltf/src/MetadataFeatureTableView.cpp b/CesiumGltf/src/MetadataFeatureTableView.cpp deleted file mode 100644 index 5c403e8c0..000000000 --- a/CesiumGltf/src/MetadataFeatureTableView.cpp +++ /dev/null @@ -1,386 +0,0 @@ -#include "CesiumGltf/MetadataFeatureTableView.h" - -namespace CesiumGltf { -template -static MetadataPropertyViewStatus checkOffsetBuffer( - const gsl::span& offsetBuffer, - size_t valueBufferSize, - size_t instanceCount, - bool checkBitSize) noexcept { - if (offsetBuffer.size() % sizeof(T) != 0) { - return MetadataPropertyViewStatus:: - InvalidBufferViewSizeNotDivisibleByTypeSize; - } - - const size_t size = offsetBuffer.size() / sizeof(T); - if (size != instanceCount + 1) { - return MetadataPropertyViewStatus::InvalidBufferViewSizeNotFitInstanceCount; - } - - const gsl::span offsetValues( - reinterpret_cast(offsetBuffer.data()), - size); - - for (size_t i = 1; i < offsetValues.size(); ++i) { - if (offsetValues[i] < offsetValues[i - 1]) { - return MetadataPropertyViewStatus::InvalidOffsetValuesNotSortedAscending; - } - } - - if (!checkBitSize) { - if (offsetValues.back() <= valueBufferSize) { - return MetadataPropertyViewStatus::Valid; - } else { - return MetadataPropertyViewStatus:: - InvalidOffsetValuePointsToOutOfBoundBuffer; - } - } - - if (offsetValues.back() / 8 <= valueBufferSize) { - return MetadataPropertyViewStatus::Valid; - } else { - return MetadataPropertyViewStatus:: - InvalidOffsetValuePointsToOutOfBoundBuffer; - } -} - -template -static MetadataPropertyViewStatus checkStringArrayOffsetBuffer( - const gsl::span& arrayOffsetBuffer, - const gsl::span& stringOffsetBuffer, - size_t valueBufferSize, - size_t instanceCount) noexcept { - const auto status = checkOffsetBuffer( - arrayOffsetBuffer, - stringOffsetBuffer.size(), - instanceCount, - false); - if (status != MetadataPropertyViewStatus::Valid) { - return status; - } - - const T* pValue = reinterpret_cast(arrayOffsetBuffer.data()); - return checkOffsetBuffer( - stringOffsetBuffer, - valueBufferSize, - pValue[instanceCount] / sizeof(T), - false); -} - -MetadataFeatureTableView::MetadataFeatureTableView( - const Model* pModel, - const FeatureTable* pFeatureTable) - : _pModel{pModel}, _pFeatureTable{pFeatureTable}, _pClass{nullptr} { - assert(pModel != nullptr && "model must not be nullptr"); - assert(pFeatureTable != nullptr && "featureTable must not be nullptr"); - - const ExtensionModelExtFeatureMetadata* pMetadata = - pModel->getExtension(); - assert( - pMetadata != nullptr && - "Model must contain ExtensionModelExtFeatureMetadata to use " - "FeatureTableView"); - - const std::optional& schema = pMetadata->schema; - assert( - schema != std::nullopt && "ExtensionModelExtFeatureMetadata must contain " - "Schema to use FeatureTableView"); - - auto classIter = - schema->classes.find(_pFeatureTable->classProperty.value_or("")); - if (classIter != schema->classes.end()) { - _pClass = &classIter->second; - } -} - -const ClassProperty* MetadataFeatureTableView::getClassProperty( - const std::string& propertyName) const { - if (_pClass == nullptr) { - return nullptr; - } - - auto propertyIter = _pClass->properties.find(propertyName); - if (propertyIter == _pClass->properties.end()) { - return nullptr; - } - - return &propertyIter->second; -} - -MetadataPropertyViewStatus MetadataFeatureTableView::getBufferSafe( - int32_t bufferViewIdx, - gsl::span& buffer) const noexcept { - buffer = {}; - - const BufferView* pBufferView = - _pModel->getSafe(&_pModel->bufferViews, bufferViewIdx); - if (!pBufferView) { - return MetadataPropertyViewStatus::InvalidValueBufferViewIndex; - } - - const Buffer* pBuffer = - _pModel->getSafe(&_pModel->buffers, pBufferView->buffer); - if (!pBuffer) { - return MetadataPropertyViewStatus::InvalidValueBufferIndex; - } - - // This is technically required for the EXT_feature_metadata spec, but not - // necessarily required for EXT_mesh_features. Due to the discrepancy between - // the two specs, a lot of EXT_feature_metadata glTFs fail to be 8-byte - // aligned. To be forgiving and more compatible, we do not enforce this. - /* - if (pBufferView->byteOffset % 8 != 0) { - return MetadataPropertyViewStatus::InvalidBufferViewNotAligned8Bytes; - } - */ - - if (pBufferView->byteOffset + pBufferView->byteLength > - static_cast(pBuffer->cesium.data.size())) { - return MetadataPropertyViewStatus::InvalidBufferViewOutOfBound; - } - - buffer = gsl::span( - pBuffer->cesium.data.data() + pBufferView->byteOffset, - static_cast(pBufferView->byteLength)); - return MetadataPropertyViewStatus::Valid; -} - -MetadataPropertyViewStatus MetadataFeatureTableView::getOffsetBufferSafe( - int32_t bufferViewIdx, - PropertyType offsetType, - size_t valueBufferSize, - size_t instanceCount, - bool checkBitsSize, - gsl::span& offsetBuffer) const noexcept { - auto status = getBufferSafe(bufferViewIdx, offsetBuffer); - if (status != MetadataPropertyViewStatus::Valid) { - return status; - } - - switch (offsetType) { - case PropertyType::Uint8: - status = checkOffsetBuffer( - offsetBuffer, - valueBufferSize, - instanceCount, - checkBitsSize); - break; - case PropertyType::Uint16: - status = checkOffsetBuffer( - offsetBuffer, - valueBufferSize, - instanceCount, - checkBitsSize); - break; - case PropertyType::Uint32: - status = checkOffsetBuffer( - offsetBuffer, - valueBufferSize, - instanceCount, - checkBitsSize); - break; - case PropertyType::Uint64: - status = checkOffsetBuffer( - offsetBuffer, - valueBufferSize, - instanceCount, - checkBitsSize); - break; - default: - status = MetadataPropertyViewStatus::InvalidOffsetType; - break; - } - - return status; -} - -MetadataPropertyView -MetadataFeatureTableView::getStringPropertyValues( - const ClassProperty& classProperty, - const FeatureTableProperty& featureTableProperty) const { - if (classProperty.type != ClassProperty::Type::STRING) { - return createInvalidPropertyView( - MetadataPropertyViewStatus::InvalidTypeMismatch); - } - - gsl::span valueBuffer; - auto status = getBufferSafe(featureTableProperty.bufferView, valueBuffer); - if (status != MetadataPropertyViewStatus::Valid) { - return createInvalidPropertyView(status); - } - - const PropertyType offsetType = - convertOffsetStringToPropertyType(featureTableProperty.offsetType); - if (offsetType == PropertyType::None) { - return createInvalidPropertyView( - MetadataPropertyViewStatus::InvalidOffsetType); - } - - gsl::span offsetBuffer; - status = getOffsetBufferSafe( - featureTableProperty.stringOffsetBufferView, - offsetType, - valueBuffer.size(), - static_cast(_pFeatureTable->count), - false, - offsetBuffer); - if (status != MetadataPropertyViewStatus::Valid) { - return createInvalidPropertyView(status); - } - - return MetadataPropertyView( - MetadataPropertyViewStatus::Valid, - valueBuffer, - gsl::span(), - offsetBuffer, - offsetType, - 0, - _pFeatureTable->count, - classProperty.normalized); -} - -MetadataPropertyView> -MetadataFeatureTableView::getStringArrayPropertyValues( - const ClassProperty& classProperty, - const FeatureTableProperty& featureTableProperty) const { - if (classProperty.type != ClassProperty::Type::ARRAY) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus::InvalidTypeMismatch); - } - - if (classProperty.componentType != ClassProperty::ComponentType::STRING) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus::InvalidTypeMismatch); - } - - // get value buffer - gsl::span valueBuffer; - auto status = getBufferSafe(featureTableProperty.bufferView, valueBuffer); - if (status != MetadataPropertyViewStatus::Valid) { - return createInvalidPropertyView>( - status); - } - - // check fixed or dynamic array - const int64_t componentCount = classProperty.componentCount.value_or(0); - if (componentCount > 0 && featureTableProperty.arrayOffsetBufferView >= 0) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus:: - InvalidArrayComponentCountAndOffsetBufferCoexist); - } - - if (componentCount <= 0 && featureTableProperty.arrayOffsetBufferView < 0) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus:: - InvalidArrayComponentCountOrOffsetBufferNotExist); - } - - // get offset type - const PropertyType offsetType = - convertOffsetStringToPropertyType(featureTableProperty.offsetType); - if (offsetType == PropertyType::None) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus::InvalidOffsetType); - } - - // get string offset buffer - if (featureTableProperty.stringOffsetBufferView < 0) { - return createInvalidPropertyView>( - MetadataPropertyViewStatus::InvalidStringOffsetBufferViewIndex); - } - - // fixed array - if (componentCount > 0) { - gsl::span stringOffsetBuffer; - status = getOffsetBufferSafe( - featureTableProperty.stringOffsetBufferView, - offsetType, - valueBuffer.size(), - static_cast(_pFeatureTable->count * componentCount), - false, - stringOffsetBuffer); - if (status != MetadataPropertyViewStatus::Valid) { - return createInvalidPropertyView>( - status); - } - - return MetadataPropertyView>( - MetadataPropertyViewStatus::Valid, - valueBuffer, - gsl::span(), - stringOffsetBuffer, - offsetType, - componentCount, - _pFeatureTable->count, - classProperty.normalized); - } - - // dynamic array - gsl::span stringOffsetBuffer; - status = getBufferSafe( - featureTableProperty.stringOffsetBufferView, - stringOffsetBuffer); - if (status != MetadataPropertyViewStatus::Valid) { - return createInvalidPropertyView>( - status); - } - - gsl::span arrayOffsetBuffer; - status = getBufferSafe( - featureTableProperty.arrayOffsetBufferView, - arrayOffsetBuffer); - if (status != MetadataPropertyViewStatus::Valid) { - return createInvalidPropertyView>( - status); - } - - switch (offsetType) { - case PropertyType::Uint8: - status = checkStringArrayOffsetBuffer( - arrayOffsetBuffer, - stringOffsetBuffer, - valueBuffer.size(), - static_cast(_pFeatureTable->count)); - break; - case PropertyType::Uint16: - status = checkStringArrayOffsetBuffer( - arrayOffsetBuffer, - stringOffsetBuffer, - valueBuffer.size(), - static_cast(_pFeatureTable->count)); - break; - case PropertyType::Uint32: - status = checkStringArrayOffsetBuffer( - arrayOffsetBuffer, - stringOffsetBuffer, - valueBuffer.size(), - static_cast(_pFeatureTable->count)); - break; - case PropertyType::Uint64: - status = checkStringArrayOffsetBuffer( - arrayOffsetBuffer, - stringOffsetBuffer, - valueBuffer.size(), - static_cast(_pFeatureTable->count)); - break; - default: - status = MetadataPropertyViewStatus::InvalidOffsetType; - break; - } - - if (status != MetadataPropertyViewStatus::Valid) { - return createInvalidPropertyView>( - status); - } - - return MetadataPropertyView>( - MetadataPropertyViewStatus::Valid, - valueBuffer, - arrayOffsetBuffer, - stringOffsetBuffer, - offsetType, - 0, - _pFeatureTable->count, - classProperty.normalized); -} -} // namespace CesiumGltf diff --git a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp b/CesiumGltf/src/PropertyTableView.cpp similarity index 93% rename from CesiumGltf/src/StructuralMetadataPropertyTableView.cpp rename to CesiumGltf/src/PropertyTableView.cpp index b6e58fa87..0e06b7d0f 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/src/PropertyTableView.cpp @@ -1,8 +1,6 @@ -#include "CesiumGltf/StructuralMetadataPropertyTableView.h" +#include "CesiumGltf/PropertyTableView.h" namespace CesiumGltf { -namespace StructuralMetadata { - template static PropertyTablePropertyViewStatus checkOffsetsBuffer( const gsl::span& offsetBuffer, @@ -333,38 +331,38 @@ PropertyTableView::getStringPropertyValues( classProperty.normalized); } -PropertyTablePropertyView> +PropertyTablePropertyView> PropertyTableView::getStringArrayPropertyValues( const ExtensionExtStructuralMetadataClassProperty& classProperty, const ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty) const { if (!classProperty.array) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } if (classProperty.type != ExtensionExtStructuralMetadataClassProperty::Type::STRING) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorTypeMismatch); } gsl::span values; auto status = getBufferSafe(propertyTableProperty.values, values); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( status); } // Check if array is fixed or variable length const int64_t fixedLengthArrayCount = classProperty.count.value_or(0); if (fixedLengthArrayCount > 0 && propertyTableProperty.arrayOffsets >= 0) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus:: ErrorArrayCountAndOffsetBufferDontExist); } @@ -374,12 +372,12 @@ PropertyTableView::getStringArrayPropertyValues( convertStringOffsetTypeStringToPropertyComponentType( propertyTableProperty.stringOffsetType); if (stringOffsetType == PropertyComponentType::None) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); } if (propertyTableProperty.stringOffsets < 0) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetBufferView); } @@ -393,11 +391,11 @@ PropertyTableView::getStringArrayPropertyValues( static_cast(_pPropertyTable->count * fixedLengthArrayCount), stringOffsets); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( status); } - return PropertyTablePropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::Valid, values, gsl::span(), @@ -414,12 +412,12 @@ PropertyTableView::getStringArrayPropertyValues( convertArrayOffsetTypeStringToPropertyComponentType( propertyTableProperty.arrayOffsetType); if (arrayOffsetType == PropertyComponentType::None) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } if (propertyTableProperty.arrayOffsets < 0) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetBufferView); } @@ -427,14 +425,14 @@ PropertyTableView::getStringArrayPropertyValues( gsl::span stringOffsets; status = getBufferSafe(propertyTableProperty.stringOffsets, stringOffsets); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( status); } gsl::span arrayOffsets; status = getBufferSafe(propertyTableProperty.arrayOffsets, arrayOffsets); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( status); } @@ -477,11 +475,11 @@ PropertyTableView::getStringArrayPropertyValues( } if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>( + return createInvalidPropertyView>( status); } - return PropertyTablePropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::Valid, values, arrayOffsets, @@ -492,6 +490,4 @@ PropertyTableView::getStringArrayPropertyValues( _pPropertyTable->count, classProperty.normalized); } - -} // namespace StructuralMetadata } // namespace CesiumGltf diff --git a/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp b/CesiumGltf/src/PropertyTexturePropertyView.cpp similarity index 96% rename from CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp rename to CesiumGltf/src/PropertyTexturePropertyView.cpp index 409c29166..d854468d2 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTexturePropertyView.cpp +++ b/CesiumGltf/src/PropertyTexturePropertyView.cpp @@ -1,8 +1,7 @@ -#include "CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h" +#include "CesiumGltf/PropertyTexturePropertyView.h" namespace CesiumGltf { -namespace StructuralMetadata { PropertyTexturePropertyView::PropertyTexturePropertyView() noexcept : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), _pClassProperty(nullptr), @@ -103,5 +102,4 @@ PropertyTexturePropertyView::PropertyTexturePropertyView( this->_status = PropertyTexturePropertyViewStatus::Valid; } -} // namespace StructuralMetadata } // namespace CesiumGltf diff --git a/CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp b/CesiumGltf/src/PropertyTextureView.cpp similarity index 94% rename from CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp rename to CesiumGltf/src/PropertyTextureView.cpp index 7ebcdab2a..7f917c8a9 100644 --- a/CesiumGltf/src/StructuralMetadataPropertyTextureView.cpp +++ b/CesiumGltf/src/PropertyTextureView.cpp @@ -1,7 +1,6 @@ -#include "CesiumGltf/StructuralMetadataPropertyTextureView.h" +#include "CesiumGltf/PropertyTextureView.h" namespace CesiumGltf { -namespace StructuralMetadata { PropertyTextureView::PropertyTextureView() noexcept : _pModel(nullptr), _pPropertyTexture(nullptr), @@ -80,6 +79,4 @@ PropertyTextureView::getClassProperty(const std::string& propertyName) const { return &propertyIter->second; } - -} // namespace StructuralMetadata } // namespace CesiumGltf diff --git a/CesiumGltf/src/PropertyType.cpp b/CesiumGltf/src/PropertyType.cpp index 91c0e9787..826997cf8 100644 --- a/CesiumGltf/src/PropertyType.cpp +++ b/CesiumGltf/src/PropertyType.cpp @@ -1,123 +1,220 @@ #include "CesiumGltf/PropertyType.h" -#include "CesiumGltf/ClassProperty.h" -#include "CesiumGltf/FeatureTable.h" +#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" +#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTable.h" namespace CesiumGltf { -std::string convertPropertyTypeToString(CesiumGltf::PropertyType type) { +std::string convertPropertyTypeToString(PropertyType type) { switch (type) { - case PropertyType::None: - return "NONE"; - case PropertyType::Uint8: - return ClassProperty::Type::UINT8; - case PropertyType::Int8: - return ClassProperty::Type::INT8; - case PropertyType::Uint16: - return ClassProperty::Type::UINT16; - case PropertyType::Int16: - return ClassProperty::Type::INT16; - case PropertyType::Uint32: - return ClassProperty::Type::UINT32; - case PropertyType::Int32: - return ClassProperty::Type::INT32; - case PropertyType::Uint64: - return ClassProperty::Type::UINT64; - case PropertyType::Int64: - return ClassProperty::Type::INT64; - case PropertyType::Float32: - return ClassProperty::Type::FLOAT32; - case PropertyType::Float64: - return ClassProperty::Type::FLOAT64; + case PropertyType::Scalar: + return ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + case PropertyType::Vec2: + return ExtensionExtStructuralMetadataClassProperty::Type::VEC2; + case PropertyType::Vec3: + return ExtensionExtStructuralMetadataClassProperty::Type::VEC3; + case PropertyType::Vec4: + return ExtensionExtStructuralMetadataClassProperty::Type::VEC4; + case PropertyType::Mat2: + return ExtensionExtStructuralMetadataClassProperty::Type::MAT2; + case PropertyType::Mat3: + return ExtensionExtStructuralMetadataClassProperty::Type::MAT3; + case PropertyType::Mat4: + return ExtensionExtStructuralMetadataClassProperty::Type::MAT4; case PropertyType::Boolean: - return ClassProperty::Type::BOOLEAN; + return ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; case PropertyType::Enum: - return ClassProperty::Type::ENUM; + return ExtensionExtStructuralMetadataClassProperty::Type::ENUM; case PropertyType::String: - return ClassProperty::Type::STRING; - case PropertyType::Array: - return ClassProperty::Type::ARRAY; + return ExtensionExtStructuralMetadataClassProperty::Type::STRING; default: - return "NONE"; + return "INVALID"; } } PropertyType convertStringToPropertyType(const std::string& str) { - if (str == ClassProperty::Type::UINT8) { - return PropertyType::Uint8; + if (str == ExtensionExtStructuralMetadataClassProperty::Type::SCALAR) { + return PropertyType::Scalar; } - if (str == ClassProperty::Type::INT8) { - return PropertyType::Int8; + if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC2) { + return PropertyType::Vec2; } - if (str == ClassProperty::Type::UINT16) { - return PropertyType::Uint16; + if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC3) { + return PropertyType::Vec3; } - if (str == ClassProperty::Type::INT16) { - return PropertyType::Int16; + if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC4) { + return PropertyType::Vec4; } - if (str == ClassProperty::Type::UINT32) { - return PropertyType::Uint32; + if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT2) { + return PropertyType::Mat2; } - if (str == ClassProperty::Type::INT32) { - return PropertyType::Int32; + if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT3) { + return PropertyType::Mat3; } - if (str == ClassProperty::Type::UINT64) { - return PropertyType::Uint64; + if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT4) { + return PropertyType::Mat4; } - if (str == ClassProperty::Type::INT64) { - return PropertyType::Int64; + if (str == ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN) { + return PropertyType::Boolean; } - if (str == ClassProperty::Type::FLOAT32) { - return PropertyType::Float32; + if (str == ExtensionExtStructuralMetadataClassProperty::Type::STRING) { + return PropertyType::String; } - if (str == ClassProperty::Type::FLOAT64) { - return PropertyType::Float64; + if (str == ExtensionExtStructuralMetadataClassProperty::Type::ENUM) { + return PropertyType::Enum; } - if (str == ClassProperty::Type::BOOLEAN) { - return PropertyType::Boolean; + return PropertyType::Invalid; +} + +std::string convertPropertyComponentTypeToString(PropertyComponentType type) { + switch (type) { + case PropertyComponentType::None: + return "NONE"; + case PropertyComponentType::Uint8: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + case PropertyComponentType::Int8: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8; + case PropertyComponentType::Uint16: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16; + case PropertyComponentType::Int16: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16; + case PropertyComponentType::Uint32: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + case PropertyComponentType::Int32: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + case PropertyComponentType::Uint64: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64; + case PropertyComponentType::Int64: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64; + case PropertyComponentType::Float32: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32; + case PropertyComponentType::Float64: + return ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64; + default: + return "NONE"; } +} - if (str == ClassProperty::Type::STRING) { - return PropertyType::String; +PropertyComponentType +convertStringToPropertyComponentType(const std::string& str) { + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8) { + return PropertyComponentType::Uint8; } - if (str == ClassProperty::Type::ENUM) { - return PropertyType::Enum; + if (str == ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8) { + return PropertyComponentType::Int8; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16) { + return PropertyComponentType::Uint16; } - if (str == ClassProperty::Type::ARRAY) { - return PropertyType::Array; + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16) { + return PropertyComponentType::Int16; } - return PropertyType::None; + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32) { + return PropertyComponentType::Uint32; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32) { + return PropertyComponentType::Int32; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64) { + return PropertyComponentType::Uint64; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64) { + return PropertyComponentType::Int64; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32) { + return PropertyComponentType::Float32; + } + + if (str == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64) { + return PropertyComponentType::Float64; + } + + return PropertyComponentType::None; } -PropertyType convertOffsetStringToPropertyType(const std::string& str) { - if (str == FeatureTableProperty::OffsetType::UINT8) { - return PropertyType::Uint8; +PropertyComponentType +convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str) { + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT8) { + return PropertyComponentType::Uint8; + } + + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT16) { + return PropertyComponentType::Uint16; } - if (str == FeatureTableProperty::OffsetType::UINT16) { - return PropertyType::Uint16; + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT32) { + return PropertyComponentType::Uint32; } - if (str == FeatureTableProperty::OffsetType::UINT32) { - return PropertyType::Uint32; + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT64) { + return PropertyComponentType::Uint64; } - if (str == FeatureTableProperty::OffsetType::UINT64) { - return PropertyType::Uint64; + return PropertyComponentType::None; +} + +PropertyComponentType +convertStringOffsetTypeStringToPropertyComponentType(const std::string& str) { + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT8) { + return PropertyComponentType::Uint8; } - return PropertyType::None; + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT16) { + return PropertyComponentType::Uint16; + } + + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT32) { + return PropertyComponentType::Uint32; + } + + if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT64) { + return PropertyComponentType::Uint64; + } + + return PropertyComponentType::None; +} + +bool isPropertyTypeVecN(PropertyType type) { + return type == PropertyType::Vec2 || type == PropertyType::Vec3 || + type == PropertyType::Vec4; +} + +bool isPropertyTypeMatN(PropertyType type) { + return type == PropertyType::Mat2 || type == PropertyType::Mat3 || + type == PropertyType::Mat4; } } // namespace CesiumGltf diff --git a/CesiumGltf/src/StructuralMetadataPropertyType.cpp b/CesiumGltf/src/StructuralMetadataPropertyType.cpp deleted file mode 100644 index ca7613023..000000000 --- a/CesiumGltf/src/StructuralMetadataPropertyType.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "CesiumGltf/StructuralMetadataPropertyType.h" - -#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTable.h" - -namespace CesiumGltf { -namespace StructuralMetadata { - -std::string convertPropertyTypeToString(StructuralMetadata::PropertyType type) { - switch (type) { - case PropertyType::Scalar: - return ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - case PropertyType::Vec2: - return ExtensionExtStructuralMetadataClassProperty::Type::VEC2; - case PropertyType::Vec3: - return ExtensionExtStructuralMetadataClassProperty::Type::VEC3; - case PropertyType::Vec4: - return ExtensionExtStructuralMetadataClassProperty::Type::VEC4; - case PropertyType::Mat2: - return ExtensionExtStructuralMetadataClassProperty::Type::MAT2; - case PropertyType::Mat3: - return ExtensionExtStructuralMetadataClassProperty::Type::MAT3; - case PropertyType::Mat4: - return ExtensionExtStructuralMetadataClassProperty::Type::MAT4; - case PropertyType::Boolean: - return ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; - case PropertyType::Enum: - return ExtensionExtStructuralMetadataClassProperty::Type::ENUM; - case PropertyType::String: - return ExtensionExtStructuralMetadataClassProperty::Type::STRING; - default: - return "INVALID"; - } -} - -PropertyType convertStringToPropertyType(const std::string& str) { - if (str == ExtensionExtStructuralMetadataClassProperty::Type::SCALAR) { - return PropertyType::Scalar; - } - - if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC2) { - return PropertyType::Vec2; - } - - if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC3) { - return PropertyType::Vec3; - } - - if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC4) { - return PropertyType::Vec4; - } - - if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT2) { - return PropertyType::Mat2; - } - - if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT3) { - return PropertyType::Mat3; - } - - if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT4) { - return PropertyType::Mat4; - } - - if (str == ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN) { - return PropertyType::Boolean; - } - - if (str == ExtensionExtStructuralMetadataClassProperty::Type::STRING) { - return PropertyType::String; - } - - if (str == ExtensionExtStructuralMetadataClassProperty::Type::ENUM) { - return PropertyType::Enum; - } - - return PropertyType::Invalid; -} - -std::string convertPropertyComponentTypeToString(PropertyComponentType type) { - switch (type) { - case PropertyComponentType::None: - return "NONE"; - case PropertyComponentType::Uint8: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; - case PropertyComponentType::Int8: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8; - case PropertyComponentType::Uint16: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16; - case PropertyComponentType::Int16: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16; - case PropertyComponentType::Uint32: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; - case PropertyComponentType::Int32: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; - case PropertyComponentType::Uint64: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64; - case PropertyComponentType::Int64: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64; - case PropertyComponentType::Float32: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32; - case PropertyComponentType::Float64: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64; - default: - return "NONE"; - } -} - -PropertyComponentType -convertStringToPropertyComponentType(const std::string& str) { - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8) { - return PropertyComponentType::Uint8; - } - - if (str == ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8) { - return PropertyComponentType::Int8; - } - - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16) { - return PropertyComponentType::Uint16; - } - - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16) { - return PropertyComponentType::Int16; - } - - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32) { - return PropertyComponentType::Uint32; - } - - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32) { - return PropertyComponentType::Int32; - } - - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64) { - return PropertyComponentType::Uint64; - } - - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64) { - return PropertyComponentType::Int64; - } - - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32) { - return PropertyComponentType::Float32; - } - - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64) { - return PropertyComponentType::Float64; - } - - return PropertyComponentType::None; -} - -PropertyComponentType -convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str) { - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT8) { - return PropertyComponentType::Uint8; - } - - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT16) { - return PropertyComponentType::Uint16; - } - - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT32) { - return PropertyComponentType::Uint32; - } - - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT64) { - return PropertyComponentType::Uint64; - } - - return PropertyComponentType::None; -} - -PropertyComponentType -convertStringOffsetTypeStringToPropertyComponentType(const std::string& str) { - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT8) { - return PropertyComponentType::Uint8; - } - - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT16) { - return PropertyComponentType::Uint16; - } - - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT32) { - return PropertyComponentType::Uint32; - } - - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT64) { - return PropertyComponentType::Uint64; - } - - return PropertyComponentType::None; -} - -bool isPropertyTypeVecN(PropertyType type) { - return type == PropertyType::Vec2 || type == PropertyType::Vec3 || - type == PropertyType::Vec4; -} - -bool isPropertyTypeMatN(PropertyType type) { - return type == PropertyType::Mat2 || type == PropertyType::Mat3 || - type == PropertyType::Mat4; -} - -} // namespace StructuralMetadata -} // namespace CesiumGltf diff --git a/CesiumGltf/test/TestMeshFeaturesFeatureIdTextureView.cpp b/CesiumGltf/test/TestFeatureIdTextureView.cpp similarity index 98% rename from CesiumGltf/test/TestMeshFeaturesFeatureIdTextureView.cpp rename to CesiumGltf/test/TestFeatureIdTextureView.cpp index cde38cd03..a6755667f 100644 --- a/CesiumGltf/test/TestMeshFeaturesFeatureIdTextureView.cpp +++ b/CesiumGltf/test/TestFeatureIdTextureView.cpp @@ -1,5 +1,5 @@ #include "CesiumGltf/ExtensionExtMeshFeatures.h" -#include "CesiumGltf/MeshFeaturesFeatureIdTextureView.h" +#include "CesiumGltf/FeatureIdTextureView.h" #include #include @@ -11,7 +11,6 @@ #include using namespace CesiumGltf; -using namespace CesiumGltf::MeshFeatures; TEST_CASE("Test FeatureIdTextureView on feature ID texture with invalid " "texture index") { diff --git a/CesiumGltf/test/TestMetadataFeatureTableView.cpp b/CesiumGltf/test/TestMetadataFeatureTableView.cpp deleted file mode 100644 index 9aabf9e6e..000000000 --- a/CesiumGltf/test/TestMetadataFeatureTableView.cpp +++ /dev/null @@ -1,1164 +0,0 @@ -#include "CesiumGltf/MetadataFeatureTableView.h" - -#include - -#include - -using namespace CesiumGltf; - -TEST_CASE("Test numeric properties") { - Model model; - - // store property value - std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; - - // Construct buffers in the scope to make sure that tests below doesn't use - // the temp variables. Use index to access the buffer and buffer view instead - size_t valueBufferIndex = 0; - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - valueBufferIndex = model.buffers.size() - 1; - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - // setup metadata - ExtensionModelExtFeatureMetadata& metadata = - model.addExtension(); - - // setup schema - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::UINT32; - - // setup feature table - FeatureTable& featureTable = metadata.featureTables["TestFeatureTable"]; - featureTable.classProperty = "TestClass"; - featureTable.count = static_cast(values.size()); - - // setup feature table property - FeatureTableProperty& featureTableProperty = - featureTable.properties["TestClassProperty"]; - featureTableProperty.bufferView = static_cast(valueBufferViewIndex); - - // test feature table view - MetadataFeatureTableView view(&model, &featureTable); - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty->type == ClassProperty::Type::UINT32); - REQUIRE(classProperty->componentCount == std::nullopt); - REQUIRE(classProperty->componentType == std::nullopt); - - SECTION("Access correct type") { - MetadataPropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE(uint32Property.status() == MetadataPropertyViewStatus::Valid); - REQUIRE(uint32Property.size() > 0); - - for (int64_t i = 0; i < uint32Property.size(); ++i) { - REQUIRE(uint32Property.get(i) == values[static_cast(i)]); - } - } - - SECTION("Access wrong type") { - MetadataPropertyView boolInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - boolInvalid.status() == - MetadataPropertyViewStatus::InvalidTypeMismatch); - - MetadataPropertyView uint8Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint8Invalid.status() == - MetadataPropertyViewStatus::InvalidTypeMismatch); - - MetadataPropertyView int32Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - int32Invalid.status() == - MetadataPropertyViewStatus::InvalidTypeMismatch); - - MetadataPropertyView unt64Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - unt64Invalid.status() == - MetadataPropertyViewStatus::InvalidTypeMismatch); - - MetadataPropertyView stringInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringInvalid.status() == - MetadataPropertyViewStatus::InvalidTypeMismatch); - - MetadataPropertyView> uint32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - uint32ArrayInvalid.status() == - MetadataPropertyViewStatus::InvalidTypeMismatch); - - MetadataPropertyView> boolArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayInvalid.status() == - MetadataPropertyViewStatus::InvalidTypeMismatch); - - MetadataPropertyView> - stringArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - stringArrayInvalid.status() == - MetadataPropertyViewStatus::InvalidTypeMismatch); - } - - SECTION("Wrong buffer index") { - model.bufferViews[valueBufferViewIndex].buffer = 2; - MetadataPropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - MetadataPropertyViewStatus::InvalidValueBufferIndex); - } - - SECTION("Wrong buffer view index") { - featureTableProperty.bufferView = -1; - MetadataPropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - MetadataPropertyViewStatus::InvalidValueBufferViewIndex); - } - - SECTION("Buffer view points outside of the real buffer length") { - model.buffers[valueBufferIndex].cesium.data.resize(12); - MetadataPropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - MetadataPropertyViewStatus::InvalidBufferViewOutOfBound); - } - - // Even though the EXT_feature_metadata spec technically compels us to - // enforce an 8-byte alignment, we avoid doing so for compatibility with - // incorrect glTFs. - /* - SECTION("Buffer view offset is not a multiple of 8") { - model.bufferViews[valueBufferViewIndex].byteOffset = 1; - MetadataPropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - MetadataPropertyViewStatus::InvalidBufferViewNotAligned8Bytes); - } - */ - - SECTION("Buffer view length isn't multiple of sizeof(T)") { - model.bufferViews[valueBufferViewIndex].byteLength = 13; - MetadataPropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - MetadataPropertyViewStatus:: - InvalidBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Buffer view length doesn't match with featureTableCount") { - model.bufferViews[valueBufferViewIndex].byteLength = 12; - MetadataPropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - MetadataPropertyViewStatus::InvalidBufferViewSizeNotFitInstanceCount); - } -} - -TEST_CASE("Test boolean properties") { - Model model; - - // store property value - int64_t instanceCount = 21; - std::vector expected; - std::vector values; - values.resize(3); - for (int64_t i = 0; i < instanceCount; ++i) { - if (i % 2 == 0) { - expected.emplace_back(true); - } else { - expected.emplace_back(false); - } - - uint8_t expectedValue = expected.back(); - int64_t byteIndex = i / 8; - int64_t bitIndex = i % 8; - values[static_cast(byteIndex)] = static_cast( - (expectedValue << bitIndex) | values[static_cast(byteIndex)]); - } - - // Create buffers in the scope, so that tests below don't accidentally refer - // to temp variable. Use index instead if the buffer is needed - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size()); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - } - - // setup metadata - ExtensionModelExtFeatureMetadata& metadata = - model.addExtension(); - - // setup schema - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::BOOLEAN; - - // setup feature table - FeatureTable& featureTable = metadata.featureTables["TestFeatureTable"]; - featureTable.classProperty = "TestClass"; - featureTable.count = static_cast(instanceCount); - - // setup feature table property - FeatureTableProperty& featureTableProperty = - featureTable.properties["TestClassProperty"]; - featureTableProperty.bufferView = - static_cast(model.bufferViews.size() - 1); - - // test feature table view - MetadataFeatureTableView view(&model, &featureTable); - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); - REQUIRE(classProperty->componentCount == std::nullopt); - REQUIRE(classProperty->componentType == std::nullopt); - - SECTION("Access correct type") { - MetadataPropertyView boolProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE(boolProperty.status() == MetadataPropertyViewStatus::Valid); - REQUIRE(boolProperty.size() == instanceCount); - for (int64_t i = 0; i < boolProperty.size(); ++i) { - bool expectedValue = expected[static_cast(i)]; - REQUIRE(boolProperty.get(i) == expectedValue); - } - } - - SECTION("Buffer size doesn't match with feature table count") { - featureTable.count = 66; - MetadataPropertyView boolProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - boolProperty.status() == - MetadataPropertyViewStatus::InvalidBufferViewSizeNotFitInstanceCount); - } -} - -TEST_CASE("Test string property") { - Model model; - - std::vector expected{"What's up", "Test_0", "Test_1", "", ""}; - size_t totalBytes = 0; - for (const std::string& expectedValue : expected) { - totalBytes += expectedValue.size(); - } - - std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); - std::vector values(totalBytes); - uint32_t* offsetValue = reinterpret_cast(offsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - const std::string& expectedValue = expected[i]; - std::memcpy( - values.data() + offsetValue[i], - expectedValue.c_str(), - expectedValue.size()); - offsetValue[i + 1] = - offsetValue[i] + static_cast(expectedValue.size()); - } - - // Create buffers in the scope, so that tests below don't accidentally refer - // to temp variable. Use index instead if the buffer is needed. - // Store property value - size_t valueBufferIndex = 0; - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - valueBufferIndex = model.buffers.size() - 1; - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(valueBufferIndex); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - // Create buffers in the scope, so that tests below don't accidentally refer - // to temp variable. Use index instead if the buffer is needed. - // Store string offset buffer - size_t offsetBufferIndex = 0; - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); - offsetBufferIndex = model.buffers.size() - 1; - - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(offsetBufferIndex); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } - - // setup metadata - ExtensionModelExtFeatureMetadata& metadata = - model.addExtension(); - - // setup schema - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::STRING; - - // setup feature table - FeatureTable& featureTable = metadata.featureTables["TestFeatureTable"]; - featureTable.classProperty = "TestClass"; - featureTable.count = static_cast(expected.size()); - - // setup feature table property - FeatureTableProperty& featureTableProperty = - featureTable.properties["TestClassProperty"]; - featureTableProperty.offsetType = FeatureTableProperty::OffsetType::UINT32; - featureTableProperty.bufferView = static_cast(valueBufferViewIndex); - featureTableProperty.stringOffsetBufferView = - static_cast(offsetBufferViewIndex); - - // test feature table view - MetadataFeatureTableView view(&model, &featureTable); - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty->type == ClassProperty::Type::STRING); - REQUIRE(classProperty->componentCount == std::nullopt); - REQUIRE(classProperty->componentType == std::nullopt); - - SECTION("Access correct type") { - MetadataPropertyView stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE(stringProperty.status() == MetadataPropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - REQUIRE(stringProperty.get(static_cast(i)) == expected[i]); - } - } - - SECTION("Wrong offset type") { - featureTableProperty.offsetType = FeatureTableProperty::OffsetType::UINT8; - MetadataPropertyView stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - MetadataPropertyViewStatus::InvalidBufferViewSizeNotFitInstanceCount); - - featureTableProperty.offsetType = FeatureTableProperty::OffsetType::UINT64; - stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - MetadataPropertyViewStatus::InvalidBufferViewSizeNotFitInstanceCount); - - featureTableProperty.offsetType = "NONSENSE"; - stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - MetadataPropertyViewStatus::InvalidOffsetType); - } - - SECTION("Offset values are not sorted ascending") { - uint32_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[2] = - static_cast(model.buffers[valueBufferIndex].byteLength + 4); - MetadataPropertyView stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - MetadataPropertyViewStatus::InvalidOffsetValuesNotSortedAscending); - } - - SECTION("Offset value points outside of value buffer") { - uint32_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[featureTable.count] = - static_cast(model.buffers[valueBufferIndex].byteLength + 4); - MetadataPropertyView stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - MetadataPropertyViewStatus::InvalidOffsetValuePointsToOutOfBoundBuffer); - } -} - -TEST_CASE("Test fixed numeric array") { - Model model; - - // store property value - std::vector values = - {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; - - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - // setup metadata - ExtensionModelExtFeatureMetadata& metadata = - model.addExtension(); - - // setup schema - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::ARRAY; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; - testClassProperty.componentCount = 3; - - // setup feature table - FeatureTable& featureTable = metadata.featureTables["TestFeatureTable"]; - featureTable.classProperty = "TestClass"; - featureTable.count = static_cast( - values.size() / - static_cast(testClassProperty.componentCount.value())); - - // setup feature table property - FeatureTableProperty& featureTableProperty = - featureTable.properties["TestClassProperty"]; - featureTableProperty.bufferView = - static_cast(model.bufferViews.size() - 1); - - // test feature table view - MetadataFeatureTableView view(&model, &featureTable); - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty->type == ClassProperty::Type::ARRAY); - REQUIRE(classProperty->componentCount == 3); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); - - SECTION("Access the right type") { - MetadataPropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE(arrayProperty.status() == MetadataPropertyViewStatus::Valid); - - for (int64_t i = 0; i < arrayProperty.size(); ++i) { - MetadataArrayView member = arrayProperty.get(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 3 + j)]); - } - } - } - - SECTION("Wrong component type") { - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - MetadataPropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - MetadataPropertyViewStatus::InvalidTypeMismatch); - } - - SECTION("Buffer size is not a multiple of type size") { - model.bufferViews[valueBufferViewIndex].byteLength = 13; - MetadataPropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - MetadataPropertyViewStatus:: - InvalidBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Negative component count") { - testClassProperty.componentCount = -1; - MetadataPropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - MetadataPropertyViewStatus:: - InvalidArrayComponentCountOrOffsetBufferNotExist); - } - - SECTION("Value buffer doesn't fit into feature table count") { - testClassProperty.componentCount = 55; - MetadataPropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - MetadataPropertyViewStatus::InvalidBufferViewSizeNotFitInstanceCount); - } -} - -TEST_CASE("Test dynamic numeric array") { - Model model; - - // store property value - std::vector> expected{ - {12, 33, 11, 344, 112, 444, 1}, - {}, - {}, - {122, 23, 333, 12}, - {}, - {333, 311, 22, 34}, - {}, - {33, 1888, 233, 33019}}; - size_t numOfElements = 0; - for (const auto& expectedMember : expected) { - numOfElements += expectedMember.size(); - } - - std::vector values(numOfElements * sizeof(uint16_t)); - std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); - uint64_t* offsetValue = reinterpret_cast(offsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - std::memcpy( - values.data() + offsetValue[i], - expected[i].data(), - expected[i].size() * sizeof(uint16_t)); - offsetValue[i + 1] = offsetValue[i] + expected[i].size() * sizeof(uint16_t); - } - - // store property value - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - // store string offset buffer - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); - - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(model.buffers.size() - 1); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } - - // setup metadata - ExtensionModelExtFeatureMetadata& metadata = - model.addExtension(); - - // setup schema - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::ARRAY; - testClassProperty.componentType = ClassProperty::ComponentType::UINT16; - - // setup feature table - FeatureTable& featureTable = metadata.featureTables["TestFeatureTable"]; - featureTable.classProperty = "TestClass"; - featureTable.count = static_cast(expected.size()); - - // setup feature table property - FeatureTableProperty& featureTableProperty = - featureTable.properties["TestClassProperty"]; - featureTableProperty.bufferView = static_cast(valueBufferViewIndex); - featureTableProperty.arrayOffsetBufferView = - static_cast(offsetBufferViewIndex); - featureTableProperty.offsetType = FeatureTableProperty::OffsetType::UINT64; - - // test feature table view - MetadataFeatureTableView view(&model, &featureTable); - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty->type == ClassProperty::Type::ARRAY); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT16); - - SECTION("Access the correct type") { - MetadataPropertyView> property = - view.getPropertyView>("TestClassProperty"); - REQUIRE(property.status() == MetadataPropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - MetadataArrayView valueMember = - property.get(static_cast(i)); - REQUIRE(valueMember.size() == static_cast(expected[i].size())); - for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(expected[i][j] == valueMember[static_cast(j)]); - } - } - } - - SECTION("Component count and offset buffer appear at the same time") { - testClassProperty.componentCount = 3; - MetadataPropertyView> property = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - property.status() == - MetadataPropertyViewStatus:: - InvalidArrayComponentCountAndOffsetBufferCoexist); - } -} - -TEST_CASE("Test fixed boolean array") { - Model model; - - // store property value - std::vector expected = { - true, - false, - false, - true, - false, - false, - true, - true, - true, - false, - false, - true}; - std::vector values; - size_t requiredBytesSize = static_cast( - glm::ceil(static_cast(expected.size()) / 8.0)); - values.resize(requiredBytesSize); - for (size_t i = 0; i < expected.size(); ++i) { - uint8_t expectedValue = expected[i]; - size_t byteIndex = i / 8; - size_t bitIndex = i % 8; - values[byteIndex] = - static_cast((expectedValue << bitIndex) | values[byteIndex]); - } - - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size()); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - } - - // setup metadata - ExtensionModelExtFeatureMetadata& metadata = - model.addExtension(); - - // setup schema - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::ARRAY; - testClassProperty.componentType = ClassProperty::ComponentType::BOOLEAN; - testClassProperty.componentCount = 3; - - // setup feature table - FeatureTable& featureTable = metadata.featureTables["TestFeatureTable"]; - featureTable.classProperty = "TestClass"; - featureTable.count = static_cast( - expected.size() / - static_cast(testClassProperty.componentCount.value())); - - // setup feature table property - FeatureTableProperty& featureTableProperty = - featureTable.properties["TestClassProperty"]; - featureTableProperty.bufferView = - static_cast(model.bufferViews.size() - 1); - - // test feature table view - MetadataFeatureTableView view(&model, &featureTable); - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty->type == ClassProperty::Type::ARRAY); - REQUIRE(classProperty->componentCount == 3); - REQUIRE( - classProperty->componentType == ClassProperty::ComponentType::BOOLEAN); - - SECTION("Access correct type") { - MetadataPropertyView> boolProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE(boolProperty.status() == MetadataPropertyViewStatus::Valid); - REQUIRE(boolProperty.size() == featureTable.count); - REQUIRE(boolProperty.size() > 0); - for (int64_t i = 0; i < boolProperty.size(); ++i) { - MetadataArrayView valueMember = boolProperty.get(i); - for (int64_t j = 0; j < valueMember.size(); ++j) { - REQUIRE(valueMember[j] == expected[static_cast(i * 3 + j)]); - } - } - } - - SECTION("Value buffer doesn't have enough required bytes") { - testClassProperty.componentCount = 11; - MetadataPropertyView> boolProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolProperty.status() == - MetadataPropertyViewStatus::InvalidBufferViewSizeNotFitInstanceCount); - } - - SECTION("Component count is negative") { - testClassProperty.componentCount = -1; - MetadataPropertyView> boolProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolProperty.status() == - MetadataPropertyViewStatus:: - InvalidArrayComponentCountOrOffsetBufferNotExist); - } -} - -TEST_CASE("Test dynamic bool array") { - Model model; - - // store property value - std::vector> expected{ - {true, false, true, true, false, true, true}, - {}, - {}, - {}, - {false, false, false, false}, - {true, false, true}, - {false}, - {true, true, true, true, true, false, false}}; - size_t numOfElements = 0; - for (const auto& expectedMember : expected) { - numOfElements += expectedMember.size(); - } - - size_t requiredBytesSize = - static_cast(glm::ceil(static_cast(numOfElements) / 8.0)); - std::vector values(requiredBytesSize); - std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); - uint64_t* offsetValue = reinterpret_cast(offsets.data()); - size_t indexSoFar = 0; - for (size_t i = 0; i < expected.size(); ++i) { - for (size_t j = 0; j < expected[i].size(); ++j) { - uint8_t expectedValue = expected[i][j]; - size_t byteIndex = indexSoFar / 8; - size_t bitIndex = indexSoFar % 8; - values[byteIndex] = static_cast( - (expectedValue << bitIndex) | static_cast(values[byteIndex])); - ++indexSoFar; - } - offsetValue[i + 1] = offsetValue[i] + expected[i].size(); - } - - // store property value - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - // store string offset buffer - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); - - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(model.buffers.size() - 1); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } - - // setup metadata - ExtensionModelExtFeatureMetadata& metadata = - model.addExtension(); - - // setup schema - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::ARRAY; - testClassProperty.componentType = ClassProperty::ComponentType::BOOLEAN; - - // setup feature table - FeatureTable& featureTable = metadata.featureTables["TestFeatureTable"]; - featureTable.classProperty = "TestClass"; - featureTable.count = static_cast(expected.size()); - - // setup feature table property - FeatureTableProperty& featureTableProperty = - featureTable.properties["TestClassProperty"]; - featureTableProperty.bufferView = static_cast(valueBufferViewIndex); - featureTableProperty.arrayOffsetBufferView = - static_cast(offsetBufferViewIndex); - featureTableProperty.offsetType = FeatureTableProperty::OffsetType::UINT64; - - // test feature table view - MetadataFeatureTableView view(&model, &featureTable); - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty->type == ClassProperty::Type::ARRAY); - REQUIRE( - classProperty->componentType == ClassProperty::ComponentType::BOOLEAN); - - SECTION("Access correct type") { - MetadataPropertyView> boolProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE(boolProperty.status() == MetadataPropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - MetadataArrayView arrayMember = - boolProperty.get(static_cast(i)); - REQUIRE(arrayMember.size() == static_cast(expected[i].size())); - for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(expected[i][j] == arrayMember[static_cast(j)]); - } - } - } - - SECTION("Component count and array offset appear at the same time") { - testClassProperty.componentCount = 3; - MetadataPropertyView> boolProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolProperty.status() == - MetadataPropertyViewStatus:: - InvalidArrayComponentCountAndOffsetBufferCoexist); - } -} - -TEST_CASE("Test fixed array of string") { - Model model; - - std::vector expected{ - "What's up", - "Breaking news!!! Aliens no longer attacks the US first", - "But they still abduct my cows! Those milk thiefs! 👽 🐮", - "I'm not crazy. My mother had me tested 🤪", - "I love you, meat bags! ❤️", - "Book in the freezer"}; - - size_t totalBytes = 0; - for (const std::string& expectedValue : expected) { - totalBytes += expectedValue.size(); - } - - std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); - std::vector values(totalBytes); - uint32_t* offsetValue = reinterpret_cast(offsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - const std::string& expectedValue = expected[i]; - std::memcpy( - values.data() + offsetValue[i], - expectedValue.c_str(), - expectedValue.size()); - offsetValue[i + 1] = - offsetValue[i] + static_cast(expectedValue.size()); - } - - // store property value - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - // store string offset buffer - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); - - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(model.buffers.size() - 1); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } - - // setup metadata - ExtensionModelExtFeatureMetadata& metadata = - model.addExtension(); - - // setup schema - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::ARRAY; - testClassProperty.componentType = ClassProperty::ComponentType::STRING; - testClassProperty.componentCount = 2; - - // setup feature table - FeatureTable& featureTable = metadata.featureTables["TestFeatureTable"]; - featureTable.classProperty = "TestClass"; - featureTable.count = static_cast( - expected.size() / - static_cast(testClassProperty.componentCount.value())); - - // setup feature table property - FeatureTableProperty& featureTableProperty = - featureTable.properties["TestClassProperty"]; - featureTableProperty.offsetType = FeatureTableProperty::OffsetType::UINT32; - featureTableProperty.bufferView = static_cast(valueBufferViewIndex); - featureTableProperty.stringOffsetBufferView = - static_cast(offsetBufferViewIndex); - - // test feature table view - MetadataFeatureTableView view(&model, &featureTable); - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty->type == ClassProperty::Type::ARRAY); - REQUIRE(classProperty->componentCount == 2); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::STRING); - - SECTION("Access correct type") { - MetadataPropertyView> stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(stringProperty.status() == MetadataPropertyViewStatus::Valid); - REQUIRE(stringProperty.size() == 3); - - MetadataArrayView v0 = stringProperty.get(0); - REQUIRE(v0.size() == 2); - REQUIRE(v0[0] == "What's up"); - REQUIRE(v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); - - MetadataArrayView v1 = stringProperty.get(1); - REQUIRE(v1.size() == 2); - REQUIRE(v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); - REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); - - MetadataArrayView v2 = stringProperty.get(2); - REQUIRE(v2.size() == 2); - REQUIRE(v2[0] == "I love you, meat bags! ❤️"); - REQUIRE(v2[1] == "Book in the freezer"); - } - - SECTION("Component count is negative") { - testClassProperty.componentCount = -1; - MetadataPropertyView> stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - stringProperty.status() == - MetadataPropertyViewStatus:: - InvalidArrayComponentCountOrOffsetBufferNotExist); - } - - SECTION("Offset type is unknown") { - featureTableProperty.offsetType = "NONSENSE"; - MetadataPropertyView> stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - stringProperty.status() == - MetadataPropertyViewStatus::InvalidOffsetType); - } - - SECTION("string offset buffer doesn't exist") { - featureTableProperty.stringOffsetBufferView = -1; - MetadataPropertyView> stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - stringProperty.status() == - MetadataPropertyViewStatus::InvalidStringOffsetBufferViewIndex); - } -} - -TEST_CASE("Test dynamic array of string") { - Model model; - - std::vector> expected{ - {"What's up"}, - {"Breaking news!!! Aliens no longer attacks the US first", - "But they still abduct my cows! Those milk thiefs! 👽 🐮"}, - {"I'm not crazy. My mother had me tested 🤪", - "I love you, meat bags! ❤️", - "Book in the freezer"}}; - - size_t totalBytes = 0; - size_t numOfElements = 0; - for (const auto& expectedValues : expected) { - for (const auto& value : expectedValues) { - totalBytes += value.size(); - } - - numOfElements += expectedValues.size(); - } - - std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); - std::vector stringOffsets((numOfElements + 1) * sizeof(uint32_t)); - std::vector values(totalBytes); - uint32_t* offsetValue = reinterpret_cast(offsets.data()); - uint32_t* stringOffsetValue = - reinterpret_cast(stringOffsets.data()); - size_t strOffsetIdx = 0; - for (size_t i = 0; i < expected.size(); ++i) { - for (size_t j = 0; j < expected[i].size(); ++j) { - const std::string& expectedValue = expected[i][j]; - std::memcpy( - values.data() + stringOffsetValue[strOffsetIdx], - expectedValue.c_str(), - expectedValue.size()); - - stringOffsetValue[strOffsetIdx + 1] = - stringOffsetValue[strOffsetIdx] + - static_cast(expectedValue.size()); - ++strOffsetIdx; - } - - offsetValue[i + 1] = - offsetValue[i] + - static_cast(expected[i].size() * sizeof(uint32_t)); - } - - // store property value - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - // store array offset buffer - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); - - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(model.buffers.size() - 1); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } - - // store string offset buffer - size_t strOffsetBufferViewIndex = 0; - { - Buffer& strOffsetBuffer = model.buffers.emplace_back(); - strOffsetBuffer.byteLength = static_cast(stringOffsets.size()); - strOffsetBuffer.cesium.data = std::move(stringOffsets); - - BufferView& strOffsetBufferView = model.bufferViews.emplace_back(); - strOffsetBufferView.buffer = static_cast(model.buffers.size() - 1); - strOffsetBufferView.byteOffset = 0; - strOffsetBufferView.byteLength = strOffsetBuffer.byteLength; - strOffsetBufferViewIndex = model.bufferViews.size() - 1; - } - - // setup metadata - ExtensionModelExtFeatureMetadata& metadata = - model.addExtension(); - - // setup schema - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::ARRAY; - testClassProperty.componentType = ClassProperty::ComponentType::STRING; - - // setup feature table - FeatureTable& featureTable = metadata.featureTables["TestFeatureTable"]; - featureTable.classProperty = "TestClass"; - featureTable.count = static_cast(expected.size()); - - // setup feature table property - FeatureTableProperty& featureTableProperty = - featureTable.properties["TestClassProperty"]; - featureTableProperty.offsetType = FeatureTableProperty::OffsetType::UINT32; - featureTableProperty.bufferView = static_cast(valueBufferViewIndex); - featureTableProperty.arrayOffsetBufferView = - static_cast(offsetBufferViewIndex); - featureTableProperty.stringOffsetBufferView = - static_cast(strOffsetBufferViewIndex); - - // test feature table view - MetadataFeatureTableView view(&model, &featureTable); - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty->type == ClassProperty::Type::ARRAY); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::STRING); - - SECTION("Access correct type") { - MetadataPropertyView> stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(stringProperty.status() == MetadataPropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - MetadataArrayView stringArray = - stringProperty.get(static_cast(i)); - for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(stringArray[static_cast(j)] == expected[i][j]); - } - } - } -} diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp similarity index 93% rename from CesiumGltf/test/TestStructuralMetadataPropertyTablePropertyView.cpp rename to CesiumGltf/test/TestPropertyTablePropertyView.cpp index d77e0a2a6..ff1e44cec 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -1,4 +1,4 @@ -#include "CesiumGltf/StructuralMetadataPropertyTablePropertyView.h" +#include "CesiumGltf/PropertyTablePropertyView.h" #include #include @@ -9,7 +9,7 @@ #include #include -using namespace CesiumGltf::StructuralMetadata; +using namespace CesiumGltf; template static void checkNumeric(const std::vector& expected) { std::vector data; @@ -46,7 +46,7 @@ static void checkVariableLengthArray( offsets.data(), offsets.size() * sizeof(OffsetType)); - PropertyTablePropertyView> property( + PropertyTablePropertyView> property( PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(offsetBuffer.data(), offsetBuffer.size()), @@ -59,7 +59,7 @@ static void checkVariableLengthArray( size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { - MetadataArrayView values = property.get(i); + PropertyArrayView values = property.get(i); for (int64_t j = 0; j < values.size(); ++j) { REQUIRE(values[j] == data[expectedIdx]); ++expectedIdx; @@ -78,7 +78,7 @@ static void checkFixedLengthArray( buffer.resize(data.size() * sizeof(T)); std::memcpy(buffer.data(), data.data(), data.size() * sizeof(T)); - PropertyTablePropertyView> property( + PropertyTablePropertyView> property( PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), @@ -91,7 +91,7 @@ static void checkFixedLengthArray( size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { - MetadataArrayView values = property.get(i); + PropertyArrayView values = property.get(i); for (int64_t j = 0; j < values.size(); ++j) { REQUIRE(values[j] == data[expectedIdx]); ++expectedIdx; @@ -101,7 +101,7 @@ static void checkFixedLengthArray( REQUIRE(expectedIdx == data.size()); } -TEST_CASE("Check StructuralMetadata scalar numeric property view") { +TEST_CASE("Check scalar numeric property view") { SECTION("Uint8 Scalar") { std::vector data{12, 33, 56, 67}; checkNumeric(data); @@ -127,7 +127,7 @@ TEST_CASE("Check StructuralMetadata scalar numeric property view") { } } -TEST_CASE("Check StructuralMetadata vecN numeric property view") { +TEST_CASE("Check vecN numeric property view") { SECTION("Float Vec2") { std::vector data{ glm::vec2(10.001f, 0.005f), @@ -156,7 +156,7 @@ TEST_CASE("Check StructuralMetadata vecN numeric property view") { } } -TEST_CASE("Check StructuralMetadata matN numeric property view") { +TEST_CASE("Check matN numeric property view") { SECTION("Float Mat2") { // clang-format off std::vector data{ @@ -218,7 +218,7 @@ TEST_CASE("Check StructuralMetadata matN numeric property view") { } } -TEST_CASE("Check StructuralMetadata boolean property") { +TEST_CASE("Check boolean property") { std::bitset bits = 0b11110101; unsigned long val = bits.to_ulong(); std::vector data(sizeof(val)); @@ -235,7 +235,7 @@ TEST_CASE("Check StructuralMetadata boolean property") { } } -TEST_CASE("Check StructuralMetadata string property") { +TEST_CASE("Check string property") { std::vector strings{ "This is a fine test", "What's going on", @@ -287,7 +287,7 @@ TEST_CASE("Check StructuralMetadata string property") { } } -TEST_CASE("Check StructuralMetadata fixed-length scalar array property") { +TEST_CASE("Check fixed-length scalar array property") { SECTION("Fixed-length array of 4 uint8_ts") { // clang-format off std::vector data{ @@ -376,7 +376,7 @@ TEST_CASE("Check StructuralMetadata fixed-length scalar array property") { } } -TEST_CASE("Check StructuralMetadata fixed-length vecN array property") { +TEST_CASE("Check fixed-length vecN array property") { SECTION("Fixed-length array of 4 u8vec2s") { // clang-format off std::vector data{ @@ -419,7 +419,7 @@ TEST_CASE("Check StructuralMetadata fixed-length vecN array property") { } } -TEST_CASE("Check StructuralMetadata fixed-length matN array property") { +TEST_CASE("Check fixed-length matN array property") { SECTION("Fixed-length array of 4 i8mat2x2") { // clang-format off std::vector data{ @@ -520,7 +520,7 @@ TEST_CASE("Check StructuralMetadata fixed-length matN array property") { } } -TEST_CASE("Check StructuralMetadata variable-length scalar array property") { +TEST_CASE("Check variable-length scalar array property") { SECTION("Variable-length array of uint8_t") { // clang-format off std::vector data{ @@ -572,7 +572,7 @@ TEST_CASE("Check StructuralMetadata variable-length scalar array property") { } } -TEST_CASE("Check StructuralMetadata variable-length vecN array property") { +TEST_CASE("Check variable-length vecN array property") { SECTION("Variable-length array of ivec2") { // clang-format off std::vector data{ @@ -636,7 +636,7 @@ TEST_CASE("Check StructuralMetadata variable-length vecN array property") { } } -TEST_CASE("Check StructuralMetadata variable-length matN array property") { +TEST_CASE("Check variable-length matN array property") { SECTION("Variable-length array of dmat2") { // clang-format off std::vector data0{ @@ -786,7 +786,7 @@ TEST_CASE("Check StructuralMetadata variable-length matN array property") { } } -TEST_CASE("Check StructuralMetadata fixed-length array of string") { +TEST_CASE("Check fixed-length array of string") { std::vector strings{ "Test 1", "Test 2", @@ -831,7 +831,7 @@ TEST_CASE("Check StructuralMetadata fixed-length array of string") { ¤tStringOffset, sizeof(uint32_t)); - PropertyTablePropertyView> property( + PropertyTablePropertyView> property( PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), @@ -844,7 +844,7 @@ TEST_CASE("Check StructuralMetadata fixed-length array of string") { size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { - MetadataArrayView values = property.get(i); + PropertyArrayView values = property.get(i); for (int64_t j = 0; j < values.size(); ++j) { std::string_view v = values[j]; REQUIRE(v == strings[expectedIdx]); @@ -856,7 +856,7 @@ TEST_CASE("Check StructuralMetadata fixed-length array of string") { } TEST_CASE( - "Check StructuralMetadata variable-length array of strings property") { + "Check variable-length array of strings property") { // clang-format off std::vector arrayOffsets{ 0, @@ -904,7 +904,7 @@ TEST_CASE( ¤tOffset, sizeof(uint32_t)); - PropertyTablePropertyView> property( + PropertyTablePropertyView> property( PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span( @@ -919,7 +919,7 @@ TEST_CASE( size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { - MetadataArrayView values = property.get(i); + PropertyArrayView values = property.get(i); for (int64_t j = 0; j < values.size(); ++j) { std::string_view v = values[j]; REQUIRE(v == strings[expectedIdx]); @@ -930,13 +930,13 @@ TEST_CASE( REQUIRE(expectedIdx == stringCount); } -TEST_CASE("Check StructuralMetadata fixed-length boolean array property") { +TEST_CASE("Check fixed-length boolean array property") { std::vector buffer{ static_cast(0b10101111), static_cast(0b11111010), static_cast(0b11100111)}; - PropertyTablePropertyView> property( + PropertyTablePropertyView> property( PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), @@ -949,7 +949,7 @@ TEST_CASE("Check StructuralMetadata fixed-length boolean array property") { REQUIRE(property.size() == 2); - MetadataArrayView val0 = property.get(0); + PropertyArrayView val0 = property.get(0); REQUIRE(val0.size() == 12); REQUIRE(static_cast(val0[0]) == 1); REQUIRE(static_cast(val0[1]) == 1); @@ -964,7 +964,7 @@ TEST_CASE("Check StructuralMetadata fixed-length boolean array property") { REQUIRE(static_cast(val0[10]) == 0); REQUIRE(static_cast(val0[11]) == 1); - MetadataArrayView val1 = property.get(1); + PropertyArrayView val1 = property.get(1); REQUIRE(static_cast(val1[0]) == 1); REQUIRE(static_cast(val1[1]) == 1); REQUIRE(static_cast(val1[2]) == 1); @@ -979,7 +979,7 @@ TEST_CASE("Check StructuralMetadata fixed-length boolean array property") { REQUIRE(static_cast(val1[11]) == 1); } -TEST_CASE("Check StructuralMetadata variable-length boolean array property") { +TEST_CASE("Check variable-length boolean array property") { std::vector buffer{ static_cast(0b10101111), static_cast(0b11111010), @@ -988,7 +988,7 @@ TEST_CASE("Check StructuralMetadata variable-length boolean array property") { std::vector offsetBuffer{0, 3, 12, 28}; - PropertyTablePropertyView> property( + PropertyTablePropertyView> property( PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span( @@ -1003,13 +1003,13 @@ TEST_CASE("Check StructuralMetadata variable-length boolean array property") { REQUIRE(property.size() == 3); - MetadataArrayView val0 = property.get(0); + PropertyArrayView val0 = property.get(0); REQUIRE(val0.size() == 3); REQUIRE(static_cast(val0[0]) == 1); REQUIRE(static_cast(val0[1]) == 1); REQUIRE(static_cast(val0[2]) == 1); - MetadataArrayView val1 = property.get(1); + PropertyArrayView val1 = property.get(1); REQUIRE(val1.size() == 9); REQUIRE(static_cast(val1[0]) == 1); REQUIRE(static_cast(val1[1]) == 0); @@ -1021,7 +1021,7 @@ TEST_CASE("Check StructuralMetadata variable-length boolean array property") { REQUIRE(static_cast(val1[7]) == 0); REQUIRE(static_cast(val1[8]) == 1); - MetadataArrayView val2 = property.get(2); + PropertyArrayView val2 = property.get(2); REQUIRE(val2.size() == 16); REQUIRE(static_cast(val2[0]) == 1); REQUIRE(static_cast(val2[1]) == 1); diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp similarity index 91% rename from CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp rename to CesiumGltf/test/TestPropertyTableView.cpp index 952f6d4cd..cfadc098b 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -1,11 +1,10 @@ -#include "CesiumGltf/StructuralMetadataPropertyTableView.h" +#include "CesiumGltf/PropertyTableView.h" #include #include using namespace CesiumGltf; -using namespace CesiumGltf::StructuralMetadata; TEST_CASE("Test PropertyTableView on model without EXT_structural_metadata " "extension") { @@ -87,7 +86,7 @@ TEST_CASE("Test property table with nonexistent class") { REQUIRE(!classProperty); } -TEST_CASE("Test StructuralMetadata scalar property") { +TEST_CASE("Test scalar property") { Model model; std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; @@ -210,8 +209,8 @@ TEST_CASE("Test StructuralMetadata scalar property") { } SECTION("Access incorrectly as array") { - PropertyTablePropertyView> uint32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> uint32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); REQUIRE( uint32ArrayInvalid.status() == PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); @@ -265,7 +264,7 @@ TEST_CASE("Test StructuralMetadata scalar property") { } } -TEST_CASE("Test StructuralMetadata vecN property") { +TEST_CASE("Test vecN property") { Model model; std::vector values = { @@ -398,8 +397,8 @@ TEST_CASE("Test StructuralMetadata vecN property") { } SECTION("Access incorrectly as array") { - PropertyTablePropertyView> ivec3ArrayInvalid = - view.getPropertyView>( + PropertyTablePropertyView> ivec3ArrayInvalid = + view.getPropertyView>( "TestClassProperty"); REQUIRE( ivec3ArrayInvalid.status() == @@ -454,7 +453,7 @@ TEST_CASE("Test StructuralMetadata vecN property") { } } -TEST_CASE("Test StructuralMetadata matN property") { +TEST_CASE("Test matN property") { Model model; // clang-format off @@ -598,9 +597,9 @@ TEST_CASE("Test StructuralMetadata matN property") { } SECTION("Access incorrectly as array") { - PropertyTablePropertyView> + PropertyTablePropertyView> u32mat2x2ArrayInvalid = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( u32mat2x2ArrayInvalid.status() == @@ -657,7 +656,7 @@ TEST_CASE("Test StructuralMetadata matN property") { } } -TEST_CASE("Test StructuralMetadata boolean property") { +TEST_CASE("Test boolean property") { Model model; int64_t instanceCount = 21; @@ -752,7 +751,7 @@ TEST_CASE("Test StructuralMetadata boolean property") { } } -TEST_CASE("Test StructuralMetadata string property") { +TEST_CASE("Test string property") { Model model; std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; @@ -855,9 +854,9 @@ TEST_CASE("Test StructuralMetadata string property") { } SECTION("Wrong array type") { - PropertyTablePropertyView> + PropertyTablePropertyView> stringArrayInvalid = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( stringArrayInvalid.status() == @@ -928,7 +927,7 @@ TEST_CASE("Test StructuralMetadata string property") { } } -TEST_CASE("Test StructuralMetadata fixed-length scalar array") { +TEST_CASE("Test fixed-length scalar array") { Model model; std::vector values = @@ -994,12 +993,12 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { REQUIRE(classProperty->count == 3); SECTION("Access the right type") { - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { - MetadataArrayView member = arrayProperty.get(i); + PropertyArrayView member = arrayProperty.get(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 3 + j)]); } @@ -1007,14 +1006,14 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { } SECTION("Wrong type") { - PropertyTablePropertyView> boolArrayInvalid = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> boolArrayInvalid = + view.getPropertyView>("TestClassProperty"); REQUIRE( boolArrayInvalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); - PropertyTablePropertyView> uvec2ArrayInvalid = - view.getPropertyView>( + PropertyTablePropertyView> uvec2ArrayInvalid = + view.getPropertyView>( "TestClassProperty"); REQUIRE( uvec2ArrayInvalid.status() == @@ -1022,8 +1021,8 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { } SECTION("Wrong component type") { - PropertyTablePropertyView> int32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> int32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); REQUIRE( int32ArrayInvalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); @@ -1039,8 +1038,8 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { SECTION("Buffer size is not a multiple of type size") { model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -1049,8 +1048,8 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { SECTION("Negative component count") { testClassProperty.count = -1; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: ErrorArrayCountAndOffsetBufferDontExist); @@ -1058,8 +1057,8 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { SECTION("Value buffer doesn't fit into property table count") { testClassProperty.count = 55; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -1067,7 +1066,7 @@ TEST_CASE("Test StructuralMetadata fixed-length scalar array") { } } -TEST_CASE("Test Structural Metadata variable-length scalar array") { +TEST_CASE("Test variable-length scalar array") { Model model; std::vector> expected{ @@ -1169,11 +1168,11 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { REQUIRE(!classProperty->count); SECTION("Access the correct type") { - PropertyTablePropertyView> property = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> property = + view.getPropertyView>("TestClassProperty"); REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { - MetadataArrayView valueMember = + PropertyArrayView valueMember = property.get(static_cast(i)); REQUIRE(valueMember.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { @@ -1185,8 +1184,8 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -1196,7 +1195,7 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT16; arrayProperty = - view.getPropertyView>("TestClassProperty"); + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -1204,7 +1203,7 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { propertyTableProperty.arrayOffsetType = "NONSENSE"; arrayProperty = - view.getPropertyView>("TestClassProperty"); + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); @@ -1214,7 +1213,7 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: UINT64; arrayProperty = - view.getPropertyView>("TestClassProperty"); + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); @@ -1227,8 +1226,8 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); @@ -1239,8 +1238,8 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); @@ -1248,15 +1247,15 @@ TEST_CASE("Test Structural Metadata variable-length scalar array") { SECTION("Count and offset buffer are both present") { testClassProperty.count = 3; - PropertyTablePropertyView> property = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> property = + view.getPropertyView>("TestClassProperty"); REQUIRE( property.status() == PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } } -TEST_CASE("Test StructuralMetadata fixed-length vecN array") { +TEST_CASE("Test fixed-length vecN array") { Model model; std::vector values = { @@ -1328,13 +1327,13 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { REQUIRE(classProperty->count == 2); SECTION("Access the right type") { - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { - MetadataArrayView member = arrayProperty.get(i); + PropertyArrayView member = arrayProperty.get(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 2 + j)]); } @@ -1342,14 +1341,14 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { } SECTION("Wrong type") { - PropertyTablePropertyView> int32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> int32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); REQUIRE( int32ArrayInvalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); - PropertyTablePropertyView> ivec2ArrayInvalid = - view.getPropertyView>( + PropertyTablePropertyView> ivec2ArrayInvalid = + view.getPropertyView>( "TestClassProperty"); REQUIRE( ivec2ArrayInvalid.status() == @@ -1357,8 +1356,8 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { } SECTION("Wrong component type") { - PropertyTablePropertyView> uvec3ArrayInvalid = - view.getPropertyView>( + PropertyTablePropertyView> uvec3ArrayInvalid = + view.getPropertyView>( "TestClassProperty"); REQUIRE( uvec3ArrayInvalid.status() == @@ -1375,8 +1374,8 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { SECTION("Buffer size is not a multiple of type size") { model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1386,8 +1385,8 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { SECTION("Negative component count") { testClassProperty.count = -1; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -1396,8 +1395,8 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { SECTION("Value buffer doesn't fit into property table count") { testClassProperty.count = 55; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1406,7 +1405,7 @@ TEST_CASE("Test StructuralMetadata fixed-length vecN array") { } } -TEST_CASE("Test Structural Metadata variable-length vecN array") { +TEST_CASE("Test variable-length vecN array") { Model model; // clang-format off @@ -1510,12 +1509,12 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { REQUIRE(!classProperty->count); SECTION("Access the correct type") { - PropertyTablePropertyView> property = - view.getPropertyView>( + PropertyTablePropertyView> property = + view.getPropertyView>( "TestClassProperty"); REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { - MetadataArrayView valueMember = + PropertyArrayView valueMember = property.get(static_cast(i)); REQUIRE(valueMember.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { @@ -1528,8 +1527,8 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1539,7 +1538,7 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT16; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1547,7 +1546,7 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1557,7 +1556,7 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { propertyTableProperty.stringOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: UINT64; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1571,8 +1570,8 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1584,8 +1583,8 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1594,8 +1593,8 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { SECTION("Count and offset buffer are both present") { testClassProperty.count = 3; - PropertyTablePropertyView> property = - view.getPropertyView>( + PropertyTablePropertyView> property = + view.getPropertyView>( "TestClassProperty"); REQUIRE( property.status() == @@ -1603,7 +1602,7 @@ TEST_CASE("Test Structural Metadata variable-length vecN array") { } } -TEST_CASE("Test StructuralMetadata fixed-length matN array") { +TEST_CASE("Test fixed-length matN array") { Model model; // clang-format off @@ -1689,13 +1688,13 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { REQUIRE(classProperty->count == 2); SECTION("Access the right type") { - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { - MetadataArrayView member = arrayProperty.get(i); + PropertyArrayView member = arrayProperty.get(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 2 + j)]); } @@ -1703,14 +1702,14 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { } SECTION("Wrong type") { - PropertyTablePropertyView> int32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> int32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); REQUIRE( int32ArrayInvalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); - PropertyTablePropertyView> ivec2ArrayInvalid = - view.getPropertyView>( + PropertyTablePropertyView> ivec2ArrayInvalid = + view.getPropertyView>( "TestClassProperty"); REQUIRE( ivec2ArrayInvalid.status() == @@ -1718,9 +1717,9 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { } SECTION("Wrong component type") { - PropertyTablePropertyView> + PropertyTablePropertyView> u32mat2x2ArrayInvalid = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( u32mat2x2ArrayInvalid.status() == @@ -1737,8 +1736,8 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { SECTION("Buffer size is not a multiple of type size") { model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1748,8 +1747,8 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { SECTION("Negative component count") { testClassProperty.count = -1; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -1758,8 +1757,8 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { SECTION("Value buffer doesn't fit into property table count") { testClassProperty.count = 55; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1768,7 +1767,7 @@ TEST_CASE("Test StructuralMetadata fixed-length matN array") { } } -TEST_CASE("Test Structural Metadata variable-length matN array") { +TEST_CASE("Test variable-length matN array") { Model model; // clang-format off @@ -1892,12 +1891,12 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { REQUIRE(!classProperty->count); SECTION("Access the correct type") { - PropertyTablePropertyView> property = - view.getPropertyView>( + PropertyTablePropertyView> property = + view.getPropertyView>( "TestClassProperty"); REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { - MetadataArrayView valueMember = + PropertyArrayView valueMember = property.get(static_cast(i)); REQUIRE(valueMember.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { @@ -1910,8 +1909,8 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1921,7 +1920,7 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT16; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1929,7 +1928,7 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1939,7 +1938,7 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { propertyTableProperty.stringOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: UINT64; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1953,8 +1952,8 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1966,8 +1965,8 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1976,8 +1975,8 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { SECTION("Count and offset buffer are both present") { testClassProperty.count = 3; - PropertyTablePropertyView> property = - view.getPropertyView>( + PropertyTablePropertyView> property = + view.getPropertyView>( "TestClassProperty"); REQUIRE( property.status() == @@ -1985,7 +1984,7 @@ TEST_CASE("Test Structural Metadata variable-length matN array") { } } -TEST_CASE("Test StructuralMetadata fixed-length boolean array") { +TEST_CASE("Test fixed-length boolean array") { Model model; std::vector expected = { @@ -2066,14 +2065,14 @@ TEST_CASE("Test StructuralMetadata fixed-length boolean array") { REQUIRE(classProperty->count == 3); SECTION("Access correct type") { - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(boolArrayProperty.size() == propertyTable.count); REQUIRE(boolArrayProperty.size() > 0); for (int64_t i = 0; i < boolArrayProperty.size(); ++i) { - MetadataArrayView valueMember = boolArrayProperty.get(i); + PropertyArrayView valueMember = boolArrayProperty.get(i); for (int64_t j = 0; j < valueMember.size(); ++j) { REQUIRE(valueMember[j] == expected[static_cast(i * 3 + j)]); } @@ -2081,8 +2080,8 @@ TEST_CASE("Test StructuralMetadata fixed-length boolean array") { } SECTION("Wrong type") { - PropertyTablePropertyView> uint8ArrayInvalid = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> uint8ArrayInvalid = + view.getPropertyView>("TestClassProperty"); REQUIRE( uint8ArrayInvalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); @@ -2098,8 +2097,8 @@ TEST_CASE("Test StructuralMetadata fixed-length boolean array") { SECTION("Value buffer doesn't have enough required bytes") { testClassProperty.count = 11; - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( boolArrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -2108,8 +2107,8 @@ TEST_CASE("Test StructuralMetadata fixed-length boolean array") { SECTION("Count is negative") { testClassProperty.count = -1; - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( boolArrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -2117,7 +2116,7 @@ TEST_CASE("Test StructuralMetadata fixed-length boolean array") { } } -TEST_CASE("Test StructuralMetadata variable-length boolean array") { +TEST_CASE("Test variable-length boolean array") { Model model; std::vector> expected{ @@ -2221,12 +2220,12 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { REQUIRE(!classProperty->count); SECTION("Access correct type") { - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { - MetadataArrayView arrayMember = + PropertyArrayView arrayMember = boolArrayProperty.get(static_cast(i)); REQUIRE(arrayMember.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { @@ -2239,8 +2238,8 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -2250,7 +2249,7 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT16; arrayProperty = - view.getPropertyView>("TestClassProperty"); + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -2258,7 +2257,7 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { propertyTableProperty.arrayOffsetType = "NONSENSE"; arrayProperty = - view.getPropertyView>("TestClassProperty"); + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); @@ -2268,7 +2267,7 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: UINT64; arrayProperty = - view.getPropertyView>("TestClassProperty"); + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); @@ -2281,8 +2280,8 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); @@ -2293,8 +2292,8 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast( model.buffers[valueBufferIndex].byteLength * 8 + 20); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); @@ -2302,15 +2301,15 @@ TEST_CASE("Test StructuralMetadata variable-length boolean array") { SECTION("Count and offset buffer both present") { testClassProperty.count = 3; - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); REQUIRE( boolArrayProperty.status() == PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } } -TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { +TEST_CASE("Test fixed-length arrays of strings") { Model model; std::vector expected{ @@ -2406,24 +2405,24 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { REQUIRE(classProperty->count == 2); SECTION("Access correct type") { - PropertyTablePropertyView> + PropertyTablePropertyView> stringProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(stringProperty.size() == 3); - MetadataArrayView v0 = stringProperty.get(0); + PropertyArrayView v0 = stringProperty.get(0); REQUIRE(v0.size() == 2); REQUIRE(v0[0] == "What's up"); REQUIRE(v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); - MetadataArrayView v1 = stringProperty.get(1); + PropertyArrayView v1 = stringProperty.get(1); REQUIRE(v1.size() == 2); REQUIRE(v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); - MetadataArrayView v2 = stringProperty.get(2); + PropertyArrayView v2 = stringProperty.get(2); REQUIRE(v2.size() == 2); REQUIRE(v2[0] == "I love you, meat bags! ❤️"); REQUIRE(v2[1] == "Book in the freezer"); @@ -2439,9 +2438,9 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { SECTION("Count is negative") { testClassProperty.count = -1; - PropertyTablePropertyView> + PropertyTablePropertyView> stringProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( stringProperty.status() == PropertyTablePropertyViewStatus:: @@ -2450,9 +2449,9 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { SECTION("Offset type is unknown") { propertyTableProperty.stringOffsetType = "NONSENSE"; - PropertyTablePropertyView> + PropertyTablePropertyView> stringProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( stringProperty.status() == @@ -2462,7 +2461,7 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT32; - stringProperty = view.getPropertyView>( + stringProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( stringProperty.status() == @@ -2471,9 +2470,9 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { SECTION("String offsets don't exist") { propertyTableProperty.stringOffsets = -1; - PropertyTablePropertyView> + PropertyTablePropertyView> stringProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( stringProperty.status() == @@ -2481,7 +2480,7 @@ TEST_CASE("Test StructuralMetadata fixed-length arrays of strings") { } } -TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { +TEST_CASE("Test variable-length arrays of strings") { Model model; std::vector> expected{ @@ -2616,13 +2615,13 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { REQUIRE(!classProperty->count); SECTION("Access correct type") { - PropertyTablePropertyView> + PropertyTablePropertyView> stringProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { - MetadataArrayView stringArray = + PropertyArrayView stringArray = stringProperty.get(static_cast(i)); for (size_t j = 0; j < expected[i].size(); ++j) { REQUIRE(stringArray[static_cast(j)] == expected[i][j]); @@ -2634,9 +2633,9 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT8; - PropertyTablePropertyView> + PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -2646,7 +2645,7 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { propertyTableProperty.arrayOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: UINT16; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -2654,7 +2653,7 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -2668,9 +2667,9 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { propertyTableProperty.stringOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: UINT8; - PropertyTablePropertyView> + PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -2680,7 +2679,7 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { propertyTableProperty.stringOffsetType = ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: UINT16; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -2688,7 +2687,7 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.stringOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -2702,9 +2701,9 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { uint32_t* offset = reinterpret_cast( model.buffers[arrayOffsetBuffer].cesium.data.data()); offset[0] = static_cast(1000); - PropertyTablePropertyView> + PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -2716,9 +2715,9 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { uint32_t* offset = reinterpret_cast( model.buffers[stringOffsetBuffer].cesium.data.data()); offset[0] = static_cast(1000); - PropertyTablePropertyView> + PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -2731,9 +2730,9 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { model.buffers[arrayOffsetBuffer].cesium.data.data()); uint32_t previousValue = offset[propertyTable.count]; offset[propertyTable.count] = static_cast(100000); - PropertyTablePropertyView> + PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -2746,9 +2745,9 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { model.buffers[stringOffsetBuffer].cesium.data.data()); uint32_t previousValue = offset[6]; offset[6] = static_cast(100000); - PropertyTablePropertyView> + PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -2758,9 +2757,9 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { SECTION("Count and offset buffer both present") { testClassProperty.count = 3; - PropertyTablePropertyView> + PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>( + view.getPropertyView>( "TestClassProperty"); REQUIRE( boolArrayProperty.status() == @@ -2768,7 +2767,7 @@ TEST_CASE("Test StructuralMetadata variable-length arrays of strings") { } } -TEST_CASE("Test StructuralMetadata callback on invalid property table view") { +TEST_CASE("Test callback on invalid property table view") { Model model; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2808,7 +2807,7 @@ TEST_CASE("Test StructuralMetadata callback on invalid property table view") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test StructuralMetadata callback for invalid property") { +TEST_CASE("Test callback for invalid property") { Model model; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2857,7 +2856,7 @@ TEST_CASE("Test StructuralMetadata callback for invalid property") { REQUIRE(invokedCallbackCount == 2); } -TEST_CASE("Test StructuralMetadata callback for scalar property") { +TEST_CASE("Test callback for scalar property") { Model model; std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; @@ -2948,7 +2947,7 @@ TEST_CASE("Test StructuralMetadata callback for scalar property") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test StructuralMetadata callback for vecN property") { +TEST_CASE("Test callback for vecN property") { Model model; std::vector values = { @@ -3044,7 +3043,7 @@ TEST_CASE("Test StructuralMetadata callback for vecN property") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test StructuralMetadata callback for matN property") { +TEST_CASE("Test callback for matN property") { Model model; // clang-format off @@ -3150,7 +3149,7 @@ TEST_CASE("Test StructuralMetadata callback for matN property") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test StructuralMetadata callback for boolean property") { +TEST_CASE("Test callback for boolean property") { Model model; int64_t instanceCount = 21; @@ -3253,7 +3252,7 @@ TEST_CASE("Test StructuralMetadata callback for boolean property") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test StructuralMetadata callback for string property") { +TEST_CASE("Test callback for string property") { Model model; std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; @@ -3375,7 +3374,7 @@ TEST_CASE("Test StructuralMetadata callback for string property") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test StructuralMetadata callback for scalar array") { +TEST_CASE("Test callback for scalar array") { Model model; std::vector values = @@ -3451,10 +3450,10 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { if constexpr (std::is_same_v< PropertyTablePropertyView< - MetadataArrayView>, + PropertyArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - MetadataArrayView member = propertyValue.get(i); + PropertyArrayView member = propertyValue.get(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 3 + j)]); } @@ -3469,7 +3468,7 @@ TEST_CASE("Test StructuralMetadata callback for scalar array") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test StructuralMetadata callback for vecN array") { +TEST_CASE("Test callback for vecN array") { Model model; std::vector values = { @@ -3551,10 +3550,10 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { if constexpr (std::is_same_v< PropertyTablePropertyView< - MetadataArrayView>, + PropertyArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - MetadataArrayView member = propertyValue.get(i); + PropertyArrayView member = propertyValue.get(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 2 + j)]); } @@ -3569,7 +3568,7 @@ TEST_CASE("Test StructuralMetadata callback for vecN array") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test StructuralMetadata callback for matN array") { +TEST_CASE("Test callback for matN array") { Model model; // clang-format off @@ -3665,10 +3664,10 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { if constexpr (std::is_same_v< PropertyTablePropertyView< - MetadataArrayView>, + PropertyArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - MetadataArrayView member = propertyValue.get(i); + PropertyArrayView member = propertyValue.get(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 2 + j)]); } @@ -3683,7 +3682,7 @@ TEST_CASE("Test StructuralMetadata callback for matN array") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test StructuralMetadata callback for boolean array") { +TEST_CASE("Test callback for boolean array") { Model model; std::vector expected = { @@ -3775,10 +3774,10 @@ TEST_CASE("Test StructuralMetadata callback for boolean array") { REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - PropertyTablePropertyView>, + PropertyTablePropertyView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - MetadataArrayView member = propertyValue.get(i); + PropertyArrayView member = propertyValue.get(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == expected[static_cast(i * 3 + j)]); } @@ -3793,7 +3792,7 @@ TEST_CASE("Test StructuralMetadata callback for boolean array") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test StructuralMetadata callback for array of strings") { +TEST_CASE("Test callback for array of strings") { Model model; std::vector expected{ @@ -3901,22 +3900,22 @@ TEST_CASE("Test StructuralMetadata callback for array of strings") { if constexpr (std::is_same_v< PropertyTablePropertyView< - MetadataArrayView>, + PropertyArrayView>, decltype(propertyValue)>) { - MetadataArrayView v0 = propertyValue.get(0); + PropertyArrayView v0 = propertyValue.get(0); REQUIRE(v0.size() == 2); REQUIRE(v0[0] == "What's up"); REQUIRE( v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); - MetadataArrayView v1 = propertyValue.get(1); + PropertyArrayView v1 = propertyValue.get(1); REQUIRE(v1.size() == 2); REQUIRE( v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); - MetadataArrayView v2 = propertyValue.get(2); + PropertyArrayView v2 = propertyValue.get(2); REQUIRE(v2.size() == 2); REQUIRE(v2[0] == "I love you, meat bags! ❤️"); REQUIRE(v2[1] == "Book in the freezer"); diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp similarity index 98% rename from CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp rename to CesiumGltf/test/TestPropertyTexturePropertyView.cpp index e697ceafc..e6d96520e 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -1,4 +1,4 @@ -#include "CesiumGltf/StructuralMetadataPropertyTexturePropertyView.h" +#include "CesiumGltf/PropertyTexturePropertyView.h" #include #include @@ -10,7 +10,6 @@ #include using namespace CesiumGltf; -using namespace CesiumGltf::StructuralMetadata; TEST_CASE( "Test PropertyTexturePropertyView on property with invalid texture index") { diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp similarity index 98% rename from CesiumGltf/test/TestStructuralMetadataPropertyTextureView.cpp rename to CesiumGltf/test/TestPropertyTextureView.cpp index 01cfed051..6ca05cad2 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -1,4 +1,4 @@ -#include "CesiumGltf/StructuralMetadataPropertyTextureView.h" +#include "CesiumGltf/PropertyTextureView.h" #include #include @@ -10,7 +10,6 @@ #include using namespace CesiumGltf; -using namespace CesiumGltf::StructuralMetadata; TEST_CASE("Test PropertyTextureView on model without EXT_structural_metadata " "extension") { diff --git a/CesiumGltf/test/TestPropertyType.cpp b/CesiumGltf/test/TestPropertyType.cpp index 4629a7736..9f345f6aa 100644 --- a/CesiumGltf/test/TestPropertyType.cpp +++ b/CesiumGltf/test/TestPropertyType.cpp @@ -1,5 +1,5 @@ -#include "CesiumGltf/ClassProperty.h" -#include "CesiumGltf/FeatureTableProperty.h" +#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" +#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTableProperty.h" #include "CesiumGltf/PropertyType.h" #include @@ -9,132 +9,244 @@ using namespace CesiumGltf; TEST_CASE("Test PropertyType utilities function") { SECTION("Convert string to PropertyType") { REQUIRE( - convertStringToPropertyType(ClassProperty::Type::UINT8) == - PropertyType::Uint8); + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR) == + PropertyType::Scalar); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::INT8) == - PropertyType::Int8); + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::VEC2) == + PropertyType::Vec2); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::UINT16) == - PropertyType::Uint16); + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::VEC3) == + PropertyType::Vec3); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::INT16) == - PropertyType::Int16); + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::VEC4) == + PropertyType::Vec4); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::UINT32) == - PropertyType::Uint32); + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::MAT2) == + PropertyType::Mat2); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::INT32) == - PropertyType::Int32); + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::MAT3) == + PropertyType::Mat3); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::UINT64) == - PropertyType::Uint64); + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::MAT4) == + PropertyType::Mat4); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::INT64) == - PropertyType::Int64); + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN) == + PropertyType::Boolean); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::FLOAT32) == - PropertyType::Float32); + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::STRING) == + PropertyType::String); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::FLOAT64) == - PropertyType::Float64); + convertStringToPropertyType( + ExtensionExtStructuralMetadataClassProperty::Type::ENUM) == + PropertyType::Enum); + + REQUIRE(convertStringToPropertyType("invalid") == PropertyType::Invalid); + } + SECTION("Convert string to PropertyComponentType") { REQUIRE( - convertStringToPropertyType(ClassProperty::Type::STRING) == - PropertyType::String); + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + UINT8) == PropertyComponentType::Uint8); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::BOOLEAN) == - PropertyType::Boolean); + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8) == + PropertyComponentType::Int8); REQUIRE( - convertStringToPropertyType(ClassProperty::Type::ARRAY) == - PropertyType::Array); + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + UINT16) == PropertyComponentType::Uint16); + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + INT16) == PropertyComponentType::Int16); - REQUIRE(convertStringToPropertyType("NONESENSE") == PropertyType::None); - } + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + UINT32) == PropertyComponentType::Uint32); + + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + INT32) == PropertyComponentType::Int32); + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + UINT64) == PropertyComponentType::Uint64); - SECTION("PropertyType to String") { REQUIRE( - convertPropertyTypeToString(PropertyType::Uint8) == - ClassProperty::Type::UINT8); + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + INT64) == PropertyComponentType::Int64); REQUIRE( - convertPropertyTypeToString(PropertyType::Int8) == - ClassProperty::Type::INT8); + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + FLOAT32) == PropertyComponentType::Float32); + REQUIRE( + convertStringToPropertyComponentType( + ExtensionExtStructuralMetadataClassProperty::ComponentType:: + FLOAT64) == PropertyComponentType::Float64); + + REQUIRE( + convertStringToPropertyComponentType("invalid") == + PropertyComponentType::None); + } + SECTION("Convert PropertyType to string") { REQUIRE( - convertPropertyTypeToString(PropertyType::Uint16) == - ClassProperty::Type::UINT16); + convertPropertyTypeToString(PropertyType::Scalar) == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); REQUIRE( - convertPropertyTypeToString(PropertyType::Int16) == - ClassProperty::Type::INT16); + convertPropertyTypeToString(PropertyType::Vec2) == + ExtensionExtStructuralMetadataClassProperty::Type::VEC2); REQUIRE( - convertPropertyTypeToString(PropertyType::Uint32) == - ClassProperty::Type::UINT32); + convertPropertyTypeToString(PropertyType::Vec3) == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3); REQUIRE( - convertPropertyTypeToString(PropertyType::Int32) == - ClassProperty::Type::INT32); + convertPropertyTypeToString(PropertyType::Vec4) == + ExtensionExtStructuralMetadataClassProperty::Type::VEC4); REQUIRE( - convertPropertyTypeToString(PropertyType::Uint64) == - ClassProperty::Type::UINT64); + convertPropertyTypeToString(PropertyType::Mat2) == + ExtensionExtStructuralMetadataClassProperty::Type::MAT2); REQUIRE( - convertPropertyTypeToString(PropertyType::Int64) == - ClassProperty::Type::INT64); + convertPropertyTypeToString(PropertyType::Mat3) == + ExtensionExtStructuralMetadataClassProperty::Type::MAT3); REQUIRE( - convertPropertyTypeToString(PropertyType::Float32) == - ClassProperty::Type::FLOAT32); + convertPropertyTypeToString(PropertyType::Mat4) == + ExtensionExtStructuralMetadataClassProperty::Type::MAT4); REQUIRE( - convertPropertyTypeToString(PropertyType::Float64) == - ClassProperty::Type::FLOAT64); + convertPropertyTypeToString(PropertyType::Boolean) == + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); REQUIRE( convertPropertyTypeToString(PropertyType::String) == - ClassProperty::Type::STRING); + ExtensionExtStructuralMetadataClassProperty::Type::STRING); REQUIRE( - convertPropertyTypeToString(PropertyType::Boolean) == - ClassProperty::Type::BOOLEAN); + convertPropertyTypeToString(PropertyType::Enum) == + ExtensionExtStructuralMetadataClassProperty::Type::ENUM); + } + + SECTION("Convert PropertyComponentType to string") { + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint8) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int8) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint16) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int16) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint32) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int32) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint64) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int64) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Float32) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Float64) == + ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); + } + + SECTION("Convert array offset type string to PropertyComponentType") { + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT8) == PropertyComponentType::Uint8); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT16) == PropertyComponentType::Uint16); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT32) == PropertyComponentType::Uint32); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + ArrayOffsetType::UINT64) == PropertyComponentType::Uint64); REQUIRE( - convertPropertyTypeToString(PropertyType::Array) == - ClassProperty::Type::ARRAY); + convertArrayOffsetTypeStringToPropertyComponentType("invalid") == + PropertyComponentType::None); } - SECTION("OffsetString to PropertyType") { + SECTION("Convert string offset type string to PropertyComponentType") { REQUIRE( - convertOffsetStringToPropertyType( - FeatureTableProperty::OffsetType::UINT8) == PropertyType::Uint8); + convertStringOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT8) == PropertyComponentType::Uint8); REQUIRE( - convertOffsetStringToPropertyType( - FeatureTableProperty::OffsetType::UINT16) == PropertyType::Uint16); + convertStringOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT16) == PropertyComponentType::Uint16); REQUIRE( - convertOffsetStringToPropertyType( - FeatureTableProperty::OffsetType::UINT32) == PropertyType::Uint32); + convertStringOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT32) == PropertyComponentType::Uint32); REQUIRE( - convertOffsetStringToPropertyType( - FeatureTableProperty::OffsetType::UINT64) == PropertyType::Uint64); + convertStringOffsetTypeStringToPropertyComponentType( + ExtensionExtStructuralMetadataPropertyTableProperty:: + StringOffsetType::UINT64) == PropertyComponentType::Uint64); REQUIRE( - convertOffsetStringToPropertyType("NONESENSE") == PropertyType::None); + convertStringOffsetTypeStringToPropertyComponentType("invalid") == + PropertyComponentType::None); } } diff --git a/CesiumGltf/test/TestPropertyTypeTrait.cpp b/CesiumGltf/test/TestPropertyTypeTrait.cpp deleted file mode 100644 index b85157eaa..000000000 --- a/CesiumGltf/test/TestPropertyTypeTrait.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "CesiumGltf/PropertyTypeTraits.h" - -#include - -TEST_CASE("Test PropertyTypeTrait") { - SECTION("IsNumeric") { - REQUIRE(CesiumGltf::IsMetadataNumeric::value); - REQUIRE(CesiumGltf::IsMetadataNumeric::value); - - REQUIRE(CesiumGltf::IsMetadataNumeric::value); - REQUIRE(CesiumGltf::IsMetadataNumeric::value); - - REQUIRE(CesiumGltf::IsMetadataNumeric::value); - REQUIRE(CesiumGltf::IsMetadataNumeric::value); - - REQUIRE(CesiumGltf::IsMetadataNumeric::value); - REQUIRE(CesiumGltf::IsMetadataNumeric::value); - - REQUIRE(CesiumGltf::IsMetadataNumeric::value); - REQUIRE(CesiumGltf::IsMetadataNumeric::value); - - REQUIRE(CesiumGltf::IsMetadataNumeric::value == false); - REQUIRE(CesiumGltf::IsMetadataNumeric::value == false); - } - - SECTION("IsBoolean") { - REQUIRE(CesiumGltf::IsMetadataBoolean::value); - REQUIRE(CesiumGltf::IsMetadataBoolean::value == false); - } - - SECTION("IsString") { - REQUIRE(CesiumGltf::IsMetadataString::value); - REQUIRE(CesiumGltf::IsMetadataString::value == false); - } - - SECTION("IsNumericArray") { - REQUIRE(CesiumGltf::IsMetadataNumericArray< - CesiumGltf::MetadataArrayView>::value); - - REQUIRE( - CesiumGltf::IsMetadataNumericArray< - CesiumGltf::MetadataArrayView>::value == false); - } - - SECTION("IsBooleanArray") { - REQUIRE(CesiumGltf::IsMetadataBooleanArray< - CesiumGltf::MetadataArrayView>::value); - - REQUIRE( - CesiumGltf::IsMetadataBooleanArray< - CesiumGltf::MetadataArrayView>::value == false); - } - - SECTION("IsStringArray") { - REQUIRE(CesiumGltf::IsMetadataStringArray< - CesiumGltf::MetadataArrayView>::value); - - REQUIRE( - CesiumGltf::IsMetadataStringArray< - CesiumGltf::MetadataArrayView>::value == false); - } - - SECTION("ArrayType") { - using type = CesiumGltf::MetadataArrayType< - CesiumGltf::MetadataArrayView>::type; - REQUIRE(std::is_same_v); - } - - SECTION("TypeToPropertyType") { - CesiumGltf::PropertyType value = - CesiumGltf::TypeToPropertyType::value; - REQUIRE(value == CesiumGltf::PropertyType::Uint32); - - auto component = CesiumGltf::TypeToPropertyType< - CesiumGltf::MetadataArrayView>::component; - value = CesiumGltf::TypeToPropertyType< - CesiumGltf::MetadataArrayView>::value; - CesiumGltf::PropertyType expected = CesiumGltf::PropertyType::Array; - REQUIRE(value == expected); - REQUIRE(component == CesiumGltf::PropertyType::Uint32); - } -} diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyTypeTraits.cpp b/CesiumGltf/test/TestPropertyTypeTraits.cpp similarity index 95% rename from CesiumGltf/test/TestStructuralMetadataPropertyTypeTraits.cpp rename to CesiumGltf/test/TestPropertyTypeTraits.cpp index 42c0a5313..caa8d1eaf 100644 --- a/CesiumGltf/test/TestStructuralMetadataPropertyTypeTraits.cpp +++ b/CesiumGltf/test/TestPropertyTypeTraits.cpp @@ -1,10 +1,10 @@ -#include "CesiumGltf/StructuralMetadataPropertyTypeTraits.h" +#include "CesiumGltf/PropertyTypeTraits.h" #include -using namespace CesiumGltf::StructuralMetadata; +using namespace CesiumGltf; -TEST_CASE("Test StructuralMetadata PropertyTypeTraits") { +TEST_CASE("Test PropertyTypeTraits") { SECTION("IsScalar") { REQUIRE(IsMetadataScalar::value); REQUIRE(IsMetadataScalar::value); @@ -140,25 +140,25 @@ TEST_CASE("Test StructuralMetadata PropertyTypeTraits") { } SECTION("IsNumericArray") { - REQUIRE(IsMetadataNumericArray>::value); - REQUIRE(IsMetadataNumericArray>::value); - REQUIRE(IsMetadataNumericArray>::value); - REQUIRE(!IsMetadataNumericArray>::value); + REQUIRE(IsMetadataNumericArray>::value); + REQUIRE(IsMetadataNumericArray>::value); + REQUIRE(IsMetadataNumericArray>::value); + REQUIRE(!IsMetadataNumericArray>::value); } SECTION("IsBooleanArray") { - REQUIRE(IsMetadataBooleanArray>::value); - REQUIRE(!IsMetadataBooleanArray>::value); + REQUIRE(IsMetadataBooleanArray>::value); + REQUIRE(!IsMetadataBooleanArray>::value); } SECTION("IsStringArray") { - REQUIRE(IsMetadataStringArray>::value); - REQUIRE(!IsMetadataStringArray>::value); - REQUIRE(!IsMetadataStringArray>::value); + REQUIRE(IsMetadataStringArray>::value); + REQUIRE(!IsMetadataStringArray>::value); + REQUIRE(!IsMetadataStringArray>::value); } SECTION("ArrayType") { - using type = MetadataArrayType>::type; + using type = MetadataArrayType>::type; REQUIRE(std::is_same_v); } diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp deleted file mode 100644 index 42a112ec8..000000000 --- a/CesiumGltf/test/TestPropertyView.cpp +++ /dev/null @@ -1,589 +0,0 @@ -#include "CesiumGltf/MetadataPropertyView.h" - -#include -#include - -#include -#include -#include -#include -#include - -template static void checkNumeric(const std::vector& expected) { - std::vector data; - data.resize(expected.size() * sizeof(T)); - std::memcpy(data.data(), expected.data(), data.size()); - - CesiumGltf::MetadataPropertyView property( - CesiumGltf::MetadataPropertyViewStatus::Valid, - gsl::span(data.data(), data.size()), - gsl::span(), - gsl::span(), - CesiumGltf::PropertyType::None, - 0, - static_cast(expected.size()), - false); - - for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.get(i) == expected[static_cast(i)]); - } -} - -template -static void checkDynamicArray( - const std::vector& data, - const std::vector offset, - CesiumGltf::PropertyType offsetType, - int64_t instanceCount) { - // copy data to buffer - std::vector buffer; - buffer.resize(data.size() * sizeof(T)); - std::memcpy(buffer.data(), data.data(), data.size() * sizeof(T)); - - // copy offset to buffer - std::vector offsetBuffer; - offsetBuffer.resize(offset.size() * sizeof(E)); - std::memcpy(offsetBuffer.data(), offset.data(), offset.size() * sizeof(E)); - - CesiumGltf::MetadataPropertyView> property( - CesiumGltf::MetadataPropertyViewStatus::Valid, - gsl::span(buffer.data(), buffer.size()), - gsl::span(offsetBuffer.data(), offsetBuffer.size()), - gsl::span(), - offsetType, - 0, - instanceCount, - false); - - size_t expectedIdx = 0; - for (int64_t i = 0; i < property.size(); ++i) { - CesiumGltf::MetadataArrayView vals = property.get(i); - for (int64_t j = 0; j < vals.size(); ++j) { - REQUIRE(vals[j] == data[expectedIdx]); - ++expectedIdx; - } - } - - REQUIRE(expectedIdx == data.size()); -} - -template -static void checkFixedArray( - const std::vector& data, - int64_t componentCount, - int64_t instanceCount) { - std::vector buffer; - buffer.resize(data.size() * sizeof(T)); - std::memcpy(buffer.data(), data.data(), data.size() * sizeof(T)); - - CesiumGltf::MetadataPropertyView> property( - CesiumGltf::MetadataPropertyViewStatus::Valid, - gsl::span(buffer.data(), buffer.size()), - gsl::span(), - gsl::span(), - CesiumGltf::PropertyType::None, - componentCount, - instanceCount, - false); - - size_t expectedIdx = 0; - for (int64_t i = 0; i < property.size(); ++i) { - CesiumGltf::MetadataArrayView vals = property.get(i); - for (int64_t j = 0; j < vals.size(); ++j) { - REQUIRE(vals[j] == data[expectedIdx]); - ++expectedIdx; - } - } - - REQUIRE(expectedIdx == data.size()); -} - -TEST_CASE("Check create numeric property view") { - SECTION("Uint8") { - std::vector data{12, 33, 56, 67}; - checkNumeric(data); - } - - SECTION("Int32") { - std::vector data{111222, -11133, -56000, 670000}; - checkNumeric(data); - } - - SECTION("Float") { - std::vector data{12.3333f, -12.44555f, -5.6111f, 6.7421f}; - checkNumeric(data); - } - - SECTION("Double") { - std::vector data{ - 12222.3302121, - -12000.44555, - -5000.6113111, - 6.7421}; - checkNumeric(data); - } -} - -TEST_CASE("Check boolean value") { - std::bitset bits = 0b11110101; - unsigned long val = bits.to_ulong(); - std::vector data(sizeof(val)); - std::memcpy(data.data(), &val, sizeof(val)); - - size_t instanceCount = sizeof(unsigned long) * CHAR_BIT; - CesiumGltf::MetadataPropertyView property( - CesiumGltf::MetadataPropertyViewStatus::Valid, - gsl::span(data.data(), data.size()), - gsl::span(), - gsl::span(), - CesiumGltf::PropertyType::None, - 0, - static_cast(instanceCount), - false); - for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.get(i) == bits[static_cast(i)]); - } -} - -TEST_CASE("Check string value") { - std::vector strings{ - "This is a fine test", - "What's going on", - "Good morning"}; - size_t totalSize = 0; - for (const auto& s : strings) { - totalSize += s.size(); - } - - uint32_t currentOffset = 0; - std::vector buffer; - buffer.resize(totalSize); - for (size_t i = 0; i < strings.size(); ++i) { - std::memcpy( - buffer.data() + currentOffset, - strings[i].data(), - strings[i].size()); - currentOffset += static_cast(strings[i].size()); - } - - // copy offset to buffer - std::vector offsetBuffer; - offsetBuffer.resize((strings.size() + 1) * sizeof(uint32_t)); - currentOffset = 0; - for (size_t i = 0; i < strings.size(); ++i) { - std::memcpy( - offsetBuffer.data() + i * sizeof(uint32_t), - ¤tOffset, - sizeof(uint32_t)); - currentOffset += static_cast(strings[i].size()); - } - std::memcpy( - offsetBuffer.data() + strings.size() * sizeof(uint32_t), - ¤tOffset, - sizeof(uint32_t)); - - CesiumGltf::MetadataPropertyView property( - CesiumGltf::MetadataPropertyViewStatus::Valid, - gsl::span(buffer.data(), buffer.size()), - gsl::span(), - gsl::span(offsetBuffer.data(), offsetBuffer.size()), - CesiumGltf::PropertyType::Uint32, - 0, - static_cast(strings.size()), - false); - for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.get(i) == strings[static_cast(i)]); - } -} - -TEST_CASE("Check fixed numeric array") { - SECTION("Fixed array of 4 uint8_ts") { - // clang-format off - std::vector data{ - 210, 211, 3, 42, - 122, 22, 1, 45}; - // clang-format on - checkFixedArray(data, 4, static_cast(data.size() / 4)); - } - - SECTION("Fixed array of 3 int8_ts") { - // clang-format off - std::vector data{ - 122, -12, 3, - 44, 11, -2, - 5, 6, -22, - 5, 6, 1}; - // clang-format on - checkFixedArray(data, 3, static_cast(data.size() / 3)); - } - - SECTION("Fixed array of 4 int16_ts") { - // clang-format off - std::vector data{ - -122, 12, 3, 44, - 11, 2, 5, -6000, - 119, 30, 51, 200, - 22000, -500, 6000, 1}; - // clang-format on - checkFixedArray(data, 4, static_cast(data.size() / 4)); - } - - SECTION("Fixed array of 6 uint32_ts") { - // clang-format off - std::vector data{ - 122, 12, 3, 44, 34444, 2222, - 11, 2, 5, 6000, 1111, 2222, - 119, 30, 51, 200, 12534, 11, - 22000, 500, 6000, 1, 3, 7}; - // clang-format on - checkFixedArray(data, 6, static_cast(data.size() / 6)); - } - - SECTION("Fixed array of 2 int32_ts") { - // clang-format off - std::vector data{ - 122, 12, - 3, 44}; - // clang-format on - checkFixedArray(data, 2, static_cast(data.size() / 2)); - } - - SECTION("Fixed array of 4 uint64_ts") { - // clang-format off - std::vector data{ - 10022, 120000, 2422, 1111, - 3, 440000, 333, 1455}; - // clang-format on - checkFixedArray(data, 4, static_cast(data.size() / 4)); - } - - SECTION("Fixed array of 4 int64_ts") { - // clang-format off - std::vector data{ - 10022, -120000, 2422, 1111, - 3, 440000, -333, 1455}; - // clang-format on - checkFixedArray(data, 4, static_cast(data.size() / 4)); - } - - SECTION("Fixed array of 4 floats") { - // clang-format off - std::vector data{ - 10.022f, -12.43f, 242.2f, 1.111f, - 3.333f, 440000.1f, -33.3f, 14.55f}; - // clang-format on - checkFixedArray(data, 4, static_cast(data.size() / 4)); - } - - SECTION("Fixed array of 4 double") { - // clang-format off - std::vector data{ - 10.022, -12.43, 242.2, 1.111, - 3.333, 440000.1, -33.3, 14.55}; - // clang-format on - checkFixedArray(data, 4, static_cast(data.size() / 4)); - } -} - -TEST_CASE("Check numeric dynamic array") { - SECTION("array of uint8_t") { - // clang-format off - std::vector data{ - 3, 2, - 0, 45, 2, 1, 4, - 1, 3, 2, - 1, 3, 4, 1 - }; - std::vector offset{ - 0, 2, 7, 10, 14 - }; - // clang-format on - - checkDynamicArray(data, offset, CesiumGltf::PropertyType::Uint32, 4); - } - - SECTION("array of int32_t") { - // clang-format off - std::vector data{ - 3, 200, - 0, 450, 200, 1, 4, - 1, 3, 2, - 1, 3, 4, 1 - }; - std::vector offset{ - 0, 2 * sizeof(int32_t), 7 * sizeof(int32_t), 10 * sizeof(int32_t), 14 * sizeof(int32_t) - }; - // clang-format on - - checkDynamicArray(data, offset, CesiumGltf::PropertyType::Uint32, 4); - } - - SECTION("array of double") { - // clang-format off - std::vector data{ - 3.333, 200.2, - 0.1122, 4.50, 2.30, 1.22, 4.444, - 1.4, 3.3, 2.2, - 1.11, 3.2, 4.111, 1.44 - }; - std::vector offset{ - 0, 2 * sizeof(double), 7 * sizeof(double), 10 * sizeof(double), 14 * sizeof(double) - }; - // clang-format on - - checkDynamicArray(data, offset, CesiumGltf::PropertyType::Uint32, 4); - } -} - -TEST_CASE("Check fixed array of string") { - std::vector strings{ - "Test 1", - "Test 2", - "Test 3", - "Test 4", - "Test 5", - "Test 6", - "This is a fine test", - "What's going on", - "Good morning"}; - size_t totalSize = 0; - for (const auto& s : strings) { - totalSize += s.size(); - } - - uint32_t currentOffset = 0; - std::vector buffer; - buffer.resize(totalSize); - for (size_t i = 0; i < strings.size(); ++i) { - std::memcpy( - buffer.data() + currentOffset, - strings[i].data(), - strings[i].size()); - currentOffset += static_cast(strings[i].size()); - } - - // copy offset to buffer - std::vector offsetBuffer; - offsetBuffer.resize((strings.size() + 1) * sizeof(uint32_t)); - currentOffset = 0; - for (size_t i = 0; i < strings.size(); ++i) { - std::memcpy( - offsetBuffer.data() + i * sizeof(uint32_t), - ¤tOffset, - sizeof(uint32_t)); - currentOffset += static_cast(strings[i].size()); - } - std::memcpy( - offsetBuffer.data() + strings.size() * sizeof(uint32_t), - ¤tOffset, - sizeof(uint32_t)); - - CesiumGltf::MetadataPropertyView< - CesiumGltf::MetadataArrayView> - property( - CesiumGltf::MetadataPropertyViewStatus::Valid, - gsl::span(buffer.data(), buffer.size()), - gsl::span(), - gsl::span(offsetBuffer.data(), offsetBuffer.size()), - CesiumGltf::PropertyType::Uint32, - 3, - static_cast(strings.size() / 3), - false); - - size_t expectedIdx = 0; - for (int64_t i = 0; i < property.size(); ++i) { - CesiumGltf::MetadataArrayView vals = property.get(i); - for (int64_t j = 0; j < vals.size(); ++j) { - std::string_view v = vals[j]; - REQUIRE(v == strings[expectedIdx]); - ++expectedIdx; - } - } - - REQUIRE(expectedIdx == strings.size()); -} - -TEST_CASE("Check dynamic array of string") { - // clang-format off - std::vector arrayOffset{ - 0, - 4 * sizeof(uint32_t), - 7 * sizeof(uint32_t), - 11 * sizeof(uint32_t) - }; - - std::vector strings{ - "Test 1", "Test 2", "Test 3", "Test 4", - "Test 5", "Test 6", "Test 7", - "test 8", "Test 9", "Test 10", "Test 11" - }; - // clang-format on - - size_t totalSize = 0; - for (const auto& s : strings) { - totalSize += s.size(); - } - - uint32_t currentOffset = 0; - std::vector buffer; - buffer.resize(totalSize); - for (size_t i = 0; i < strings.size(); ++i) { - std::memcpy( - buffer.data() + currentOffset, - strings[i].data(), - strings[i].size()); - currentOffset += static_cast(strings[i].size()); - } - - std::vector offsetBuffer; - offsetBuffer.resize((strings.size() + 1) * sizeof(uint32_t)); - currentOffset = 0; - for (size_t i = 0; i < strings.size(); ++i) { - std::memcpy( - offsetBuffer.data() + i * sizeof(uint32_t), - ¤tOffset, - sizeof(uint32_t)); - currentOffset += static_cast(strings[i].size()); - } - std::memcpy( - offsetBuffer.data() + strings.size() * sizeof(uint32_t), - ¤tOffset, - sizeof(uint32_t)); - - CesiumGltf::MetadataPropertyView< - CesiumGltf::MetadataArrayView> - property( - CesiumGltf::MetadataPropertyViewStatus::Valid, - gsl::span(buffer.data(), buffer.size()), - gsl::span( - reinterpret_cast(arrayOffset.data()), - arrayOffset.size() * sizeof(uint32_t)), - gsl::span(offsetBuffer.data(), offsetBuffer.size()), - CesiumGltf::PropertyType::Uint32, - 0, - 3, - false); - - size_t expectedIdx = 0; - for (int64_t i = 0; i < property.size(); ++i) { - CesiumGltf::MetadataArrayView vals = property.get(i); - for (int64_t j = 0; j < vals.size(); ++j) { - std::string_view v = vals[j]; - REQUIRE(v == strings[expectedIdx]); - ++expectedIdx; - } - } - - REQUIRE(expectedIdx == strings.size()); -} - -TEST_CASE("Check fixed array of boolean") { - std::vector buffer{ - static_cast(0b10101111), - static_cast(0b11111010), - static_cast(0b11100111)}; - - CesiumGltf::MetadataPropertyView> - property( - CesiumGltf::MetadataPropertyViewStatus::Valid, - gsl::span(buffer.data(), buffer.size()), - gsl::span(), - gsl::span(), - CesiumGltf::PropertyType::Uint32, - 12, - 2, - false); - - REQUIRE(property.size() == 2); - - CesiumGltf::MetadataArrayView val0 = property.get(0); - REQUIRE(val0.size() == 12); - REQUIRE(static_cast(val0[0]) == 1); - REQUIRE(static_cast(val0[1]) == 1); - REQUIRE(static_cast(val0[2]) == 1); - REQUIRE(static_cast(val0[3]) == 1); - REQUIRE(static_cast(val0[4]) == 0); - REQUIRE(static_cast(val0[5]) == 1); - REQUIRE(static_cast(val0[6]) == 0); - REQUIRE(static_cast(val0[7]) == 1); - REQUIRE(static_cast(val0[8]) == 0); - REQUIRE(static_cast(val0[9]) == 1); - REQUIRE(static_cast(val0[10]) == 0); - REQUIRE(static_cast(val0[11]) == 1); - - CesiumGltf::MetadataArrayView val1 = property.get(1); - REQUIRE(static_cast(val1[0]) == 1); - REQUIRE(static_cast(val1[1]) == 1); - REQUIRE(static_cast(val1[2]) == 1); - REQUIRE(static_cast(val1[3]) == 1); - REQUIRE(static_cast(val1[4]) == 1); - REQUIRE(static_cast(val1[5]) == 1); - REQUIRE(static_cast(val1[6]) == 1); - REQUIRE(static_cast(val1[7]) == 0); - REQUIRE(static_cast(val1[8]) == 0); - REQUIRE(static_cast(val1[9]) == 1); - REQUIRE(static_cast(val1[10]) == 1); - REQUIRE(static_cast(val1[11]) == 1); -} - -TEST_CASE("Check dynamic array of boolean") { - std::vector buffer{ - static_cast(0b10101111), - static_cast(0b11111010), - static_cast(0b11100111), - static_cast(0b11110110)}; - - std::vector offsetBuffer{0, 3, 12, 28}; - - CesiumGltf::MetadataPropertyView> - property( - CesiumGltf::MetadataPropertyViewStatus::Valid, - gsl::span(buffer.data(), buffer.size()), - gsl::span( - reinterpret_cast(offsetBuffer.data()), - offsetBuffer.size() * sizeof(uint32_t)), - gsl::span(), - CesiumGltf::PropertyType::Uint32, - 0, - 3, - false); - - REQUIRE(property.size() == 3); - - CesiumGltf::MetadataArrayView val0 = property.get(0); - REQUIRE(val0.size() == 3); - REQUIRE(static_cast(val0[0]) == 1); - REQUIRE(static_cast(val0[1]) == 1); - REQUIRE(static_cast(val0[2]) == 1); - - CesiumGltf::MetadataArrayView val1 = property.get(1); - REQUIRE(val1.size() == 9); - REQUIRE(static_cast(val1[0]) == 1); - REQUIRE(static_cast(val1[1]) == 0); - REQUIRE(static_cast(val1[2]) == 1); - REQUIRE(static_cast(val1[3]) == 0); - REQUIRE(static_cast(val1[4]) == 1); - REQUIRE(static_cast(val1[5]) == 0); - REQUIRE(static_cast(val1[6]) == 1); - REQUIRE(static_cast(val1[7]) == 0); - REQUIRE(static_cast(val1[8]) == 1); - - CesiumGltf::MetadataArrayView val2 = property.get(2); - REQUIRE(val2.size() == 16); - REQUIRE(static_cast(val2[0]) == 1); - REQUIRE(static_cast(val2[1]) == 1); - REQUIRE(static_cast(val2[2]) == 1); - REQUIRE(static_cast(val2[3]) == 1); - REQUIRE(static_cast(val2[4]) == 1); - REQUIRE(static_cast(val2[5]) == 1); - REQUIRE(static_cast(val2[6]) == 1); - REQUIRE(static_cast(val2[7]) == 0); - REQUIRE(static_cast(val2[8]) == 0); - REQUIRE(static_cast(val2[9]) == 1); - REQUIRE(static_cast(val2[10]) == 1); - REQUIRE(static_cast(val2[11]) == 1); - REQUIRE(static_cast(val2[12]) == 0); - REQUIRE(static_cast(val2[13]) == 1); - REQUIRE(static_cast(val2[14]) == 1); - REQUIRE(static_cast(val2[15]) == 0); -} diff --git a/CesiumGltf/test/TestStructuralMetadataPropertyType.cpp b/CesiumGltf/test/TestStructuralMetadataPropertyType.cpp deleted file mode 100644 index fbd27e44a..000000000 --- a/CesiumGltf/test/TestStructuralMetadataPropertyType.cpp +++ /dev/null @@ -1,253 +0,0 @@ -#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTableProperty.h" -#include "CesiumGltf/StructuralMetadataPropertyType.h" - -#include - -using namespace CesiumGltf; -using namespace StructuralMetadata; - -TEST_CASE("Test StructuralMetadata PropertyType utilities function") { - SECTION("Convert string to PropertyType") { - REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR) == - PropertyType::Scalar); - - REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::VEC2) == - PropertyType::Vec2); - - REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::VEC3) == - PropertyType::Vec3); - - REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::VEC4) == - PropertyType::Vec4); - - REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::MAT2) == - PropertyType::Mat2); - - REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::MAT3) == - PropertyType::Mat3); - - REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::MAT4) == - PropertyType::Mat4); - - REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN) == - PropertyType::Boolean); - - REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::STRING) == - PropertyType::String); - - REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::ENUM) == - PropertyType::Enum); - - REQUIRE(convertStringToPropertyType("invalid") == PropertyType::Invalid); - } - - SECTION("Convert string to PropertyComponentType") { - REQUIRE( - convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - UINT8) == PropertyComponentType::Uint8); - - REQUIRE( - convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8) == - PropertyComponentType::Int8); - - REQUIRE( - convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - UINT16) == PropertyComponentType::Uint16); - REQUIRE( - convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - INT16) == PropertyComponentType::Int16); - - REQUIRE( - convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - UINT32) == PropertyComponentType::Uint32); - - REQUIRE( - convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - INT32) == PropertyComponentType::Int32); - REQUIRE( - convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - UINT64) == PropertyComponentType::Uint64); - - REQUIRE( - convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - INT64) == PropertyComponentType::Int64); - - REQUIRE( - convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - FLOAT32) == PropertyComponentType::Float32); - REQUIRE( - convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - FLOAT64) == PropertyComponentType::Float64); - - REQUIRE( - convertStringToPropertyComponentType("invalid") == - PropertyComponentType::None); - } - - SECTION("Convert PropertyType to string") { - REQUIRE( - convertPropertyTypeToString(PropertyType::Scalar) == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Vec2) == - ExtensionExtStructuralMetadataClassProperty::Type::VEC2); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Vec3) == - ExtensionExtStructuralMetadataClassProperty::Type::VEC3); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Vec4) == - ExtensionExtStructuralMetadataClassProperty::Type::VEC4); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Mat2) == - ExtensionExtStructuralMetadataClassProperty::Type::MAT2); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Mat3) == - ExtensionExtStructuralMetadataClassProperty::Type::MAT3); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Mat4) == - ExtensionExtStructuralMetadataClassProperty::Type::MAT4); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Boolean) == - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); - - REQUIRE( - convertPropertyTypeToString(PropertyType::String) == - ExtensionExtStructuralMetadataClassProperty::Type::STRING); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Enum) == - ExtensionExtStructuralMetadataClassProperty::Type::ENUM); - } - - SECTION("Convert PropertyComponentType to string") { - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Uint8) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Int8) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Uint16) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Int16) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Uint32) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Int32) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Uint64) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Int64) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Float32) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Float64) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); - } - - SECTION("Convert array offset type string to PropertyComponentType") { - REQUIRE( - convertArrayOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT8) == PropertyComponentType::Uint8); - - REQUIRE( - convertArrayOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT16) == PropertyComponentType::Uint16); - - REQUIRE( - convertArrayOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT32) == PropertyComponentType::Uint32); - - REQUIRE( - convertArrayOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT64) == PropertyComponentType::Uint64); - - REQUIRE( - convertArrayOffsetTypeStringToPropertyComponentType("invalid") == - PropertyComponentType::None); - } - - SECTION("Convert string offset type string to PropertyComponentType") { - REQUIRE( - convertStringOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT8) == PropertyComponentType::Uint8); - - REQUIRE( - convertStringOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT16) == PropertyComponentType::Uint16); - - REQUIRE( - convertStringOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT32) == PropertyComponentType::Uint32); - - REQUIRE( - convertStringOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT64) == PropertyComponentType::Uint64); - - REQUIRE( - convertStringOffsetTypeStringToPropertyComponentType("invalid") == - PropertyComponentType::None); - } -} From bc67ba84908f68c3e0c7f4211582eabe1fc66587 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 6 Jun 2023 11:37:35 -0400 Subject: [PATCH 049/121] Fix other files --- .../src/BatchTableToGltfStructuralMetadata.cpp | 5 ++--- .../TestUpgradeBatchTableToExtStructuralMetadata.cpp | 11 +++++------ CesiumGltf/test/TestPropertyTablePropertyView.cpp | 3 +-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 1262edbc8..46e63c715 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -6,8 +6,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -19,7 +19,6 @@ #include using namespace CesiumGltf; -using namespace CesiumGltf::StructuralMetadata; using namespace Cesium3DTilesSelection::CesiumImpl; namespace Cesium3DTilesSelection { diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 712098bff..702ec8bb7 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -5,8 +5,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -18,7 +18,6 @@ #include using namespace CesiumGltf; -using namespace CesiumGltf::StructuralMetadata; using namespace Cesium3DTilesSelection; using namespace CesiumUtility; @@ -88,13 +87,13 @@ static void checkArrayProperty( REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - PropertyTablePropertyView> propertyView = - view.getPropertyView>(propertyName); + PropertyTablePropertyView> propertyView = + view.getPropertyView>(propertyName); REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() == propertyTable.count); REQUIRE(propertyView.size() == static_cast(expectedTotalInstances)); for (size_t i = 0; i < expectedTotalInstances; ++i) { - MetadataArrayView value = + PropertyArrayView value = propertyView.get(static_cast(i)); if (expectedCount > 0) { REQUIRE(value.size() == expectedCount); diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index ff1e44cec..ae1075ec3 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -855,8 +855,7 @@ TEST_CASE("Check fixed-length array of string") { REQUIRE(expectedIdx == stringCount); } -TEST_CASE( - "Check variable-length array of strings property") { +TEST_CASE("Check variable-length array of strings property") { // clang-format off std::vector arrayOffsets{ 0, From c34b321b303d109a1207d2e27c4a03ef6b661e27 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 6 Jun 2023 12:10:02 -0400 Subject: [PATCH 050/121] Add changelog and delete unused files --- CHANGES.md | 22 ++ .../CesiumGltf/FeatureTexturePropertyView.h | 253 ------------------ .../include/CesiumGltf/FeatureTextureView.h | 110 -------- 3 files changed, 22 insertions(+), 363 deletions(-) delete mode 100644 CesiumGltf/include/CesiumGltf/FeatureTexturePropertyView.h delete mode 100644 CesiumGltf/include/CesiumGltf/FeatureTextureView.h diff --git a/CHANGES.md b/CHANGES.md index 13c2ed0d8..5343e5d35 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,27 @@ # Change Log +### ? - ? + +##### Breaking Changes :mega: + +Many classes have been overhauled to support `EXT_mesh_features` and `EXT_structural_metadata`. This includes the following changes: + +- Replaced `FeatureIDTextureView` with `FeatureIdTextureView`, which views a `ExtensionExtMeshFeaturesFeatureIdTexture`. + - Replaced `FeatureIDTextureViewStatus` with `FeatureIdTextureViewStatus`. + - Replaced `getChannel` with `getChannels`. This retrieves the channels as a vector of integers, instead of a single integer. + - Renamed `getTextureCoordinateAttributeId` to `getTexCoordSetIndex`. +- Replaced `MetadataFeatureTableView` with `PropertyTableView`, which views a `ExtensionExtStructuralMetadataPropertyTable`. + - Added `PropertyTableViewStatus` to indicate whether or not `PropertyTableView` is valid. +- Renamed `MetadataArrayView` to `PropertyArrayView`. +- Replaced `FeatureTextureView` with `PropertyTextureView`, which views a `ExtensionExtMeshFeaturesPropertyTexture`. + - Replaced `FeatureTextureViewStatus` with `PropertyTextureViewStatus`. +- Replaced `FeatureTexturePropertyView` with `PropertyTexturePropertyView`, which views a `ExtensionExtMeshFeaturesPropertyTextureProperty`. + - Replaced `FeatureTexturePropertyViewStatus` with `PropertyTexturePropertyViewStatus`. +- Refactored the `PropertyType` enum to reflect the values of `type` in an `ExtensionExtStructuralMetadataClassProperty`. +- Added the `PropertyComponentType` enum to reflect the values of `componentType` in an `ExtensionExtStructuralMetadataClassProperty`. + +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`. + ### v0.25.0 - 2023-06-01 ##### Additions :tada: diff --git a/CesiumGltf/include/CesiumGltf/FeatureTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/FeatureTexturePropertyView.h deleted file mode 100644 index bbe87a546..000000000 --- a/CesiumGltf/include/CesiumGltf/FeatureTexturePropertyView.h +++ /dev/null @@ -1,253 +0,0 @@ -#pragma once - -#include "CesiumGltf/ClassProperty.h" -#include "CesiumGltf/ExtensionModelExtFeatureMetadata.h" -#include "CesiumGltf/FeatureTexture.h" -#include "CesiumGltf/Sampler.h" -#include "CesiumGltf/Texture.h" -#include "CesiumGltf/TextureAccessor.h" -#include "CesiumGltf/TextureInfo.h" -#include "Image.h" -#include "ImageCesium.h" -#include "Model.h" - -#include -#include -#include - -namespace CesiumGltf { - -/** - * @brief Indicates the status of a feature texture property view. - * - * The {@link FeatureTexturePropertyView} constructor always completes - * successfully. However it may not always reflect the actual content of the - * corresponding feature texture property. This enumeration provides the reason. - */ -enum class FeatureTexturePropertyViewStatus { - /** - * @brief This view is valid and ready to use. - */ - Valid, - - /** - * @brief This view has not been initialized. - */ - InvalidUninitialized, - - /** - * @brief This feature texture property has a texture index that does not - * exist in the glTF. - */ - InvalidTextureIndex, - - /** - * @brief This feature texture property has a texture sampler index that does - * not exist in the glTF. - */ - InvalidTextureSamplerIndex, - - /** - * @brief This feature texture property has an image index that does not - * exist in the glTF. - */ - InvalidImageIndex, - - /** - * @brief This feature texture property points to an empty image. - */ - InvalidEmptyImage, - - /** - * @brief This feature texture property has an invalid channels string. - */ - InvalidChannelsString -}; - -/** - * @brief The supported component types that can exist in feature id textures. - */ -enum class FeatureTexturePropertyComponentType { - Uint8 - // TODO: add more types. Currently this is the only one outputted by stb, - // so change stb call to output more of the original types. -}; - -/** - * @brief Specifies which channel each component exists in or -1 if the channel - * isn't present. This can be used to un-swizzle pixel data. - */ -struct FeatureTexturePropertyChannelOffsets { - int32_t r = -1; - int32_t g = -1; - int32_t b = -1; - int32_t a = -1; -}; - -/** - * @brief The feature texture property value for a pixel. This will contain - * four channels of the specified type. - * - * Only the first n components will be valid, where n is the number of channels - * in this feature texture property. - * - * @tparam T The component type, must correspond to a valid - * {@link FeatureTexturePropertyComponentType}. - */ -template struct FeatureTexturePropertyValue { T components[4]; }; - -/** - * @brief A view of the data specified by a property from a - * {@link FeatureTexture}. - * - * Provides utilities to sample the feature texture property using texture - * coordinates. - */ -class FeatureTexturePropertyView { -public: - /** - * @brief Construct an uninitialized, invalid view. - */ - FeatureTexturePropertyView() noexcept; - - /** - * @brief Construct a view of the data specified by a feature texture - * property. - * - * @param model The glTF in which to look for the data specified by the - * feature texture property. - * @param classProperty The property description. - * @param textureAccessor The texture accessor for this property. - */ - FeatureTexturePropertyView( - const Model& model, - const ClassProperty& classProperty, - const TextureAccessor& textureAccessor) noexcept; - - /** - * @brief Get the property for the given texture coordinates. - * - * Will return -1s when the status is not Valid or when the templated - * component type doesn't match the image's channel byte-size. - * - * @tparam T The component type to use when interpreting the channels of the - * property's pixel value. - * @param u The u-component of the texture coordinates. Must be within - * [0.0, 1.0]. - * @param v The v-component of the texture coordinates. Must be within - * [0.0, 1.0]. - * @return The property at the nearest pixel to the texture coordinates. - */ - template - FeatureTexturePropertyValue - getProperty(double u, double v) const noexcept { - if (this->_status != FeatureTexturePropertyViewStatus::Valid || - sizeof(T) != this->_pImage->bytesPerChannel) { - FeatureTexturePropertyValue property; - property.components[0] = -1; - property.components[1] = -1; - property.components[2] = -1; - property.components[3] = -1; - return property; - } - - // TODO: actually use the sampler?? - int64_t x = std::clamp( - std::llround(u * this->_pImage->width), - 0LL, - (long long)this->_pImage->width); - int64_t y = std::clamp( - std::llround(v * this->_pImage->height), - 0LL, - (long long)this->_pImage->height); - - int64_t pixelOffset = this->_pImage->bytesPerChannel * - this->_pImage->channels * - (y * this->_pImage->width + x); - const T* pRedChannel = reinterpret_cast( - this->_pImage->pixelData.data() + pixelOffset); - - FeatureTexturePropertyValue property; - property.components[0] = *(pRedChannel + this->_channelOffsets.r); - property.components[1] = *(pRedChannel + this->_channelOffsets.g); - property.components[2] = *(pRedChannel + this->_channelOffsets.b); - property.components[3] = *(pRedChannel + this->_channelOffsets.a); - - return property; - } - - /** - * @brief Get the status of this view. - * - * If invalid, it will not be safe to sample feature ids from this view. - */ - FeatureTexturePropertyViewStatus status() const noexcept { - return this->_status; - } - - /** - * @brief Get the component type for this property. - */ - FeatureTexturePropertyComponentType getPropertyType() const noexcept { - return this->_type; - } - - /** - * @brief Get the component count for this property. - * - * This is also how many channels a pixel value for this property will use. - */ - int64_t getComponentCount() const noexcept { return this->_componentCount; } - - /** - * @brief Get the texture coordinate attribute index for this property. - */ - int64_t getTextureCoordinateAttributeId() const noexcept { - return this->_textureCoordinateAttributeId; - } - - /** - * @brief Whether the component type for this property should be normalized. - */ - bool isNormalized() const noexcept { return this->_normalized; } - - /** - * @brief Get the image containing this property's data. - * - * This will be nullptr if the feature texture property view runs into - * problems during construction. - */ - const ImageCesium* getImage() const noexcept { return this->_pImage; } - - /** - * @brief Get the swizzle string for this texture's channels. Used to - * determine which channel represents red, green, blue, and alpha - * respectively. - */ - const std::string& getSwizzle() const noexcept { - const static std::string empty_str = ""; - return this->_pSwizzle ? *this->_pSwizzle : empty_str; - } - - /** - * @brief Get the {@link FeatureTexturePropertyChannelOffsets} that specifies - * how to un-swizzle this property's pixel values. - */ - const FeatureTexturePropertyChannelOffsets& - getChannelOffsets() const noexcept { - return this->_channelOffsets; - } - -private: - const Sampler* _pSampler; - const ImageCesium* _pImage; - const ClassProperty* _pClassProperty; - const std::string* _pSwizzle; - int64_t _textureCoordinateAttributeId; - FeatureTexturePropertyViewStatus _status; - FeatureTexturePropertyChannelOffsets _channelOffsets; - FeatureTexturePropertyComponentType _type; - int64_t _componentCount; - bool _normalized; -}; -} // namespace CesiumGltf \ No newline at end of file diff --git a/CesiumGltf/include/CesiumGltf/FeatureTextureView.h b/CesiumGltf/include/CesiumGltf/FeatureTextureView.h deleted file mode 100644 index 8b6410579..000000000 --- a/CesiumGltf/include/CesiumGltf/FeatureTextureView.h +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -#include "CesiumGltf/Class.h" -#include "CesiumGltf/ClassProperty.h" -#include "CesiumGltf/ExtensionModelExtFeatureMetadata.h" -#include "CesiumGltf/FeatureTexture.h" -#include "CesiumGltf/FeatureTexturePropertyView.h" -#include "CesiumGltf/Texture.h" -#include "CesiumGltf/TextureAccessor.h" -#include "Image.h" -#include "ImageCesium.h" -#include "Model.h" - -namespace CesiumGltf { - -/** - * @brief Indicates the status of a feature texture view. - * - * The {@link FeatureTextureView} constructor always completes successfully. - * However it may not always reflect the actual content of the - * {@link FeatureTexture}. This enumeration provides the reason. - */ -enum class FeatureTextureViewStatus { - /** - * @brief This feature texture view is valid and ready to use. - */ - Valid, - - /** - * @brief This feature texture view is not initialized. - */ - InvalidUninitialized, - - /** - * @brief The glTF is missing the EXT_feature_metadata extension. - */ - InvalidMissingMetadataExtension, - - /** - * @brief The glTF EXT_feature_metadata extension doesn't contain a schema. - */ - InvalidMissingSchema, - - /** - * @brief The feature texture's specified class could not be found in the - * extension. - * - */ - InvalidClassNotFound, - - /** - * @brief A property name specified in the feature texture could not be found - * in the class. - */ - InvalidClassPropertyNotFound, - - /** - * @brief A property view for one of this feature texture's properties failed - * to initialize successfully. Look for the invalid property view's status to - * find why it failed. - */ - InvalidPropertyViewStatus -}; - -/** - * @brief A view on the {@link FeatureTexture}. - * - * Provides access to views on the feature texture properties. - */ -class FeatureTextureView { -public: - /** - * @brief Construct an uninitialized, invalid feature texture view. - */ - FeatureTextureView() noexcept; - - /** - * @brief Construct a view for the feature texture. - * - * @param model The glTF in which to look for the feature texture's data. - * @param featureTexture The feature texture to create a view for. - */ - FeatureTextureView( - const Model& model, - const FeatureTexture& featureTexture) noexcept; - - /** - * @brief Gets the status of this feature texture view. - * - * Indicates whether the view accurately reflects the feature texture's data, - * or whether an error occurred. - */ - FeatureTextureViewStatus status() const noexcept { return this->_status; } - - /** - * @brief Get the views for this feature texture's properties. - */ - const std::unordered_map& - getProperties() const noexcept { - return this->_propertyViews; - } - -private: - const Model* _pModel; - const FeatureTexture* _pFeatureTexture; - const Class* _pClass; - std::unordered_map _propertyViews; - FeatureTextureViewStatus _status; -}; -} // namespace CesiumGltf \ No newline at end of file From a743bb882e6add15928060b1f6c9d754aef77ec5 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 6 Jun 2023 12:54:28 -0400 Subject: [PATCH 051/121] Small changes to BatchTableToGltfStructuralMetadata --- .../BatchTableToGltfStructuralMetadata.cpp | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 46e63c715..915756d45 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -120,82 +120,82 @@ struct CompatibleTypes { // MaskedType or MaskedArrayType, they are considered incompatible with the // other type. private: - std::variant type; + std::variant _type; public: - CompatibleTypes() : type(){}; + CompatibleTypes() : _type(){}; - CompatibleTypes(const MaskedType& maskedType) : type(maskedType){}; + CompatibleTypes(const MaskedType& maskedType) : _type(maskedType){}; CompatibleTypes(const MaskedArrayType& maskedArrayType) - : type(maskedArrayType){}; + : _type(maskedArrayType){}; /** * Whether this is exclusively compatible with array types. */ bool isExclusivelyArray() const { - return std::holds_alternative(type); + return std::holds_alternative(_type); } /** * Marks as incompatible with every type. Fully-incompatible types will be * treated as strings. */ - void makeIncompatible() { type = MaskedType(false); } + void makeIncompatible() { _type = MaskedType(false); } /** * Merges a MaskedType into this CompatibleTypes. */ void operator&=(const MaskedType& inMaskedType) { - if (std::holds_alternative(type)) { - MaskedType& maskedType = std::get(type); + if (std::holds_alternative(_type)) { + MaskedType& maskedType = std::get(_type); maskedType &= inMaskedType; return; } - if (std::holds_alternative(type)) { + if (std::holds_alternative(_type)) { makeIncompatible(); return; } - type = inMaskedType; + _type = inMaskedType; } /** * Merges a MaskedArrayType into this CompatibleTypes. */ void operator&=(const MaskedArrayType& inArrayType) { - if (std::holds_alternative(type)) { - MaskedArrayType& arrayType = std::get(type); + if (std::holds_alternative(_type)) { + MaskedArrayType& arrayType = std::get(_type); arrayType &= inArrayType; return; } - if (std::holds_alternative(type)) { + if (std::holds_alternative(_type)) { makeIncompatible(); return; } - type = inArrayType; + _type = inArrayType; } /** * Merges another CompatibleTypes into this one. */ void operator&=(const CompatibleTypes& inCompatibleTypes) { - if (std::holds_alternative(inCompatibleTypes.type)) { + if (std::holds_alternative(inCompatibleTypes._type)) { // The other CompatibleTypes is compatible with everything, so it does not // change this one. return; } - if (std::holds_alternative(inCompatibleTypes.type)) { + if (std::holds_alternative(inCompatibleTypes._type)) { const MaskedArrayType& arrayType = - std::get(inCompatibleTypes.type); + std::get(inCompatibleTypes._type); operator&=(arrayType); return; } - const MaskedType& maskedType = std::get(inCompatibleTypes.type); + const MaskedType& maskedType = std::get(inCompatibleTypes._type); operator&=(maskedType); } @@ -205,11 +205,11 @@ struct CompatibleTypes { * MaskedType. */ MaskedType toMaskedType() const { - if (std::holds_alternative(type)) { - return std::get(type); + if (std::holds_alternative(_type)) { + return std::get(_type); } - bool isArray = std::holds_alternative(type); + bool isArray = std::holds_alternative(_type); return MaskedType(!isArray); } @@ -219,11 +219,11 @@ struct CompatibleTypes { * incompatible MaskedArrayType. */ MaskedArrayType toMaskedArrayType() const { - if (std::holds_alternative(type)) { - return std::get(type); + if (std::holds_alternative(_type)) { + return std::get(_type); } - bool isNonArray = std::holds_alternative(type); + bool isNonArray = std::holds_alternative(_type); return MaskedArrayType(!isNonArray); } }; @@ -306,7 +306,7 @@ int64_t roundUp(int64_t num, int64_t multiple) noexcept { } template bool isInRangeForSignedInteger(int64_t value) noexcept { - // this only work if sizeof(T) is smaller than int64_t + // This only works if sizeof(T) is smaller than int64_t static_assert( !std::is_same_v && !std::is_same_v && !std::is_same_v); @@ -959,7 +959,8 @@ void updateBooleanArrayProperty( const TValueGetter& propertyValue) { assert(propertyValue.size() >= propertyTable.count); - classProperty.type = "BOOLEAN"; + classProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; classProperty.array = true; // Fixed-length array of booleans @@ -1493,6 +1494,7 @@ void convertBatchTableToGltfStructuralMetadataExtension( ExtensionExtStructuralMetadataPropertyTable& propertyTable = modelExtension.propertyTables.emplace_back(); + propertyTable.name = "default"; propertyTable.count = featureCount; propertyTable.classProperty = "default"; From 3e6e9ce764664499773ee6561e8c62a39e4021fc Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 6 Jun 2023 13:53:16 -0400 Subject: [PATCH 052/121] Fix formatting --- .../src/BatchTableToGltfStructuralMetadata.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 915756d45..9879ff418 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -195,7 +195,8 @@ struct CompatibleTypes { return; } - const MaskedType& maskedType = std::get(inCompatibleTypes._type); + const MaskedType& maskedType = + std::get(inCompatibleTypes._type); operator&=(maskedType); } From b25ad79bdcb6be8c12022c87d096c2c40b786103 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 16 Jun 2023 13:55:43 -0400 Subject: [PATCH 053/121] Start reworking property texture view --- .../include/CesiumGltf/FeatureIdTextureView.h | 12 +- .../CesiumGltf/PropertyTablePropertyView.h | 4 +- .../include/CesiumGltf/PropertyTableView.h | 7 +- .../CesiumGltf/PropertyTexturePropertyView.h | 93 ++++++-- .../include/CesiumGltf/PropertyTextureView.h | 9 +- CesiumGltf/src/FeatureIdTextureView.cpp | 19 +- .../src/PropertyTexturePropertyView.cpp | 83 +++++-- CesiumGltf/src/PropertyTextureView.cpp | 8 - CesiumGltf/test/TestFeatureIdTextureView.cpp | 220 ++++++++++++++++-- .../test/TestPropertyTexturePropertyView.cpp | 176 ++++++++++++-- CesiumGltf/test/TestPropertyTextureView.cpp | 6 +- 11 files changed, 524 insertions(+), 113 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h b/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h index c579ca836..dc86b9924 100644 --- a/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h +++ b/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h @@ -57,11 +57,6 @@ enum class FeatureIdTextureViewStatus { */ ErrorInvalidImageBytesPerChannel, - /** - * @brief This feature ID texture has a negative TEXCOORD set index. - */ - ErrorInvalidTexCoordSetIndex, - /** * @brief The channels of this feature ID texture property are invalid. * Channels must be in the range 0-3, with a minimum of one channel. Although @@ -97,9 +92,8 @@ class FeatureIdTextureView { featureIdTexture) noexcept; /** - * @brief Get the Feature ID for the given texture coordinates. - * - * Will return -1 when the status is not Valid. + * @brief Get the feature ID from the texture at the given texture + * coordinates. If the texture is somehow invalid, this returns -1. * * @param u The u-component of the texture coordinates. Must be within * [0.0, 1.0]. @@ -107,7 +101,7 @@ class FeatureIdTextureView { * [0.0, 1.0]. * @return The feature ID at the nearest pixel to the texture coordinates. */ - int64_t getFeatureId(double u, double v) const noexcept; + int64_t getFeatureID(double u, double v) const noexcept; /** * @brief Get the status of this view. diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 451c5f14d..b9333402d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -28,7 +28,7 @@ enum class PropertyTablePropertyViewStatus { Valid, /** - * @brief This property view was attempting to view an invalid + * @brief This property view was initialized from an invalid * {@link ExtensionExtStructuralMetadataPropertyTable}. */ ErrorInvalidPropertyTable, @@ -38,7 +38,7 @@ enum class PropertyTablePropertyViewStatus { * in the * {@link ExtensionExtStructuralMetadataPropertyTable}. */ - ErrorPropertyDoesNotExist, + ErrorNonexistentProperty, /** * @brief This property view's type does not match what is diff --git a/CesiumGltf/include/CesiumGltf/PropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h index 84757d07f..e36e9f1d5 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -124,7 +124,8 @@ class PropertyTableView { getClassProperty(propertyName); if (!pClassProperty) { return createInvalidPropertyView( - PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist); + StructuralMetadata::PropertyTablePropertyViewStatus:: + ErrorNonexistentProperty); } return getPropertyViewImpl(propertyName, *pClassProperty); @@ -166,7 +167,7 @@ class PropertyTableView { callback( propertyName, createInvalidPropertyView( - PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist)); + PropertyTablePropertyViewStatus::ErrorNonexistentProperty)); return; } @@ -971,7 +972,7 @@ class PropertyTableView { _pPropertyTable->properties.find(propertyName); if (propertyTablePropertyIter == _pPropertyTable->properties.end()) { return createInvalidPropertyView( - PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist); + PropertyTablePropertyViewStatus::ErrorNonexistentProperty); } const ExtensionExtStructuralMetadataPropertyTableProperty& diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index a6b97ccd1..18180cc2d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -33,6 +33,12 @@ enum class PropertyTexturePropertyViewStatus { */ ErrorUninitialized, + /** + * @brief This property texture property is associated with a class property + * with an invalid or unsupported type. + */ + ErrorInvalidClassProperty, + /** * @brief This property texture property has a texture index that does not * exist in the glTF. @@ -56,11 +62,6 @@ enum class PropertyTexturePropertyViewStatus { */ ErrorEmptyImage, - /** - * @brief This property texture property has a negative TEXCOORD set index. - */ - ErrorInvalidTexCoordSetIndex, - /** * @brief The channels of this property texture property are invalid. * Channels must be in the range 0-3, with a minimum of one channel. Although @@ -89,7 +90,9 @@ enum class PropertyTexturePropertyComponentType { * @tparam T The component type, must correspond to a valid * {@link PropertyTexturePropertyComponentType}. */ -template struct PropertyTexturePropertyValue { T components[4]; }; +template struct PropertyTexturePropertyValue { + T components[4]; +}; /** * @brief A view of the data specified by a @@ -122,9 +125,10 @@ class PropertyTexturePropertyView { propertyTextureProperty) noexcept; /** - * @brief Gets the unswizzled property for the given texture coordinates. + * @brief Gets the unswizzled property value for the given texture + * coordinates. * - * Will return -1s when the status is not Valid or when the templated + * Will return 0s when the status is not Valid or when the templated * component type doesn't match the image's channel byte-size. * * @tparam T The component type to use when interpreting the channels of the @@ -136,28 +140,65 @@ class PropertyTexturePropertyView { * @return The property at the nearest pixel to the texture coordinates. */ template - PropertyTexturePropertyValue - getProperty(double u, double v) const noexcept { + PropertyTexturePropertyValue get(double u, double v) const noexcept { PropertyTexturePropertyValue property; - property.components[0] = -1; - property.components[1] = -1; - property.components[2] = -1; - property.components[3] = -1; + property.components[0] = 0; + property.components[1] = 0; + property.components[2] = 0; + property.components[3] = 0; if (this->_status != PropertyTexturePropertyViewStatus::Valid || sizeof(T) != this->_pImage->bytesPerChannel) { return property; } - // TODO: actually use the sampler?? + double fraction = 0, integral = 0; + int64_t integer = 0; + switch (this->_pSampler->wrapS) { + case Sampler::WrapS::REPEAT: + fraction = std::modf(u, &integral); + // Wrap negative values. + u = fraction < 0 ? 1.0 - fraction : fraction; + break; + case Sampler::WrapS::MIRRORED_REPEAT: + fraction = std::abs(std::modf(u, &integral)); + integer = static_cast(std::abs(integral)); + // If the integer part is odd, the direction is reversed. + u = integer % 2 == 1 ? 1.0 - fraction : fraction; + break; + case Sampler::WrapS::CLAMP_TO_EDGE: + default: + u = std::clamp(u, 0.0, 1.0); + break; + } + + switch (this->_pSampler->wrapT) { + case Sampler::WrapT::REPEAT: + fraction = std::modf(v, &integral); + // Wrap negative values. + v = fraction < 0 ? 1.0 - fraction : fraction; + break; + case Sampler::WrapT::MIRRORED_REPEAT: + fraction = std::abs(std::modf(v, &integral)); + integer = static_cast(std::abs(integral)); + // If the integer part is odd, the direction is reversed. + v = integer % 2 == 1 ? 1.0 - fraction : fraction; + break; + case Sampler::WrapT::CLAMP_TO_EDGE: + default: + v = std::clamp(u, 0.0, 1.0); + break; + } + + // Clamp here to ensure no out-of-bounds data access. int64_t x = std::clamp( std::llround(u * this->_pImage->width), 0LL, - (long long)this->_pImage->width); + static_cast(this->_pImage->width) - 1); int64_t y = std::clamp( std::llround(v * this->_pImage->height), 0LL, - (long long)this->_pImage->height); + static_cast(this->_pImage->height) - 1); int64_t pixelOffset = this->_pImage->bytesPerChannel * this->_pImage->channels * @@ -165,6 +206,9 @@ class PropertyTexturePropertyView { const T* pRedChannel = reinterpret_cast( this->_pImage->pixelData.data() + pixelOffset); + // TODO: account for the sampler filter. + // TODO: it is possible for channels to represent multi-byte values for a + // property. But we only support uint8 property types at the moment. for (size_t i = 0; i < this->_channels.size(); i++) { const size_t channel = static_cast(this->_channels[i]); property.components[channel] = *(pRedChannel + channel); @@ -185,15 +229,16 @@ class PropertyTexturePropertyView { /** * @brief Get the component type for this property. */ - PropertyTexturePropertyComponentType getPropertyType() const noexcept { - return this->_type; + PropertyTexturePropertyComponentType + getPropertyComponentType() const noexcept { + return this->_componentType; } /** - * @brief Get the count for this property. This is equivalent to how many - * channels a pixel value for this property will use. + * @brief Get the component count of this property. This is equivalent to how + * many channels a pixel value for this property will use. */ - int64_t getCount() const noexcept { return this->_count; } + int64_t getComponentCount() const noexcept { return this->_componentCount; } /** * @brief Get the texture coordinate set index for this property. @@ -236,8 +281,8 @@ class PropertyTexturePropertyView { int64_t _texCoordSetIndex; std::vector _channels; std::string _swizzle; - PropertyTexturePropertyComponentType _type; - int64_t _count; + PropertyTexturePropertyComponentType _componentType; + int64_t _componentCount; bool _normalized; }; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 69c0f70e2..5cd5e5b34 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -50,14 +50,7 @@ enum class PropertyTextureViewStatus { * @brief A property name specified in the property texture could not be found * in the class. */ - ErrorClassPropertyNotFound, - - /** - * @brief A property view for one of this property texture's properties failed - * to initialize successfully. Look for the invalid property view's status to - * find why it failed. - */ - ErrorInvalidPropertyView + ErrorClassPropertyNotFound }; /** diff --git a/CesiumGltf/src/FeatureIdTextureView.cpp b/CesiumGltf/src/FeatureIdTextureView.cpp index 589f98ac2..a51b72595 100644 --- a/CesiumGltf/src/FeatureIdTextureView.cpp +++ b/CesiumGltf/src/FeatureIdTextureView.cpp @@ -3,7 +3,7 @@ namespace CesiumGltf { FeatureIdTextureView::FeatureIdTextureView() noexcept : _status(FeatureIdTextureViewStatus::ErrorUninitialized), - _texCoordSetIndex(-1), + _texCoordSetIndex(0), _channels(), _pImage(nullptr) {} @@ -11,8 +11,8 @@ FeatureIdTextureView::FeatureIdTextureView( const Model& model, const ExtensionExtMeshFeaturesFeatureIdTexture& featureIdTexture) noexcept : _status(FeatureIdTextureViewStatus::ErrorUninitialized), - _texCoordSetIndex(-1), - _channels(featureIdTexture.channels), + _texCoordSetIndex(featureIdTexture.texCoord), + _channels(), _pImage(nullptr) { int32_t textureIndex = featureIdTexture.index; if (textureIndex < 0 || @@ -29,7 +29,6 @@ FeatureIdTextureView::FeatureIdTextureView( } // Ignore the texture's sampler, we will always use nearest pixel sampling. - this->_pImage = &model.images[static_cast(texture.source)].cesium; if (this->_pImage->width < 1 || this->_pImage->height < 1) { this->_status = FeatureIdTextureViewStatus::ErrorEmptyImage; @@ -45,12 +44,6 @@ FeatureIdTextureView::FeatureIdTextureView( return; } - if (featureIdTexture.texCoord < 0) { - this->_status = FeatureIdTextureViewStatus::ErrorInvalidTexCoordSetIndex; - return; - } - this->_texCoordSetIndex = featureIdTexture.texCoord; - const std::vector& channels = featureIdTexture.channels; if (channels.size() == 0 || channels.size() > 4 || channels.size() > static_cast(this->_pImage->channels)) { @@ -70,7 +63,7 @@ FeatureIdTextureView::FeatureIdTextureView( this->_status = FeatureIdTextureViewStatus::Valid; } -int64_t FeatureIdTextureView::getFeatureId(double u, double v) const noexcept { +int64_t FeatureIdTextureView::getFeatureID(double u, double v) const noexcept { if (this->_status != FeatureIdTextureViewStatus::Valid) { return -1; } @@ -78,11 +71,11 @@ int64_t FeatureIdTextureView::getFeatureId(double u, double v) const noexcept { int64_t x = std::clamp( std::llround(u * this->_pImage->width), 0LL, - (long long)this->_pImage->width); + (long long)this->_pImage->width - 1); int64_t y = std::clamp( std::llround(v * this->_pImage->height), 0LL, - (long long)this->_pImage->height); + (long long)this->_pImage->height - 1); int64_t pixelOffset = this->_pImage->bytesPerChannel * this->_pImage->channels * diff --git a/CesiumGltf/src/PropertyTexturePropertyView.cpp b/CesiumGltf/src/PropertyTexturePropertyView.cpp index d854468d2..495b5da55 100644 --- a/CesiumGltf/src/PropertyTexturePropertyView.cpp +++ b/CesiumGltf/src/PropertyTexturePropertyView.cpp @@ -1,17 +1,47 @@ #include "CesiumGltf/PropertyTexturePropertyView.h" +#include + namespace CesiumGltf { +namespace { +static std::unordered_set supportedTypes{ + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, + ExtensionExtStructuralMetadataClassProperty::Type::VEC2, + ExtensionExtStructuralMetadataClassProperty::Type::VEC3, + ExtensionExtStructuralMetadataClassProperty::Type::VEC4}; + +bool isValidClassProperty( + const ExtensionExtStructuralMetadataClassProperty& classProperty) { + if (supportedTypes.find(classProperty.type) == supportedTypes.end()) { + return false; + } + + // Non-arrays don't need further validation. + if (!classProperty.array) { + return true; + } + + if (classProperty.type != + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR) { + return false; + } + + int64_t count = classProperty.count.value_or(0); + return count > 0 && count <= 4; +} +} // namespace + PropertyTexturePropertyView::PropertyTexturePropertyView() noexcept : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), _pClassProperty(nullptr), _pSampler(nullptr), _pImage(nullptr), - _texCoordSetIndex(-1), + _texCoordSetIndex(0), _channels(), _swizzle(""), - _type(PropertyTexturePropertyComponentType::Uint8), - _count(0), + _componentType(PropertyTexturePropertyComponentType::Uint8), + _componentCount(0), _normalized(false) {} PropertyTexturePropertyView::PropertyTexturePropertyView( @@ -26,9 +56,36 @@ PropertyTexturePropertyView::PropertyTexturePropertyView( _texCoordSetIndex(propertyTextureProperty.texCoord), _channels(), _swizzle(""), - _type(PropertyTexturePropertyComponentType::Uint8), - _count(0), + _componentType(PropertyTexturePropertyComponentType::Uint8), + _componentCount(0), _normalized(false) { + + if (!isValidClassProperty(classProperty)) { + this->_status = + PropertyTexturePropertyViewStatus::ErrorInvalidClassProperty; + return; + } + + if (classProperty.array) { + this->_componentCount = *classProperty.count; + } else if ( + classProperty.type == + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR) { + this->_componentCount = 1; + } else if ( + classProperty.type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC2) { + this->_componentCount = 2; + } else if ( + classProperty.type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC3) { + this->_componentCount = 3; + } else if ( + classProperty.type == + ExtensionExtStructuralMetadataClassProperty::Type::VEC4) { + this->_componentCount = 4; + } + const int64_t index = propertyTextureProperty.index; if (index < 0 || static_cast(index) >= model.textures.size()) { this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidTexture; @@ -57,23 +114,17 @@ PropertyTexturePropertyView::PropertyTexturePropertyView( return; } - if (this->_texCoordSetIndex < 0) { - this->_status = - PropertyTexturePropertyViewStatus::ErrorInvalidTexCoordSetIndex; - return; - } - - // TODO: support more types - // this->_type = ... + // TODO: support more component types + // this->_componentType = ... - this->_count = - this->_pClassProperty->count ? *this->_pClassProperty->count : 1; this->_normalized = this->_pClassProperty->normalized; + // TODO: channels can represent a multi-byte value, so the last check will + // need to change. const std::vector& channels = propertyTextureProperty.channels; if (channels.size() == 0 || channels.size() > 4 || channels.size() > static_cast(this->_pImage->channels) || - channels.size() != static_cast(this->_count)) { + channels.size() != static_cast(this->_componentCount)) { this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidChannels; return; } diff --git a/CesiumGltf/src/PropertyTextureView.cpp b/CesiumGltf/src/PropertyTextureView.cpp index 7f917c8a9..bd795ad6f 100644 --- a/CesiumGltf/src/PropertyTextureView.cpp +++ b/CesiumGltf/src/PropertyTextureView.cpp @@ -55,14 +55,6 @@ PropertyTextureView::PropertyTextureView( property.second); } - for (const auto& propertyView : this->_propertyViews) { - if (propertyView.second.status() != - PropertyTexturePropertyViewStatus::Valid) { - this->_status = PropertyTextureViewStatus::ErrorInvalidPropertyView; - return; - } - } - this->_status = PropertyTextureViewStatus::Valid; } diff --git a/CesiumGltf/test/TestFeatureIdTextureView.cpp b/CesiumGltf/test/TestFeatureIdTextureView.cpp index a6755667f..112148ed0 100644 --- a/CesiumGltf/test/TestFeatureIdTextureView.cpp +++ b/CesiumGltf/test/TestFeatureIdTextureView.cpp @@ -123,8 +123,7 @@ TEST_CASE("Test FeatureIdTextureView on feature ID texture with too many bytes " } TEST_CASE( - "Test FeatureIdTextureView on feature ID texture with negative texcoord " - "set index") { + "Test FeatureIdTextureView on feature ID texture with zero channels") { Model model; Mesh& mesh = model.meshes.emplace_back(); MeshPrimitive& primitive = mesh.primitives.emplace_back(); @@ -142,21 +141,19 @@ TEST_CASE( ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; featureIdTexture.index = 0; - featureIdTexture.texCoord = -1; - featureIdTexture.channels = {0}; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {}; ExtensionExtMeshFeaturesFeatureId featureId = meshFeatures.featureIds.emplace_back(); featureId.texture = featureIdTexture; FeatureIdTextureView view(model, featureIdTexture); - REQUIRE( - view.status() == - FeatureIdTextureViewStatus::ErrorInvalidTexCoordSetIndex); + REQUIRE(view.status() == FeatureIdTextureViewStatus::ErrorInvalidChannels); } TEST_CASE( - "Test FeatureIdTextureView on feature ID texture with zero channels") { + "Test FeatureIdTextureView on feature ID texture with too many channels") { Model model; Mesh& mesh = model.meshes.emplace_back(); MeshPrimitive& primitive = mesh.primitives.emplace_back(); @@ -175,7 +172,7 @@ TEST_CASE( ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; featureIdTexture.index = 0; featureIdTexture.texCoord = 0; - featureIdTexture.channels = {}; + featureIdTexture.channels = {0, 1, 2, 3, 3}; ExtensionExtMeshFeaturesFeatureId featureId = meshFeatures.featureIds.emplace_back(); @@ -185,8 +182,8 @@ TEST_CASE( REQUIRE(view.status() == FeatureIdTextureViewStatus::ErrorInvalidChannels); } -TEST_CASE( - "Test FeatureIdTextureView on feature ID texture with too many channels") { +TEST_CASE("Test FeatureIdTextureView on feature ID texture with out of range " + "channel") { Model model; Mesh& mesh = model.meshes.emplace_back(); MeshPrimitive& primitive = mesh.primitives.emplace_back(); @@ -205,7 +202,7 @@ TEST_CASE( ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; featureIdTexture.index = 0; featureIdTexture.texCoord = 0; - featureIdTexture.channels = {0, 1, 2, 3, 3}; + featureIdTexture.channels = {4}; ExtensionExtMeshFeaturesFeatureId featureId = meshFeatures.featureIds.emplace_back(); @@ -215,8 +212,36 @@ TEST_CASE( REQUIRE(view.status() == FeatureIdTextureViewStatus::ErrorInvalidChannels); } -TEST_CASE("Test FeatureIdTextureView on feature ID texture with out of range " - "channel") { +TEST_CASE("Test FeatureIdTextureView on valid feature ID texture") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {0}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::Valid); +} + +TEST_CASE("Test getFeatureID on invalid feature ID texture view") { Model model; Mesh& mesh = model.meshes.emplace_back(); MeshPrimitive& primitive = mesh.primitives.emplace_back(); @@ -243,4 +268,171 @@ TEST_CASE("Test FeatureIdTextureView on feature ID texture with out of range " FeatureIdTextureView view(model, featureIdTexture); REQUIRE(view.status() == FeatureIdTextureViewStatus::ErrorInvalidChannels); + REQUIRE(view.getFeatureID(0, 0) == -1); +} + +TEST_CASE("Test getFeatureID on valid feature ID texture view") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector featureIDs{1, 2, 0, 7}; + + Image& image = model.images.emplace_back(); + image.cesium.width = 2; + image.cesium.height = 2; + image.cesium.channels = 1; + image.cesium.bytesPerChannel = 1; + image.cesium.pixelData.resize(featureIDs.size()); + std::memcpy( + image.cesium.pixelData.data(), + featureIDs.data(), + featureIDs.size()); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {0}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::Valid); + REQUIRE(view.getFeatureID(0, 0) == 1); + REQUIRE(view.getFeatureID(1, 0) == 2); + REQUIRE(view.getFeatureID(0, 1) == 0); + REQUIRE(view.getFeatureID(1, 1) == 7); +} + +TEST_CASE("Test getFeatureID rounds to nearest pixel") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector featureIDs{1, 2, 0, 7}; + + Image& image = model.images.emplace_back(); + image.cesium.width = 2; + image.cesium.height = 2; + image.cesium.channels = 1; + image.cesium.bytesPerChannel = 1; + image.cesium.pixelData.resize(featureIDs.size()); + std::memcpy( + image.cesium.pixelData.data(), + featureIDs.data(), + featureIDs.size()); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {0}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::Valid); + REQUIRE(view.getFeatureID(0.1, 0.24) == 1); + REQUIRE(view.getFeatureID(0.86, 0.2) == 2); + REQUIRE(view.getFeatureID(0.21, 0.555) == 0); + REQUIRE(view.getFeatureID(0.99, 0.81) == 7); +} + +TEST_CASE("Test getFeatureID clamps values") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector featureIDs{1, 2, 0, 7}; + + Image& image = model.images.emplace_back(); + image.cesium.width = 2; + image.cesium.height = 2; + image.cesium.channels = 1; + image.cesium.bytesPerChannel = 1; + + auto& data = image.cesium.pixelData; + data.resize(featureIDs.size() * sizeof(uint8_t)); + std::memcpy(data.data(), featureIDs.data(), data.size()); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {0}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::Valid); + REQUIRE(view.getFeatureID(-1, -1) == 1); + REQUIRE(view.getFeatureID(2, 0) == 2); + REQUIRE(view.getFeatureID(-1, 2) == 0); + REQUIRE(view.getFeatureID(3, 4) == 7); +} + +TEST_CASE("Test getFeatureID handles multiple channels") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector featureIDs{260, 512, 8, 17}; + + Image& image = model.images.emplace_back(); + image.cesium.width = 2; + image.cesium.height = 2; + image.cesium.channels = 2; + image.cesium.bytesPerChannel = 1; + + auto& data = image.cesium.pixelData; + data.resize(featureIDs.size() * sizeof(uint16_t)); + std::memcpy(data.data(), featureIDs.data(), data.size()); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtMeshFeatures& meshFeatures = + primitive.addExtension(); + + ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + featureIdTexture.index = 0; + featureIdTexture.texCoord = 0; + featureIdTexture.channels = {0, 1}; + + ExtensionExtMeshFeaturesFeatureId featureId = + meshFeatures.featureIds.emplace_back(); + featureId.texture = featureIdTexture; + + FeatureIdTextureView view(model, featureIdTexture); + REQUIRE(view.status() == FeatureIdTextureViewStatus::Valid); + REQUIRE(view.getFeatureID(0, 0) == 260); + REQUIRE(view.getFeatureID(1, 0) == 512); + REQUIRE(view.getFeatureID(0, 1) == 8); + REQUIRE(view.getFeatureID(1, 1) == 17); } diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index e6d96520e..378fad54d 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -161,8 +161,8 @@ TEST_CASE("Test PropertyTexturePropertyView on property with empty image") { REQUIRE(view.status() == PropertyTexturePropertyViewStatus::ErrorEmptyImage); } -TEST_CASE("Test PropertyTextureView on property table property with negative " - "texcoord set index") { +TEST_CASE("Test PropertyTextureView on property texture property with zero " + "channels") { Model model; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -179,6 +179,7 @@ TEST_CASE("Test PropertyTextureView on property table property with negative " Image& image = model.images.emplace_back(); image.cesium.width = 1; image.cesium.height = 1; + image.cesium.channels = 1; model.samplers.emplace_back(); @@ -192,19 +193,18 @@ TEST_CASE("Test PropertyTextureView on property table property with negative " ExtensionExtStructuralMetadataPropertyTextureProperty& propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = -1; - propertyTextureProperty.channels = {0}; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {}; PropertyTexturePropertyView view( model, testClassProperty, propertyTextureProperty); REQUIRE( - view.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidTexCoordSetIndex); + view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidChannels); } -TEST_CASE("Test PropertyTextureView on property texture property with zero " +TEST_CASE("Test PropertyTextureView on property texture property with too many " "channels") { Model model; ExtensionModelExtStructuralMetadata& metadata = @@ -237,7 +237,7 @@ TEST_CASE("Test PropertyTextureView on property texture property with zero " propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {}; + propertyTextureProperty.channels = {0, 1}; PropertyTexturePropertyView view( model, @@ -247,8 +247,7 @@ TEST_CASE("Test PropertyTextureView on property texture property with zero " view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidChannels); } -TEST_CASE("Test PropertyTextureView on property texture property with too many " - "channels") { +TEST_CASE("Test PropertyTexturePropertyView on valid property texture") { Model model; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -280,12 +279,163 @@ TEST_CASE("Test PropertyTextureView on property texture property with too many " propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0, 1}; + propertyTextureProperty.channels = {0}; PropertyTexturePropertyView view( model, testClassProperty, propertyTextureProperty); - REQUIRE( - view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidChannels); + REQUIRE(view.status() == PropertyTexturePropertyViewStatus::Valid); +} + +TEST_CASE("Test getSwizzle") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + testClassProperty.count = 4; + + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + image.cesium.channels = 4; + + model.samplers.emplace_back(); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0, 2, 3, 1}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE(view.status() == PropertyTexturePropertyViewStatus::Valid); + REQUIRE(view.getCount() == 4); + REQUIRE(view.getSwizzle() == "rbag"); +} + +TEST_CASE("Test getting value from invalid view") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + Image& image = model.images.emplace_back(); + image.cesium.width = 0; + image.cesium.height = 1; + image.cesium.channels = 1; + + model.samplers.emplace_back(); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE(view.status() != PropertyTexturePropertyViewStatus::Valid); + PropertyTexturePropertyValue value = view.get(0, 0); + REQUIRE(value.components[0] == 0); + REQUIRE(value.components[1] == 0); + REQUIRE(value.components[2] == 0); + REQUIRE(value.components[3] == 0); +} + +TEST_CASE("Test getting value from valid view") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); + ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; + ExtensionExtStructuralMetadataClassProperty& testClassProperty = + testClass.properties["TestClassProperty"]; + testClassProperty.type = + ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + testClassProperty.componentType = + ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + + std::vector values{10, 8, 4, 22}; + + Image& image = model.images.emplace_back(); + image.cesium.width = 2; + image.cesium.height = 2; + image.cesium.channels = 1; + image.cesium.bytesPerChannel = 1; + image.cesium.pixelData.resize(values.size()); + std::memcpy(image.cesium.pixelData.data(), values.data(), values.size()); + + Sampler& sampler = model.samplers.emplace_back(); + sampler.wrapS = Sampler::WrapS::CLAMP_TO_EDGE; + sampler.wrapT = Sampler::WrapT::CLAMP_TO_EDGE; + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + ExtensionExtStructuralMetadataPropertyTextureProperty& + propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE(view.status() == PropertyTexturePropertyViewStatus::Valid); + + std::vector> viewValues{ + view.get(0, 0), + view.get(1.0, 0), + view.get(0, 1.0), + view.get(1.0, 1.0)}; + + for (size_t i = 0; i < viewValues.size(); i++) { + PropertyTexturePropertyValue& actual = viewValues[i]; + REQUIRE(actual.components[0] == values[i]); + REQUIRE(actual.components[1] == 0); + REQUIRE(actual.components[2] == 0); + REQUIRE(actual.components[3] == 0); + } } diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index 6ca05cad2..7e3e674e4 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -130,7 +130,7 @@ TEST_CASE("Test property texture with nonexistent class property") { REQUIRE(!classProperty); } -TEST_CASE("Test property texture with invalid property") { +TEST_CASE("Test property texture with invalid property is still valid") { Model model; ExtensionModelExtStructuralMetadata& metadata = @@ -154,7 +154,7 @@ TEST_CASE("Test property texture with invalid property") { propertyTextureProperty.index = -1; PropertyTextureView view(model, propertyTexture); - REQUIRE(view.status() == PropertyTextureViewStatus::ErrorInvalidPropertyView); + REQUIRE(view.status() == PropertyTextureViewStatus::Valid); auto properties = view.getProperties(); REQUIRE(properties.size() == 1); @@ -164,5 +164,5 @@ TEST_CASE("Test property texture with invalid property") { const ExtensionExtStructuralMetadataClassProperty* classProperty = view.getClassProperty("TestClassProperty"); - REQUIRE(!classProperty); + REQUIRE(classProperty == &testClassProperty); } From 2a29791df80dfa4eec4dee7e2272cc8526db4fb2 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 16 Jun 2023 14:31:58 -0400 Subject: [PATCH 054/121] Update upsampleGltfForRasterOverlays for EXT_structural_metadata --- .../src/upsampleGltfForRasterOverlays.cpp | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/Cesium3DTilesSelection/src/upsampleGltfForRasterOverlays.cpp b/Cesium3DTilesSelection/src/upsampleGltfForRasterOverlays.cpp index 3a0409607..8469f1134 100644 --- a/Cesium3DTilesSelection/src/upsampleGltfForRasterOverlays.cpp +++ b/Cesium3DTilesSelection/src/upsampleGltfForRasterOverlays.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -1244,24 +1244,21 @@ static int32_t copyBufferView( return static_cast(bufferViewId); } -// Copy and reconstruct buffer views and buffers from EXT_feature_metadata -// feature tables. +// Copy and reconstruct buffer views and buffers from EXT_structural_metadata +// property tables. static void copyMetadataTables(const Model& parentModel, Model& result) { - ExtensionModelExtFeatureMetadata* pMetadata = - result.getExtension(); + ExtensionModelExtStructuralMetadata* pMetadata = + result.getExtension(); if (pMetadata) { - for (auto& featureTablePair : pMetadata->featureTables) { - for (auto& propertyPair : featureTablePair.second.properties) { - FeatureTableProperty& property = propertyPair.second; - - property.bufferView = - copyBufferView(parentModel, property.bufferView, result); - property.arrayOffsetBufferView = - copyBufferView(parentModel, property.arrayOffsetBufferView, result); - property.stringOffsetBufferView = copyBufferView( - parentModel, - property.stringOffsetBufferView, - result); + for (auto& propertyTable : pMetadata->propertyTables) { + for (auto& propertyPair : propertyTable.properties) { + ExtensionExtStructuralMetadataPropertyTableProperty& property = + propertyPair.second; + property.values = copyBufferView(parentModel, property.values, result); + property.arrayOffsets = + copyBufferView(parentModel, property.arrayOffsets, result); + property.stringOffsets = + copyBufferView(parentModel, property.stringOffsets, result); } } } From e0f49321c55de1ab407df3a4e078878ec98a08b4 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 16 Jun 2023 15:16:05 -0400 Subject: [PATCH 055/121] Prefix EXT_feature_metadata files, rename EXT_mesh_features files --- .../BatchTableToGltfStructuralMetadata.cpp | 6 +- .../test/TestPntsToGltfConverter.cpp | 15 +- ...gradeBatchTableToExtStructuralMetadata.cpp | 15 +- ...s.h => ExtensionExtFeatureMetadataClass.h} | 13 +- ...xtensionExtFeatureMetadataClassProperty.h} | 5 +- ...ensionExtFeatureMetadataClassStatistics.h} | 12 +- ...um.h => ExtensionExtFeatureMetadataEnum.h} | 10 +- ...=> ExtensionExtFeatureMetadataEnumValue.h} | 6 +- ...ionExtFeatureMetadataFeatureIDAttribute.h} | 9 +- ...nsionExtFeatureMetadataFeatureIDTexture.h} | 9 +- ...> ExtensionExtFeatureMetadataFeatureIDs.h} | 5 +- ...ExtensionExtFeatureMetadataFeatureTable.h} | 12 +- ...nExtFeatureMetadataFeatureTableProperty.h} | 5 +- ...tensionExtFeatureMetadataFeatureTexture.h} | 12 +- ...ionExtFeatureMetadataPropertyStatistics.h} | 5 +- ....h => ExtensionExtFeatureMetadataSchema.h} | 16 +- ...> ExtensionExtFeatureMetadataStatistics.h} | 12 +- ...ensionExtFeatureMetadataTextureAccessor.h} | 5 +- .../CesiumGltf/ExtensionExtMeshFeatures.h | 4 +- ...ExtensionMeshPrimitiveExtFeatureMetadata.h | 10 +- .../ExtensionModelExtFeatureMetadata.h | 22 +- ...ExtMeshFeaturesFeatureId.h => FeatureId.h} | 10 +- ...sFeatureIdTexture.h => FeatureIdTexture.h} | 6 +- .../include/CesiumGltf/FeatureIdTextureView.h | 20 +- .../include/CesiumGltf/PropertyTextureView.h | 1 - CesiumGltf/src/FeatureIdTextureView.cpp | 2 +- CesiumGltf/test/TestFeatureIdTextureView.cpp | 40 +- .../generated/src/ClassJsonHandler.h | 41 - .../generated/src/EnumJsonHandler.h | 42 - ...ensionExtFeatureMetadataClassJsonHandler.h | 45 + ...FeatureMetadataClassPropertyJsonHandler.h} | 18 +- ...atureMetadataClassStatisticsJsonHandler.h} | 25 +- ...tensionExtFeatureMetadataEnumJsonHandler.h | 46 + ...nExtFeatureMetadataEnumValueJsonHandler.h} | 18 +- ...ureMetadataFeatureIDAttributeJsonHandler.h | 40 + ...atureMetadataFeatureIDTextureJsonHandler.h | 40 + ...ExtFeatureMetadataFeatureIDsJsonHandler.h} | 18 +- ...tFeatureMetadataFeatureTableJsonHandler.h} | 24 +- ...MetadataFeatureTablePropertyJsonHandler.h} | 17 +- ...eatureMetadataFeatureTextureJsonHandler.h} | 24 +- ...reMetadataPropertyStatisticsJsonHandler.h} | 19 +- ...nsionExtFeatureMetadataSchemaJsonHandler.h | 51 + ...nExtFeatureMetadataStatisticsJsonHandler.h | 42 + ...atureMetadataTextureAccessorJsonHandler.h} | 19 +- .../src/ExtensionExtMeshFeaturesJsonHandler.h | 9 +- ...shPrimitiveExtFeatureMetadataJsonHandler.h | 12 +- ...ensionModelExtFeatureMetadataJsonHandler.h | 23 +- .../src/FeatureIDAttributeJsonHandler.h | 39 - .../src/FeatureIDTextureJsonHandler.h | 39 - ...IdJsonHandler.h => FeatureIdJsonHandler.h} | 22 +- ...andler.h => FeatureIdTextureJsonHandler.h} | 20 +- .../generated/src/GeneratedJsonHandlers.cpp | 3509 ++++------------- .../generated/src/SchemaJsonHandler.h | 44 - .../generated/src/StatisticsJsonHandler.h | 40 - .../generated/src/registerExtensions.cpp | 123 +- .../generated/src/ModelJsonWriter.cpp | 177 +- .../generated/src/ModelJsonWriter.h | 136 +- tools/generate-classes/glTF.json | 34 +- 58 files changed, 1632 insertions(+), 3411 deletions(-) rename CesiumGltf/generated/include/CesiumGltf/{Class.h => ExtensionExtFeatureMetadataClass.h} (63%) rename CesiumGltf/generated/include/CesiumGltf/{ClassProperty.h => ExtensionExtFeatureMetadataClassProperty.h} (97%) rename CesiumGltf/generated/include/CesiumGltf/{ClassStatistics.h => ExtensionExtFeatureMetadataClassStatistics.h} (66%) rename CesiumGltf/generated/include/CesiumGltf/{Enum.h => ExtensionExtFeatureMetadataEnum.h} (80%) rename CesiumGltf/generated/include/CesiumGltf/{EnumValue.h => ExtensionExtFeatureMetadataEnumValue.h} (73%) rename CesiumGltf/generated/include/CesiumGltf/{FeatureIDAttribute.h => ExtensionExtFeatureMetadataFeatureIDAttribute.h} (72%) rename CesiumGltf/generated/include/CesiumGltf/{FeatureIDTexture.h => ExtensionExtFeatureMetadataFeatureIDTexture.h} (75%) rename CesiumGltf/generated/include/CesiumGltf/{FeatureIDs.h => ExtensionExtFeatureMetadataFeatureIDs.h} (87%) rename CesiumGltf/generated/include/CesiumGltf/{FeatureTable.h => ExtensionExtFeatureMetadataFeatureTable.h} (73%) rename CesiumGltf/generated/include/CesiumGltf/{FeatureTableProperty.h => ExtensionExtFeatureMetadataFeatureTableProperty.h} (95%) rename CesiumGltf/generated/include/CesiumGltf/{FeatureTexture.h => ExtensionExtFeatureMetadataFeatureTexture.h} (71%) rename CesiumGltf/generated/include/CesiumGltf/{PropertyStatistics.h => ExtensionExtFeatureMetadataPropertyStatistics.h} (95%) rename CesiumGltf/generated/include/CesiumGltf/{Schema.h => ExtensionExtFeatureMetadataSchema.h} (63%) rename CesiumGltf/generated/include/CesiumGltf/{Statistics.h => ExtensionExtFeatureMetadataStatistics.h} (61%) rename CesiumGltf/generated/include/CesiumGltf/{TextureAccessor.h => ExtensionExtFeatureMetadataTextureAccessor.h} (80%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtMeshFeaturesFeatureId.h => FeatureId.h} (79%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtMeshFeaturesFeatureIdTexture.h => FeatureIdTexture.h} (76%) delete mode 100644 CesiumGltfReader/generated/src/ClassJsonHandler.h delete mode 100644 CesiumGltfReader/generated/src/EnumJsonHandler.h create mode 100644 CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataClassJsonHandler.h rename CesiumGltfReader/generated/src/{ClassPropertyJsonHandler.h => ExtensionExtFeatureMetadataClassPropertyJsonHandler.h} (70%) rename CesiumGltfReader/generated/src/{ClassStatisticsJsonHandler.h => ExtensionExtFeatureMetadataClassStatisticsJsonHandler.h} (50%) create mode 100644 CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataEnumJsonHandler.h rename CesiumGltfReader/generated/src/{EnumValueJsonHandler.h => ExtensionExtFeatureMetadataEnumValueJsonHandler.h} (60%) create mode 100644 CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler.h create mode 100644 CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler.h rename CesiumGltfReader/generated/src/{FeatureIDsJsonHandler.h => ExtensionExtFeatureMetadataFeatureIDsJsonHandler.h} (60%) rename CesiumGltfReader/generated/src/{FeatureTableJsonHandler.h => ExtensionExtFeatureMetadataFeatureTableJsonHandler.h} (53%) rename CesiumGltfReader/generated/src/{FeatureTablePropertyJsonHandler.h => ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler.h} (62%) rename CesiumGltfReader/generated/src/{FeatureTextureJsonHandler.h => ExtensionExtFeatureMetadataFeatureTextureJsonHandler.h} (50%) rename CesiumGltfReader/generated/src/{PropertyStatisticsJsonHandler.h => ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler.h} (65%) create mode 100644 CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataSchemaJsonHandler.h create mode 100644 CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataStatisticsJsonHandler.h rename CesiumGltfReader/generated/src/{TextureAccessorJsonHandler.h => ExtensionExtFeatureMetadataTextureAccessorJsonHandler.h} (55%) delete mode 100644 CesiumGltfReader/generated/src/FeatureIDAttributeJsonHandler.h delete mode 100644 CesiumGltfReader/generated/src/FeatureIDTextureJsonHandler.h rename CesiumGltfReader/generated/src/{ExtensionExtMeshFeaturesFeatureIdJsonHandler.h => FeatureIdJsonHandler.h} (59%) rename CesiumGltfReader/generated/src/{ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler.h => FeatureIdTextureJsonHandler.h} (53%) delete mode 100644 CesiumGltfReader/generated/src/SchemaJsonHandler.h delete mode 100644 CesiumGltfReader/generated/src/StatisticsJsonHandler.h diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 9879ff418..93dce98d2 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -1631,8 +1631,7 @@ ErrorList BatchTableToGltfStructuralMetadata::convertFromB3dm( ExtensionExtMeshFeatures& extension = primitive.addExtension(); - ExtensionExtMeshFeaturesFeatureId& featureID = - extension.featureIds.emplace_back(); + FeatureId& featureID = extension.featureIds.emplace_back(); // No fast way to count the unique feature IDs in this primitive, so // subtitute the batch table length. featureID.featureCount = batchLength; @@ -1705,8 +1704,7 @@ ErrorList BatchTableToGltfStructuralMetadata::convertFromPnts( ExtensionExtMeshFeatures& extension = primitive.addExtension(); - ExtensionExtMeshFeaturesFeatureId& featureID = - extension.featureIds.emplace_back(); + FeatureId& featureID = extension.featureIds.emplace_back(); // Setting the feature count is sufficient for implicit feature IDs. featureID.featureCount = featureCount; diff --git a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp index ca7bdca5a..e93e333f2 100644 --- a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp +++ b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp @@ -678,8 +678,7 @@ TEST_CASE("Converts point cloud with batch IDs to glTF with " auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); REQUIRE(primitiveExtension->featureIds.size() == 1); - ExtensionExtMeshFeaturesFeatureId& featureId = - primitiveExtension->featureIds[0]; + FeatureId& featureId = primitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 8); CHECK(featureId.attribute == 0); @@ -757,8 +756,7 @@ TEST_CASE("Converts point cloud with per-point properties to glTF with " auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); REQUIRE(primitiveExtension->featureIds.size() == 1); - ExtensionExtMeshFeaturesFeatureId& featureId = - primitiveExtension->featureIds[0]; + FeatureId& featureId = primitiveExtension->featureIds[0]; // Check for implicit feature IDs CHECK(featureId.featureCount == pointsLength); CHECK(!featureId.attribute); @@ -816,8 +814,7 @@ TEST_CASE("Converts point cloud with Draco compression to glTF") { auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); REQUIRE(primitiveExtension->featureIds.size() == 1); - ExtensionExtMeshFeaturesFeatureId& featureId = - primitiveExtension->featureIds[0]; + FeatureId& featureId = primitiveExtension->featureIds[0]; // Check for implicit feature IDs CHECK(featureId.featureCount == pointsLength); CHECK(!featureId.attribute); @@ -960,8 +957,7 @@ TEST_CASE("Converts point cloud with partial Draco compression to glTF") { auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); REQUIRE(primitiveExtension->featureIds.size() == 1); - ExtensionExtMeshFeaturesFeatureId& featureId = - primitiveExtension->featureIds[0]; + FeatureId& featureId = primitiveExtension->featureIds[0]; // Check for implicit feature IDs CHECK(featureId.featureCount == pointsLength); CHECK(!featureId.attribute); @@ -1099,8 +1095,7 @@ TEST_CASE("Converts batched point cloud with Draco compression to glTF") { auto primitiveExtension = primitive.getExtension(); REQUIRE(primitiveExtension); REQUIRE(primitiveExtension->featureIds.size() == 1); - ExtensionExtMeshFeaturesFeatureId& featureId = - primitiveExtension->featureIds[0]; + FeatureId& featureId = primitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 8); CHECK(featureId.attribute == 0); diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 702ec8bb7..74c81c281 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -411,8 +411,7 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { primitive.getExtension(); REQUIRE(pPrimitiveExtension); REQUIRE(pPrimitiveExtension->featureIds.size() == 1); - ExtensionExtMeshFeaturesFeatureId& featureId = - pPrimitiveExtension->featureIds[0]; + FeatureId& featureId = pPrimitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 10); CHECK(featureId.attribute == 0); CHECK(featureId.propertyTable == 0); @@ -557,8 +556,7 @@ TEST_CASE("Convert binary B3DM batch table to EXT_structural_metadata") { primitive.getExtension(); REQUIRE(pPrimitiveExtension); REQUIRE(pPrimitiveExtension->featureIds.size() == 1); - const ExtensionExtMeshFeaturesFeatureId& featureId = - pPrimitiveExtension->featureIds[0]; + const FeatureId& featureId = pPrimitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 10); CHECK(featureId.attribute == 0); CHECK(featureId.propertyTable == 0); @@ -780,8 +778,7 @@ TEST_CASE("Converts batched PNTS batch table to EXT_structural_metadata") { primitive.getExtension(); REQUIRE(pPrimitiveExtension); REQUIRE(pPrimitiveExtension->featureIds.size() == 1); - const ExtensionExtMeshFeaturesFeatureId& featureId = - pPrimitiveExtension->featureIds[0]; + const FeatureId& featureId = pPrimitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 8); CHECK(featureId.attribute == 0); CHECK(featureId.propertyTable == 0); @@ -942,8 +939,7 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_structural_metadata") { primitive.getExtension(); REQUIRE(pPrimitiveExtension); REQUIRE(pPrimitiveExtension->featureIds.size() == 1); - const ExtensionExtMeshFeaturesFeatureId& featureId = - pPrimitiveExtension->featureIds[0]; + const FeatureId& featureId = pPrimitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 8); CHECK(!featureId.attribute); CHECK(featureId.propertyTable == 0); @@ -1104,8 +1100,7 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " primitive.getExtension(); REQUIRE(pPrimitiveExtension); REQUIRE(pPrimitiveExtension->featureIds.size() == 1); - const ExtensionExtMeshFeaturesFeatureId& featureId = - pPrimitiveExtension->featureIds[0]; + const FeatureId& featureId = pPrimitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 8); CHECK(!featureId.attribute); CHECK(featureId.propertyTable == 0); diff --git a/CesiumGltf/generated/include/CesiumGltf/Class.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataClass.h similarity index 63% rename from CesiumGltf/generated/include/CesiumGltf/Class.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataClass.h index e48709493..85faeb5b3 100644 --- a/CesiumGltf/generated/include/CesiumGltf/Class.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataClass.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ClassProperty.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataClassProperty.h" #include "CesiumGltf/Library.h" #include @@ -15,8 +15,10 @@ namespace CesiumGltf { /** * @brief A class containing a set of properties. */ -struct CESIUMGLTF_API Class final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "Class"; +struct CESIUMGLTF_API ExtensionExtFeatureMetadataClass final + : public CesiumUtility::ExtensibleObject { + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataClass"; /** * @brief The name of the class, e.g. for display purposes. @@ -32,6 +34,9 @@ struct CESIUMGLTF_API Class final : public CesiumUtility::ExtensibleObject { * @brief A dictionary, where each key is a property ID and each value is an * object defining the property. */ - std::unordered_map properties; + std::unordered_map< + std::string, + CesiumGltf::ExtensionExtFeatureMetadataClassProperty> + properties; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/ClassProperty.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataClassProperty.h similarity index 97% rename from CesiumGltf/generated/include/CesiumGltf/ClassProperty.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataClassProperty.h index 106d0d1b1..9ab79dd51 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ClassProperty.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataClassProperty.h @@ -15,9 +15,10 @@ namespace CesiumGltf { /** * @brief A class property. */ -struct CESIUMGLTF_API ClassProperty final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataClassProperty final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "ClassProperty"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataClassProperty"; /** * @brief Known values for The property type. If `ENUM` is used, then diff --git a/CesiumGltf/generated/include/CesiumGltf/ClassStatistics.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataClassStatistics.h similarity index 66% rename from CesiumGltf/generated/include/CesiumGltf/ClassStatistics.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataClassStatistics.h index 83f8a5963..5a2439814 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ClassStatistics.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataClassStatistics.h @@ -2,8 +2,8 @@ // DO NOT EDIT THIS FILE! #pragma once +#include "CesiumGltf/ExtensionExtFeatureMetadataPropertyStatistics.h" #include "CesiumGltf/Library.h" -#include "CesiumGltf/PropertyStatistics.h" #include @@ -15,9 +15,10 @@ namespace CesiumGltf { /** * @brief Statistics about features that conform to the class. */ -struct CESIUMGLTF_API ClassStatistics final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataClassStatistics final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "ClassStatistics"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataClassStatistics"; /** * @brief The number of features that conform to the class. @@ -29,6 +30,9 @@ struct CESIUMGLTF_API ClassStatistics final * class' `properties` dictionary and each value is an object containing * statistics about property values. */ - std::unordered_map properties; + std::unordered_map< + std::string, + CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics> + properties; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/Enum.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataEnum.h similarity index 80% rename from CesiumGltf/generated/include/CesiumGltf/Enum.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataEnum.h index 2aac09e6a..37770f8d0 100644 --- a/CesiumGltf/generated/include/CesiumGltf/Enum.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataEnum.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/EnumValue.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataEnumValue.h" #include "CesiumGltf/Library.h" #include @@ -15,8 +15,10 @@ namespace CesiumGltf { /** * @brief An object defining the values of an enum. */ -struct CESIUMGLTF_API Enum final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "Enum"; +struct CESIUMGLTF_API ExtensionExtFeatureMetadataEnum final + : public CesiumUtility::ExtensibleObject { + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataEnum"; /** * @brief Known values for The type of the integer enum value. @@ -61,6 +63,6 @@ struct CESIUMGLTF_API Enum final : public CesiumUtility::ExtensibleObject { * @brief An array of enum values. Duplicate names or duplicate integer values * are not allowed. */ - std::vector values; + std::vector values; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/EnumValue.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataEnumValue.h similarity index 73% rename from CesiumGltf/generated/include/CesiumGltf/EnumValue.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataEnumValue.h index d1c505a4e..78480490c 100644 --- a/CesiumGltf/generated/include/CesiumGltf/EnumValue.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataEnumValue.h @@ -14,8 +14,10 @@ namespace CesiumGltf { /** * @brief An enum value. */ -struct CESIUMGLTF_API EnumValue final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "EnumValue"; +struct CESIUMGLTF_API ExtensionExtFeatureMetadataEnumValue final + : public CesiumUtility::ExtensibleObject { + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataEnumValue"; /** * @brief The name of the enum value. diff --git a/CesiumGltf/generated/include/CesiumGltf/FeatureIDAttribute.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureIDAttribute.h similarity index 72% rename from CesiumGltf/generated/include/CesiumGltf/FeatureIDAttribute.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureIDAttribute.h index 458be2019..109391ce7 100644 --- a/CesiumGltf/generated/include/CesiumGltf/FeatureIDAttribute.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureIDAttribute.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/FeatureIDs.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataFeatureIDs.h" #include "CesiumGltf/Library.h" #include @@ -13,9 +13,10 @@ namespace CesiumGltf { /** * @brief An object mapping feature IDs to a feature table. */ -struct CESIUMGLTF_API FeatureIDAttribute final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataFeatureIDAttribute final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "FeatureIDAttribute"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataFeatureIDAttribute"; /** * @brief The ID of the feature table in the model's root @@ -29,6 +30,6 @@ struct CESIUMGLTF_API FeatureIDAttribute final * `[0, count - 1]` (inclusive), where `count` is the total number of features * in the feature table. */ - CesiumGltf::FeatureIDs featureIds; + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs featureIds; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/FeatureIDTexture.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureIDTexture.h similarity index 75% rename from CesiumGltf/generated/include/CesiumGltf/FeatureIDTexture.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureIDTexture.h index 27bc4a51f..754f2117e 100644 --- a/CesiumGltf/generated/include/CesiumGltf/FeatureIDTexture.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureIDTexture.h @@ -2,8 +2,8 @@ // DO NOT EDIT THIS FILE! #pragma once +#include "CesiumGltf/ExtensionExtFeatureMetadataTextureAccessor.h" #include "CesiumGltf/Library.h" -#include "CesiumGltf/TextureAccessor.h" #include @@ -13,9 +13,10 @@ namespace CesiumGltf { /** * @brief An object describing a texture used for storing per-texel feature IDs. */ -struct CESIUMGLTF_API FeatureIDTexture final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataFeatureIDTexture final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "FeatureIDTexture"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataFeatureIDTexture"; /** * @brief The ID of the feature table in the model's root @@ -31,6 +32,6 @@ struct CESIUMGLTF_API FeatureIDTexture final * must be read as integers. Texture filtering should be disabled when * fetching feature IDs. */ - CesiumGltf::TextureAccessor featureIds; + CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor featureIds; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/FeatureIDs.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureIDs.h similarity index 87% rename from CesiumGltf/generated/include/CesiumGltf/FeatureIDs.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureIDs.h index 402625edc..ff40460e8 100644 --- a/CesiumGltf/generated/include/CesiumGltf/FeatureIDs.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureIDs.h @@ -15,9 +15,10 @@ namespace CesiumGltf { * @brief Feature IDs to be used as indices to property arrays in the feature * table. */ -struct CESIUMGLTF_API FeatureIDs final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataFeatureIDs final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "FeatureIDs"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataFeatureIDs"; /** * @brief The name of the attribute containing feature IDs. diff --git a/CesiumGltf/generated/include/CesiumGltf/FeatureTable.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureTable.h similarity index 73% rename from CesiumGltf/generated/include/CesiumGltf/FeatureTable.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureTable.h index 410f8b11a..d94cbf113 100644 --- a/CesiumGltf/generated/include/CesiumGltf/FeatureTable.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureTable.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/FeatureTableProperty.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataFeatureTableProperty.h" #include "CesiumGltf/Library.h" #include @@ -17,9 +17,10 @@ namespace CesiumGltf { * @brief A feature table defined by a class and property values stored in * arrays. */ -struct CESIUMGLTF_API FeatureTable final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataFeatureTable final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "FeatureTable"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataFeatureTable"; /** * @brief The class that property values conform to. The value must be a class @@ -39,6 +40,9 @@ struct CESIUMGLTF_API FeatureTable final * property values are stored. Optional properties may be excluded from this * dictionary. */ - std::unordered_map properties; + std::unordered_map< + std::string, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty> + properties; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/FeatureTableProperty.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureTableProperty.h similarity index 95% rename from CesiumGltf/generated/include/CesiumGltf/FeatureTableProperty.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureTableProperty.h index e314c3341..69dfbf0ce 100644 --- a/CesiumGltf/generated/include/CesiumGltf/FeatureTableProperty.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureTableProperty.h @@ -13,9 +13,10 @@ namespace CesiumGltf { /** * @brief An array of binary property values. */ -struct CESIUMGLTF_API FeatureTableProperty final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataFeatureTableProperty final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "FeatureTableProperty"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataFeatureTableProperty"; /** * @brief Known values for The type of values in `arrayOffsetBufferView` and diff --git a/CesiumGltf/generated/include/CesiumGltf/FeatureTexture.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureTexture.h similarity index 71% rename from CesiumGltf/generated/include/CesiumGltf/FeatureTexture.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureTexture.h index fe9666e18..5a9d2b029 100644 --- a/CesiumGltf/generated/include/CesiumGltf/FeatureTexture.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataFeatureTexture.h @@ -2,8 +2,8 @@ // DO NOT EDIT THIS FILE! #pragma once +#include "CesiumGltf/ExtensionExtFeatureMetadataTextureAccessor.h" #include "CesiumGltf/Library.h" -#include "CesiumGltf/TextureAccessor.h" #include @@ -16,9 +16,10 @@ namespace CesiumGltf { * channels. This is not to be confused with feature ID textures which store * feature IDs for use with a feature table. */ -struct CESIUMGLTF_API FeatureTexture final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataFeatureTexture final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "FeatureTexture"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataFeatureTexture"; /** * @brief The class this feature texture conforms to. The value must be a @@ -31,6 +32,9 @@ struct CESIUMGLTF_API FeatureTexture final * class' `properties` dictionary and each value describes the texture * channels containing property values. */ - std::unordered_map properties; + std::unordered_map< + std::string, + CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor> + properties; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/PropertyStatistics.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataPropertyStatistics.h similarity index 95% rename from CesiumGltf/generated/include/CesiumGltf/PropertyStatistics.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataPropertyStatistics.h index 97eae4d4a..c13d7e2f3 100644 --- a/CesiumGltf/generated/include/CesiumGltf/PropertyStatistics.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataPropertyStatistics.h @@ -14,9 +14,10 @@ namespace CesiumGltf { /** * @brief Statistics about property values. */ -struct CESIUMGLTF_API PropertyStatistics final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataPropertyStatistics final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "PropertyStatistics"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataPropertyStatistics"; /** * @brief The minimum property value. Only applicable for numeric types and diff --git a/CesiumGltf/generated/include/CesiumGltf/Schema.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataSchema.h similarity index 63% rename from CesiumGltf/generated/include/CesiumGltf/Schema.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataSchema.h index 838b1e567..bb6d741ea 100644 --- a/CesiumGltf/generated/include/CesiumGltf/Schema.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataSchema.h @@ -2,8 +2,8 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/Class.h" -#include "CesiumGltf/Enum.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataClass.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataEnum.h" #include "CesiumGltf/Library.h" #include @@ -16,8 +16,10 @@ namespace CesiumGltf { /** * @brief An object defining classes and enums. */ -struct CESIUMGLTF_API Schema final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "Schema"; +struct CESIUMGLTF_API ExtensionExtFeatureMetadataSchema final + : public CesiumUtility::ExtensibleObject { + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataSchema"; /** * @brief The name of the schema. @@ -38,12 +40,14 @@ struct CESIUMGLTF_API Schema final : public CesiumUtility::ExtensibleObject { * @brief A dictionary, where each key is a class ID and each value is an * object defining the class. */ - std::unordered_map classes; + std::unordered_map + classes; /** * @brief A dictionary, where each key is an enum ID and each value is an * object defining the values for the enum. */ - std::unordered_map enums; + std::unordered_map + enums; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/Statistics.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataStatistics.h similarity index 61% rename from CesiumGltf/generated/include/CesiumGltf/Statistics.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataStatistics.h index 98f2ebc77..1c5b4adab 100644 --- a/CesiumGltf/generated/include/CesiumGltf/Statistics.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataStatistics.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ClassStatistics.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataClassStatistics.h" #include "CesiumGltf/Library.h" #include @@ -13,15 +13,19 @@ namespace CesiumGltf { /** * @brief Statistics about features. */ -struct CESIUMGLTF_API Statistics final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataStatistics final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "Statistics"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataStatistics"; /** * @brief A dictionary, where each key is a class ID declared in the `classes` * dictionary and each value is an object containing statistics about features * that conform to the class. */ - std::unordered_map classes; + std::unordered_map< + std::string, + CesiumGltf::ExtensionExtFeatureMetadataClassStatistics> + classes; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/TextureAccessor.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataTextureAccessor.h similarity index 80% rename from CesiumGltf/generated/include/CesiumGltf/TextureAccessor.h rename to CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataTextureAccessor.h index 97b52e28a..f6c15d1af 100644 --- a/CesiumGltf/generated/include/CesiumGltf/TextureAccessor.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtFeatureMetadataTextureAccessor.h @@ -14,9 +14,10 @@ namespace CesiumGltf { * @brief A description of how to access property values from the color channels * of a texture. */ -struct CESIUMGLTF_API TextureAccessor final +struct CESIUMGLTF_API ExtensionExtFeatureMetadataTextureAccessor final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = "TextureAccessor"; + static inline constexpr const char* TypeName = + "ExtensionExtFeatureMetadataTextureAccessor"; /** * @brief Texture channels containing property values. Channels are labeled by diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtMeshFeatures.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtMeshFeatures.h index 397b37282..3d02adb86 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtMeshFeatures.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionExtMeshFeatures.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ExtensionExtMeshFeaturesFeatureId.h" +#include "CesiumGltf/FeatureId.h" #include "CesiumGltf/Library.h" #include @@ -21,6 +21,6 @@ struct CESIUMGLTF_API ExtensionExtMeshFeatures final /** * @brief An array of feature ID sets. */ - std::vector featureIds; + std::vector featureIds; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionMeshPrimitiveExtFeatureMetadata.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionMeshPrimitiveExtFeatureMetadata.h index 5cf35aacb..d7008fbbb 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionMeshPrimitiveExtFeatureMetadata.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionMeshPrimitiveExtFeatureMetadata.h @@ -2,8 +2,8 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/FeatureIDAttribute.h" -#include "CesiumGltf/FeatureIDTexture.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataFeatureIDAttribute.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataFeatureIDTexture.h" #include "CesiumGltf/Library.h" #include @@ -26,13 +26,15 @@ struct CESIUMGLTF_API ExtensionMeshPrimitiveExtFeatureMetadata final * @brief An array of objects mapping per-vertex feature IDs to a feature * table. */ - std::vector featureIdAttributes; + std::vector + featureIdAttributes; /** * @brief An array of objects mapping per-texel feature IDs to a feature * table. */ - std::vector featureIdTextures; + std::vector + featureIdTextures; /** * @brief An array of IDs of feature textures from the root diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionModelExtFeatureMetadata.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionModelExtFeatureMetadata.h index 7fb51dc7c..049f350cf 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionModelExtFeatureMetadata.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionModelExtFeatureMetadata.h @@ -2,11 +2,11 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/FeatureTable.h" -#include "CesiumGltf/FeatureTexture.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataFeatureTable.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataFeatureTexture.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataSchema.h" +#include "CesiumGltf/ExtensionExtFeatureMetadataStatistics.h" #include "CesiumGltf/Library.h" -#include "CesiumGltf/Schema.h" -#include "CesiumGltf/Statistics.h" #include @@ -27,7 +27,7 @@ struct CESIUMGLTF_API ExtensionModelExtFeatureMetadata final /** * @brief An object defining classes and enums. */ - std::optional schema; + std::optional schema; /** * @brief The URI (or IRI) of the external schema file. @@ -37,18 +37,24 @@ struct CESIUMGLTF_API ExtensionModelExtFeatureMetadata final /** * @brief An object containing statistics about features. */ - std::optional statistics; + std::optional statistics; /** * @brief A dictionary, where each key is a feature table ID and each value is * an object defining the feature table. */ - std::unordered_map featureTables; + std::unordered_map< + std::string, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTable> + featureTables; /** * @brief A dictionary, where each key is a feature texture ID and each value * is an object defining the feature texture. */ - std::unordered_map featureTextures; + std::unordered_map< + std::string, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture> + featureTextures; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtMeshFeaturesFeatureId.h b/CesiumGltf/generated/include/CesiumGltf/FeatureId.h similarity index 79% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtMeshFeaturesFeatureId.h rename to CesiumGltf/generated/include/CesiumGltf/FeatureId.h index 5895e8ea4..aef4877e1 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtMeshFeaturesFeatureId.h +++ b/CesiumGltf/generated/include/CesiumGltf/FeatureId.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ExtensionExtMeshFeaturesFeatureIdTexture.h" +#include "CesiumGltf/FeatureIdTexture.h" #include "CesiumGltf/Library.h" #include @@ -15,10 +15,8 @@ namespace CesiumGltf { /** * @brief Feature IDs stored in an attribute or texture. */ -struct CESIUMGLTF_API ExtensionExtMeshFeaturesFeatureId final - : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtMeshFeaturesFeatureId"; +struct CESIUMGLTF_API FeatureId final : public CesiumUtility::ExtensibleObject { + static inline constexpr const char* TypeName = "FeatureId"; /** * @brief The number of unique features in the attribute or texture. @@ -48,7 +46,7 @@ struct CESIUMGLTF_API ExtensionExtMeshFeaturesFeatureId final /** * @brief A texture containing feature IDs. */ - std::optional texture; + std::optional texture; /** * @brief The index of the property table containing per-feature property diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtMeshFeaturesFeatureIdTexture.h b/CesiumGltf/generated/include/CesiumGltf/FeatureIdTexture.h similarity index 76% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtMeshFeaturesFeatureIdTexture.h rename to CesiumGltf/generated/include/CesiumGltf/FeatureIdTexture.h index de709adf1..2ce9dc76e 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtMeshFeaturesFeatureIdTexture.h +++ b/CesiumGltf/generated/include/CesiumGltf/FeatureIdTexture.h @@ -12,10 +12,8 @@ namespace CesiumGltf { /** * @brief A texture containing feature IDs */ -struct CESIUMGLTF_API ExtensionExtMeshFeaturesFeatureIdTexture final - : public TextureInfo { - static inline constexpr const char* TypeName = - "ExtensionExtMeshFeaturesFeatureIdTexture"; +struct CESIUMGLTF_API FeatureIdTexture final : public TextureInfo { + static inline constexpr const char* TypeName = "FeatureIdTexture"; /** * @brief Texture channels containing feature IDs, identified by index. diff --git a/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h b/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h index c579ca836..11f6ee726 100644 --- a/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h +++ b/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h @@ -1,18 +1,15 @@ #pragma once -#include "CesiumGltf/ExtensionExtMeshFeaturesFeatureIdTexture.h" +#include "CesiumGltf/FeatureIdTexture.h" #include "CesiumGltf/Texture.h" -#include "CesiumGltf/TextureAccessor.h" #include "Image.h" #include "ImageCesium.h" #include "Model.h" #include -#include #include #include #include -#include namespace CesiumGltf { /** @@ -20,7 +17,7 @@ namespace CesiumGltf { * * The {@link FeatureIdTextureView} constructor always completes successfully, * but it may not always reflect the actual content of the - * {@link ExtensionExtMeshFeaturesFeatureIdTexture}. This enumeration provides the reason. + * {@link FeatureIdTexture}. This enumeration provides the reason. */ enum class FeatureIdTextureViewStatus { /** @@ -72,10 +69,10 @@ enum class FeatureIdTextureViewStatus { }; /** - * @brief A view on the image data of {@link ExtensionExtMeshFeaturesFeatureIdTexture}. + * @brief A view on the image data of {@link FeatureIdTexture}. * * It provides the ability to sample the feature IDs from the - * {@link ExtensionExtMeshFeaturesFeatureIdTexture} using texture coordinates. + * {@link FeatureIdTexture} using texture coordinates. */ class FeatureIdTextureView { public: @@ -86,15 +83,14 @@ class FeatureIdTextureView { /** * @brief Construct a view of the data specified by a - * {@link ExtensionExtMeshFeaturesFeatureIdTexture}. + * {@link FeatureIdTexture}. * - * @param model The glTF in which to look for the feature id texture's data. - * @param featureIDTexture The feature id texture to create a view for. + * @param model The glTF in which to look for the feature ID texture's data. + * @param featureIDTexture The feature ID texture to create a view for. */ FeatureIdTextureView( const Model& model, - const ExtensionExtMeshFeaturesFeatureIdTexture& - featureIdTexture) noexcept; + const FeatureIdTexture& featureIdTexture) noexcept; /** * @brief Get the Feature ID for the given texture coordinates. diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 69c0f70e2..8fc438670 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -6,7 +6,6 @@ #include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" #include "CesiumGltf/PropertyTexturePropertyView.h" #include "CesiumGltf/Texture.h" -#include "CesiumGltf/TextureAccessor.h" #include "Image.h" #include "ImageCesium.h" #include "Model.h" diff --git a/CesiumGltf/src/FeatureIdTextureView.cpp b/CesiumGltf/src/FeatureIdTextureView.cpp index 589f98ac2..6879069e0 100644 --- a/CesiumGltf/src/FeatureIdTextureView.cpp +++ b/CesiumGltf/src/FeatureIdTextureView.cpp @@ -9,7 +9,7 @@ FeatureIdTextureView::FeatureIdTextureView() noexcept FeatureIdTextureView::FeatureIdTextureView( const Model& model, - const ExtensionExtMeshFeaturesFeatureIdTexture& featureIdTexture) noexcept + const FeatureIdTexture& featureIdTexture) noexcept : _status(FeatureIdTextureViewStatus::ErrorUninitialized), _texCoordSetIndex(-1), _channels(featureIdTexture.channels), diff --git a/CesiumGltf/test/TestFeatureIdTextureView.cpp b/CesiumGltf/test/TestFeatureIdTextureView.cpp index a6755667f..d632db45b 100644 --- a/CesiumGltf/test/TestFeatureIdTextureView.cpp +++ b/CesiumGltf/test/TestFeatureIdTextureView.cpp @@ -21,13 +21,12 @@ TEST_CASE("Test FeatureIdTextureView on feature ID texture with invalid " ExtensionExtMeshFeatures& meshFeatures = primitive.addExtension(); - ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + FeatureIdTexture featureIdTexture; featureIdTexture.index = -1; featureIdTexture.texCoord = 0; featureIdTexture.channels = {0}; - ExtensionExtMeshFeaturesFeatureId featureId = - meshFeatures.featureIds.emplace_back(); + FeatureId featureId = meshFeatures.featureIds.emplace_back(); featureId.texture = featureIdTexture; FeatureIdTextureView view(model, featureIdTexture); @@ -47,13 +46,12 @@ TEST_CASE("Test FeatureIdTextureView on feature ID texture with invalid image " ExtensionExtMeshFeatures& meshFeatures = primitive.addExtension(); - ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + FeatureIdTexture featureIdTexture; featureIdTexture.index = 0; featureIdTexture.texCoord = 0; featureIdTexture.channels = {0}; - ExtensionExtMeshFeaturesFeatureId featureId = - meshFeatures.featureIds.emplace_back(); + FeatureId featureId = meshFeatures.featureIds.emplace_back(); featureId.texture = featureIdTexture; FeatureIdTextureView view(model, featureIdTexture); @@ -76,13 +74,12 @@ TEST_CASE("Test FeatureIdTextureView on feature ID texture with empty image") { ExtensionExtMeshFeatures& meshFeatures = primitive.addExtension(); - ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + FeatureIdTexture featureIdTexture; featureIdTexture.index = 0; featureIdTexture.texCoord = 0; featureIdTexture.channels = {0}; - ExtensionExtMeshFeaturesFeatureId featureId = - meshFeatures.featureIds.emplace_back(); + FeatureId featureId = meshFeatures.featureIds.emplace_back(); featureId.texture = featureIdTexture; FeatureIdTextureView view(model, featureIdTexture); @@ -107,13 +104,12 @@ TEST_CASE("Test FeatureIdTextureView on feature ID texture with too many bytes " ExtensionExtMeshFeatures& meshFeatures = primitive.addExtension(); - ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + FeatureIdTexture featureIdTexture; featureIdTexture.index = 0; featureIdTexture.texCoord = 0; featureIdTexture.channels = {0}; - ExtensionExtMeshFeaturesFeatureId featureId = - meshFeatures.featureIds.emplace_back(); + FeatureId featureId = meshFeatures.featureIds.emplace_back(); featureId.texture = featureIdTexture; FeatureIdTextureView view(model, featureIdTexture); @@ -140,13 +136,12 @@ TEST_CASE( ExtensionExtMeshFeatures& meshFeatures = primitive.addExtension(); - ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + FeatureIdTexture featureIdTexture; featureIdTexture.index = 0; featureIdTexture.texCoord = -1; featureIdTexture.channels = {0}; - ExtensionExtMeshFeaturesFeatureId featureId = - meshFeatures.featureIds.emplace_back(); + FeatureId featureId = meshFeatures.featureIds.emplace_back(); featureId.texture = featureIdTexture; FeatureIdTextureView view(model, featureIdTexture); @@ -172,13 +167,12 @@ TEST_CASE( ExtensionExtMeshFeatures& meshFeatures = primitive.addExtension(); - ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + FeatureIdTexture featureIdTexture; featureIdTexture.index = 0; featureIdTexture.texCoord = 0; featureIdTexture.channels = {}; - ExtensionExtMeshFeaturesFeatureId featureId = - meshFeatures.featureIds.emplace_back(); + FeatureId featureId = meshFeatures.featureIds.emplace_back(); featureId.texture = featureIdTexture; FeatureIdTextureView view(model, featureIdTexture); @@ -202,13 +196,12 @@ TEST_CASE( ExtensionExtMeshFeatures& meshFeatures = primitive.addExtension(); - ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + FeatureIdTexture featureIdTexture; featureIdTexture.index = 0; featureIdTexture.texCoord = 0; featureIdTexture.channels = {0, 1, 2, 3, 3}; - ExtensionExtMeshFeaturesFeatureId featureId = - meshFeatures.featureIds.emplace_back(); + FeatureId featureId = meshFeatures.featureIds.emplace_back(); featureId.texture = featureIdTexture; FeatureIdTextureView view(model, featureIdTexture); @@ -232,13 +225,12 @@ TEST_CASE("Test FeatureIdTextureView on feature ID texture with out of range " ExtensionExtMeshFeatures& meshFeatures = primitive.addExtension(); - ExtensionExtMeshFeaturesFeatureIdTexture featureIdTexture; + FeatureIdTexture featureIdTexture; featureIdTexture.index = 0; featureIdTexture.texCoord = 0; featureIdTexture.channels = {4}; - ExtensionExtMeshFeaturesFeatureId featureId = - meshFeatures.featureIds.emplace_back(); + FeatureId featureId = meshFeatures.featureIds.emplace_back(); featureId.texture = featureIdTexture; FeatureIdTextureView view(model, featureIdTexture); diff --git a/CesiumGltfReader/generated/src/ClassJsonHandler.h b/CesiumGltfReader/generated/src/ClassJsonHandler.h deleted file mode 100644 index 580791944..000000000 --- a/CesiumGltfReader/generated/src/ClassJsonHandler.h +++ /dev/null @@ -1,41 +0,0 @@ -// This file was generated by generate-classes. -// DO NOT EDIT THIS FILE! -#pragma once - -#include "ClassPropertyJsonHandler.h" - -#include -#include -#include -#include - -namespace CesiumJsonReader { -class ExtensionReaderContext; -} - -namespace CesiumGltfReader { -class ClassJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { -public: - using ValueType = CesiumGltf::Class; - - ClassJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset(IJsonHandler* pParentHandler, CesiumGltf::Class* pObject); - - virtual IJsonHandler* readObjectKey(const std::string_view& str) override; - -protected: - IJsonHandler* readObjectKeyClass( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Class& o); - -private: - CesiumGltf::Class* _pObject = nullptr; - CesiumJsonReader::StringJsonHandler _name; - CesiumJsonReader::StringJsonHandler _description; - CesiumJsonReader:: - DictionaryJsonHandler - _properties; -}; -} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/EnumJsonHandler.h b/CesiumGltfReader/generated/src/EnumJsonHandler.h deleted file mode 100644 index 355e88790..000000000 --- a/CesiumGltfReader/generated/src/EnumJsonHandler.h +++ /dev/null @@ -1,42 +0,0 @@ -// This file was generated by generate-classes. -// DO NOT EDIT THIS FILE! -#pragma once - -#include "EnumValueJsonHandler.h" - -#include -#include -#include -#include - -namespace CesiumJsonReader { -class ExtensionReaderContext; -} - -namespace CesiumGltfReader { -class EnumJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { -public: - using ValueType = CesiumGltf::Enum; - - EnumJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset(IJsonHandler* pParentHandler, CesiumGltf::Enum* pObject); - - virtual IJsonHandler* readObjectKey(const std::string_view& str) override; - -protected: - IJsonHandler* readObjectKeyEnum( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Enum& o); - -private: - CesiumGltf::Enum* _pObject = nullptr; - CesiumJsonReader::StringJsonHandler _name; - CesiumJsonReader::StringJsonHandler _description; - CesiumJsonReader::StringJsonHandler _valueType; - CesiumJsonReader:: - ArrayJsonHandler - _values; -}; -} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataClassJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataClassJsonHandler.h new file mode 100644 index 000000000..e8f8c7a2b --- /dev/null +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataClassJsonHandler.h @@ -0,0 +1,45 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include "ExtensionExtFeatureMetadataClassPropertyJsonHandler.h" + +#include +#include +#include +#include + +namespace CesiumJsonReader { +class ExtensionReaderContext; +} + +namespace CesiumGltfReader { +class ExtensionExtFeatureMetadataClassJsonHandler + : public CesiumJsonReader::ExtensibleObjectJsonHandler { +public: + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataClass; + + ExtensionExtFeatureMetadataClassJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept; + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataClass* pObject); + + virtual IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataClass( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataClass& o); + +private: + CesiumGltf::ExtensionExtFeatureMetadataClass* _pObject = nullptr; + CesiumJsonReader::StringJsonHandler _name; + CesiumJsonReader::StringJsonHandler _description; + CesiumJsonReader::DictionaryJsonHandler< + CesiumGltf::ExtensionExtFeatureMetadataClassProperty, + ExtensionExtFeatureMetadataClassPropertyJsonHandler> + _properties; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ClassPropertyJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataClassPropertyJsonHandler.h similarity index 70% rename from CesiumGltfReader/generated/src/ClassPropertyJsonHandler.h rename to CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataClassPropertyJsonHandler.h index aa176fe01..60b3f82cf 100644 --- a/CesiumGltfReader/generated/src/ClassPropertyJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataClassPropertyJsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include #include @@ -14,25 +14,27 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ClassPropertyJsonHandler +class ExtensionExtFeatureMetadataClassPropertyJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::ClassProperty; + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataClassProperty; - ClassPropertyJsonHandler( + ExtensionExtFeatureMetadataClassPropertyJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset(IJsonHandler* pParentHandler, CesiumGltf::ClassProperty* pObject); + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataClassProperty* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyClassProperty( + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataClassProperty( const std::string& objectType, const std::string_view& str, - CesiumGltf::ClassProperty& o); + CesiumGltf::ExtensionExtFeatureMetadataClassProperty& o); private: - CesiumGltf::ClassProperty* _pObject = nullptr; + CesiumGltf::ExtensionExtFeatureMetadataClassProperty* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _name; CesiumJsonReader::StringJsonHandler _description; CesiumJsonReader::StringJsonHandler _type; diff --git a/CesiumGltfReader/generated/src/ClassStatisticsJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataClassStatisticsJsonHandler.h similarity index 50% rename from CesiumGltfReader/generated/src/ClassStatisticsJsonHandler.h rename to CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataClassStatisticsJsonHandler.h index 840492669..02bd6d76a 100644 --- a/CesiumGltfReader/generated/src/ClassStatisticsJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataClassStatisticsJsonHandler.h @@ -2,9 +2,9 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "PropertyStatisticsJsonHandler.h" +#include "ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler.h" -#include +#include #include #include #include @@ -14,30 +14,31 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ClassStatisticsJsonHandler +class ExtensionExtFeatureMetadataClassStatisticsJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::ClassStatistics; + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataClassStatistics; - ClassStatisticsJsonHandler( + ExtensionExtFeatureMetadataClassStatisticsJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void - reset(IJsonHandler* pParentHandler, CesiumGltf::ClassStatistics* pObject); + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataClassStatistics* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyClassStatistics( + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataClassStatistics( const std::string& objectType, const std::string_view& str, - CesiumGltf::ClassStatistics& o); + CesiumGltf::ExtensionExtFeatureMetadataClassStatistics& o); private: - CesiumGltf::ClassStatistics* _pObject = nullptr; + CesiumGltf::ExtensionExtFeatureMetadataClassStatistics* _pObject = nullptr; CesiumJsonReader::IntegerJsonHandler _count; CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::PropertyStatistics, - PropertyStatisticsJsonHandler> + CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics, + ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler> _properties; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataEnumJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataEnumJsonHandler.h new file mode 100644 index 000000000..e8a635833 --- /dev/null +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataEnumJsonHandler.h @@ -0,0 +1,46 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include "ExtensionExtFeatureMetadataEnumValueJsonHandler.h" + +#include +#include +#include +#include + +namespace CesiumJsonReader { +class ExtensionReaderContext; +} + +namespace CesiumGltfReader { +class ExtensionExtFeatureMetadataEnumJsonHandler + : public CesiumJsonReader::ExtensibleObjectJsonHandler { +public: + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataEnum; + + ExtensionExtFeatureMetadataEnumJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept; + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataEnum* pObject); + + virtual IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataEnum( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataEnum& o); + +private: + CesiumGltf::ExtensionExtFeatureMetadataEnum* _pObject = nullptr; + CesiumJsonReader::StringJsonHandler _name; + CesiumJsonReader::StringJsonHandler _description; + CesiumJsonReader::StringJsonHandler _valueType; + CesiumJsonReader::ArrayJsonHandler< + CesiumGltf::ExtensionExtFeatureMetadataEnumValue, + ExtensionExtFeatureMetadataEnumValueJsonHandler> + _values; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/EnumValueJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataEnumValueJsonHandler.h similarity index 60% rename from CesiumGltfReader/generated/src/EnumValueJsonHandler.h rename to CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataEnumValueJsonHandler.h index d56d90722..30ee048b4 100644 --- a/CesiumGltfReader/generated/src/EnumValueJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataEnumValueJsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include #include @@ -12,25 +12,27 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class EnumValueJsonHandler +class ExtensionExtFeatureMetadataEnumValueJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::EnumValue; + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataEnumValue; - EnumValueJsonHandler( + ExtensionExtFeatureMetadataEnumValueJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset(IJsonHandler* pParentHandler, CesiumGltf::EnumValue* pObject); + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataEnumValue* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyEnumValue( + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataEnumValue( const std::string& objectType, const std::string_view& str, - CesiumGltf::EnumValue& o); + CesiumGltf::ExtensionExtFeatureMetadataEnumValue& o); private: - CesiumGltf::EnumValue* _pObject = nullptr; + CesiumGltf::ExtensionExtFeatureMetadataEnumValue* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _name; CesiumJsonReader::StringJsonHandler _description; CesiumJsonReader::IntegerJsonHandler _value; diff --git a/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler.h new file mode 100644 index 000000000..0cd99c005 --- /dev/null +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler.h @@ -0,0 +1,40 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include "ExtensionExtFeatureMetadataFeatureIDsJsonHandler.h" + +#include +#include +#include + +namespace CesiumJsonReader { +class ExtensionReaderContext; +} + +namespace CesiumGltfReader { +class ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler + : public CesiumJsonReader::ExtensibleObjectJsonHandler { +public: + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute; + + ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept; + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute* pObject); + + virtual IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataFeatureIDAttribute( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute& o); + +private: + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute* _pObject = nullptr; + CesiumJsonReader::StringJsonHandler _featureTable; + ExtensionExtFeatureMetadataFeatureIDsJsonHandler _featureIds; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler.h new file mode 100644 index 000000000..413396acf --- /dev/null +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler.h @@ -0,0 +1,40 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include "ExtensionExtFeatureMetadataTextureAccessorJsonHandler.h" + +#include +#include +#include + +namespace CesiumJsonReader { +class ExtensionReaderContext; +} + +namespace CesiumGltfReader { +class ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler + : public CesiumJsonReader::ExtensibleObjectJsonHandler { +public: + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture; + + ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept; + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture* pObject); + + virtual IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataFeatureIDTexture( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture& o); + +private: + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture* _pObject = nullptr; + CesiumJsonReader::StringJsonHandler _featureTable; + ExtensionExtFeatureMetadataTextureAccessorJsonHandler _featureIds; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/FeatureIDsJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDsJsonHandler.h similarity index 60% rename from CesiumGltfReader/generated/src/FeatureIDsJsonHandler.h rename to CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDsJsonHandler.h index 3501f6207..a8db907d5 100644 --- a/CesiumGltfReader/generated/src/FeatureIDsJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureIDsJsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include #include @@ -12,25 +12,27 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class FeatureIDsJsonHandler +class ExtensionExtFeatureMetadataFeatureIDsJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::FeatureIDs; + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs; - FeatureIDsJsonHandler( + ExtensionExtFeatureMetadataFeatureIDsJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset(IJsonHandler* pParentHandler, CesiumGltf::FeatureIDs* pObject); + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyFeatureIDs( + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataFeatureIDs( const std::string& objectType, const std::string_view& str, - CesiumGltf::FeatureIDs& o); + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs& o); private: - CesiumGltf::FeatureIDs* _pObject = nullptr; + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _attribute; CesiumJsonReader::IntegerJsonHandler _constant; CesiumJsonReader::IntegerJsonHandler _divisor; diff --git a/CesiumGltfReader/generated/src/FeatureTableJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureTableJsonHandler.h similarity index 53% rename from CesiumGltfReader/generated/src/FeatureTableJsonHandler.h rename to CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureTableJsonHandler.h index f2d5f34ac..e49cb7a69 100644 --- a/CesiumGltfReader/generated/src/FeatureTableJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureTableJsonHandler.h @@ -2,9 +2,9 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "FeatureTablePropertyJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler.h" -#include +#include #include #include #include @@ -15,30 +15,32 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class FeatureTableJsonHandler +class ExtensionExtFeatureMetadataFeatureTableJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::FeatureTable; + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureTable; - FeatureTableJsonHandler( + ExtensionExtFeatureMetadataFeatureTableJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset(IJsonHandler* pParentHandler, CesiumGltf::FeatureTable* pObject); + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTable* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyFeatureTable( + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataFeatureTable( const std::string& objectType, const std::string_view& str, - CesiumGltf::FeatureTable& o); + CesiumGltf::ExtensionExtFeatureMetadataFeatureTable& o); private: - CesiumGltf::FeatureTable* _pObject = nullptr; + CesiumGltf::ExtensionExtFeatureMetadataFeatureTable* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _classProperty; CesiumJsonReader::IntegerJsonHandler _count; CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::FeatureTableProperty, - FeatureTablePropertyJsonHandler> + CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty, + ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler> _properties; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/FeatureTablePropertyJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler.h similarity index 62% rename from CesiumGltfReader/generated/src/FeatureTablePropertyJsonHandler.h rename to CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler.h index fab2ff647..943702750 100644 --- a/CesiumGltfReader/generated/src/FeatureTablePropertyJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include #include @@ -12,27 +12,28 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class FeatureTablePropertyJsonHandler +class ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::FeatureTableProperty; + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty; - FeatureTablePropertyJsonHandler( + ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; void reset( IJsonHandler* pParentHandler, - CesiumGltf::FeatureTableProperty* pObject); + CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyFeatureTableProperty( + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataFeatureTableProperty( const std::string& objectType, const std::string_view& str, - CesiumGltf::FeatureTableProperty& o); + CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty& o); private: - CesiumGltf::FeatureTableProperty* _pObject = nullptr; + CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty* _pObject = + nullptr; CesiumJsonReader::IntegerJsonHandler _bufferView; CesiumJsonReader::StringJsonHandler _offsetType; CesiumJsonReader::IntegerJsonHandler _arrayOffsetBufferView; diff --git a/CesiumGltfReader/generated/src/FeatureTextureJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureTextureJsonHandler.h similarity index 50% rename from CesiumGltfReader/generated/src/FeatureTextureJsonHandler.h rename to CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureTextureJsonHandler.h index 0cf3ad846..ac9efd63f 100644 --- a/CesiumGltfReader/generated/src/FeatureTextureJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataFeatureTextureJsonHandler.h @@ -2,9 +2,9 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "TextureAccessorJsonHandler.h" +#include "ExtensionExtFeatureMetadataTextureAccessorJsonHandler.h" -#include +#include #include #include #include @@ -14,29 +14,31 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class FeatureTextureJsonHandler +class ExtensionExtFeatureMetadataFeatureTextureJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::FeatureTexture; + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture; - FeatureTextureJsonHandler( + ExtensionExtFeatureMetadataFeatureTextureJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset(IJsonHandler* pParentHandler, CesiumGltf::FeatureTexture* pObject); + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyFeatureTexture( + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataFeatureTexture( const std::string& objectType, const std::string_view& str, - CesiumGltf::FeatureTexture& o); + CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture& o); private: - CesiumGltf::FeatureTexture* _pObject = nullptr; + CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _classProperty; CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::TextureAccessor, - TextureAccessorJsonHandler> + CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor, + ExtensionExtFeatureMetadataTextureAccessorJsonHandler> _properties; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/PropertyStatisticsJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler.h similarity index 65% rename from CesiumGltfReader/generated/src/PropertyStatisticsJsonHandler.h rename to CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler.h index 6d28e4c5f..b2568c348 100644 --- a/CesiumGltfReader/generated/src/PropertyStatisticsJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include #include @@ -12,26 +12,27 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class PropertyStatisticsJsonHandler +class ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::PropertyStatistics; + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics; - PropertyStatisticsJsonHandler( + ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void - reset(IJsonHandler* pParentHandler, CesiumGltf::PropertyStatistics* pObject); + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyPropertyStatistics( + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataPropertyStatistics( const std::string& objectType, const std::string_view& str, - CesiumGltf::PropertyStatistics& o); + CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics& o); private: - CesiumGltf::PropertyStatistics* _pObject = nullptr; + CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics* _pObject = nullptr; CesiumJsonReader::JsonObjectJsonHandler _min; CesiumJsonReader::JsonObjectJsonHandler _max; CesiumJsonReader::JsonObjectJsonHandler _mean; diff --git a/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataSchemaJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataSchemaJsonHandler.h new file mode 100644 index 000000000..190a3b5fc --- /dev/null +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataSchemaJsonHandler.h @@ -0,0 +1,51 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include "ExtensionExtFeatureMetadataClassJsonHandler.h" +#include "ExtensionExtFeatureMetadataEnumJsonHandler.h" + +#include +#include +#include +#include + +namespace CesiumJsonReader { +class ExtensionReaderContext; +} + +namespace CesiumGltfReader { +class ExtensionExtFeatureMetadataSchemaJsonHandler + : public CesiumJsonReader::ExtensibleObjectJsonHandler { +public: + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataSchema; + + ExtensionExtFeatureMetadataSchemaJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept; + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataSchema* pObject); + + virtual IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataSchema( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataSchema& o); + +private: + CesiumGltf::ExtensionExtFeatureMetadataSchema* _pObject = nullptr; + CesiumJsonReader::StringJsonHandler _name; + CesiumJsonReader::StringJsonHandler _description; + CesiumJsonReader::StringJsonHandler _version; + CesiumJsonReader::DictionaryJsonHandler< + CesiumGltf::ExtensionExtFeatureMetadataClass, + ExtensionExtFeatureMetadataClassJsonHandler> + _classes; + CesiumJsonReader::DictionaryJsonHandler< + CesiumGltf::ExtensionExtFeatureMetadataEnum, + ExtensionExtFeatureMetadataEnumJsonHandler> + _enums; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataStatisticsJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataStatisticsJsonHandler.h new file mode 100644 index 000000000..62edc7334 --- /dev/null +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataStatisticsJsonHandler.h @@ -0,0 +1,42 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include "ExtensionExtFeatureMetadataClassStatisticsJsonHandler.h" + +#include +#include +#include + +namespace CesiumJsonReader { +class ExtensionReaderContext; +} + +namespace CesiumGltfReader { +class ExtensionExtFeatureMetadataStatisticsJsonHandler + : public CesiumJsonReader::ExtensibleObjectJsonHandler { +public: + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataStatistics; + + ExtensionExtFeatureMetadataStatisticsJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept; + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataStatistics* pObject); + + virtual IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataStatistics( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataStatistics& o); + +private: + CesiumGltf::ExtensionExtFeatureMetadataStatistics* _pObject = nullptr; + CesiumJsonReader::DictionaryJsonHandler< + CesiumGltf::ExtensionExtFeatureMetadataClassStatistics, + ExtensionExtFeatureMetadataClassStatisticsJsonHandler> + _classes; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/TextureAccessorJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataTextureAccessorJsonHandler.h similarity index 55% rename from CesiumGltfReader/generated/src/TextureAccessorJsonHandler.h rename to CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataTextureAccessorJsonHandler.h index cb0d84e57..eec2bd6e9 100644 --- a/CesiumGltfReader/generated/src/TextureAccessorJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionExtFeatureMetadataTextureAccessorJsonHandler.h @@ -4,7 +4,7 @@ #include "TextureInfoJsonHandler.h" -#include +#include #include #include @@ -13,26 +13,27 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class TextureAccessorJsonHandler +class ExtensionExtFeatureMetadataTextureAccessorJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::TextureAccessor; + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor; - TextureAccessorJsonHandler( + ExtensionExtFeatureMetadataTextureAccessorJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void - reset(IJsonHandler* pParentHandler, CesiumGltf::TextureAccessor* pObject); + void reset( + IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyTextureAccessor( + IJsonHandler* readObjectKeyExtensionExtFeatureMetadataTextureAccessor( const std::string& objectType, const std::string_view& str, - CesiumGltf::TextureAccessor& o); + CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor& o); private: - CesiumGltf::TextureAccessor* _pObject = nullptr; + CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _channels; TextureInfoJsonHandler _texture; }; diff --git a/CesiumGltfReader/generated/src/ExtensionExtMeshFeaturesJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtMeshFeaturesJsonHandler.h index e8609c68f..98c2aadf9 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtMeshFeaturesJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionExtMeshFeaturesJsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "ExtensionExtMeshFeaturesFeatureIdJsonHandler.h" +#include "FeatureIdJsonHandler.h" #include #include @@ -87,9 +87,8 @@ class ExtensionExtMeshFeaturesJsonHandler private: CesiumGltf::ExtensionExtMeshFeatures* _pObject = nullptr; - CesiumJsonReader::ArrayJsonHandler< - CesiumGltf::ExtensionExtMeshFeaturesFeatureId, - ExtensionExtMeshFeaturesFeatureIdJsonHandler> - _featureIds; + CesiumJsonReader:: + ArrayJsonHandler + _featureIds; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler.h index 90f363195..ebb538825 100644 --- a/CesiumGltfReader/generated/src/ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler.h @@ -2,8 +2,8 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "FeatureIDAttributeJsonHandler.h" -#include "FeatureIDTextureJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler.h" #include #include @@ -90,12 +90,12 @@ class ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler private: CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata* _pObject = nullptr; CesiumJsonReader::ArrayJsonHandler< - CesiumGltf::FeatureIDAttribute, - FeatureIDAttributeJsonHandler> + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute, + ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler> _featureIdAttributes; CesiumJsonReader::ArrayJsonHandler< - CesiumGltf::FeatureIDTexture, - FeatureIDTextureJsonHandler> + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture, + ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler> _featureIdTextures; CesiumJsonReader:: ArrayJsonHandler diff --git a/CesiumGltfReader/generated/src/ExtensionModelExtFeatureMetadataJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionModelExtFeatureMetadataJsonHandler.h index 0b4b93203..964ea0008 100644 --- a/CesiumGltfReader/generated/src/ExtensionModelExtFeatureMetadataJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionModelExtFeatureMetadataJsonHandler.h @@ -2,10 +2,10 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "FeatureTableJsonHandler.h" -#include "FeatureTextureJsonHandler.h" -#include "SchemaJsonHandler.h" -#include "StatisticsJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureTableJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureTextureJsonHandler.h" +#include "ExtensionExtFeatureMetadataSchemaJsonHandler.h" +#include "ExtensionExtFeatureMetadataStatisticsJsonHandler.h" #include #include @@ -91,15 +91,16 @@ class ExtensionModelExtFeatureMetadataJsonHandler private: CesiumGltf::ExtensionModelExtFeatureMetadata* _pObject = nullptr; - SchemaJsonHandler _schema; + ExtensionExtFeatureMetadataSchemaJsonHandler _schema; CesiumJsonReader::StringJsonHandler _schemaUri; - StatisticsJsonHandler _statistics; - CesiumJsonReader:: - DictionaryJsonHandler - _featureTables; + ExtensionExtFeatureMetadataStatisticsJsonHandler _statistics; CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::FeatureTexture, - FeatureTextureJsonHandler> + CesiumGltf::ExtensionExtFeatureMetadataFeatureTable, + ExtensionExtFeatureMetadataFeatureTableJsonHandler> + _featureTables; + CesiumJsonReader::DictionaryJsonHandler< + CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture, + ExtensionExtFeatureMetadataFeatureTextureJsonHandler> _featureTextures; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/FeatureIDAttributeJsonHandler.h b/CesiumGltfReader/generated/src/FeatureIDAttributeJsonHandler.h deleted file mode 100644 index 3241d8a22..000000000 --- a/CesiumGltfReader/generated/src/FeatureIDAttributeJsonHandler.h +++ /dev/null @@ -1,39 +0,0 @@ -// This file was generated by generate-classes. -// DO NOT EDIT THIS FILE! -#pragma once - -#include "FeatureIDsJsonHandler.h" - -#include -#include -#include - -namespace CesiumJsonReader { -class ExtensionReaderContext; -} - -namespace CesiumGltfReader { -class FeatureIDAttributeJsonHandler - : public CesiumJsonReader::ExtensibleObjectJsonHandler { -public: - using ValueType = CesiumGltf::FeatureIDAttribute; - - FeatureIDAttributeJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void - reset(IJsonHandler* pParentHandler, CesiumGltf::FeatureIDAttribute* pObject); - - virtual IJsonHandler* readObjectKey(const std::string_view& str) override; - -protected: - IJsonHandler* readObjectKeyFeatureIDAttribute( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::FeatureIDAttribute& o); - -private: - CesiumGltf::FeatureIDAttribute* _pObject = nullptr; - CesiumJsonReader::StringJsonHandler _featureTable; - FeatureIDsJsonHandler _featureIds; -}; -} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/FeatureIDTextureJsonHandler.h b/CesiumGltfReader/generated/src/FeatureIDTextureJsonHandler.h deleted file mode 100644 index fda07ea9c..000000000 --- a/CesiumGltfReader/generated/src/FeatureIDTextureJsonHandler.h +++ /dev/null @@ -1,39 +0,0 @@ -// This file was generated by generate-classes. -// DO NOT EDIT THIS FILE! -#pragma once - -#include "TextureAccessorJsonHandler.h" - -#include -#include -#include - -namespace CesiumJsonReader { -class ExtensionReaderContext; -} - -namespace CesiumGltfReader { -class FeatureIDTextureJsonHandler - : public CesiumJsonReader::ExtensibleObjectJsonHandler { -public: - using ValueType = CesiumGltf::FeatureIDTexture; - - FeatureIDTextureJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void - reset(IJsonHandler* pParentHandler, CesiumGltf::FeatureIDTexture* pObject); - - virtual IJsonHandler* readObjectKey(const std::string_view& str) override; - -protected: - IJsonHandler* readObjectKeyFeatureIDTexture( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::FeatureIDTexture& o); - -private: - CesiumGltf::FeatureIDTexture* _pObject = nullptr; - CesiumJsonReader::StringJsonHandler _featureTable; - TextureAccessorJsonHandler _featureIds; -}; -} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtMeshFeaturesFeatureIdJsonHandler.h b/CesiumGltfReader/generated/src/FeatureIdJsonHandler.h similarity index 59% rename from CesiumGltfReader/generated/src/ExtensionExtMeshFeaturesFeatureIdJsonHandler.h rename to CesiumGltfReader/generated/src/FeatureIdJsonHandler.h index 9c8229e9a..0aa7db73b 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtMeshFeaturesFeatureIdJsonHandler.h +++ b/CesiumGltfReader/generated/src/FeatureIdJsonHandler.h @@ -2,9 +2,9 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler.h" +#include "FeatureIdTextureJsonHandler.h" -#include +#include #include #include #include @@ -14,32 +14,30 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ExtensionExtMeshFeaturesFeatureIdJsonHandler +class FeatureIdJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::ExtensionExtMeshFeaturesFeatureId; + using ValueType = CesiumGltf::FeatureId; - ExtensionExtMeshFeaturesFeatureIdJsonHandler( + FeatureIdJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset( - IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtMeshFeaturesFeatureId* pObject); + void reset(IJsonHandler* pParentHandler, CesiumGltf::FeatureId* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyExtensionExtMeshFeaturesFeatureId( + IJsonHandler* readObjectKeyFeatureId( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionExtMeshFeaturesFeatureId& o); + CesiumGltf::FeatureId& o); private: - CesiumGltf::ExtensionExtMeshFeaturesFeatureId* _pObject = nullptr; + CesiumGltf::FeatureId* _pObject = nullptr; CesiumJsonReader::IntegerJsonHandler _featureCount; CesiumJsonReader::IntegerJsonHandler _nullFeatureId; CesiumJsonReader::StringJsonHandler _label; CesiumJsonReader::IntegerJsonHandler _attribute; - ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler _texture; + FeatureIdTextureJsonHandler _texture; CesiumJsonReader::IntegerJsonHandler _propertyTable; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler.h b/CesiumGltfReader/generated/src/FeatureIdTextureJsonHandler.h similarity index 53% rename from CesiumGltfReader/generated/src/ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler.h rename to CesiumGltfReader/generated/src/FeatureIdTextureJsonHandler.h index 667b85ab6..f20f16ef3 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler.h +++ b/CesiumGltfReader/generated/src/FeatureIdTextureJsonHandler.h @@ -4,7 +4,7 @@ #include "TextureInfoJsonHandler.h" -#include +#include #include #include @@ -13,27 +13,25 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler - : public TextureInfoJsonHandler { +class FeatureIdTextureJsonHandler : public TextureInfoJsonHandler { public: - using ValueType = CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture; + using ValueType = CesiumGltf::FeatureIdTexture; - ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler( + FeatureIdTextureJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset( - IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture* pObject); + void + reset(IJsonHandler* pParentHandler, CesiumGltf::FeatureIdTexture* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyExtensionExtMeshFeaturesFeatureIdTexture( + IJsonHandler* readObjectKeyFeatureIdTexture( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture& o); + CesiumGltf::FeatureIdTexture& o); private: - CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture* _pObject = nullptr; + CesiumGltf::FeatureIdTexture* _pObject = nullptr; CesiumJsonReader:: ArrayJsonHandler> _channels; diff --git a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp index c305b3691..bde0586ff 100644 --- a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp +++ b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp @@ -9,30 +9,19 @@ namespace CesiumGltfReader { -ExtensionCesiumRTCJsonHandler::ExtensionCesiumRTCJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _center() {} +ExtensionCesiumRTCJsonHandler::ExtensionCesiumRTCJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _center() {} -void ExtensionCesiumRTCJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionCesiumRTC* pObject) { +void ExtensionCesiumRTCJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionCesiumRTC* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionCesiumRTCJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionCesiumRTCJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionCesiumRTC( - CesiumGltf::ExtensionCesiumRTC::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionCesiumRTC(CesiumGltf::ExtensionCesiumRTC::TypeName, str, *this->_pObject); } -void ExtensionCesiumRTCJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionCesiumRTCJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = o.extensions.emplace(extensionName, CesiumGltf::ExtensionCesiumRTC()) .first->second; @@ -41,15 +30,10 @@ void ExtensionCesiumRTCJsonHandler::reset( &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionCesiumRTCJsonHandler::readObjectKeyExtensionCesiumRTC( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionCesiumRTC& o) { +CesiumJsonReader::IJsonHandler* ExtensionCesiumRTCJsonHandler::readObjectKeyExtensionCesiumRTC(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionCesiumRTC& o) { using namespace std::string_literals; - if ("center"s == str) - return property("center", this->_center, o.center); + if ("center"s == str) return property("center", this->_center, o.center); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -66,59 +50,34 @@ ExtensionCesiumRTCJsonHandler::readObjectKeyExtensionCesiumRTC( namespace CesiumGltfReader { -ExtensionCesiumTileEdgesJsonHandler::ExtensionCesiumTileEdgesJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _left(), - _bottom(), - _right(), - _top() {} - -void ExtensionCesiumTileEdgesJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionCesiumTileEdges* pObject) { +ExtensionCesiumTileEdgesJsonHandler::ExtensionCesiumTileEdgesJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _left(), _bottom(), _right(), _top() {} + +void ExtensionCesiumTileEdgesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionCesiumTileEdges* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionCesiumTileEdgesJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionCesiumTileEdgesJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionCesiumTileEdges( - CesiumGltf::ExtensionCesiumTileEdges::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionCesiumTileEdges(CesiumGltf::ExtensionCesiumTileEdges::TypeName, str, *this->_pObject); } -void ExtensionCesiumTileEdgesJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionCesiumTileEdgesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace(extensionName, CesiumGltf::ExtensionCesiumTileEdges()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionCesiumTileEdges()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionCesiumTileEdgesJsonHandler::readObjectKeyExtensionCesiumTileEdges( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionCesiumTileEdges& o) { +CesiumJsonReader::IJsonHandler* ExtensionCesiumTileEdgesJsonHandler::readObjectKeyExtensionCesiumTileEdges(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionCesiumTileEdges& o) { using namespace std::string_literals; - if ("left"s == str) - return property("left", this->_left, o.left); - if ("bottom"s == str) - return property("bottom", this->_bottom, o.bottom); - if ("right"s == str) - return property("right", this->_right, o.right); - if ("top"s == str) - return property("top", this->_top, o.top); + if ("left"s == str) return property("left", this->_left, o.left); + if ("bottom"s == str) return property("bottom", this->_bottom, o.bottom); + if ("right"s == str) return property("right", this->_right, o.right); + if ("top"s == str) return property("top", this->_top, o.top); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -135,67 +94,35 @@ ExtensionCesiumTileEdgesJsonHandler::readObjectKeyExtensionCesiumTileEdges( namespace CesiumGltfReader { -ExtensionModelExtFeatureMetadataJsonHandler:: - ExtensionModelExtFeatureMetadataJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _schema(context), - _schemaUri(), - _statistics(context), - _featureTables(context), - _featureTextures(context) {} - -void ExtensionModelExtFeatureMetadataJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionModelExtFeatureMetadata* pObject) { +ExtensionModelExtFeatureMetadataJsonHandler::ExtensionModelExtFeatureMetadataJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _schema(context), _schemaUri(), _statistics(context), _featureTables(context), _featureTextures(context) {} + +void ExtensionModelExtFeatureMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelExtFeatureMetadata* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionModelExtFeatureMetadataJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionModelExtFeatureMetadataJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelExtFeatureMetadata( - CesiumGltf::ExtensionModelExtFeatureMetadata::TypeName, - str, - *this->_pObject); -} - -void ExtensionModelExtFeatureMetadataJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { - std::any& value = o.extensions - .emplace( - extensionName, - CesiumGltf::ExtensionModelExtFeatureMetadata()) - .first->second; + return this->readObjectKeyExtensionModelExtFeatureMetadata(CesiumGltf::ExtensionModelExtFeatureMetadata::TypeName, str, *this->_pObject); +} + +void ExtensionModelExtFeatureMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { + std::any& value = + o.extensions.emplace(extensionName, CesiumGltf::ExtensionModelExtFeatureMetadata()) + .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionModelExtFeatureMetadataJsonHandler:: - readObjectKeyExtensionModelExtFeatureMetadata( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionModelExtFeatureMetadata& o) { +CesiumJsonReader::IJsonHandler* ExtensionModelExtFeatureMetadataJsonHandler::readObjectKeyExtensionModelExtFeatureMetadata(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelExtFeatureMetadata& o) { using namespace std::string_literals; - if ("schema"s == str) - return property("schema", this->_schema, o.schema); - if ("schemaUri"s == str) - return property("schemaUri", this->_schemaUri, o.schemaUri); - if ("statistics"s == str) - return property("statistics", this->_statistics, o.statistics); - if ("featureTables"s == str) - return property("featureTables", this->_featureTables, o.featureTables); - if ("featureTextures"s == str) - return property( - "featureTextures", - this->_featureTextures, - o.featureTextures); + if ("schema"s == str) return property("schema", this->_schema, o.schema); + if ("schemaUri"s == str) return property("schemaUri", this->_schemaUri, o.schemaUri); + if ("statistics"s == str) return property("statistics", this->_statistics, o.statistics); + if ("featureTables"s == str) return property("featureTables", this->_featureTables, o.featureTables); + if ("featureTextures"s == str) return property("featureTextures", this->_featureTextures, o.featureTextures); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -212,70 +139,33 @@ CesiumJsonReader::IJsonHandler* ExtensionModelExtFeatureMetadataJsonHandler:: namespace CesiumGltfReader { -ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler:: - ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _featureIdAttributes(context), - _featureIdTextures(context), - _featureTextures() {} - -void ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata* pObject) { +ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureIdAttributes(context), _featureIdTextures(context), _featureTextures() {} + +void ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionMeshPrimitiveExtFeatureMetadata( - CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionMeshPrimitiveExtFeatureMetadata(CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata::TypeName, str, *this->_pObject); } -void ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace( - extensionName, - CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata()) .first->second; this->reset( pParentHandler, - &std::any_cast( - value)); + &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler:: - readObjectKeyExtensionMeshPrimitiveExtFeatureMetadata( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata& o) { +CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::readObjectKeyExtensionMeshPrimitiveExtFeatureMetadata(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata& o) { using namespace std::string_literals; - if ("featureIdAttributes"s == str) - return property( - "featureIdAttributes", - this->_featureIdAttributes, - o.featureIdAttributes); - if ("featureIdTextures"s == str) - return property( - "featureIdTextures", - this->_featureIdTextures, - o.featureIdTextures); - if ("featureTextures"s == str) - return property( - "featureTextures", - this->_featureTextures, - o.featureTextures); + if ("featureIdAttributes"s == str) return property("featureIdAttributes", this->_featureIdAttributes, o.featureIdAttributes); + if ("featureIdTextures"s == str) return property("featureIdTextures", this->_featureIdTextures, o.featureIdTextures); + if ("featureTextures"s == str) return property("featureTextures", this->_featureTextures, o.featureTextures); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -292,51 +182,31 @@ ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler:: namespace CesiumGltfReader { -ExtensionExtInstanceFeaturesJsonHandler:: - ExtensionExtInstanceFeaturesJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _featureIds(context) {} +ExtensionExtInstanceFeaturesJsonHandler::ExtensionExtInstanceFeaturesJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureIds(context) {} -void ExtensionExtInstanceFeaturesJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtInstanceFeatures* pObject) { +void ExtensionExtInstanceFeaturesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtInstanceFeatures* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtInstanceFeaturesJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtInstanceFeatures( - CesiumGltf::ExtensionExtInstanceFeatures::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtInstanceFeatures(CesiumGltf::ExtensionExtInstanceFeatures::TypeName, str, *this->_pObject); } -void ExtensionExtInstanceFeaturesJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionExtInstanceFeaturesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace(extensionName, CesiumGltf::ExtensionExtInstanceFeatures()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionExtInstanceFeatures()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesJsonHandler:: - readObjectKeyExtensionExtInstanceFeatures( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtInstanceFeatures& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesJsonHandler::readObjectKeyExtensionExtInstanceFeatures(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtInstanceFeatures& o) { using namespace std::string_literals; - if ("featureIds"s == str) - return property("featureIds", this->_featureIds, o.featureIds); + if ("featureIds"s == str) return property("featureIds", this->_featureIds, o.featureIds); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -353,50 +223,31 @@ CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesJsonHandler:: namespace CesiumGltfReader { -ExtensionExtMeshFeaturesJsonHandler::ExtensionExtMeshFeaturesJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _featureIds(context) {} +ExtensionExtMeshFeaturesJsonHandler::ExtensionExtMeshFeaturesJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureIds(context) {} -void ExtensionExtMeshFeaturesJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtMeshFeatures* pObject) { +void ExtensionExtMeshFeaturesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtMeshFeatures* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtMeshFeaturesJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtMeshFeaturesJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtMeshFeatures( - CesiumGltf::ExtensionExtMeshFeatures::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtMeshFeatures(CesiumGltf::ExtensionExtMeshFeatures::TypeName, str, *this->_pObject); } -void ExtensionExtMeshFeaturesJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionExtMeshFeaturesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace(extensionName, CesiumGltf::ExtensionExtMeshFeatures()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionExtMeshFeatures()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionExtMeshFeaturesJsonHandler::readObjectKeyExtensionExtMeshFeatures( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtMeshFeatures& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtMeshFeaturesJsonHandler::readObjectKeyExtensionExtMeshFeatures(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtMeshFeatures& o) { using namespace std::string_literals; - if ("featureIds"s == str) - return property("featureIds", this->_featureIds, o.featureIds); + if ("featureIds"s == str) return property("featureIds", this->_featureIds, o.featureIds); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -413,50 +264,31 @@ ExtensionExtMeshFeaturesJsonHandler::readObjectKeyExtensionExtMeshFeatures( namespace CesiumGltfReader { -ExtensionExtMeshGpuInstancingJsonHandler:: - ExtensionExtMeshGpuInstancingJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attributes() {} +ExtensionExtMeshGpuInstancingJsonHandler::ExtensionExtMeshGpuInstancingJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attributes() {} -void ExtensionExtMeshGpuInstancingJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtMeshGpuInstancing* pObject) { +void ExtensionExtMeshGpuInstancingJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtMeshGpuInstancing* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtMeshGpuInstancingJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtMeshGpuInstancingJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtMeshGpuInstancing( - CesiumGltf::ExtensionExtMeshGpuInstancing::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtMeshGpuInstancing(CesiumGltf::ExtensionExtMeshGpuInstancing::TypeName, str, *this->_pObject); } -void ExtensionExtMeshGpuInstancingJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionExtMeshGpuInstancingJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace(extensionName, CesiumGltf::ExtensionExtMeshGpuInstancing()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionExtMeshGpuInstancing()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionExtMeshGpuInstancingJsonHandler:: - readObjectKeyExtensionExtMeshGpuInstancing( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtMeshGpuInstancing& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtMeshGpuInstancingJsonHandler::readObjectKeyExtensionExtMeshGpuInstancing(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtMeshGpuInstancing& o) { using namespace std::string_literals; - if ("attributes"s == str) - return property("attributes", this->_attributes, o.attributes); + if ("attributes"s == str) return property("attributes", this->_attributes, o.attributes); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -473,52 +305,31 @@ CesiumJsonReader::IJsonHandler* ExtensionExtMeshGpuInstancingJsonHandler:: namespace CesiumGltfReader { -ExtensionBufferExtMeshoptCompressionJsonHandler:: - ExtensionBufferExtMeshoptCompressionJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _fallback() {} +ExtensionBufferExtMeshoptCompressionJsonHandler::ExtensionBufferExtMeshoptCompressionJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _fallback() {} -void ExtensionBufferExtMeshoptCompressionJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionBufferExtMeshoptCompression* pObject) { +void ExtensionBufferExtMeshoptCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionBufferExtMeshoptCompression* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionBufferExtMeshoptCompressionJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionBufferExtMeshoptCompressionJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionBufferExtMeshoptCompression( - CesiumGltf::ExtensionBufferExtMeshoptCompression::TypeName, - str, - *this->_pObject); -} - -void ExtensionBufferExtMeshoptCompressionJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { - std::any& value = o.extensions - .emplace( - extensionName, - CesiumGltf::ExtensionBufferExtMeshoptCompression()) - .first->second; + return this->readObjectKeyExtensionBufferExtMeshoptCompression(CesiumGltf::ExtensionBufferExtMeshoptCompression::TypeName, str, *this->_pObject); +} + +void ExtensionBufferExtMeshoptCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { + std::any& value = + o.extensions.emplace(extensionName, CesiumGltf::ExtensionBufferExtMeshoptCompression()) + .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionBufferExtMeshoptCompressionJsonHandler:: - readObjectKeyExtensionBufferExtMeshoptCompression( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionBufferExtMeshoptCompression& o) { +CesiumJsonReader::IJsonHandler* ExtensionBufferExtMeshoptCompressionJsonHandler::readObjectKeyExtensionBufferExtMeshoptCompression(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionBufferExtMeshoptCompression& o) { using namespace std::string_literals; - if ("fallback"s == str) - return property("fallback", this->_fallback, o.fallback); + if ("fallback"s == str) return property("fallback", this->_fallback, o.fallback); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -535,73 +346,37 @@ ExtensionBufferExtMeshoptCompressionJsonHandler:: namespace CesiumGltfReader { -ExtensionBufferViewExtMeshoptCompressionJsonHandler:: - ExtensionBufferViewExtMeshoptCompressionJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _buffer(), - _byteOffset(), - _byteLength(), - _byteStride(), - _count(), - _mode(), - _filter() {} - -void ExtensionBufferViewExtMeshoptCompressionJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionBufferViewExtMeshoptCompression* pObject) { +ExtensionBufferViewExtMeshoptCompressionJsonHandler::ExtensionBufferViewExtMeshoptCompressionJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _buffer(), _byteOffset(), _byteLength(), _byteStride(), _count(), _mode(), _filter() {} + +void ExtensionBufferViewExtMeshoptCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionBufferViewExtMeshoptCompression* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionBufferViewExtMeshoptCompressionJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionBufferViewExtMeshoptCompressionJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionBufferViewExtMeshoptCompression( - CesiumGltf::ExtensionBufferViewExtMeshoptCompression::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionBufferViewExtMeshoptCompression(CesiumGltf::ExtensionBufferViewExtMeshoptCompression::TypeName, str, *this->_pObject); } -void ExtensionBufferViewExtMeshoptCompressionJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionBufferViewExtMeshoptCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace( - extensionName, - CesiumGltf::ExtensionBufferViewExtMeshoptCompression()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionBufferViewExtMeshoptCompression()) .first->second; this->reset( pParentHandler, - &std::any_cast( - value)); + &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionBufferViewExtMeshoptCompressionJsonHandler:: - readObjectKeyExtensionBufferViewExtMeshoptCompression( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionBufferViewExtMeshoptCompression& o) { +CesiumJsonReader::IJsonHandler* ExtensionBufferViewExtMeshoptCompressionJsonHandler::readObjectKeyExtensionBufferViewExtMeshoptCompression(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionBufferViewExtMeshoptCompression& o) { using namespace std::string_literals; - if ("buffer"s == str) - return property("buffer", this->_buffer, o.buffer); - if ("byteOffset"s == str) - return property("byteOffset", this->_byteOffset, o.byteOffset); - if ("byteLength"s == str) - return property("byteLength", this->_byteLength, o.byteLength); - if ("byteStride"s == str) - return property("byteStride", this->_byteStride, o.byteStride); - if ("count"s == str) - return property("count", this->_count, o.count); - if ("mode"s == str) - return property("mode", this->_mode, o.mode); - if ("filter"s == str) - return property("filter", this->_filter, o.filter); + if ("buffer"s == str) return property("buffer", this->_buffer, o.buffer); + if ("byteOffset"s == str) return property("byteOffset", this->_byteOffset, o.byteOffset); + if ("byteLength"s == str) return property("byteLength", this->_byteLength, o.byteLength); + if ("byteStride"s == str) return property("byteStride", this->_byteStride, o.byteStride); + if ("count"s == str) return property("count", this->_count, o.count); + if ("mode"s == str) return property("mode", this->_mode, o.mode); + if ("filter"s == str) return property("filter", this->_filter, o.filter); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -618,70 +393,35 @@ ExtensionBufferViewExtMeshoptCompressionJsonHandler:: namespace CesiumGltfReader { -ExtensionModelExtStructuralMetadataJsonHandler:: - ExtensionModelExtStructuralMetadataJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _schema(context), - _schemaUri(), - _propertyTables(context), - _propertyTextures(context), - _propertyAttributes(context) {} - -void ExtensionModelExtStructuralMetadataJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionModelExtStructuralMetadata* pObject) { +ExtensionModelExtStructuralMetadataJsonHandler::ExtensionModelExtStructuralMetadataJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _schema(context), _schemaUri(), _propertyTables(context), _propertyTextures(context), _propertyAttributes(context) {} + +void ExtensionModelExtStructuralMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelExtStructuralMetadata* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionModelExtStructuralMetadataJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionModelExtStructuralMetadataJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelExtStructuralMetadata( - CesiumGltf::ExtensionModelExtStructuralMetadata::TypeName, - str, - *this->_pObject); -} - -void ExtensionModelExtStructuralMetadataJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { - std::any& value = o.extensions - .emplace( - extensionName, - CesiumGltf::ExtensionModelExtStructuralMetadata()) - .first->second; + return this->readObjectKeyExtensionModelExtStructuralMetadata(CesiumGltf::ExtensionModelExtStructuralMetadata::TypeName, str, *this->_pObject); +} + +void ExtensionModelExtStructuralMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { + std::any& value = + o.extensions.emplace(extensionName, CesiumGltf::ExtensionModelExtStructuralMetadata()) + .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionModelExtStructuralMetadataJsonHandler:: - readObjectKeyExtensionModelExtStructuralMetadata( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionModelExtStructuralMetadata& o) { +CesiumJsonReader::IJsonHandler* ExtensionModelExtStructuralMetadataJsonHandler::readObjectKeyExtensionModelExtStructuralMetadata(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelExtStructuralMetadata& o) { using namespace std::string_literals; - if ("schema"s == str) - return property("schema", this->_schema, o.schema); - if ("schemaUri"s == str) - return property("schemaUri", this->_schemaUri, o.schemaUri); - if ("propertyTables"s == str) - return property("propertyTables", this->_propertyTables, o.propertyTables); - if ("propertyTextures"s == str) - return property( - "propertyTextures", - this->_propertyTextures, - o.propertyTextures); - if ("propertyAttributes"s == str) - return property( - "propertyAttributes", - this->_propertyAttributes, - o.propertyAttributes); + if ("schema"s == str) return property("schema", this->_schema, o.schema); + if ("schemaUri"s == str) return property("schemaUri", this->_schemaUri, o.schemaUri); + if ("propertyTables"s == str) return property("propertyTables", this->_propertyTables, o.propertyTables); + if ("propertyTextures"s == str) return property("propertyTextures", this->_propertyTextures, o.propertyTextures); + if ("propertyAttributes"s == str) return property("propertyAttributes", this->_propertyAttributes, o.propertyAttributes); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -698,64 +438,32 @@ CesiumJsonReader::IJsonHandler* ExtensionModelExtStructuralMetadataJsonHandler:: namespace CesiumGltfReader { -ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler:: - ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _propertyTextures(), - _propertyAttributes() {} +ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _propertyTextures(), _propertyAttributes() {} -void ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata* pObject) { +void ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionMeshPrimitiveExtStructuralMetadata( - CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionMeshPrimitiveExtStructuralMetadata(CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata::TypeName, str, *this->_pObject); } -void ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace( - extensionName, - CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata()) .first->second; this->reset( pParentHandler, - &std::any_cast( - value)); + &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler:: - readObjectKeyExtensionMeshPrimitiveExtStructuralMetadata( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata& o) { +CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::readObjectKeyExtensionMeshPrimitiveExtStructuralMetadata(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata& o) { using namespace std::string_literals; - if ("propertyTextures"s == str) - return property( - "propertyTextures", - this->_propertyTextures, - o.propertyTextures); - if ("propertyAttributes"s == str) - return property( - "propertyAttributes", - this->_propertyAttributes, - o.propertyAttributes); + if ("propertyTextures"s == str) return property("propertyTextures", this->_propertyTextures, o.propertyTextures); + if ("propertyAttributes"s == str) return property("propertyAttributes", this->_propertyAttributes, o.propertyAttributes); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -772,55 +480,32 @@ ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler:: namespace CesiumGltfReader { -ExtensionKhrDracoMeshCompressionJsonHandler:: - ExtensionKhrDracoMeshCompressionJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _bufferView(), - _attributes() {} +ExtensionKhrDracoMeshCompressionJsonHandler::ExtensionKhrDracoMeshCompressionJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _bufferView(), _attributes() {} -void ExtensionKhrDracoMeshCompressionJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionKhrDracoMeshCompression* pObject) { +void ExtensionKhrDracoMeshCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionKhrDracoMeshCompression* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionKhrDracoMeshCompressionJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionKhrDracoMeshCompressionJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionKhrDracoMeshCompression( - CesiumGltf::ExtensionKhrDracoMeshCompression::TypeName, - str, - *this->_pObject); -} - -void ExtensionKhrDracoMeshCompressionJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { - std::any& value = o.extensions - .emplace( - extensionName, - CesiumGltf::ExtensionKhrDracoMeshCompression()) - .first->second; + return this->readObjectKeyExtensionKhrDracoMeshCompression(CesiumGltf::ExtensionKhrDracoMeshCompression::TypeName, str, *this->_pObject); +} + +void ExtensionKhrDracoMeshCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { + std::any& value = + o.extensions.emplace(extensionName, CesiumGltf::ExtensionKhrDracoMeshCompression()) + .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionKhrDracoMeshCompressionJsonHandler:: - readObjectKeyExtensionKhrDracoMeshCompression( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionKhrDracoMeshCompression& o) { +CesiumJsonReader::IJsonHandler* ExtensionKhrDracoMeshCompressionJsonHandler::readObjectKeyExtensionKhrDracoMeshCompression(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionKhrDracoMeshCompression& o) { using namespace std::string_literals; - if ("bufferView"s == str) - return property("bufferView", this->_bufferView, o.bufferView); - if ("attributes"s == str) - return property("attributes", this->_attributes, o.attributes); + if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); + if ("attributes"s == str) return property("attributes", this->_attributes, o.attributes); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -837,45 +522,28 @@ CesiumJsonReader::IJsonHandler* ExtensionKhrDracoMeshCompressionJsonHandler:: namespace CesiumGltfReader { -ExtensionKhrMaterialsUnlitJsonHandler::ExtensionKhrMaterialsUnlitJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context) {} +ExtensionKhrMaterialsUnlitJsonHandler::ExtensionKhrMaterialsUnlitJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context) {} -void ExtensionKhrMaterialsUnlitJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionKhrMaterialsUnlit* pObject) { +void ExtensionKhrMaterialsUnlitJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionKhrMaterialsUnlit* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionKhrMaterialsUnlitJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionKhrMaterialsUnlitJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionKhrMaterialsUnlit( - CesiumGltf::ExtensionKhrMaterialsUnlit::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionKhrMaterialsUnlit(CesiumGltf::ExtensionKhrMaterialsUnlit::TypeName, str, *this->_pObject); } -void ExtensionKhrMaterialsUnlitJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionKhrMaterialsUnlitJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace(extensionName, CesiumGltf::ExtensionKhrMaterialsUnlit()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionKhrMaterialsUnlit()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionKhrMaterialsUnlitJsonHandler::readObjectKeyExtensionKhrMaterialsUnlit( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionKhrMaterialsUnlit& o) { +CesiumJsonReader::IJsonHandler* ExtensionKhrMaterialsUnlitJsonHandler::readObjectKeyExtensionKhrMaterialsUnlit(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionKhrMaterialsUnlit& o) { using namespace std::string_literals; (void)o; @@ -895,52 +563,31 @@ ExtensionKhrMaterialsUnlitJsonHandler::readObjectKeyExtensionKhrMaterialsUnlit( namespace CesiumGltfReader { -ExtensionModelKhrMaterialsVariantsJsonHandler:: - ExtensionModelKhrMaterialsVariantsJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _variants(context) {} +ExtensionModelKhrMaterialsVariantsJsonHandler::ExtensionModelKhrMaterialsVariantsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _variants(context) {} -void ExtensionModelKhrMaterialsVariantsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionModelKhrMaterialsVariants* pObject) { +void ExtensionModelKhrMaterialsVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelKhrMaterialsVariants* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionModelKhrMaterialsVariantsJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelKhrMaterialsVariants( - CesiumGltf::ExtensionModelKhrMaterialsVariants::TypeName, - str, - *this->_pObject); -} - -void ExtensionModelKhrMaterialsVariantsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { - std::any& value = o.extensions - .emplace( - extensionName, - CesiumGltf::ExtensionModelKhrMaterialsVariants()) - .first->second; + return this->readObjectKeyExtensionModelKhrMaterialsVariants(CesiumGltf::ExtensionModelKhrMaterialsVariants::TypeName, str, *this->_pObject); +} + +void ExtensionModelKhrMaterialsVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { + std::any& value = + o.extensions.emplace(extensionName, CesiumGltf::ExtensionModelKhrMaterialsVariants()) + .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsJsonHandler:: - readObjectKeyExtensionModelKhrMaterialsVariants( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionModelKhrMaterialsVariants& o) { +CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsJsonHandler::readObjectKeyExtensionModelKhrMaterialsVariants(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelKhrMaterialsVariants& o) { using namespace std::string_literals; - if ("variants"s == str) - return property("variants", this->_variants, o.variants); + if ("variants"s == str) return property("variants", this->_variants, o.variants); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -957,55 +604,31 @@ CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsJsonHandler:: namespace CesiumGltfReader { -ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler:: - ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _mappings(context) {} +ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _mappings(context) {} -void ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants* pObject) { +void ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariants( - CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariants(CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants::TypeName, str, *this->_pObject); } -void ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace( - extensionName, - CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants()) .first->second; this->reset( pParentHandler, - &std::any_cast( - value)); + &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler:: - readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariants( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants& o) { +CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariants(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants& o) { using namespace std::string_literals; - if ("mappings"s == str) - return property("mappings", this->_mappings, o.mappings); + if ("mappings"s == str) return property("mappings", this->_mappings, o.mappings); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1022,49 +645,31 @@ ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler:: namespace CesiumGltfReader { -ExtensionKhrTextureBasisuJsonHandler::ExtensionKhrTextureBasisuJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _source() {} +ExtensionKhrTextureBasisuJsonHandler::ExtensionKhrTextureBasisuJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _source() {} -void ExtensionKhrTextureBasisuJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionKhrTextureBasisu* pObject) { +void ExtensionKhrTextureBasisuJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionKhrTextureBasisu* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionKhrTextureBasisuJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionKhrTextureBasisuJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionKhrTextureBasisu( - CesiumGltf::ExtensionKhrTextureBasisu::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionKhrTextureBasisu(CesiumGltf::ExtensionKhrTextureBasisu::TypeName, str, *this->_pObject); } -void ExtensionKhrTextureBasisuJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionKhrTextureBasisuJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace(extensionName, CesiumGltf::ExtensionKhrTextureBasisu()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionKhrTextureBasisu()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionKhrTextureBasisuJsonHandler::readObjectKeyExtensionKhrTextureBasisu( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionKhrTextureBasisu& o) { +CesiumJsonReader::IJsonHandler* ExtensionKhrTextureBasisuJsonHandler::readObjectKeyExtensionKhrTextureBasisu(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionKhrTextureBasisu& o) { using namespace std::string_literals; - if ("source"s == str) - return property("source", this->_source, o.source); + if ("source"s == str) return property("source", this->_source, o.source); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1081,54 +686,32 @@ ExtensionKhrTextureBasisuJsonHandler::readObjectKeyExtensionKhrTextureBasisu( namespace CesiumGltfReader { -ExtensionModelMaxarMeshVariantsJsonHandler:: - ExtensionModelMaxarMeshVariantsJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _defaultProperty(), - _variants(context) {} +ExtensionModelMaxarMeshVariantsJsonHandler::ExtensionModelMaxarMeshVariantsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _defaultProperty(), _variants(context) {} -void ExtensionModelMaxarMeshVariantsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionModelMaxarMeshVariants* pObject) { +void ExtensionModelMaxarMeshVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelMaxarMeshVariants* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionModelMaxarMeshVariantsJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelMaxarMeshVariants( - CesiumGltf::ExtensionModelMaxarMeshVariants::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionModelMaxarMeshVariants(CesiumGltf::ExtensionModelMaxarMeshVariants::TypeName, str, *this->_pObject); } -void ExtensionModelMaxarMeshVariantsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionModelMaxarMeshVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace(extensionName, CesiumGltf::ExtensionModelMaxarMeshVariants()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionModelMaxarMeshVariants()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsJsonHandler:: - readObjectKeyExtensionModelMaxarMeshVariants( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionModelMaxarMeshVariants& o) { +CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsJsonHandler::readObjectKeyExtensionModelMaxarMeshVariants(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelMaxarMeshVariants& o) { using namespace std::string_literals; - if ("default"s == str) - return property("default", this->_defaultProperty, o.defaultProperty); - if ("variants"s == str) - return property("variants", this->_variants, o.variants); + if ("default"s == str) return property("default", this->_defaultProperty, o.defaultProperty); + if ("variants"s == str) return property("variants", this->_variants, o.variants); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1145,51 +728,31 @@ CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsJsonHandler:: namespace CesiumGltfReader { -ExtensionNodeMaxarMeshVariantsJsonHandler:: - ExtensionNodeMaxarMeshVariantsJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _mappings(context) {} +ExtensionNodeMaxarMeshVariantsJsonHandler::ExtensionNodeMaxarMeshVariantsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _mappings(context) {} -void ExtensionNodeMaxarMeshVariantsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionNodeMaxarMeshVariants* pObject) { +void ExtensionNodeMaxarMeshVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionNodeMaxarMeshVariants* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionNodeMaxarMeshVariantsJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionNodeMaxarMeshVariants( - CesiumGltf::ExtensionNodeMaxarMeshVariants::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionNodeMaxarMeshVariants(CesiumGltf::ExtensionNodeMaxarMeshVariants::TypeName, str, *this->_pObject); } -void ExtensionNodeMaxarMeshVariantsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionNodeMaxarMeshVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace(extensionName, CesiumGltf::ExtensionNodeMaxarMeshVariants()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionNodeMaxarMeshVariants()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsJsonHandler:: - readObjectKeyExtensionNodeMaxarMeshVariants( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionNodeMaxarMeshVariants& o) { +CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsJsonHandler::readObjectKeyExtensionNodeMaxarMeshVariants(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionNodeMaxarMeshVariants& o) { using namespace std::string_literals; - if ("mappings"s == str) - return property("mappings", this->_mappings, o.mappings); + if ("mappings"s == str) return property("mappings", this->_mappings, o.mappings); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1206,60 +769,34 @@ CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsJsonHandler:: namespace CesiumGltfReader { -ExtensionKhrTextureTransformJsonHandler:: - ExtensionKhrTextureTransformJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _offset(), - _rotation(), - _scale(), - _texCoord() {} - -void ExtensionKhrTextureTransformJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionKhrTextureTransform* pObject) { +ExtensionKhrTextureTransformJsonHandler::ExtensionKhrTextureTransformJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _offset(), _rotation(), _scale(), _texCoord() {} + +void ExtensionKhrTextureTransformJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionKhrTextureTransform* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionKhrTextureTransformJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionKhrTextureTransformJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionKhrTextureTransform( - CesiumGltf::ExtensionKhrTextureTransform::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionKhrTextureTransform(CesiumGltf::ExtensionKhrTextureTransform::TypeName, str, *this->_pObject); } -void ExtensionKhrTextureTransformJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionKhrTextureTransformJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = - o.extensions - .emplace(extensionName, CesiumGltf::ExtensionKhrTextureTransform()) + o.extensions.emplace(extensionName, CesiumGltf::ExtensionKhrTextureTransform()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionKhrTextureTransformJsonHandler:: - readObjectKeyExtensionKhrTextureTransform( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionKhrTextureTransform& o) { +CesiumJsonReader::IJsonHandler* ExtensionKhrTextureTransformJsonHandler::readObjectKeyExtensionKhrTextureTransform(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionKhrTextureTransform& o) { using namespace std::string_literals; - if ("offset"s == str) - return property("offset", this->_offset, o.offset); - if ("rotation"s == str) - return property("rotation", this->_rotation, o.rotation); - if ("scale"s == str) - return property("scale", this->_scale, o.scale); - if ("texCoord"s == str) - return property("texCoord", this->_texCoord, o.texCoord); + if ("offset"s == str) return property("offset", this->_offset, o.offset); + if ("rotation"s == str) return property("rotation", this->_rotation, o.rotation); + if ("scale"s == str) return property("scale", this->_scale, o.scale); + if ("texCoord"s == str) return property("texCoord", this->_texCoord, o.texCoord); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1276,30 +813,19 @@ CesiumJsonReader::IJsonHandler* ExtensionKhrTextureTransformJsonHandler:: namespace CesiumGltfReader { -ExtensionTextureWebpJsonHandler::ExtensionTextureWebpJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _source() {} +ExtensionTextureWebpJsonHandler::ExtensionTextureWebpJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _source() {} -void ExtensionTextureWebpJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionTextureWebp* pObject) { +void ExtensionTextureWebpJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionTextureWebp* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionTextureWebpJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionTextureWebpJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionTextureWebp( - CesiumGltf::ExtensionTextureWebp::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionTextureWebp(CesiumGltf::ExtensionTextureWebp::TypeName, str, *this->_pObject); } -void ExtensionTextureWebpJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumUtility::ExtensibleObject& o, - const std::string_view& extensionName) { +void ExtensionTextureWebpJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { std::any& value = o.extensions.emplace(extensionName, CesiumGltf::ExtensionTextureWebp()) .first->second; @@ -1308,15 +834,10 @@ void ExtensionTextureWebpJsonHandler::reset( &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* -ExtensionTextureWebpJsonHandler::readObjectKeyExtensionTextureWebp( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionTextureWebp& o) { +CesiumJsonReader::IJsonHandler* ExtensionTextureWebpJsonHandler::readObjectKeyExtensionTextureWebp(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionTextureWebp& o) { using namespace std::string_literals; - if ("source"s == str) - return property("source", this->_source, o.source); + if ("source"s == str) return property("source", this->_source, o.source); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1333,45 +854,24 @@ ExtensionTextureWebpJsonHandler::readObjectKeyExtensionTextureWebp( namespace CesiumGltfReader { -ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler:: - ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _variants(), - _mesh(), - _name() {} - -void ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue* pObject) { +ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _variants(), _mesh(), _name() {} + +void ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionNodeMaxarMeshVariantsMappingsValue( - CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler:: - readObjectKeyExtensionNodeMaxarMeshVariantsMappingsValue( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue& o) { + return this->readObjectKeyExtensionNodeMaxarMeshVariantsMappingsValue(CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::readObjectKeyExtensionNodeMaxarMeshVariantsMappingsValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue& o) { using namespace std::string_literals; - if ("variants"s == str) - return property("variants", this->_variants, o.variants); - if ("mesh"s == str) - return property("mesh", this->_mesh, o.mesh); - if ("name"s == str) - return property("name", this->_name, o.name); + if ("variants"s == str) return property("variants", this->_variants, o.variants); + if ("mesh"s == str) return property("mesh", this->_mesh, o.mesh); + if ("name"s == str) return property("name", this->_name, o.name); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1388,38 +888,22 @@ ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler:: namespace CesiumGltfReader { -ExtensionModelMaxarMeshVariantsValueJsonHandler:: - ExtensionModelMaxarMeshVariantsValueJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), _name() {} +ExtensionModelMaxarMeshVariantsValueJsonHandler::ExtensionModelMaxarMeshVariantsValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _name() {} -void ExtensionModelMaxarMeshVariantsValueJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionModelMaxarMeshVariantsValue* pObject) { +void ExtensionModelMaxarMeshVariantsValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelMaxarMeshVariantsValue* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionModelMaxarMeshVariantsValueJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsValueJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelMaxarMeshVariantsValue( - CesiumGltf::ExtensionModelMaxarMeshVariantsValue::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionModelMaxarMeshVariantsValueJsonHandler:: - readObjectKeyExtensionModelMaxarMeshVariantsValue( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionModelMaxarMeshVariantsValue& o) { + return this->readObjectKeyExtensionModelMaxarMeshVariantsValue(CesiumGltf::ExtensionModelMaxarMeshVariantsValue::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsValueJsonHandler::readObjectKeyExtensionModelMaxarMeshVariantsValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelMaxarMeshVariantsValue& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); + if ("name"s == str) return property("name", this->_name, o.name); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -1436,49 +920,24 @@ ExtensionModelMaxarMeshVariantsValueJsonHandler:: namespace CesiumGltfReader { -ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler:: - ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _variants(), - _material(), - _name() {} - -void ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue* - pObject) { +ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _variants(), _material(), _name() {} + +void ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler:: - readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this - ->readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue( - CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue:: - TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler:: - readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue& - o) { + return this->readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue(CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler::readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue& o) { using namespace std::string_literals; - if ("variants"s == str) - return property("variants", this->_variants, o.variants); - if ("material"s == str) - return property("material", this->_material, o.material); - if ("name"s == str) - return property("name", this->_name, o.name); + if ("variants"s == str) return property("variants", this->_variants, o.variants); + if ("material"s == str) return property("material", this->_material, o.material); + if ("name"s == str) return property("name", this->_name, o.name); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1495,38 +954,22 @@ ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler:: namespace CesiumGltfReader { -ExtensionModelKhrMaterialsVariantsValueJsonHandler:: - ExtensionModelKhrMaterialsVariantsValueJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), _name() {} +ExtensionModelKhrMaterialsVariantsValueJsonHandler::ExtensionModelKhrMaterialsVariantsValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _name() {} -void ExtensionModelKhrMaterialsVariantsValueJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionModelKhrMaterialsVariantsValue* pObject) { +void ExtensionModelKhrMaterialsVariantsValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelKhrMaterialsVariantsValue* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionModelKhrMaterialsVariantsValueJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsValueJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelKhrMaterialsVariantsValue( - CesiumGltf::ExtensionModelKhrMaterialsVariantsValue::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionModelKhrMaterialsVariantsValueJsonHandler:: - readObjectKeyExtensionModelKhrMaterialsVariantsValue( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionModelKhrMaterialsVariantsValue& o) { + return this->readObjectKeyExtensionModelKhrMaterialsVariantsValue(CesiumGltf::ExtensionModelKhrMaterialsVariantsValue::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsValueJsonHandler::readObjectKeyExtensionModelKhrMaterialsVariantsValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelKhrMaterialsVariantsValue& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); + if ("name"s == str) return property("name", this->_name, o.name); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -1543,45 +986,24 @@ ExtensionModelKhrMaterialsVariantsValueJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyAttributeJsonHandler:: - ExtensionExtStructuralMetadataPropertyAttributeJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _classProperty(), - _properties(context) {} - -void ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute* pObject) { +ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::ExtensionExtStructuralMetadataPropertyAttributeJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _classProperty(), _properties(context) {} + +void ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyAttribute( - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyAttributeJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyAttribute( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute& o) { + return this->readObjectKeyExtensionExtStructuralMetadataPropertyAttribute(CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyAttribute(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("class"s == str) - return property("class", this->_classProperty, o.classProperty); - if ("properties"s == str) - return property("properties", this->_properties, o.properties); + if ("name"s == str) return property("name", this->_name, o.name); + if ("class"s == str) return property("class", this->_classProperty, o.classProperty); + if ("properties"s == str) return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1598,55 +1020,26 @@ ExtensionExtStructuralMetadataPropertyAttributeJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: - ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _attribute(), - _offset(), - _scale(), - _max(), - _min() {} - -void ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty* - pObject) { +ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attribute(), _offset(), _scale(), _max(), _min() {} + +void ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: - readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this - ->readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty( - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty:: - TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty& - o) { + return this->readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty(CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty& o) { using namespace std::string_literals; - if ("attribute"s == str) - return property("attribute", this->_attribute, o.attribute); - if ("offset"s == str) - return property("offset", this->_offset, o.offset); - if ("scale"s == str) - return property("scale", this->_scale, o.scale); - if ("max"s == str) - return property("max", this->_max, o.max); - if ("min"s == str) - return property("min", this->_min, o.min); + if ("attribute"s == str) return property("attribute", this->_attribute, o.attribute); + if ("offset"s == str) return property("offset", this->_offset, o.offset); + if ("scale"s == str) return property("scale", this->_scale, o.scale); + if ("max"s == str) return property("max", this->_max, o.max); + if ("min"s == str) return property("min", this->_min, o.min); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1663,45 +1056,24 @@ ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTextureJsonHandler:: - ExtensionExtStructuralMetadataPropertyTextureJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _classProperty(), - _properties(context) {} - -void ExtensionExtStructuralMetadataPropertyTextureJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture* pObject) { +ExtensionExtStructuralMetadataPropertyTextureJsonHandler::ExtensionExtStructuralMetadataPropertyTextureJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _classProperty(), _properties(context) {} + +void ExtensionExtStructuralMetadataPropertyTextureJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTextureJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTextureJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyTexture( - CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTextureJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyTexture( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture& o) { + return this->readObjectKeyExtensionExtStructuralMetadataPropertyTexture(CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTextureJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyTexture(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("class"s == str) - return property("class", this->_classProperty, o.classProperty); - if ("properties"s == str) - return property("properties", this->_properties, o.properties); + if ("name"s == str) return property("name", this->_name, o.name); + if ("class"s == str) return property("class", this->_classProperty, o.classProperty); + if ("properties"s == str) return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1718,54 +1090,26 @@ ExtensionExtStructuralMetadataPropertyTextureJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler:: - ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : TextureInfoJsonHandler(context), - _channels(), - _offset(), - _scale(), - _max(), - _min() {} - -void ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty* - pObject) { +ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : TextureInfoJsonHandler(context), _channels(), _offset(), _scale(), _max(), _min() {} + +void ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty* pObject) { TextureInfoJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this - ->readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty( - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty:: - TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty& o) { + return this->readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty(CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty& o) { using namespace std::string_literals; - if ("channels"s == str) - return property("channels", this->_channels, o.channels); - if ("offset"s == str) - return property("offset", this->_offset, o.offset); - if ("scale"s == str) - return property("scale", this->_scale, o.scale); - if ("max"s == str) - return property("max", this->_max, o.max); - if ("min"s == str) - return property("min", this->_min, o.min); + if ("channels"s == str) return property("channels", this->_channels, o.channels); + if ("offset"s == str) return property("offset", this->_offset, o.offset); + if ("scale"s == str) return property("scale", this->_scale, o.scale); + if ("max"s == str) return property("max", this->_max, o.max); + if ("min"s == str) return property("min", this->_min, o.min); return this->readObjectKeyTextureInfo(objectType, str, *this->_pObject); } @@ -1782,39 +1126,23 @@ ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler:: namespace CesiumGltfReader { -TextureInfoJsonHandler::TextureInfoJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _index(), - _texCoord() {} +TextureInfoJsonHandler::TextureInfoJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _index(), _texCoord() {} -void TextureInfoJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::TextureInfo* pObject) { +void TextureInfoJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::TextureInfo* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -TextureInfoJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* TextureInfoJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyTextureInfo( - CesiumGltf::TextureInfo::TypeName, - str, - *this->_pObject); + return this->readObjectKeyTextureInfo(CesiumGltf::TextureInfo::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -TextureInfoJsonHandler::readObjectKeyTextureInfo( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::TextureInfo& o) { +CesiumJsonReader::IJsonHandler* TextureInfoJsonHandler::readObjectKeyTextureInfo(const std::string& objectType, const std::string_view& str, CesiumGltf::TextureInfo& o) { using namespace std::string_literals; - if ("index"s == str) - return property("index", this->_index, o.index); - if ("texCoord"s == str) - return property("texCoord", this->_texCoord, o.texCoord); + if ("index"s == str) return property("index", this->_index, o.index); + if ("texCoord"s == str) return property("texCoord", this->_texCoord, o.texCoord); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1831,48 +1159,25 @@ TextureInfoJsonHandler::readObjectKeyTextureInfo( namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTableJsonHandler:: - ExtensionExtStructuralMetadataPropertyTableJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _classProperty(), - _count(), - _properties(context) {} - -void ExtensionExtStructuralMetadataPropertyTableJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTable* pObject) { +ExtensionExtStructuralMetadataPropertyTableJsonHandler::ExtensionExtStructuralMetadataPropertyTableJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _classProperty(), _count(), _properties(context) {} + +void ExtensionExtStructuralMetadataPropertyTableJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyTable* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTableJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTableJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyTable( - CesiumGltf::ExtensionExtStructuralMetadataPropertyTable::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTableJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyTable( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTable& o) { + return this->readObjectKeyExtensionExtStructuralMetadataPropertyTable(CesiumGltf::ExtensionExtStructuralMetadataPropertyTable::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTableJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyTable(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyTable& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("class"s == str) - return property("class", this->_classProperty, o.classProperty); - if ("count"s == str) - return property("count", this->_count, o.count); - if ("properties"s == str) - return property("properties", this->_properties, o.properties); + if ("name"s == str) return property("name", this->_name, o.name); + if ("class"s == str) return property("class", this->_classProperty, o.classProperty); + if ("count"s == str) return property("count", this->_count, o.count); + if ("properties"s == str) return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1889,69 +1194,30 @@ ExtensionExtStructuralMetadataPropertyTableJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler:: - ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _values(), - _arrayOffsets(), - _stringOffsets(), - _arrayOffsetType(), - _stringOffsetType(), - _offset(), - _scale(), - _max(), - _min() {} - -void ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty* pObject) { +ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _values(), _arrayOffsets(), _stringOffsets(), _arrayOffsetType(), _stringOffsetType(), _offset(), _scale(), _max(), _min() {} + +void ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty( - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty& o) { + return this->readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty(CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty& o) { using namespace std::string_literals; - if ("values"s == str) - return property("values", this->_values, o.values); - if ("arrayOffsets"s == str) - return property("arrayOffsets", this->_arrayOffsets, o.arrayOffsets); - if ("stringOffsets"s == str) - return property("stringOffsets", this->_stringOffsets, o.stringOffsets); - if ("arrayOffsetType"s == str) - return property( - "arrayOffsetType", - this->_arrayOffsetType, - o.arrayOffsetType); - if ("stringOffsetType"s == str) - return property( - "stringOffsetType", - this->_stringOffsetType, - o.stringOffsetType); - if ("offset"s == str) - return property("offset", this->_offset, o.offset); - if ("scale"s == str) - return property("scale", this->_scale, o.scale); - if ("max"s == str) - return property("max", this->_max, o.max); - if ("min"s == str) - return property("min", this->_min, o.min); + if ("values"s == str) return property("values", this->_values, o.values); + if ("arrayOffsets"s == str) return property("arrayOffsets", this->_arrayOffsets, o.arrayOffsets); + if ("stringOffsets"s == str) return property("stringOffsets", this->_stringOffsets, o.stringOffsets); + if ("arrayOffsetType"s == str) return property("arrayOffsetType", this->_arrayOffsetType, o.arrayOffsetType); + if ("stringOffsetType"s == str) return property("stringOffsetType", this->_stringOffsetType, o.stringOffsetType); + if ("offset"s == str) return property("offset", this->_offset, o.offset); + if ("scale"s == str) return property("scale", this->_scale, o.scale); + if ("max"s == str) return property("max", this->_max, o.max); + if ("min"s == str) return property("min", this->_min, o.min); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1968,54 +1234,27 @@ ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataSchemaJsonHandler:: - ExtensionExtStructuralMetadataSchemaJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _id(), - _name(), - _description(), - _version(), - _classes(context), - _enums(context) {} - -void ExtensionExtStructuralMetadataSchemaJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataSchema* pObject) { +ExtensionExtStructuralMetadataSchemaJsonHandler::ExtensionExtStructuralMetadataSchemaJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _id(), _name(), _description(), _version(), _classes(context), _enums(context) {} + +void ExtensionExtStructuralMetadataSchemaJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataSchema* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataSchemaJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataSchemaJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataSchema( - CesiumGltf::ExtensionExtStructuralMetadataSchema::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataSchemaJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataSchema( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataSchema& o) { + return this->readObjectKeyExtensionExtStructuralMetadataSchema(CesiumGltf::ExtensionExtStructuralMetadataSchema::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataSchemaJsonHandler::readObjectKeyExtensionExtStructuralMetadataSchema(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataSchema& o) { using namespace std::string_literals; - if ("id"s == str) - return property("id", this->_id, o.id); - if ("name"s == str) - return property("name", this->_name, o.name); - if ("description"s == str) - return property("description", this->_description, o.description); - if ("version"s == str) - return property("version", this->_version, o.version); - if ("classes"s == str) - return property("classes", this->_classes, o.classes); - if ("enums"s == str) - return property("enums", this->_enums, o.enums); + if ("id"s == str) return property("id", this->_id, o.id); + if ("name"s == str) return property("name", this->_name, o.name); + if ("description"s == str) return property("description", this->_description, o.description); + if ("version"s == str) return property("version", this->_version, o.version); + if ("classes"s == str) return property("classes", this->_classes, o.classes); + if ("enums"s == str) return property("enums", this->_enums, o.enums); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2032,47 +1271,25 @@ ExtensionExtStructuralMetadataSchemaJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataEnumJsonHandler:: - ExtensionExtStructuralMetadataEnumJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _description(), - _valueType(), - _values(context) {} - -void ExtensionExtStructuralMetadataEnumJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataEnum* pObject) { +ExtensionExtStructuralMetadataEnumJsonHandler::ExtensionExtStructuralMetadataEnumJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _valueType(), _values(context) {} + +void ExtensionExtStructuralMetadataEnumJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataEnum* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataEnumJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataEnum( - CesiumGltf::ExtensionExtStructuralMetadataEnum::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtStructuralMetadataEnum(CesiumGltf::ExtensionExtStructuralMetadataEnum::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataEnum( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataEnum& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumJsonHandler::readObjectKeyExtensionExtStructuralMetadataEnum(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataEnum& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("description"s == str) - return property("description", this->_description, o.description); - if ("valueType"s == str) - return property("valueType", this->_valueType, o.valueType); - if ("values"s == str) - return property("values", this->_values, o.values); + if ("name"s == str) return property("name", this->_name, o.name); + if ("description"s == str) return property("description", this->_description, o.description); + if ("valueType"s == str) return property("valueType", this->_valueType, o.valueType); + if ("values"s == str) return property("values", this->_values, o.values); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2089,45 +1306,24 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataEnumValueJsonHandler:: - ExtensionExtStructuralMetadataEnumValueJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _description(), - _value() {} - -void ExtensionExtStructuralMetadataEnumValueJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataEnumValue* pObject) { +ExtensionExtStructuralMetadataEnumValueJsonHandler::ExtensionExtStructuralMetadataEnumValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _value() {} + +void ExtensionExtStructuralMetadataEnumValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataEnumValue* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataEnumValueJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumValueJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataEnumValue( - CesiumGltf::ExtensionExtStructuralMetadataEnumValue::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataEnumValueJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataEnumValue( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataEnumValue& o) { + return this->readObjectKeyExtensionExtStructuralMetadataEnumValue(CesiumGltf::ExtensionExtStructuralMetadataEnumValue::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumValueJsonHandler::readObjectKeyExtensionExtStructuralMetadataEnumValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataEnumValue& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("description"s == str) - return property("description", this->_description, o.description); - if ("value"s == str) - return property("value", this->_value, o.value); + if ("name"s == str) return property("name", this->_name, o.name); + if ("description"s == str) return property("description", this->_description, o.description); + if ("value"s == str) return property("value", this->_value, o.value); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2144,44 +1340,24 @@ ExtensionExtStructuralMetadataEnumValueJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataClassJsonHandler:: - ExtensionExtStructuralMetadataClassJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _description(), - _properties(context) {} - -void ExtensionExtStructuralMetadataClassJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataClass* pObject) { +ExtensionExtStructuralMetadataClassJsonHandler::ExtensionExtStructuralMetadataClassJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _properties(context) {} + +void ExtensionExtStructuralMetadataClassJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataClass* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataClassJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataClass( - CesiumGltf::ExtensionExtStructuralMetadataClass::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtStructuralMetadataClass(CesiumGltf::ExtensionExtStructuralMetadataClass::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataClass( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataClass& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassJsonHandler::readObjectKeyExtensionExtStructuralMetadataClass(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataClass& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("description"s == str) - return property("description", this->_description, o.description); - if ("properties"s == str) - return property("properties", this->_properties, o.properties); + if ("name"s == str) return property("name", this->_name, o.name); + if ("description"s == str) return property("description", this->_description, o.description); + if ("properties"s == str) return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2198,84 +1374,37 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataClassPropertyJsonHandler:: - ExtensionExtStructuralMetadataClassPropertyJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _description(), - _type(), - _componentType(), - _enumType(), - _array(), - _count(), - _normalized(), - _offset(), - _scale(), - _max(), - _min(), - _required(), - _noData(), - _defaultProperty(), - _semantic() {} - -void ExtensionExtStructuralMetadataClassPropertyJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataClassProperty* pObject) { +ExtensionExtStructuralMetadataClassPropertyJsonHandler::ExtensionExtStructuralMetadataClassPropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _type(), _componentType(), _enumType(), _array(), _count(), _normalized(), _offset(), _scale(), _max(), _min(), _required(), _noData(), _defaultProperty(), _semantic() {} + +void ExtensionExtStructuralMetadataClassPropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataClassProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataClassPropertyJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassPropertyJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataClassProperty( - CesiumGltf::ExtensionExtStructuralMetadataClassProperty::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataClassPropertyJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataClassProperty( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataClassProperty& o) { + return this->readObjectKeyExtensionExtStructuralMetadataClassProperty(CesiumGltf::ExtensionExtStructuralMetadataClassProperty::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassPropertyJsonHandler::readObjectKeyExtensionExtStructuralMetadataClassProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataClassProperty& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("description"s == str) - return property("description", this->_description, o.description); - if ("type"s == str) - return property("type", this->_type, o.type); - if ("componentType"s == str) - return property("componentType", this->_componentType, o.componentType); - if ("enumType"s == str) - return property("enumType", this->_enumType, o.enumType); - if ("array"s == str) - return property("array", this->_array, o.array); - if ("count"s == str) - return property("count", this->_count, o.count); - if ("normalized"s == str) - return property("normalized", this->_normalized, o.normalized); - if ("offset"s == str) - return property("offset", this->_offset, o.offset); - if ("scale"s == str) - return property("scale", this->_scale, o.scale); - if ("max"s == str) - return property("max", this->_max, o.max); - if ("min"s == str) - return property("min", this->_min, o.min); - if ("required"s == str) - return property("required", this->_required, o.required); - if ("noData"s == str) - return property("noData", this->_noData, o.noData); - if ("default"s == str) - return property("default", this->_defaultProperty, o.defaultProperty); - if ("semantic"s == str) - return property("semantic", this->_semantic, o.semantic); + if ("name"s == str) return property("name", this->_name, o.name); + if ("description"s == str) return property("description", this->_description, o.description); + if ("type"s == str) return property("type", this->_type, o.type); + if ("componentType"s == str) return property("componentType", this->_componentType, o.componentType); + if ("enumType"s == str) return property("enumType", this->_enumType, o.enumType); + if ("array"s == str) return property("array", this->_array, o.array); + if ("count"s == str) return property("count", this->_count, o.count); + if ("normalized"s == str) return property("normalized", this->_normalized, o.normalized); + if ("offset"s == str) return property("offset", this->_offset, o.offset); + if ("scale"s == str) return property("scale", this->_scale, o.scale); + if ("max"s == str) return property("max", this->_max, o.max); + if ("min"s == str) return property("min", this->_min, o.min); + if ("required"s == str) return property("required", this->_required, o.required); + if ("noData"s == str) return property("noData", this->_noData, o.noData); + if ("default"s == str) return property("default", this->_defaultProperty, o.defaultProperty); + if ("semantic"s == str) return property("semantic", this->_semantic, o.semantic); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2283,62 +1412,36 @@ ExtensionExtStructuralMetadataClassPropertyJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtMeshFeaturesFeatureIdJsonHandler.h" +#include "FeatureIdJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtMeshFeaturesFeatureIdJsonHandler:: - ExtensionExtMeshFeaturesFeatureIdJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _featureCount(), - _nullFeatureId(), - _label(), - _attribute(), - _texture(context), - _propertyTable() {} - -void ExtensionExtMeshFeaturesFeatureIdJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtMeshFeaturesFeatureId* pObject) { +FeatureIdJsonHandler::FeatureIdJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureCount(), _nullFeatureId(), _label(), _attribute(), _texture(context), _propertyTable() {} + +void FeatureIdJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::FeatureId* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtMeshFeaturesFeatureIdJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* FeatureIdJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtMeshFeaturesFeatureId( - CesiumGltf::ExtensionExtMeshFeaturesFeatureId::TypeName, - str, - *this->_pObject); + return this->readObjectKeyFeatureId(CesiumGltf::FeatureId::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* ExtensionExtMeshFeaturesFeatureIdJsonHandler:: - readObjectKeyExtensionExtMeshFeaturesFeatureId( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtMeshFeaturesFeatureId& o) { +CesiumJsonReader::IJsonHandler* FeatureIdJsonHandler::readObjectKeyFeatureId(const std::string& objectType, const std::string_view& str, CesiumGltf::FeatureId& o) { using namespace std::string_literals; - if ("featureCount"s == str) - return property("featureCount", this->_featureCount, o.featureCount); - if ("nullFeatureId"s == str) - return property("nullFeatureId", this->_nullFeatureId, o.nullFeatureId); - if ("label"s == str) - return property("label", this->_label, o.label); - if ("attribute"s == str) - return property("attribute", this->_attribute, o.attribute); - if ("texture"s == str) - return property("texture", this->_texture, o.texture); - if ("propertyTable"s == str) - return property("propertyTable", this->_propertyTable, o.propertyTable); + if ("featureCount"s == str) return property("featureCount", this->_featureCount, o.featureCount); + if ("nullFeatureId"s == str) return property("nullFeatureId", this->_nullFeatureId, o.nullFeatureId); + if ("label"s == str) return property("label", this->_label, o.label); + if ("attribute"s == str) return property("attribute", this->_attribute, o.attribute); + if ("texture"s == str) return property("texture", this->_texture, o.texture); + if ("propertyTable"s == str) return property("propertyTable", this->_propertyTable, o.propertyTable); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2346,47 +1449,31 @@ CesiumJsonReader::IJsonHandler* ExtensionExtMeshFeaturesFeatureIdJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler.h" +#include "FeatureIdTextureJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler:: - ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : TextureInfoJsonHandler(context), _channels() {} +FeatureIdTextureJsonHandler::FeatureIdTextureJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : TextureInfoJsonHandler(context), _channels() {} -void ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture* pObject) { +void FeatureIdTextureJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::FeatureIdTexture* pObject) { TextureInfoJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* FeatureIdTextureJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtMeshFeaturesFeatureIdTexture( - CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler:: - readObjectKeyExtensionExtMeshFeaturesFeatureIdTexture( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture& o) { + return this->readObjectKeyFeatureIdTexture(CesiumGltf::FeatureIdTexture::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* FeatureIdTextureJsonHandler::readObjectKeyFeatureIdTexture(const std::string& objectType, const std::string_view& str, CesiumGltf::FeatureIdTexture& o) { using namespace std::string_literals; - if ("channels"s == str) - return property("channels", this->_channels, o.channels); + if ("channels"s == str) return property("channels", this->_channels, o.channels); return this->readObjectKeyTextureInfo(objectType, str, *this->_pObject); } @@ -2403,51 +1490,26 @@ ExtensionExtMeshFeaturesFeatureIdTextureJsonHandler:: namespace CesiumGltfReader { -ExtensionExtInstanceFeaturesFeatureIdJsonHandler:: - ExtensionExtInstanceFeaturesFeatureIdJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _featureCount(), - _nullFeatureId(), - _label(), - _attribute(), - _propertyTable() {} - -void ExtensionExtInstanceFeaturesFeatureIdJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtInstanceFeaturesFeatureId* pObject) { +ExtensionExtInstanceFeaturesFeatureIdJsonHandler::ExtensionExtInstanceFeaturesFeatureIdJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureCount(), _nullFeatureId(), _label(), _attribute(), _propertyTable() {} + +void ExtensionExtInstanceFeaturesFeatureIdJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtInstanceFeaturesFeatureId* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ExtensionExtInstanceFeaturesFeatureIdJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesFeatureIdJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtInstanceFeaturesFeatureId( - CesiumGltf::ExtensionExtInstanceFeaturesFeatureId::TypeName, - str, - *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* -ExtensionExtInstanceFeaturesFeatureIdJsonHandler:: - readObjectKeyExtensionExtInstanceFeaturesFeatureId( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtInstanceFeaturesFeatureId& o) { + return this->readObjectKeyExtensionExtInstanceFeaturesFeatureId(CesiumGltf::ExtensionExtInstanceFeaturesFeatureId::TypeName, str, *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesFeatureIdJsonHandler::readObjectKeyExtensionExtInstanceFeaturesFeatureId(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtInstanceFeaturesFeatureId& o) { using namespace std::string_literals; - if ("featureCount"s == str) - return property("featureCount", this->_featureCount, o.featureCount); - if ("nullFeatureId"s == str) - return property("nullFeatureId", this->_nullFeatureId, o.nullFeatureId); - if ("label"s == str) - return property("label", this->_label, o.label); - if ("attribute"s == str) - return property("attribute", this->_attribute, o.attribute); - if ("propertyTable"s == str) - return property("propertyTable", this->_propertyTable, o.propertyTable); + if ("featureCount"s == str) return property("featureCount", this->_featureCount, o.featureCount); + if ("nullFeatureId"s == str) return property("nullFeatureId", this->_nullFeatureId, o.nullFeatureId); + if ("label"s == str) return property("label", this->_label, o.label); + if ("attribute"s == str) return property("attribute", this->_attribute, o.attribute); + if ("propertyTable"s == str) return property("propertyTable", this->_propertyTable, o.propertyTable); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2455,48 +1517,32 @@ ExtensionExtInstanceFeaturesFeatureIdJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "FeatureIDTextureJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -FeatureIDTextureJsonHandler::FeatureIDTextureJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _featureTable(), - _featureIds(context) {} +ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler::ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureTable(), _featureIds(context) {} -void FeatureIDTextureJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::FeatureIDTexture* pObject) { +void ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -FeatureIDTextureJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyFeatureIDTexture( - CesiumGltf::FeatureIDTexture::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataFeatureIDTexture(CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -FeatureIDTextureJsonHandler::readObjectKeyFeatureIDTexture( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::FeatureIDTexture& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureIDTexture(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture& o) { using namespace std::string_literals; - if ("featureTable"s == str) - return property("featureTable", this->_featureTable, o.featureTable); - if ("featureIds"s == str) - return property("featureIds", this->_featureIds, o.featureIds); + if ("featureTable"s == str) return property("featureTable", this->_featureTable, o.featureTable); + if ("featureIds"s == str) return property("featureIds", this->_featureIds, o.featureIds); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2504,48 +1550,32 @@ FeatureIDTextureJsonHandler::readObjectKeyFeatureIDTexture( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "TextureAccessorJsonHandler.h" +#include "ExtensionExtFeatureMetadataTextureAccessorJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -TextureAccessorJsonHandler::TextureAccessorJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _channels(), - _texture(context) {} +ExtensionExtFeatureMetadataTextureAccessorJsonHandler::ExtensionExtFeatureMetadataTextureAccessorJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _channels(), _texture(context) {} -void TextureAccessorJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::TextureAccessor* pObject) { +void ExtensionExtFeatureMetadataTextureAccessorJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -TextureAccessorJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataTextureAccessorJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyTextureAccessor( - CesiumGltf::TextureAccessor::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataTextureAccessor(CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -TextureAccessorJsonHandler::readObjectKeyTextureAccessor( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::TextureAccessor& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataTextureAccessorJsonHandler::readObjectKeyExtensionExtFeatureMetadataTextureAccessor(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor& o) { using namespace std::string_literals; - if ("channels"s == str) - return property("channels", this->_channels, o.channels); - if ("texture"s == str) - return property("texture", this->_texture, o.texture); + if ("channels"s == str) return property("channels", this->_channels, o.channels); + if ("texture"s == str) return property("texture", this->_texture, o.texture); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2553,48 +1583,32 @@ TextureAccessorJsonHandler::readObjectKeyTextureAccessor( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "FeatureIDAttributeJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -FeatureIDAttributeJsonHandler::FeatureIDAttributeJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _featureTable(), - _featureIds(context) {} +ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler::ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureTable(), _featureIds(context) {} -void FeatureIDAttributeJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::FeatureIDAttribute* pObject) { +void ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -FeatureIDAttributeJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyFeatureIDAttribute( - CesiumGltf::FeatureIDAttribute::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataFeatureIDAttribute(CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -FeatureIDAttributeJsonHandler::readObjectKeyFeatureIDAttribute( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::FeatureIDAttribute& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureIDAttribute(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute& o) { using namespace std::string_literals; - if ("featureTable"s == str) - return property("featureTable", this->_featureTable, o.featureTable); - if ("featureIds"s == str) - return property("featureIds", this->_featureIds, o.featureIds); + if ("featureTable"s == str) return property("featureTable", this->_featureTable, o.featureTable); + if ("featureIds"s == str) return property("featureIds", this->_featureIds, o.featureIds); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2602,50 +1616,33 @@ FeatureIDAttributeJsonHandler::readObjectKeyFeatureIDAttribute( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "FeatureIDsJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureIDsJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -FeatureIDsJsonHandler::FeatureIDsJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _attribute(), - _constant(), - _divisor() {} +ExtensionExtFeatureMetadataFeatureIDsJsonHandler::ExtensionExtFeatureMetadataFeatureIDsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attribute(), _constant(), _divisor() {} -void FeatureIDsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::FeatureIDs* pObject) { +void ExtensionExtFeatureMetadataFeatureIDsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -FeatureIDsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDsJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyFeatureIDs( - CesiumGltf::FeatureIDs::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataFeatureIDs(CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* FeatureIDsJsonHandler::readObjectKeyFeatureIDs( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::FeatureIDs& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDsJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureIDs(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs& o) { using namespace std::string_literals; - if ("attribute"s == str) - return property("attribute", this->_attribute, o.attribute); - if ("constant"s == str) - return property("constant", this->_constant, o.constant); - if ("divisor"s == str) - return property("divisor", this->_divisor, o.divisor); + if ("attribute"s == str) return property("attribute", this->_attribute, o.attribute); + if ("constant"s == str) return property("constant", this->_constant, o.constant); + if ("divisor"s == str) return property("divisor", this->_divisor, o.divisor); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2653,48 +1650,32 @@ CesiumJsonReader::IJsonHandler* FeatureIDsJsonHandler::readObjectKeyFeatureIDs( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "FeatureTextureJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureTextureJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -FeatureTextureJsonHandler::FeatureTextureJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _classProperty(), - _properties(context) {} +ExtensionExtFeatureMetadataFeatureTextureJsonHandler::ExtensionExtFeatureMetadataFeatureTextureJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _classProperty(), _properties(context) {} -void FeatureTextureJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::FeatureTexture* pObject) { +void ExtensionExtFeatureMetadataFeatureTextureJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -FeatureTextureJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTextureJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyFeatureTexture( - CesiumGltf::FeatureTexture::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataFeatureTexture(CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -FeatureTextureJsonHandler::readObjectKeyFeatureTexture( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::FeatureTexture& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTextureJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureTexture(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture& o) { using namespace std::string_literals; - if ("class"s == str) - return property("class", this->_classProperty, o.classProperty); - if ("properties"s == str) - return property("properties", this->_properties, o.properties); + if ("class"s == str) return property("class", this->_classProperty, o.classProperty); + if ("properties"s == str) return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2702,51 +1683,33 @@ FeatureTextureJsonHandler::readObjectKeyFeatureTexture( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "FeatureTableJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureTableJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -FeatureTableJsonHandler::FeatureTableJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _classProperty(), - _count(), - _properties(context) {} +ExtensionExtFeatureMetadataFeatureTableJsonHandler::ExtensionExtFeatureMetadataFeatureTableJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _classProperty(), _count(), _properties(context) {} -void FeatureTableJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::FeatureTable* pObject) { +void ExtensionExtFeatureMetadataFeatureTableJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureTable* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -FeatureTableJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTableJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyFeatureTable( - CesiumGltf::FeatureTable::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataFeatureTable(CesiumGltf::ExtensionExtFeatureMetadataFeatureTable::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -FeatureTableJsonHandler::readObjectKeyFeatureTable( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::FeatureTable& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTableJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureTable(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureTable& o) { using namespace std::string_literals; - if ("class"s == str) - return property("class", this->_classProperty, o.classProperty); - if ("count"s == str) - return property("count", this->_count, o.count); - if ("properties"s == str) - return property("properties", this->_properties, o.properties); + if ("class"s == str) return property("class", this->_classProperty, o.classProperty); + if ("count"s == str) return property("count", this->_count, o.count); + if ("properties"s == str) return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2754,60 +1717,34 @@ FeatureTableJsonHandler::readObjectKeyFeatureTable( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "FeatureTablePropertyJsonHandler.h" +#include "ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -FeatureTablePropertyJsonHandler::FeatureTablePropertyJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _bufferView(), - _offsetType(), - _arrayOffsetBufferView(), - _stringOffsetBufferView() {} - -void FeatureTablePropertyJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::FeatureTableProperty* pObject) { +ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler::ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _bufferView(), _offsetType(), _arrayOffsetBufferView(), _stringOffsetBufferView() {} + +void ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -FeatureTablePropertyJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyFeatureTableProperty( - CesiumGltf::FeatureTableProperty::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataFeatureTableProperty(CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -FeatureTablePropertyJsonHandler::readObjectKeyFeatureTableProperty( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::FeatureTableProperty& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureTableProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty& o) { using namespace std::string_literals; - if ("bufferView"s == str) - return property("bufferView", this->_bufferView, o.bufferView); - if ("offsetType"s == str) - return property("offsetType", this->_offsetType, o.offsetType); - if ("arrayOffsetBufferView"s == str) - return property( - "arrayOffsetBufferView", - this->_arrayOffsetBufferView, - o.arrayOffsetBufferView); - if ("stringOffsetBufferView"s == str) - return property( - "stringOffsetBufferView", - this->_stringOffsetBufferView, - o.stringOffsetBufferView); + if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); + if ("offsetType"s == str) return property("offsetType", this->_offsetType, o.offsetType); + if ("arrayOffsetBufferView"s == str) return property("arrayOffsetBufferView", this->_arrayOffsetBufferView, o.arrayOffsetBufferView); + if ("stringOffsetBufferView"s == str) return property("stringOffsetBufferView", this->_stringOffsetBufferView, o.stringOffsetBufferView); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2815,44 +1752,31 @@ FeatureTablePropertyJsonHandler::readObjectKeyFeatureTableProperty( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "StatisticsJsonHandler.h" +#include "ExtensionExtFeatureMetadataStatisticsJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -StatisticsJsonHandler::StatisticsJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _classes(context) {} +ExtensionExtFeatureMetadataStatisticsJsonHandler::ExtensionExtFeatureMetadataStatisticsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _classes(context) {} -void StatisticsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Statistics* pObject) { +void ExtensionExtFeatureMetadataStatisticsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataStatistics* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -StatisticsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataStatisticsJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyStatistics( - CesiumGltf::Statistics::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataStatistics(CesiumGltf::ExtensionExtFeatureMetadataStatistics::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* StatisticsJsonHandler::readObjectKeyStatistics( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Statistics& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataStatisticsJsonHandler::readObjectKeyExtensionExtFeatureMetadataStatistics(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataStatistics& o) { using namespace std::string_literals; - if ("classes"s == str) - return property("classes", this->_classes, o.classes); + if ("classes"s == str) return property("classes", this->_classes, o.classes); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2860,48 +1784,32 @@ CesiumJsonReader::IJsonHandler* StatisticsJsonHandler::readObjectKeyStatistics( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ClassStatisticsJsonHandler.h" +#include "ExtensionExtFeatureMetadataClassStatisticsJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ClassStatisticsJsonHandler::ClassStatisticsJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _count(), - _properties(context) {} +ExtensionExtFeatureMetadataClassStatisticsJsonHandler::ExtensionExtFeatureMetadataClassStatisticsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _count(), _properties(context) {} -void ClassStatisticsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ClassStatistics* pObject) { +void ExtensionExtFeatureMetadataClassStatisticsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataClassStatistics* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ClassStatisticsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassStatisticsJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyClassStatistics( - CesiumGltf::ClassStatistics::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataClassStatistics(CesiumGltf::ExtensionExtFeatureMetadataClassStatistics::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -ClassStatisticsJsonHandler::readObjectKeyClassStatistics( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ClassStatistics& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassStatisticsJsonHandler::readObjectKeyExtensionExtFeatureMetadataClassStatistics(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataClassStatistics& o) { using namespace std::string_literals; - if ("count"s == str) - return property("count", this->_count, o.count); - if ("properties"s == str) - return property("properties", this->_properties, o.properties); + if ("count"s == str) return property("count", this->_count, o.count); + if ("properties"s == str) return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2909,69 +1817,38 @@ ClassStatisticsJsonHandler::readObjectKeyClassStatistics( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "PropertyStatisticsJsonHandler.h" +#include "ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -PropertyStatisticsJsonHandler::PropertyStatisticsJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _min(), - _max(), - _mean(), - _median(), - _standardDeviation(), - _variance(), - _sum(), - _occurrences() {} - -void PropertyStatisticsJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::PropertyStatistics* pObject) { +ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler::ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _min(), _max(), _mean(), _median(), _standardDeviation(), _variance(), _sum(), _occurrences() {} + +void ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -PropertyStatisticsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyPropertyStatistics( - CesiumGltf::PropertyStatistics::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataPropertyStatistics(CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -PropertyStatisticsJsonHandler::readObjectKeyPropertyStatistics( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::PropertyStatistics& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler::readObjectKeyExtensionExtFeatureMetadataPropertyStatistics(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics& o) { using namespace std::string_literals; - if ("min"s == str) - return property("min", this->_min, o.min); - if ("max"s == str) - return property("max", this->_max, o.max); - if ("mean"s == str) - return property("mean", this->_mean, o.mean); - if ("median"s == str) - return property("median", this->_median, o.median); - if ("standardDeviation"s == str) - return property( - "standardDeviation", - this->_standardDeviation, - o.standardDeviation); - if ("variance"s == str) - return property("variance", this->_variance, o.variance); - if ("sum"s == str) - return property("sum", this->_sum, o.sum); - if ("occurrences"s == str) - return property("occurrences", this->_occurrences, o.occurrences); + if ("min"s == str) return property("min", this->_min, o.min); + if ("max"s == str) return property("max", this->_max, o.max); + if ("mean"s == str) return property("mean", this->_mean, o.mean); + if ("median"s == str) return property("median", this->_median, o.median); + if ("standardDeviation"s == str) return property("standardDeviation", this->_standardDeviation, o.standardDeviation); + if ("variance"s == str) return property("variance", this->_variance, o.variance); + if ("sum"s == str) return property("sum", this->_sum, o.sum); + if ("occurrences"s == str) return property("occurrences", this->_occurrences, o.occurrences); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2979,56 +1856,35 @@ PropertyStatisticsJsonHandler::readObjectKeyPropertyStatistics( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "SchemaJsonHandler.h" +#include "ExtensionExtFeatureMetadataSchemaJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -SchemaJsonHandler::SchemaJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _description(), - _version(), - _classes(context), - _enums(context) {} - -void SchemaJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Schema* pObject) { +ExtensionExtFeatureMetadataSchemaJsonHandler::ExtensionExtFeatureMetadataSchemaJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _version(), _classes(context), _enums(context) {} + +void ExtensionExtFeatureMetadataSchemaJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataSchema* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -SchemaJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataSchemaJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeySchema( - CesiumGltf::Schema::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataSchema(CesiumGltf::ExtensionExtFeatureMetadataSchema::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* SchemaJsonHandler::readObjectKeySchema( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Schema& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataSchemaJsonHandler::readObjectKeyExtensionExtFeatureMetadataSchema(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataSchema& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("description"s == str) - return property("description", this->_description, o.description); - if ("version"s == str) - return property("version", this->_version, o.version); - if ("classes"s == str) - return property("classes", this->_classes, o.classes); - if ("enums"s == str) - return property("enums", this->_enums, o.enums); + if ("name"s == str) return property("name", this->_name, o.name); + if ("description"s == str) return property("description", this->_description, o.description); + if ("version"s == str) return property("version", this->_version, o.version); + if ("classes"s == str) return property("classes", this->_classes, o.classes); + if ("enums"s == str) return property("enums", this->_enums, o.enums); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -3036,53 +1892,34 @@ CesiumJsonReader::IJsonHandler* SchemaJsonHandler::readObjectKeySchema( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "EnumJsonHandler.h" +#include "ExtensionExtFeatureMetadataEnumJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -EnumJsonHandler::EnumJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _description(), - _valueType(), - _values(context) {} - -void EnumJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Enum* pObject) { +ExtensionExtFeatureMetadataEnumJsonHandler::ExtensionExtFeatureMetadataEnumJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _valueType(), _values(context) {} + +void ExtensionExtFeatureMetadataEnumJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataEnum* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -EnumJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyEnum( - CesiumGltf::Enum::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataEnum(CesiumGltf::ExtensionExtFeatureMetadataEnum::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* EnumJsonHandler::readObjectKeyEnum( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Enum& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumJsonHandler::readObjectKeyExtensionExtFeatureMetadataEnum(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataEnum& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("description"s == str) - return property("description", this->_description, o.description); - if ("valueType"s == str) - return property("valueType", this->_valueType, o.valueType); - if ("values"s == str) - return property("values", this->_values, o.values); + if ("name"s == str) return property("name", this->_name, o.name); + if ("description"s == str) return property("description", this->_description, o.description); + if ("valueType"s == str) return property("valueType", this->_valueType, o.valueType); + if ("values"s == str) return property("values", this->_values, o.values); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -3090,50 +1927,33 @@ CesiumJsonReader::IJsonHandler* EnumJsonHandler::readObjectKeyEnum( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "EnumValueJsonHandler.h" +#include "ExtensionExtFeatureMetadataEnumValueJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -EnumValueJsonHandler::EnumValueJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _description(), - _value() {} +ExtensionExtFeatureMetadataEnumValueJsonHandler::ExtensionExtFeatureMetadataEnumValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _value() {} -void EnumValueJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::EnumValue* pObject) { +void ExtensionExtFeatureMetadataEnumValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataEnumValue* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -EnumValueJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumValueJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyEnumValue( - CesiumGltf::EnumValue::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataEnumValue(CesiumGltf::ExtensionExtFeatureMetadataEnumValue::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* EnumValueJsonHandler::readObjectKeyEnumValue( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::EnumValue& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumValueJsonHandler::readObjectKeyExtensionExtFeatureMetadataEnumValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataEnumValue& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("description"s == str) - return property("description", this->_description, o.description); - if ("value"s == str) - return property("value", this->_value, o.value); + if ("name"s == str) return property("name", this->_name, o.name); + if ("description"s == str) return property("description", this->_description, o.description); + if ("value"s == str) return property("value", this->_value, o.value); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -3141,50 +1961,33 @@ CesiumJsonReader::IJsonHandler* EnumValueJsonHandler::readObjectKeyEnumValue( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ClassJsonHandler.h" +#include "ExtensionExtFeatureMetadataClassJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ClassJsonHandler::ClassJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _description(), - _properties(context) {} +ExtensionExtFeatureMetadataClassJsonHandler::ExtensionExtFeatureMetadataClassJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _properties(context) {} -void ClassJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Class* pObject) { +void ExtensionExtFeatureMetadataClassJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataClass* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ClassJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyClass( - CesiumGltf::Class::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataClass(CesiumGltf::ExtensionExtFeatureMetadataClass::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* ClassJsonHandler::readObjectKeyClass( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Class& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassJsonHandler::readObjectKeyExtensionExtFeatureMetadataClass(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataClass& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("description"s == str) - return property("description", this->_description, o.description); - if ("properties"s == str) - return property("properties", this->_properties, o.properties); + if ("name"s == str) return property("name", this->_name, o.name); + if ("description"s == str) return property("description", this->_description, o.description); + if ("properties"s == str) return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -3192,78 +1995,42 @@ CesiumJsonReader::IJsonHandler* ClassJsonHandler::readObjectKeyClass( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ClassPropertyJsonHandler.h" +#include "ExtensionExtFeatureMetadataClassPropertyJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ClassPropertyJsonHandler::ClassPropertyJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _name(), - _description(), - _type(), - _enumType(), - _componentType(), - _componentCount(), - _normalized(), - _max(), - _min(), - _defaultProperty(), - _optional(), - _semantic() {} - -void ClassPropertyJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ClassProperty* pObject) { +ExtensionExtFeatureMetadataClassPropertyJsonHandler::ExtensionExtFeatureMetadataClassPropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _type(), _enumType(), _componentType(), _componentCount(), _normalized(), _max(), _min(), _defaultProperty(), _optional(), _semantic() {} + +void ExtensionExtFeatureMetadataClassPropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataClassProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ClassPropertyJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassPropertyJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyClassProperty( - CesiumGltf::ClassProperty::TypeName, - str, - *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataClassProperty(CesiumGltf::ExtensionExtFeatureMetadataClassProperty::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -ClassPropertyJsonHandler::readObjectKeyClassProperty( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ClassProperty& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassPropertyJsonHandler::readObjectKeyExtensionExtFeatureMetadataClassProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataClassProperty& o) { using namespace std::string_literals; - if ("name"s == str) - return property("name", this->_name, o.name); - if ("description"s == str) - return property("description", this->_description, o.description); - if ("type"s == str) - return property("type", this->_type, o.type); - if ("enumType"s == str) - return property("enumType", this->_enumType, o.enumType); - if ("componentType"s == str) - return property("componentType", this->_componentType, o.componentType); - if ("componentCount"s == str) - return property("componentCount", this->_componentCount, o.componentCount); - if ("normalized"s == str) - return property("normalized", this->_normalized, o.normalized); - if ("max"s == str) - return property("max", this->_max, o.max); - if ("min"s == str) - return property("min", this->_min, o.min); - if ("default"s == str) - return property("default", this->_defaultProperty, o.defaultProperty); - if ("optional"s == str) - return property("optional", this->_optional, o.optional); - if ("semantic"s == str) - return property("semantic", this->_semantic, o.semantic); + if ("name"s == str) return property("name", this->_name, o.name); + if ("description"s == str) return property("description", this->_description, o.description); + if ("type"s == str) return property("type", this->_type, o.type); + if ("enumType"s == str) return property("enumType", this->_enumType, o.enumType); + if ("componentType"s == str) return property("componentType", this->_componentType, o.componentType); + if ("componentCount"s == str) return property("componentCount", this->_componentCount, o.componentCount); + if ("normalized"s == str) return property("normalized", this->_normalized, o.normalized); + if ("max"s == str) return property("max", this->_max, o.max); + if ("min"s == str) return property("min", this->_min, o.min); + if ("default"s == str) return property("default", this->_defaultProperty, o.defaultProperty); + if ("optional"s == str) return property("optional", this->_optional, o.optional); + if ("semantic"s == str) return property("semantic", this->_semantic, o.semantic); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -3280,86 +2047,38 @@ ClassPropertyJsonHandler::readObjectKeyClassProperty( namespace CesiumGltfReader { -ModelJsonHandler::ModelJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _extensionsUsed(), - _extensionsRequired(), - _accessors(context), - _animations(context), - _asset(context), - _buffers(context), - _bufferViews(context), - _cameras(context), - _images(context), - _materials(context), - _meshes(context), - _nodes(context), - _samplers(context), - _scene(), - _scenes(context), - _skins(context), - _textures(context) {} - -void ModelJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Model* pObject) { +ModelJsonHandler::ModelJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _extensionsUsed(), _extensionsRequired(), _accessors(context), _animations(context), _asset(context), _buffers(context), _bufferViews(context), _cameras(context), _images(context), _materials(context), _meshes(context), _nodes(context), _samplers(context), _scene(), _scenes(context), _skins(context), _textures(context) {} + +void ModelJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Model* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ModelJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ModelJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyModel( - CesiumGltf::Model::TypeName, - str, - *this->_pObject); + return this->readObjectKeyModel(CesiumGltf::Model::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* ModelJsonHandler::readObjectKeyModel( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Model& o) { +CesiumJsonReader::IJsonHandler* ModelJsonHandler::readObjectKeyModel(const std::string& objectType, const std::string_view& str, CesiumGltf::Model& o) { using namespace std::string_literals; - if ("extensionsUsed"s == str) - return property("extensionsUsed", this->_extensionsUsed, o.extensionsUsed); - if ("extensionsRequired"s == str) - return property( - "extensionsRequired", - this->_extensionsRequired, - o.extensionsRequired); - if ("accessors"s == str) - return property("accessors", this->_accessors, o.accessors); - if ("animations"s == str) - return property("animations", this->_animations, o.animations); - if ("asset"s == str) - return property("asset", this->_asset, o.asset); - if ("buffers"s == str) - return property("buffers", this->_buffers, o.buffers); - if ("bufferViews"s == str) - return property("bufferViews", this->_bufferViews, o.bufferViews); - if ("cameras"s == str) - return property("cameras", this->_cameras, o.cameras); - if ("images"s == str) - return property("images", this->_images, o.images); - if ("materials"s == str) - return property("materials", this->_materials, o.materials); - if ("meshes"s == str) - return property("meshes", this->_meshes, o.meshes); - if ("nodes"s == str) - return property("nodes", this->_nodes, o.nodes); - if ("samplers"s == str) - return property("samplers", this->_samplers, o.samplers); - if ("scene"s == str) - return property("scene", this->_scene, o.scene); - if ("scenes"s == str) - return property("scenes", this->_scenes, o.scenes); - if ("skins"s == str) - return property("skins", this->_skins, o.skins); - if ("textures"s == str) - return property("textures", this->_textures, o.textures); + if ("extensionsUsed"s == str) return property("extensionsUsed", this->_extensionsUsed, o.extensionsUsed); + if ("extensionsRequired"s == str) return property("extensionsRequired", this->_extensionsRequired, o.extensionsRequired); + if ("accessors"s == str) return property("accessors", this->_accessors, o.accessors); + if ("animations"s == str) return property("animations", this->_animations, o.animations); + if ("asset"s == str) return property("asset", this->_asset, o.asset); + if ("buffers"s == str) return property("buffers", this->_buffers, o.buffers); + if ("bufferViews"s == str) return property("bufferViews", this->_bufferViews, o.bufferViews); + if ("cameras"s == str) return property("cameras", this->_cameras, o.cameras); + if ("images"s == str) return property("images", this->_images, o.images); + if ("materials"s == str) return property("materials", this->_materials, o.materials); + if ("meshes"s == str) return property("meshes", this->_meshes, o.meshes); + if ("nodes"s == str) return property("nodes", this->_nodes, o.nodes); + if ("samplers"s == str) return property("samplers", this->_samplers, o.samplers); + if ("scene"s == str) return property("scene", this->_scene, o.scene); + if ("scenes"s == str) return property("scenes", this->_scenes, o.scenes); + if ("skins"s == str) return property("skins", this->_skins, o.skins); + if ("textures"s == str) return property("textures", this->_textures, o.textures); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -3376,38 +2095,23 @@ CesiumJsonReader::IJsonHandler* ModelJsonHandler::readObjectKeyModel( namespace CesiumGltfReader { -TextureJsonHandler::TextureJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _sampler(), - _source() {} +TextureJsonHandler::TextureJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _sampler(), _source() {} -void TextureJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Texture* pObject) { +void TextureJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Texture* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -TextureJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* TextureJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyTexture( - CesiumGltf::Texture::TypeName, - str, - *this->_pObject); + return this->readObjectKeyTexture(CesiumGltf::Texture::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* TextureJsonHandler::readObjectKeyTexture( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Texture& o) { +CesiumJsonReader::IJsonHandler* TextureJsonHandler::readObjectKeyTexture(const std::string& objectType, const std::string_view& str, CesiumGltf::Texture& o) { using namespace std::string_literals; - if ("sampler"s == str) - return property("sampler", this->_sampler, o.sampler); - if ("source"s == str) - return property("source", this->_source, o.source); + if ("sampler"s == str) return property("sampler", this->_sampler, o.sampler); + if ("source"s == str) return property("source", this->_source, o.source); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -3424,44 +2128,24 @@ CesiumJsonReader::IJsonHandler* TextureJsonHandler::readObjectKeyTexture( namespace CesiumGltfReader { -SkinJsonHandler::SkinJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _inverseBindMatrices(), - _skeleton(), - _joints() {} +SkinJsonHandler::SkinJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _inverseBindMatrices(), _skeleton(), _joints() {} -void SkinJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Skin* pObject) { +void SkinJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Skin* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -SkinJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* SkinJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeySkin( - CesiumGltf::Skin::TypeName, - str, - *this->_pObject); + return this->readObjectKeySkin(CesiumGltf::Skin::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* SkinJsonHandler::readObjectKeySkin( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Skin& o) { +CesiumJsonReader::IJsonHandler* SkinJsonHandler::readObjectKeySkin(const std::string& objectType, const std::string_view& str, CesiumGltf::Skin& o) { using namespace std::string_literals; - if ("inverseBindMatrices"s == str) - return property( - "inverseBindMatrices", - this->_inverseBindMatrices, - o.inverseBindMatrices); - if ("skeleton"s == str) - return property("skeleton", this->_skeleton, o.skeleton); - if ("joints"s == str) - return property("joints", this->_joints, o.joints); + if ("inverseBindMatrices"s == str) return property("inverseBindMatrices", this->_inverseBindMatrices, o.inverseBindMatrices); + if ("skeleton"s == str) return property("skeleton", this->_skeleton, o.skeleton); + if ("joints"s == str) return property("joints", this->_joints, o.joints); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -3478,34 +2162,22 @@ CesiumJsonReader::IJsonHandler* SkinJsonHandler::readObjectKeySkin( namespace CesiumGltfReader { -SceneJsonHandler::SceneJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), _nodes() {} +SceneJsonHandler::SceneJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _nodes() {} -void SceneJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Scene* pObject) { +void SceneJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Scene* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -SceneJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* SceneJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyScene( - CesiumGltf::Scene::TypeName, - str, - *this->_pObject); + return this->readObjectKeyScene(CesiumGltf::Scene::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* SceneJsonHandler::readObjectKeyScene( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Scene& o) { +CesiumJsonReader::IJsonHandler* SceneJsonHandler::readObjectKeyScene(const std::string& objectType, const std::string_view& str, CesiumGltf::Scene& o) { using namespace std::string_literals; - if ("nodes"s == str) - return property("nodes", this->_nodes, o.nodes); + if ("nodes"s == str) return property("nodes", this->_nodes, o.nodes); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -3522,44 +2194,25 @@ CesiumJsonReader::IJsonHandler* SceneJsonHandler::readObjectKeyScene( namespace CesiumGltfReader { -SamplerJsonHandler::SamplerJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _magFilter(), - _minFilter(), - _wrapS(), - _wrapT() {} - -void SamplerJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Sampler* pObject) { +SamplerJsonHandler::SamplerJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _magFilter(), _minFilter(), _wrapS(), _wrapT() {} + +void SamplerJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Sampler* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -SamplerJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* SamplerJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeySampler( - CesiumGltf::Sampler::TypeName, - str, - *this->_pObject); + return this->readObjectKeySampler(CesiumGltf::Sampler::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* SamplerJsonHandler::readObjectKeySampler( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Sampler& o) { +CesiumJsonReader::IJsonHandler* SamplerJsonHandler::readObjectKeySampler(const std::string& objectType, const std::string_view& str, CesiumGltf::Sampler& o) { using namespace std::string_literals; - if ("magFilter"s == str) - return property("magFilter", this->_magFilter, o.magFilter); - if ("minFilter"s == str) - return property("minFilter", this->_minFilter, o.minFilter); - if ("wrapS"s == str) - return property("wrapS", this->_wrapS, o.wrapS); - if ("wrapT"s == str) - return property("wrapT", this->_wrapT, o.wrapT); + if ("magFilter"s == str) return property("magFilter", this->_magFilter, o.magFilter); + if ("minFilter"s == str) return property("minFilter", this->_minFilter, o.minFilter); + if ("wrapS"s == str) return property("wrapS", this->_wrapS, o.wrapS); + if ("wrapT"s == str) return property("wrapT", this->_wrapT, o.wrapT); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -3576,59 +2229,30 @@ CesiumJsonReader::IJsonHandler* SamplerJsonHandler::readObjectKeySampler( namespace CesiumGltfReader { -NodeJsonHandler::NodeJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _camera(), - _children(), - _skin(), - _matrix(), - _mesh(), - _rotation(), - _scale(), - _translation(), - _weights() {} - -void NodeJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Node* pObject) { +NodeJsonHandler::NodeJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _camera(), _children(), _skin(), _matrix(), _mesh(), _rotation(), _scale(), _translation(), _weights() {} + +void NodeJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Node* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -NodeJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* NodeJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyNode( - CesiumGltf::Node::TypeName, - str, - *this->_pObject); + return this->readObjectKeyNode(CesiumGltf::Node::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* NodeJsonHandler::readObjectKeyNode( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Node& o) { +CesiumJsonReader::IJsonHandler* NodeJsonHandler::readObjectKeyNode(const std::string& objectType, const std::string_view& str, CesiumGltf::Node& o) { using namespace std::string_literals; - if ("camera"s == str) - return property("camera", this->_camera, o.camera); - if ("children"s == str) - return property("children", this->_children, o.children); - if ("skin"s == str) - return property("skin", this->_skin, o.skin); - if ("matrix"s == str) - return property("matrix", this->_matrix, o.matrix); - if ("mesh"s == str) - return property("mesh", this->_mesh, o.mesh); - if ("rotation"s == str) - return property("rotation", this->_rotation, o.rotation); - if ("scale"s == str) - return property("scale", this->_scale, o.scale); - if ("translation"s == str) - return property("translation", this->_translation, o.translation); - if ("weights"s == str) - return property("weights", this->_weights, o.weights); + if ("camera"s == str) return property("camera", this->_camera, o.camera); + if ("children"s == str) return property("children", this->_children, o.children); + if ("skin"s == str) return property("skin", this->_skin, o.skin); + if ("matrix"s == str) return property("matrix", this->_matrix, o.matrix); + if ("mesh"s == str) return property("mesh", this->_mesh, o.mesh); + if ("rotation"s == str) return property("rotation", this->_rotation, o.rotation); + if ("scale"s == str) return property("scale", this->_scale, o.scale); + if ("translation"s == str) return property("translation", this->_translation, o.translation); + if ("weights"s == str) return property("weights", this->_weights, o.weights); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -3645,38 +2269,23 @@ CesiumJsonReader::IJsonHandler* NodeJsonHandler::readObjectKeyNode( namespace CesiumGltfReader { -MeshJsonHandler::MeshJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _primitives(context), - _weights() {} +MeshJsonHandler::MeshJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _primitives(context), _weights() {} -void MeshJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Mesh* pObject) { +void MeshJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Mesh* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -MeshJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* MeshJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMesh( - CesiumGltf::Mesh::TypeName, - str, - *this->_pObject); + return this->readObjectKeyMesh(CesiumGltf::Mesh::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* MeshJsonHandler::readObjectKeyMesh( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Mesh& o) { +CesiumJsonReader::IJsonHandler* MeshJsonHandler::readObjectKeyMesh(const std::string& objectType, const std::string_view& str, CesiumGltf::Mesh& o) { using namespace std::string_literals; - if ("primitives"s == str) - return property("primitives", this->_primitives, o.primitives); - if ("weights"s == str) - return property("weights", this->_weights, o.weights); + if ("primitives"s == str) return property("primitives", this->_primitives, o.primitives); + if ("weights"s == str) return property("weights", this->_weights, o.weights); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -3693,48 +2302,26 @@ CesiumJsonReader::IJsonHandler* MeshJsonHandler::readObjectKeyMesh( namespace CesiumGltfReader { -MeshPrimitiveJsonHandler::MeshPrimitiveJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _attributes(), - _indices(), - _material(), - _mode(), - _targets() {} - -void MeshPrimitiveJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::MeshPrimitive* pObject) { +MeshPrimitiveJsonHandler::MeshPrimitiveJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attributes(), _indices(), _material(), _mode(), _targets() {} + +void MeshPrimitiveJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::MeshPrimitive* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -MeshPrimitiveJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* MeshPrimitiveJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMeshPrimitive( - CesiumGltf::MeshPrimitive::TypeName, - str, - *this->_pObject); + return this->readObjectKeyMeshPrimitive(CesiumGltf::MeshPrimitive::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -MeshPrimitiveJsonHandler::readObjectKeyMeshPrimitive( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::MeshPrimitive& o) { +CesiumJsonReader::IJsonHandler* MeshPrimitiveJsonHandler::readObjectKeyMeshPrimitive(const std::string& objectType, const std::string_view& str, CesiumGltf::MeshPrimitive& o) { using namespace std::string_literals; - if ("attributes"s == str) - return property("attributes", this->_attributes, o.attributes); - if ("indices"s == str) - return property("indices", this->_indices, o.indices); - if ("material"s == str) - return property("material", this->_material, o.material); - if ("mode"s == str) - return property("mode", this->_mode, o.mode); - if ("targets"s == str) - return property("targets", this->_targets, o.targets); + if ("attributes"s == str) return property("attributes", this->_attributes, o.attributes); + if ("indices"s == str) return property("indices", this->_indices, o.indices); + if ("material"s == str) return property("material", this->_material, o.material); + if ("mode"s == str) return property("mode", this->_mode, o.mode); + if ("targets"s == str) return property("targets", this->_targets, o.targets); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -3751,65 +2338,29 @@ MeshPrimitiveJsonHandler::readObjectKeyMeshPrimitive( namespace CesiumGltfReader { -MaterialJsonHandler::MaterialJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _pbrMetallicRoughness(context), - _normalTexture(context), - _occlusionTexture(context), - _emissiveTexture(context), - _emissiveFactor(), - _alphaMode(), - _alphaCutoff(), - _doubleSided() {} - -void MaterialJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Material* pObject) { +MaterialJsonHandler::MaterialJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _pbrMetallicRoughness(context), _normalTexture(context), _occlusionTexture(context), _emissiveTexture(context), _emissiveFactor(), _alphaMode(), _alphaCutoff(), _doubleSided() {} + +void MaterialJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Material* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -MaterialJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* MaterialJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMaterial( - CesiumGltf::Material::TypeName, - str, - *this->_pObject); + return this->readObjectKeyMaterial(CesiumGltf::Material::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* MaterialJsonHandler::readObjectKeyMaterial( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Material& o) { +CesiumJsonReader::IJsonHandler* MaterialJsonHandler::readObjectKeyMaterial(const std::string& objectType, const std::string_view& str, CesiumGltf::Material& o) { using namespace std::string_literals; - if ("pbrMetallicRoughness"s == str) - return property( - "pbrMetallicRoughness", - this->_pbrMetallicRoughness, - o.pbrMetallicRoughness); - if ("normalTexture"s == str) - return property("normalTexture", this->_normalTexture, o.normalTexture); - if ("occlusionTexture"s == str) - return property( - "occlusionTexture", - this->_occlusionTexture, - o.occlusionTexture); - if ("emissiveTexture"s == str) - return property( - "emissiveTexture", - this->_emissiveTexture, - o.emissiveTexture); - if ("emissiveFactor"s == str) - return property("emissiveFactor", this->_emissiveFactor, o.emissiveFactor); - if ("alphaMode"s == str) - return property("alphaMode", this->_alphaMode, o.alphaMode); - if ("alphaCutoff"s == str) - return property("alphaCutoff", this->_alphaCutoff, o.alphaCutoff); - if ("doubleSided"s == str) - return property("doubleSided", this->_doubleSided, o.doubleSided); + if ("pbrMetallicRoughness"s == str) return property("pbrMetallicRoughness", this->_pbrMetallicRoughness, o.pbrMetallicRoughness); + if ("normalTexture"s == str) return property("normalTexture", this->_normalTexture, o.normalTexture); + if ("occlusionTexture"s == str) return property("occlusionTexture", this->_occlusionTexture, o.occlusionTexture); + if ("emissiveTexture"s == str) return property("emissiveTexture", this->_emissiveTexture, o.emissiveTexture); + if ("emissiveFactor"s == str) return property("emissiveFactor", this->_emissiveFactor, o.emissiveFactor); + if ("alphaMode"s == str) return property("alphaMode", this->_alphaMode, o.alphaMode); + if ("alphaCutoff"s == str) return property("alphaCutoff", this->_alphaCutoff, o.alphaCutoff); + if ("doubleSided"s == str) return property("doubleSided", this->_doubleSided, o.doubleSided); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -3826,37 +2377,22 @@ CesiumJsonReader::IJsonHandler* MaterialJsonHandler::readObjectKeyMaterial( namespace CesiumGltfReader { -MaterialOcclusionTextureInfoJsonHandler:: - MaterialOcclusionTextureInfoJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : TextureInfoJsonHandler(context), _strength() {} +MaterialOcclusionTextureInfoJsonHandler::MaterialOcclusionTextureInfoJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : TextureInfoJsonHandler(context), _strength() {} -void MaterialOcclusionTextureInfoJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::MaterialOcclusionTextureInfo* pObject) { +void MaterialOcclusionTextureInfoJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::MaterialOcclusionTextureInfo* pObject) { TextureInfoJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -MaterialOcclusionTextureInfoJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* MaterialOcclusionTextureInfoJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMaterialOcclusionTextureInfo( - CesiumGltf::MaterialOcclusionTextureInfo::TypeName, - str, - *this->_pObject); + return this->readObjectKeyMaterialOcclusionTextureInfo(CesiumGltf::MaterialOcclusionTextureInfo::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* MaterialOcclusionTextureInfoJsonHandler:: - readObjectKeyMaterialOcclusionTextureInfo( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::MaterialOcclusionTextureInfo& o) { +CesiumJsonReader::IJsonHandler* MaterialOcclusionTextureInfoJsonHandler::readObjectKeyMaterialOcclusionTextureInfo(const std::string& objectType, const std::string_view& str, CesiumGltf::MaterialOcclusionTextureInfo& o) { using namespace std::string_literals; - if ("strength"s == str) - return property("strength", this->_strength, o.strength); + if ("strength"s == str) return property("strength", this->_strength, o.strength); return this->readObjectKeyTextureInfo(objectType, str, *this->_pObject); } @@ -3873,36 +2409,22 @@ CesiumJsonReader::IJsonHandler* MaterialOcclusionTextureInfoJsonHandler:: namespace CesiumGltfReader { -MaterialNormalTextureInfoJsonHandler::MaterialNormalTextureInfoJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : TextureInfoJsonHandler(context), _scale() {} +MaterialNormalTextureInfoJsonHandler::MaterialNormalTextureInfoJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : TextureInfoJsonHandler(context), _scale() {} -void MaterialNormalTextureInfoJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::MaterialNormalTextureInfo* pObject) { +void MaterialNormalTextureInfoJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::MaterialNormalTextureInfo* pObject) { TextureInfoJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -MaterialNormalTextureInfoJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* MaterialNormalTextureInfoJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMaterialNormalTextureInfo( - CesiumGltf::MaterialNormalTextureInfo::TypeName, - str, - *this->_pObject); + return this->readObjectKeyMaterialNormalTextureInfo(CesiumGltf::MaterialNormalTextureInfo::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -MaterialNormalTextureInfoJsonHandler::readObjectKeyMaterialNormalTextureInfo( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::MaterialNormalTextureInfo& o) { +CesiumJsonReader::IJsonHandler* MaterialNormalTextureInfoJsonHandler::readObjectKeyMaterialNormalTextureInfo(const std::string& objectType, const std::string_view& str, CesiumGltf::MaterialNormalTextureInfo& o) { using namespace std::string_literals; - if ("scale"s == str) - return property("scale", this->_scale, o.scale); + if ("scale"s == str) return property("scale", this->_scale, o.scale); return this->readObjectKeyTextureInfo(objectType, str, *this->_pObject); } @@ -3919,62 +2441,26 @@ MaterialNormalTextureInfoJsonHandler::readObjectKeyMaterialNormalTextureInfo( namespace CesiumGltfReader { -MaterialPBRMetallicRoughnessJsonHandler:: - MaterialPBRMetallicRoughnessJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _baseColorFactor(), - _baseColorTexture(context), - _metallicFactor(), - _roughnessFactor(), - _metallicRoughnessTexture(context) {} - -void MaterialPBRMetallicRoughnessJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::MaterialPBRMetallicRoughness* pObject) { +MaterialPBRMetallicRoughnessJsonHandler::MaterialPBRMetallicRoughnessJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _baseColorFactor(), _baseColorTexture(context), _metallicFactor(), _roughnessFactor(), _metallicRoughnessTexture(context) {} + +void MaterialPBRMetallicRoughnessJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::MaterialPBRMetallicRoughness* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -MaterialPBRMetallicRoughnessJsonHandler::readObjectKey( - const std::string_view& str) { +CesiumJsonReader::IJsonHandler* MaterialPBRMetallicRoughnessJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMaterialPBRMetallicRoughness( - CesiumGltf::MaterialPBRMetallicRoughness::TypeName, - str, - *this->_pObject); + return this->readObjectKeyMaterialPBRMetallicRoughness(CesiumGltf::MaterialPBRMetallicRoughness::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* MaterialPBRMetallicRoughnessJsonHandler:: - readObjectKeyMaterialPBRMetallicRoughness( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::MaterialPBRMetallicRoughness& o) { +CesiumJsonReader::IJsonHandler* MaterialPBRMetallicRoughnessJsonHandler::readObjectKeyMaterialPBRMetallicRoughness(const std::string& objectType, const std::string_view& str, CesiumGltf::MaterialPBRMetallicRoughness& o) { using namespace std::string_literals; - if ("baseColorFactor"s == str) - return property( - "baseColorFactor", - this->_baseColorFactor, - o.baseColorFactor); - if ("baseColorTexture"s == str) - return property( - "baseColorTexture", - this->_baseColorTexture, - o.baseColorTexture); - if ("metallicFactor"s == str) - return property("metallicFactor", this->_metallicFactor, o.metallicFactor); - if ("roughnessFactor"s == str) - return property( - "roughnessFactor", - this->_roughnessFactor, - o.roughnessFactor); - if ("metallicRoughnessTexture"s == str) - return property( - "metallicRoughnessTexture", - this->_metallicRoughnessTexture, - o.metallicRoughnessTexture); + if ("baseColorFactor"s == str) return property("baseColorFactor", this->_baseColorFactor, o.baseColorFactor); + if ("baseColorTexture"s == str) return property("baseColorTexture", this->_baseColorTexture, o.baseColorTexture); + if ("metallicFactor"s == str) return property("metallicFactor", this->_metallicFactor, o.metallicFactor); + if ("roughnessFactor"s == str) return property("roughnessFactor", this->_roughnessFactor, o.roughnessFactor); + if ("metallicRoughnessTexture"s == str) return property("metallicRoughnessTexture", this->_metallicRoughnessTexture, o.metallicRoughnessTexture); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -3991,41 +2477,24 @@ CesiumJsonReader::IJsonHandler* MaterialPBRMetallicRoughnessJsonHandler:: namespace CesiumGltfReader { -ImageJsonHandler::ImageJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _uri(), - _mimeType(), - _bufferView() {} +ImageJsonHandler::ImageJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _uri(), _mimeType(), _bufferView() {} -void ImageJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Image* pObject) { +void ImageJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Image* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -ImageJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* ImageJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyImage( - CesiumGltf::Image::TypeName, - str, - *this->_pObject); + return this->readObjectKeyImage(CesiumGltf::Image::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* ImageJsonHandler::readObjectKeyImage( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Image& o) { +CesiumJsonReader::IJsonHandler* ImageJsonHandler::readObjectKeyImage(const std::string& objectType, const std::string_view& str, CesiumGltf::Image& o) { using namespace std::string_literals; - if ("uri"s == str) - return property("uri", this->_uri, o.uri); - if ("mimeType"s == str) - return property("mimeType", this->_mimeType, o.mimeType); - if ("bufferView"s == str) - return property("bufferView", this->_bufferView, o.bufferView); + if ("uri"s == str) return property("uri", this->_uri, o.uri); + if ("mimeType"s == str) return property("mimeType", this->_mimeType, o.mimeType); + if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -4042,41 +2511,24 @@ CesiumJsonReader::IJsonHandler* ImageJsonHandler::readObjectKeyImage( namespace CesiumGltfReader { -CameraJsonHandler::CameraJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _orthographic(context), - _perspective(context), - _type() {} +CameraJsonHandler::CameraJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _orthographic(context), _perspective(context), _type() {} -void CameraJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Camera* pObject) { +void CameraJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Camera* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -CameraJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* CameraJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyCamera( - CesiumGltf::Camera::TypeName, - str, - *this->_pObject); + return this->readObjectKeyCamera(CesiumGltf::Camera::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* CameraJsonHandler::readObjectKeyCamera( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Camera& o) { +CesiumJsonReader::IJsonHandler* CameraJsonHandler::readObjectKeyCamera(const std::string& objectType, const std::string_view& str, CesiumGltf::Camera& o) { using namespace std::string_literals; - if ("orthographic"s == str) - return property("orthographic", this->_orthographic, o.orthographic); - if ("perspective"s == str) - return property("perspective", this->_perspective, o.perspective); - if ("type"s == str) - return property("type", this->_type, o.type); + if ("orthographic"s == str) return property("orthographic", this->_orthographic, o.orthographic); + if ("perspective"s == str) return property("perspective", this->_perspective, o.perspective); + if ("type"s == str) return property("type", this->_type, o.type); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -4093,45 +2545,25 @@ CesiumJsonReader::IJsonHandler* CameraJsonHandler::readObjectKeyCamera( namespace CesiumGltfReader { -CameraPerspectiveJsonHandler::CameraPerspectiveJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _aspectRatio(), - _yfov(), - _zfar(), - _znear() {} - -void CameraPerspectiveJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::CameraPerspective* pObject) { +CameraPerspectiveJsonHandler::CameraPerspectiveJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _aspectRatio(), _yfov(), _zfar(), _znear() {} + +void CameraPerspectiveJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::CameraPerspective* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -CameraPerspectiveJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* CameraPerspectiveJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyCameraPerspective( - CesiumGltf::CameraPerspective::TypeName, - str, - *this->_pObject); + return this->readObjectKeyCameraPerspective(CesiumGltf::CameraPerspective::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -CameraPerspectiveJsonHandler::readObjectKeyCameraPerspective( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::CameraPerspective& o) { +CesiumJsonReader::IJsonHandler* CameraPerspectiveJsonHandler::readObjectKeyCameraPerspective(const std::string& objectType, const std::string_view& str, CesiumGltf::CameraPerspective& o) { using namespace std::string_literals; - if ("aspectRatio"s == str) - return property("aspectRatio", this->_aspectRatio, o.aspectRatio); - if ("yfov"s == str) - return property("yfov", this->_yfov, o.yfov); - if ("zfar"s == str) - return property("zfar", this->_zfar, o.zfar); - if ("znear"s == str) - return property("znear", this->_znear, o.znear); + if ("aspectRatio"s == str) return property("aspectRatio", this->_aspectRatio, o.aspectRatio); + if ("yfov"s == str) return property("yfov", this->_yfov, o.yfov); + if ("zfar"s == str) return property("zfar", this->_zfar, o.zfar); + if ("znear"s == str) return property("znear", this->_znear, o.znear); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -4148,45 +2580,25 @@ CameraPerspectiveJsonHandler::readObjectKeyCameraPerspective( namespace CesiumGltfReader { -CameraOrthographicJsonHandler::CameraOrthographicJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _xmag(), - _ymag(), - _zfar(), - _znear() {} - -void CameraOrthographicJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::CameraOrthographic* pObject) { +CameraOrthographicJsonHandler::CameraOrthographicJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _xmag(), _ymag(), _zfar(), _znear() {} + +void CameraOrthographicJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::CameraOrthographic* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -CameraOrthographicJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* CameraOrthographicJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyCameraOrthographic( - CesiumGltf::CameraOrthographic::TypeName, - str, - *this->_pObject); + return this->readObjectKeyCameraOrthographic(CesiumGltf::CameraOrthographic::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -CameraOrthographicJsonHandler::readObjectKeyCameraOrthographic( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::CameraOrthographic& o) { +CesiumJsonReader::IJsonHandler* CameraOrthographicJsonHandler::readObjectKeyCameraOrthographic(const std::string& objectType, const std::string_view& str, CesiumGltf::CameraOrthographic& o) { using namespace std::string_literals; - if ("xmag"s == str) - return property("xmag", this->_xmag, o.xmag); - if ("ymag"s == str) - return property("ymag", this->_ymag, o.ymag); - if ("zfar"s == str) - return property("zfar", this->_zfar, o.zfar); - if ("znear"s == str) - return property("znear", this->_znear, o.znear); + if ("xmag"s == str) return property("xmag", this->_xmag, o.xmag); + if ("ymag"s == str) return property("ymag", this->_ymag, o.ymag); + if ("zfar"s == str) return property("zfar", this->_zfar, o.zfar); + if ("znear"s == str) return property("znear", this->_znear, o.znear); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -4203,47 +2615,26 @@ CameraOrthographicJsonHandler::readObjectKeyCameraOrthographic( namespace CesiumGltfReader { -BufferViewJsonHandler::BufferViewJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _buffer(), - _byteOffset(), - _byteLength(), - _byteStride(), - _target() {} - -void BufferViewJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::BufferView* pObject) { +BufferViewJsonHandler::BufferViewJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _buffer(), _byteOffset(), _byteLength(), _byteStride(), _target() {} + +void BufferViewJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::BufferView* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -BufferViewJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* BufferViewJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyBufferView( - CesiumGltf::BufferView::TypeName, - str, - *this->_pObject); + return this->readObjectKeyBufferView(CesiumGltf::BufferView::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* BufferViewJsonHandler::readObjectKeyBufferView( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::BufferView& o) { +CesiumJsonReader::IJsonHandler* BufferViewJsonHandler::readObjectKeyBufferView(const std::string& objectType, const std::string_view& str, CesiumGltf::BufferView& o) { using namespace std::string_literals; - if ("buffer"s == str) - return property("buffer", this->_buffer, o.buffer); - if ("byteOffset"s == str) - return property("byteOffset", this->_byteOffset, o.byteOffset); - if ("byteLength"s == str) - return property("byteLength", this->_byteLength, o.byteLength); - if ("byteStride"s == str) - return property("byteStride", this->_byteStride, o.byteStride); - if ("target"s == str) - return property("target", this->_target, o.target); + if ("buffer"s == str) return property("buffer", this->_buffer, o.buffer); + if ("byteOffset"s == str) return property("byteOffset", this->_byteOffset, o.byteOffset); + if ("byteLength"s == str) return property("byteLength", this->_byteLength, o.byteLength); + if ("byteStride"s == str) return property("byteStride", this->_byteStride, o.byteStride); + if ("target"s == str) return property("target", this->_target, o.target); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -4260,38 +2651,23 @@ CesiumJsonReader::IJsonHandler* BufferViewJsonHandler::readObjectKeyBufferView( namespace CesiumGltfReader { -BufferJsonHandler::BufferJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _uri(), - _byteLength() {} +BufferJsonHandler::BufferJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _uri(), _byteLength() {} -void BufferJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Buffer* pObject) { +void BufferJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Buffer* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -BufferJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* BufferJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyBuffer( - CesiumGltf::Buffer::TypeName, - str, - *this->_pObject); + return this->readObjectKeyBuffer(CesiumGltf::Buffer::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* BufferJsonHandler::readObjectKeyBuffer( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Buffer& o) { +CesiumJsonReader::IJsonHandler* BufferJsonHandler::readObjectKeyBuffer(const std::string& objectType, const std::string_view& str, CesiumGltf::Buffer& o) { using namespace std::string_literals; - if ("uri"s == str) - return property("uri", this->_uri, o.uri); - if ("byteLength"s == str) - return property("byteLength", this->_byteLength, o.byteLength); + if ("uri"s == str) return property("uri", this->_uri, o.uri); + if ("byteLength"s == str) return property("byteLength", this->_byteLength, o.byteLength); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -4308,44 +2684,25 @@ CesiumJsonReader::IJsonHandler* BufferJsonHandler::readObjectKeyBuffer( namespace CesiumGltfReader { -AssetJsonHandler::AssetJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _copyright(), - _generator(), - _version(), - _minVersion() {} - -void AssetJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Asset* pObject) { +AssetJsonHandler::AssetJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _copyright(), _generator(), _version(), _minVersion() {} + +void AssetJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Asset* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -AssetJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* AssetJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAsset( - CesiumGltf::Asset::TypeName, - str, - *this->_pObject); + return this->readObjectKeyAsset(CesiumGltf::Asset::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* AssetJsonHandler::readObjectKeyAsset( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Asset& o) { +CesiumJsonReader::IJsonHandler* AssetJsonHandler::readObjectKeyAsset(const std::string& objectType, const std::string_view& str, CesiumGltf::Asset& o) { using namespace std::string_literals; - if ("copyright"s == str) - return property("copyright", this->_copyright, o.copyright); - if ("generator"s == str) - return property("generator", this->_generator, o.generator); - if ("version"s == str) - return property("version", this->_version, o.version); - if ("minVersion"s == str) - return property("minVersion", this->_minVersion, o.minVersion); + if ("copyright"s == str) return property("copyright", this->_copyright, o.copyright); + if ("generator"s == str) return property("generator", this->_generator, o.generator); + if ("version"s == str) return property("version", this->_version, o.version); + if ("minVersion"s == str) return property("minVersion", this->_minVersion, o.minVersion); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -4362,38 +2719,23 @@ CesiumJsonReader::IJsonHandler* AssetJsonHandler::readObjectKeyAsset( namespace CesiumGltfReader { -AnimationJsonHandler::AnimationJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _channels(context), - _samplers(context) {} +AnimationJsonHandler::AnimationJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _channels(context), _samplers(context) {} -void AnimationJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Animation* pObject) { +void AnimationJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Animation* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -AnimationJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* AnimationJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAnimation( - CesiumGltf::Animation::TypeName, - str, - *this->_pObject); + return this->readObjectKeyAnimation(CesiumGltf::Animation::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* AnimationJsonHandler::readObjectKeyAnimation( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Animation& o) { +CesiumJsonReader::IJsonHandler* AnimationJsonHandler::readObjectKeyAnimation(const std::string& objectType, const std::string_view& str, CesiumGltf::Animation& o) { using namespace std::string_literals; - if ("channels"s == str) - return property("channels", this->_channels, o.channels); - if ("samplers"s == str) - return property("samplers", this->_samplers, o.samplers); + if ("channels"s == str) return property("channels", this->_channels, o.channels); + if ("samplers"s == str) return property("samplers", this->_samplers, o.samplers); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -4410,42 +2752,24 @@ CesiumJsonReader::IJsonHandler* AnimationJsonHandler::readObjectKeyAnimation( namespace CesiumGltfReader { -AnimationSamplerJsonHandler::AnimationSamplerJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _input(), - _interpolation(), - _output() {} +AnimationSamplerJsonHandler::AnimationSamplerJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _input(), _interpolation(), _output() {} -void AnimationSamplerJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::AnimationSampler* pObject) { +void AnimationSamplerJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AnimationSampler* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -AnimationSamplerJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* AnimationSamplerJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAnimationSampler( - CesiumGltf::AnimationSampler::TypeName, - str, - *this->_pObject); + return this->readObjectKeyAnimationSampler(CesiumGltf::AnimationSampler::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -AnimationSamplerJsonHandler::readObjectKeyAnimationSampler( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::AnimationSampler& o) { +CesiumJsonReader::IJsonHandler* AnimationSamplerJsonHandler::readObjectKeyAnimationSampler(const std::string& objectType, const std::string_view& str, CesiumGltf::AnimationSampler& o) { using namespace std::string_literals; - if ("input"s == str) - return property("input", this->_input, o.input); - if ("interpolation"s == str) - return property("interpolation", this->_interpolation, o.interpolation); - if ("output"s == str) - return property("output", this->_output, o.output); + if ("input"s == str) return property("input", this->_input, o.input); + if ("interpolation"s == str) return property("interpolation", this->_interpolation, o.interpolation); + if ("output"s == str) return property("output", this->_output, o.output); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -4462,39 +2786,23 @@ AnimationSamplerJsonHandler::readObjectKeyAnimationSampler( namespace CesiumGltfReader { -AnimationChannelJsonHandler::AnimationChannelJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _sampler(), - _target(context) {} +AnimationChannelJsonHandler::AnimationChannelJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _sampler(), _target(context) {} -void AnimationChannelJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::AnimationChannel* pObject) { +void AnimationChannelJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AnimationChannel* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -AnimationChannelJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* AnimationChannelJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAnimationChannel( - CesiumGltf::AnimationChannel::TypeName, - str, - *this->_pObject); + return this->readObjectKeyAnimationChannel(CesiumGltf::AnimationChannel::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -AnimationChannelJsonHandler::readObjectKeyAnimationChannel( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::AnimationChannel& o) { +CesiumJsonReader::IJsonHandler* AnimationChannelJsonHandler::readObjectKeyAnimationChannel(const std::string& objectType, const std::string_view& str, CesiumGltf::AnimationChannel& o) { using namespace std::string_literals; - if ("sampler"s == str) - return property("sampler", this->_sampler, o.sampler); - if ("target"s == str) - return property("target", this->_target, o.target); + if ("sampler"s == str) return property("sampler", this->_sampler, o.sampler); + if ("target"s == str) return property("target", this->_target, o.target); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -4511,39 +2819,23 @@ AnimationChannelJsonHandler::readObjectKeyAnimationChannel( namespace CesiumGltfReader { -AnimationChannelTargetJsonHandler::AnimationChannelTargetJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _node(), - _path() {} +AnimationChannelTargetJsonHandler::AnimationChannelTargetJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _node(), _path() {} -void AnimationChannelTargetJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::AnimationChannelTarget* pObject) { +void AnimationChannelTargetJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AnimationChannelTarget* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -AnimationChannelTargetJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* AnimationChannelTargetJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAnimationChannelTarget( - CesiumGltf::AnimationChannelTarget::TypeName, - str, - *this->_pObject); + return this->readObjectKeyAnimationChannelTarget(CesiumGltf::AnimationChannelTarget::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -AnimationChannelTargetJsonHandler::readObjectKeyAnimationChannelTarget( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::AnimationChannelTarget& o) { +CesiumJsonReader::IJsonHandler* AnimationChannelTargetJsonHandler::readObjectKeyAnimationChannelTarget(const std::string& objectType, const std::string_view& str, CesiumGltf::AnimationChannelTarget& o) { using namespace std::string_literals; - if ("node"s == str) - return property("node", this->_node, o.node); - if ("path"s == str) - return property("path", this->_path, o.path); + if ("node"s == str) return property("node", this->_node, o.node); + if ("path"s == str) return property("path", this->_path, o.path); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -4560,59 +2852,30 @@ AnimationChannelTargetJsonHandler::readObjectKeyAnimationChannelTarget( namespace CesiumGltfReader { -AccessorJsonHandler::AccessorJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumGltfReader::NamedObjectJsonHandler(context), - _bufferView(), - _byteOffset(), - _componentType(), - _normalized(), - _count(), - _type(), - _max(), - _min(), - _sparse(context) {} - -void AccessorJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::Accessor* pObject) { +AccessorJsonHandler::AccessorJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _bufferView(), _byteOffset(), _componentType(), _normalized(), _count(), _type(), _max(), _min(), _sparse(context) {} + +void AccessorJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Accessor* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -AccessorJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* AccessorJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAccessor( - CesiumGltf::Accessor::TypeName, - str, - *this->_pObject); + return this->readObjectKeyAccessor(CesiumGltf::Accessor::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* AccessorJsonHandler::readObjectKeyAccessor( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Accessor& o) { +CesiumJsonReader::IJsonHandler* AccessorJsonHandler::readObjectKeyAccessor(const std::string& objectType, const std::string_view& str, CesiumGltf::Accessor& o) { using namespace std::string_literals; - if ("bufferView"s == str) - return property("bufferView", this->_bufferView, o.bufferView); - if ("byteOffset"s == str) - return property("byteOffset", this->_byteOffset, o.byteOffset); - if ("componentType"s == str) - return property("componentType", this->_componentType, o.componentType); - if ("normalized"s == str) - return property("normalized", this->_normalized, o.normalized); - if ("count"s == str) - return property("count", this->_count, o.count); - if ("type"s == str) - return property("type", this->_type, o.type); - if ("max"s == str) - return property("max", this->_max, o.max); - if ("min"s == str) - return property("min", this->_min, o.min); - if ("sparse"s == str) - return property("sparse", this->_sparse, o.sparse); + if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); + if ("byteOffset"s == str) return property("byteOffset", this->_byteOffset, o.byteOffset); + if ("componentType"s == str) return property("componentType", this->_componentType, o.componentType); + if ("normalized"s == str) return property("normalized", this->_normalized, o.normalized); + if ("count"s == str) return property("count", this->_count, o.count); + if ("type"s == str) return property("type", this->_type, o.type); + if ("max"s == str) return property("max", this->_max, o.max); + if ("min"s == str) return property("min", this->_min, o.min); + if ("sparse"s == str) return property("sparse", this->_sparse, o.sparse); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -4629,42 +2892,24 @@ CesiumJsonReader::IJsonHandler* AccessorJsonHandler::readObjectKeyAccessor( namespace CesiumGltfReader { -AccessorSparseJsonHandler::AccessorSparseJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _count(), - _indices(context), - _values(context) {} +AccessorSparseJsonHandler::AccessorSparseJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _count(), _indices(context), _values(context) {} -void AccessorSparseJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::AccessorSparse* pObject) { +void AccessorSparseJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AccessorSparse* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -AccessorSparseJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* AccessorSparseJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAccessorSparse( - CesiumGltf::AccessorSparse::TypeName, - str, - *this->_pObject); + return this->readObjectKeyAccessorSparse(CesiumGltf::AccessorSparse::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -AccessorSparseJsonHandler::readObjectKeyAccessorSparse( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::AccessorSparse& o) { +CesiumJsonReader::IJsonHandler* AccessorSparseJsonHandler::readObjectKeyAccessorSparse(const std::string& objectType, const std::string_view& str, CesiumGltf::AccessorSparse& o) { using namespace std::string_literals; - if ("count"s == str) - return property("count", this->_count, o.count); - if ("indices"s == str) - return property("indices", this->_indices, o.indices); - if ("values"s == str) - return property("values", this->_values, o.values); + if ("count"s == str) return property("count", this->_count, o.count); + if ("indices"s == str) return property("indices", this->_indices, o.indices); + if ("values"s == str) return property("values", this->_values, o.values); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -4681,39 +2926,23 @@ AccessorSparseJsonHandler::readObjectKeyAccessorSparse( namespace CesiumGltfReader { -AccessorSparseValuesJsonHandler::AccessorSparseValuesJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _bufferView(), - _byteOffset() {} +AccessorSparseValuesJsonHandler::AccessorSparseValuesJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _bufferView(), _byteOffset() {} -void AccessorSparseValuesJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::AccessorSparseValues* pObject) { +void AccessorSparseValuesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AccessorSparseValues* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -AccessorSparseValuesJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* AccessorSparseValuesJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAccessorSparseValues( - CesiumGltf::AccessorSparseValues::TypeName, - str, - *this->_pObject); + return this->readObjectKeyAccessorSparseValues(CesiumGltf::AccessorSparseValues::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -AccessorSparseValuesJsonHandler::readObjectKeyAccessorSparseValues( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::AccessorSparseValues& o) { +CesiumJsonReader::IJsonHandler* AccessorSparseValuesJsonHandler::readObjectKeyAccessorSparseValues(const std::string& objectType, const std::string_view& str, CesiumGltf::AccessorSparseValues& o) { using namespace std::string_literals; - if ("bufferView"s == str) - return property("bufferView", this->_bufferView, o.bufferView); - if ("byteOffset"s == str) - return property("byteOffset", this->_byteOffset, o.byteOffset); + if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); + if ("byteOffset"s == str) return property("byteOffset", this->_byteOffset, o.byteOffset); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -4730,42 +2959,24 @@ AccessorSparseValuesJsonHandler::readObjectKeyAccessorSparseValues( namespace CesiumGltfReader { -AccessorSparseIndicesJsonHandler::AccessorSparseIndicesJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept - : CesiumJsonReader::ExtensibleObjectJsonHandler(context), - _bufferView(), - _byteOffset(), - _componentType() {} +AccessorSparseIndicesJsonHandler::AccessorSparseIndicesJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _bufferView(), _byteOffset(), _componentType() {} -void AccessorSparseIndicesJsonHandler::reset( - CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::AccessorSparseIndices* pObject) { +void AccessorSparseIndicesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AccessorSparseIndices* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* -AccessorSparseIndicesJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* AccessorSparseIndicesJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAccessorSparseIndices( - CesiumGltf::AccessorSparseIndices::TypeName, - str, - *this->_pObject); + return this->readObjectKeyAccessorSparseIndices(CesiumGltf::AccessorSparseIndices::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -AccessorSparseIndicesJsonHandler::readObjectKeyAccessorSparseIndices( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::AccessorSparseIndices& o) { +CesiumJsonReader::IJsonHandler* AccessorSparseIndicesJsonHandler::readObjectKeyAccessorSparseIndices(const std::string& objectType, const std::string_view& str, CesiumGltf::AccessorSparseIndices& o) { using namespace std::string_literals; - if ("bufferView"s == str) - return property("bufferView", this->_bufferView, o.bufferView); - if ("byteOffset"s == str) - return property("byteOffset", this->_byteOffset, o.byteOffset); - if ("componentType"s == str) - return property("componentType", this->_componentType, o.componentType); + if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); + if ("byteOffset"s == str) return property("byteOffset", this->_byteOffset, o.byteOffset); + if ("componentType"s == str) return property("componentType", this->_componentType, o.componentType); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } diff --git a/CesiumGltfReader/generated/src/SchemaJsonHandler.h b/CesiumGltfReader/generated/src/SchemaJsonHandler.h deleted file mode 100644 index 496e45c14..000000000 --- a/CesiumGltfReader/generated/src/SchemaJsonHandler.h +++ /dev/null @@ -1,44 +0,0 @@ -// This file was generated by generate-classes. -// DO NOT EDIT THIS FILE! -#pragma once - -#include "ClassJsonHandler.h" -#include "EnumJsonHandler.h" - -#include -#include -#include -#include - -namespace CesiumJsonReader { -class ExtensionReaderContext; -} - -namespace CesiumGltfReader { -class SchemaJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { -public: - using ValueType = CesiumGltf::Schema; - - SchemaJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset(IJsonHandler* pParentHandler, CesiumGltf::Schema* pObject); - - virtual IJsonHandler* readObjectKey(const std::string_view& str) override; - -protected: - IJsonHandler* readObjectKeySchema( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Schema& o); - -private: - CesiumGltf::Schema* _pObject = nullptr; - CesiumJsonReader::StringJsonHandler _name; - CesiumJsonReader::StringJsonHandler _description; - CesiumJsonReader::StringJsonHandler _version; - CesiumJsonReader::DictionaryJsonHandler - _classes; - CesiumJsonReader::DictionaryJsonHandler - _enums; -}; -} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/StatisticsJsonHandler.h b/CesiumGltfReader/generated/src/StatisticsJsonHandler.h deleted file mode 100644 index 5e6eb875e..000000000 --- a/CesiumGltfReader/generated/src/StatisticsJsonHandler.h +++ /dev/null @@ -1,40 +0,0 @@ -// This file was generated by generate-classes. -// DO NOT EDIT THIS FILE! -#pragma once - -#include "ClassStatisticsJsonHandler.h" - -#include -#include -#include - -namespace CesiumJsonReader { -class ExtensionReaderContext; -} - -namespace CesiumGltfReader { -class StatisticsJsonHandler - : public CesiumJsonReader::ExtensibleObjectJsonHandler { -public: - using ValueType = CesiumGltf::Statistics; - - StatisticsJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset(IJsonHandler* pParentHandler, CesiumGltf::Statistics* pObject); - - virtual IJsonHandler* readObjectKey(const std::string_view& str) override; - -protected: - IJsonHandler* readObjectKeyStatistics( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::Statistics& o); - -private: - CesiumGltf::Statistics* _pObject = nullptr; - CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::ClassStatistics, - ClassStatisticsJsonHandler> - _classes; -}; -} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/registerExtensions.cpp b/CesiumGltfReader/generated/src/registerExtensions.cpp index 15deefecc..1c46f4ba9 100644 --- a/CesiumGltfReader/generated/src/registerExtensions.cpp +++ b/CesiumGltfReader/generated/src/registerExtensions.cpp @@ -3,98 +3,61 @@ #include "registerExtensions.h" -#include "ExtensionBufferExtMeshoptCompressionJsonHandler.h" -#include "ExtensionBufferViewExtMeshoptCompressionJsonHandler.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + #include "ExtensionCesiumRTCJsonHandler.h" -#include "ExtensionCesiumTileEdgesJsonHandler.h" -#include "ExtensionExtInstanceFeaturesJsonHandler.h" -#include "ExtensionExtMeshFeaturesJsonHandler.h" -#include "ExtensionExtMeshGpuInstancingJsonHandler.h" -#include "ExtensionKhrDracoMeshCompressionJsonHandler.h" -#include "ExtensionKhrMaterialsUnlitJsonHandler.h" -#include "ExtensionKhrTextureBasisuJsonHandler.h" -#include "ExtensionKhrTextureTransformJsonHandler.h" -#include "ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler.h" -#include "ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler.h" -#include "ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler.h" #include "ExtensionModelExtFeatureMetadataJsonHandler.h" #include "ExtensionModelExtStructuralMetadataJsonHandler.h" #include "ExtensionModelKhrMaterialsVariantsJsonHandler.h" #include "ExtensionModelMaxarMeshVariantsJsonHandler.h" +#include "ExtensionCesiumTileEdgesJsonHandler.h" +#include "ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler.h" +#include "ExtensionExtMeshFeaturesJsonHandler.h" +#include "ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler.h" +#include "ExtensionKhrDracoMeshCompressionJsonHandler.h" +#include "ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler.h" +#include "ExtensionExtInstanceFeaturesJsonHandler.h" +#include "ExtensionExtMeshGpuInstancingJsonHandler.h" #include "ExtensionNodeMaxarMeshVariantsJsonHandler.h" +#include "ExtensionBufferExtMeshoptCompressionJsonHandler.h" +#include "ExtensionBufferViewExtMeshoptCompressionJsonHandler.h" +#include "ExtensionKhrMaterialsUnlitJsonHandler.h" +#include "ExtensionKhrTextureBasisuJsonHandler.h" #include "ExtensionTextureWebpJsonHandler.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "ExtensionKhrTextureTransformJsonHandler.h" namespace CesiumGltfReader { void registerExtensions(CesiumJsonReader::ExtensionReaderContext& context) { (void)context; context.registerExtension(); - context.registerExtension< - CesiumGltf::Model, - ExtensionModelExtFeatureMetadataJsonHandler>(); - context.registerExtension< - CesiumGltf::Model, - ExtensionModelExtStructuralMetadataJsonHandler>(); - context.registerExtension< - CesiumGltf::Model, - ExtensionModelKhrMaterialsVariantsJsonHandler>(); - context.registerExtension< - CesiumGltf::Model, - ExtensionModelMaxarMeshVariantsJsonHandler>(); - context.registerExtension< - CesiumGltf::MeshPrimitive, - ExtensionCesiumTileEdgesJsonHandler>(); - context.registerExtension< - CesiumGltf::MeshPrimitive, - ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler>(); - context.registerExtension< - CesiumGltf::MeshPrimitive, - ExtensionExtMeshFeaturesJsonHandler>(); - context.registerExtension< - CesiumGltf::MeshPrimitive, - ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler>(); - context.registerExtension< - CesiumGltf::MeshPrimitive, - ExtensionKhrDracoMeshCompressionJsonHandler>(); - context.registerExtension< - CesiumGltf::MeshPrimitive, - ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler>(); - context.registerExtension< - CesiumGltf::Node, - ExtensionExtInstanceFeaturesJsonHandler>(); - context.registerExtension< - CesiumGltf::Node, - ExtensionExtMeshGpuInstancingJsonHandler>(); - context.registerExtension< - CesiumGltf::Node, - ExtensionNodeMaxarMeshVariantsJsonHandler>(); - context.registerExtension< - CesiumGltf::Buffer, - ExtensionBufferExtMeshoptCompressionJsonHandler>(); - context.registerExtension< - CesiumGltf::BufferView, - ExtensionBufferViewExtMeshoptCompressionJsonHandler>(); - context.registerExtension< - CesiumGltf::Material, - ExtensionKhrMaterialsUnlitJsonHandler>(); - context.registerExtension< - CesiumGltf::Texture, - ExtensionKhrTextureBasisuJsonHandler>(); - context.registerExtension< - CesiumGltf::Texture, - ExtensionTextureWebpJsonHandler>(); - context.registerExtension< - CesiumGltf::TextureInfo, - ExtensionKhrTextureTransformJsonHandler>(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); +context.registerExtension(); } } // namespace CesiumGltfReader diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp index ec6644ff5..a008e3e3c 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp @@ -17,20 +17,28 @@ #include #include #include -#include -#include -#include -#include -#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include #include #include #include @@ -60,12 +68,8 @@ #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include #include #include #include @@ -75,14 +79,10 @@ #include #include #include -#include #include #include -#include #include -#include #include -#include #include #include #include @@ -278,12 +278,12 @@ void writeJson( const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtMeshFeaturesFeatureId& obj, + const CesiumGltf::FeatureId& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture& obj, + const CesiumGltf::FeatureIdTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); @@ -293,77 +293,77 @@ void writeJson( const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::FeatureIDTexture& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::TextureAccessor& obj, + const CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::FeatureIDAttribute& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::FeatureIDs& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::FeatureTexture& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::FeatureTable& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTable& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::FeatureTableProperty& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::Statistics& obj, + const CesiumGltf::ExtensionExtFeatureMetadataStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ClassStatistics& obj, + const CesiumGltf::ExtensionExtFeatureMetadataClassStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::PropertyStatistics& obj, + const CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::Schema& obj, + const CesiumGltf::ExtensionExtFeatureMetadataSchema& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::Enum& obj, + const CesiumGltf::ExtensionExtFeatureMetadataEnum& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::EnumValue& obj, + const CesiumGltf::ExtensionExtFeatureMetadataEnumValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::Class& obj, + const CesiumGltf::ExtensionExtFeatureMetadataClass& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ClassProperty& obj, + const CesiumGltf::ExtensionExtFeatureMetadataClassProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); @@ -1595,7 +1595,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtMeshFeaturesFeatureId& obj, + const CesiumGltf::FeatureId& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1634,7 +1634,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture& obj, + const CesiumGltf::FeatureIdTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1685,7 +1685,7 @@ void writeJson( } void writeJson( - const CesiumGltf::FeatureIDTexture& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1702,7 +1702,7 @@ void writeJson( } void writeJson( - const CesiumGltf::TextureAccessor& obj, + const CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1719,7 +1719,7 @@ void writeJson( } void writeJson( - const CesiumGltf::FeatureIDAttribute& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1736,7 +1736,7 @@ void writeJson( } void writeJson( - const CesiumGltf::FeatureIDs& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1762,7 +1762,7 @@ void writeJson( } void writeJson( - const CesiumGltf::FeatureTexture& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1781,7 +1781,7 @@ void writeJson( } void writeJson( - const CesiumGltf::FeatureTable& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTable& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1805,7 +1805,7 @@ void writeJson( } void writeJson( - const CesiumGltf::FeatureTableProperty& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1815,7 +1815,9 @@ void writeJson( writeJson(obj.bufferView, jsonWriter, context); } - if (obj.offsetType != CesiumGltf::FeatureTableProperty::OffsetType::UINT32) { + if (obj.offsetType != + CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty::OffsetType:: + UINT32) { jsonWriter.Key("offsetType"); writeJson(obj.offsetType, jsonWriter, context); } @@ -1836,7 +1838,7 @@ void writeJson( } void writeJson( - const CesiumGltf::Statistics& obj, + const CesiumGltf::ExtensionExtFeatureMetadataStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1852,7 +1854,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ClassStatistics& obj, + const CesiumGltf::ExtensionExtFeatureMetadataClassStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1873,7 +1875,7 @@ void writeJson( } void writeJson( - const CesiumGltf::PropertyStatistics& obj, + const CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1924,7 +1926,7 @@ void writeJson( } void writeJson( - const CesiumGltf::Schema& obj, + const CesiumGltf::ExtensionExtFeatureMetadataSchema& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1960,7 +1962,7 @@ void writeJson( } void writeJson( - const CesiumGltf::Enum& obj, + const CesiumGltf::ExtensionExtFeatureMetadataEnum& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1975,7 +1977,8 @@ void writeJson( writeJson(obj.description, jsonWriter, context); } - if (obj.valueType != CesiumGltf::Enum::ValueType::UINT16) { + if (obj.valueType != + CesiumGltf::ExtensionExtFeatureMetadataEnum::ValueType::UINT16) { jsonWriter.Key("valueType"); writeJson(obj.valueType, jsonWriter, context); } @@ -1991,7 +1994,7 @@ void writeJson( } void writeJson( - const CesiumGltf::EnumValue& obj, + const CesiumGltf::ExtensionExtFeatureMetadataEnumValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -2013,7 +2016,7 @@ void writeJson( } void writeJson( - const CesiumGltf::Class& obj, + const CesiumGltf::ExtensionExtFeatureMetadataClass& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -2039,7 +2042,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ClassProperty& obj, + const CesiumGltf::ExtensionExtFeatureMetadataClassProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -3174,15 +3177,15 @@ void ExtensionExtStructuralMetadataClassPropertyJsonWriter::write( writeJson(obj, jsonWriter, context); } -void ExtensionExtMeshFeaturesFeatureIdJsonWriter::write( - const CesiumGltf::ExtensionExtMeshFeaturesFeatureId& obj, +void FeatureIdJsonWriter::write( + const CesiumGltf::FeatureId& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ExtensionExtMeshFeaturesFeatureIdTextureJsonWriter::write( - const CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture& obj, +void FeatureIdTextureJsonWriter::write( + const CesiumGltf::FeatureIdTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); @@ -3195,106 +3198,106 @@ void ExtensionExtInstanceFeaturesFeatureIdJsonWriter::write( writeJson(obj, jsonWriter, context); } -void FeatureIDTextureJsonWriter::write( - const CesiumGltf::FeatureIDTexture& obj, +void ExtensionExtFeatureMetadataFeatureIDTextureJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void TextureAccessorJsonWriter::write( - const CesiumGltf::TextureAccessor& obj, +void ExtensionExtFeatureMetadataTextureAccessorJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void FeatureIDAttributeJsonWriter::write( - const CesiumGltf::FeatureIDAttribute& obj, +void ExtensionExtFeatureMetadataFeatureIDAttributeJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void FeatureIDsJsonWriter::write( - const CesiumGltf::FeatureIDs& obj, +void ExtensionExtFeatureMetadataFeatureIDsJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void FeatureTextureJsonWriter::write( - const CesiumGltf::FeatureTexture& obj, +void ExtensionExtFeatureMetadataFeatureTextureJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void FeatureTableJsonWriter::write( - const CesiumGltf::FeatureTable& obj, +void ExtensionExtFeatureMetadataFeatureTableJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTable& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void FeatureTablePropertyJsonWriter::write( - const CesiumGltf::FeatureTableProperty& obj, +void ExtensionExtFeatureMetadataFeatureTablePropertyJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void StatisticsJsonWriter::write( - const CesiumGltf::Statistics& obj, +void ExtensionExtFeatureMetadataStatisticsJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ClassStatisticsJsonWriter::write( - const CesiumGltf::ClassStatistics& obj, +void ExtensionExtFeatureMetadataClassStatisticsJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataClassStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void PropertyStatisticsJsonWriter::write( - const CesiumGltf::PropertyStatistics& obj, +void ExtensionExtFeatureMetadataPropertyStatisticsJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void SchemaJsonWriter::write( - const CesiumGltf::Schema& obj, +void ExtensionExtFeatureMetadataSchemaJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataSchema& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void EnumJsonWriter::write( - const CesiumGltf::Enum& obj, +void ExtensionExtFeatureMetadataEnumJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataEnum& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void EnumValueJsonWriter::write( - const CesiumGltf::EnumValue& obj, +void ExtensionExtFeatureMetadataEnumValueJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataEnumValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ClassJsonWriter::write( - const CesiumGltf::Class& obj, +void ExtensionExtFeatureMetadataClassJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataClass& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ClassPropertyJsonWriter::write( - const CesiumGltf::ClassProperty& obj, +void ExtensionExtFeatureMetadataClassPropertyJsonWriter::write( + const CesiumGltf::ExtensionExtFeatureMetadataClassProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.h b/CesiumGltfWriter/generated/src/ModelJsonWriter.h index 0d67c79b5..6ea76be94 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.h +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.h @@ -46,24 +46,24 @@ struct ExtensionExtStructuralMetadataEnum; struct ExtensionExtStructuralMetadataEnumValue; struct ExtensionExtStructuralMetadataClass; struct ExtensionExtStructuralMetadataClassProperty; -struct ExtensionExtMeshFeaturesFeatureId; -struct ExtensionExtMeshFeaturesFeatureIdTexture; +struct FeatureId; +struct FeatureIdTexture; struct ExtensionExtInstanceFeaturesFeatureId; -struct FeatureIDTexture; -struct TextureAccessor; -struct FeatureIDAttribute; -struct FeatureIDs; -struct FeatureTexture; -struct FeatureTable; -struct FeatureTableProperty; -struct Statistics; -struct ClassStatistics; -struct PropertyStatistics; -struct Schema; -struct Enum; -struct EnumValue; -struct Class; -struct ClassProperty; +struct ExtensionExtFeatureMetadataFeatureIDTexture; +struct ExtensionExtFeatureMetadataTextureAccessor; +struct ExtensionExtFeatureMetadataFeatureIDAttribute; +struct ExtensionExtFeatureMetadataFeatureIDs; +struct ExtensionExtFeatureMetadataFeatureTexture; +struct ExtensionExtFeatureMetadataFeatureTable; +struct ExtensionExtFeatureMetadataFeatureTableProperty; +struct ExtensionExtFeatureMetadataStatistics; +struct ExtensionExtFeatureMetadataClassStatistics; +struct ExtensionExtFeatureMetadataPropertyStatistics; +struct ExtensionExtFeatureMetadataSchema; +struct ExtensionExtFeatureMetadataEnum; +struct ExtensionExtFeatureMetadataEnumValue; +struct ExtensionExtFeatureMetadataClass; +struct ExtensionExtFeatureMetadataClassProperty; struct Model; struct Texture; struct Skin; @@ -468,20 +468,20 @@ struct ExtensionExtStructuralMetadataClassPropertyJsonWriter { const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtMeshFeaturesFeatureIdJsonWriter { - using ValueType = CesiumGltf::ExtensionExtMeshFeaturesFeatureId; +struct FeatureIdJsonWriter { + using ValueType = CesiumGltf::FeatureId; static void write( - const CesiumGltf::ExtensionExtMeshFeaturesFeatureId& obj, + const CesiumGltf::FeatureId& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtMeshFeaturesFeatureIdTextureJsonWriter { - using ValueType = CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture; +struct FeatureIdTextureJsonWriter { + using ValueType = CesiumGltf::FeatureIdTexture; static void write( - const CesiumGltf::ExtensionExtMeshFeaturesFeatureIdTexture& obj, + const CesiumGltf::FeatureIdTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; @@ -495,137 +495,137 @@ struct ExtensionExtInstanceFeaturesFeatureIdJsonWriter { const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct FeatureIDTextureJsonWriter { - using ValueType = CesiumGltf::FeatureIDTexture; +struct ExtensionExtFeatureMetadataFeatureIDTextureJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture; static void write( - const CesiumGltf::FeatureIDTexture& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct TextureAccessorJsonWriter { - using ValueType = CesiumGltf::TextureAccessor; +struct ExtensionExtFeatureMetadataTextureAccessorJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor; static void write( - const CesiumGltf::TextureAccessor& obj, + const CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct FeatureIDAttributeJsonWriter { - using ValueType = CesiumGltf::FeatureIDAttribute; +struct ExtensionExtFeatureMetadataFeatureIDAttributeJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute; static void write( - const CesiumGltf::FeatureIDAttribute& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct FeatureIDsJsonWriter { - using ValueType = CesiumGltf::FeatureIDs; +struct ExtensionExtFeatureMetadataFeatureIDsJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs; static void write( - const CesiumGltf::FeatureIDs& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct FeatureTextureJsonWriter { - using ValueType = CesiumGltf::FeatureTexture; +struct ExtensionExtFeatureMetadataFeatureTextureJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture; static void write( - const CesiumGltf::FeatureTexture& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct FeatureTableJsonWriter { - using ValueType = CesiumGltf::FeatureTable; +struct ExtensionExtFeatureMetadataFeatureTableJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureTable; static void write( - const CesiumGltf::FeatureTable& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTable& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct FeatureTablePropertyJsonWriter { - using ValueType = CesiumGltf::FeatureTableProperty; +struct ExtensionExtFeatureMetadataFeatureTablePropertyJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty; static void write( - const CesiumGltf::FeatureTableProperty& obj, + const CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct StatisticsJsonWriter { - using ValueType = CesiumGltf::Statistics; +struct ExtensionExtFeatureMetadataStatisticsJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataStatistics; static void write( - const CesiumGltf::Statistics& obj, + const CesiumGltf::ExtensionExtFeatureMetadataStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ClassStatisticsJsonWriter { - using ValueType = CesiumGltf::ClassStatistics; +struct ExtensionExtFeatureMetadataClassStatisticsJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataClassStatistics; static void write( - const CesiumGltf::ClassStatistics& obj, + const CesiumGltf::ExtensionExtFeatureMetadataClassStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct PropertyStatisticsJsonWriter { - using ValueType = CesiumGltf::PropertyStatistics; +struct ExtensionExtFeatureMetadataPropertyStatisticsJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics; static void write( - const CesiumGltf::PropertyStatistics& obj, + const CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct SchemaJsonWriter { - using ValueType = CesiumGltf::Schema; +struct ExtensionExtFeatureMetadataSchemaJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataSchema; static void write( - const CesiumGltf::Schema& obj, + const CesiumGltf::ExtensionExtFeatureMetadataSchema& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct EnumJsonWriter { - using ValueType = CesiumGltf::Enum; +struct ExtensionExtFeatureMetadataEnumJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataEnum; static void write( - const CesiumGltf::Enum& obj, + const CesiumGltf::ExtensionExtFeatureMetadataEnum& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct EnumValueJsonWriter { - using ValueType = CesiumGltf::EnumValue; +struct ExtensionExtFeatureMetadataEnumValueJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataEnumValue; static void write( - const CesiumGltf::EnumValue& obj, + const CesiumGltf::ExtensionExtFeatureMetadataEnumValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ClassJsonWriter { - using ValueType = CesiumGltf::Class; +struct ExtensionExtFeatureMetadataClassJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataClass; static void write( - const CesiumGltf::Class& obj, + const CesiumGltf::ExtensionExtFeatureMetadataClass& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ClassPropertyJsonWriter { - using ValueType = CesiumGltf::ClassProperty; +struct ExtensionExtFeatureMetadataClassPropertyJsonWriter { + using ValueType = CesiumGltf::ExtensionExtFeatureMetadataClassProperty; static void write( - const CesiumGltf::ClassProperty& obj, + const CesiumGltf::ExtensionExtFeatureMetadataClassProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; diff --git a/tools/generate-classes/glTF.json b/tools/generate-classes/glTF.json index daf36eedb..e6b7e699a 100644 --- a/tools/generate-classes/glTF.json +++ b/tools/generate-classes/glTF.json @@ -43,49 +43,49 @@ "overrideName": "ExtensionMeshPrimitiveExtFeatureMetadata" }, "Class Property in EXT_feature_metadata": { - "overrideName": "ClassProperty" + "overrideName": "ExtensionExtFeatureMetadataClassProperty" }, "Class in EXT_feature_metadata": { - "overrideName": "Class" + "overrideName": "ExtensionExtFeatureMetadataClass" }, "Enum in EXT_feature_metadata": { - "overrideName": "Enum" + "overrideName": "ExtensionExtFeatureMetadataEnum" }, "Enum Value in EXT_feature_metadata": { - "overrideName": "EnumValue" + "overrideName": "ExtensionExtFeatureMetadataEnumValue" }, "Feature IDs in EXT_feature_metadata": { - "overrideName": "FeatureIDs" + "overrideName": "ExtensionExtFeatureMetadataFeatureIDs" }, "Feature ID Attribute in EXT_feature_metadata": { - "overrideName": "FeatureIDAttribute" + "overrideName": "ExtensionExtFeatureMetadataFeatureIDAttribute" }, "Feature ID Texture in EXT_feature_metadata": { - "overrideName": "FeatureIDTexture" + "overrideName": "ExtensionExtFeatureMetadataFeatureIDTexture" }, "Feature Table Property in EXT_feature_metadata": { - "overrideName": "FeatureTableProperty" + "overrideName": "ExtensionExtFeatureMetadataFeatureTableProperty" }, "Feature Table in EXT_feature_metadata": { - "overrideName": "FeatureTable" + "overrideName": "ExtensionExtFeatureMetadataFeatureTable" }, "Feature Texture in EXT_feature_metadata": { - "overrideName": "FeatureTexture" + "overrideName": "ExtensionExtFeatureMetadataFeatureTexture" }, "Schema in EXT_feature_metadata": { - "overrideName": "Schema" + "overrideName": "ExtensionExtFeatureMetadataSchema" }, "Class Property Statistics in EXT_feature_metadata": { - "overrideName": "PropertyStatistics" + "overrideName": "ExtensionExtFeatureMetadataPropertyStatistics" }, "Class Statistics in EXT_feature_metadata": { - "overrideName": "ClassStatistics" + "overrideName": "ExtensionExtFeatureMetadataClassStatistics" }, "Statistics in EXT_feature_metadata": { - "overrideName": "Statistics" + "overrideName": "ExtensionExtFeatureMetadataStatistics" }, "Texture Accessor in EXT_feature_metadata": { - "overrideName": "TextureAccessor" + "overrideName": "ExtensionExtFeatureMetadataTextureAccessor" }, "EXT_instance_features glTF Node extension": { "overrideName": "ExtensionExtInstanceFeatures" @@ -97,10 +97,10 @@ "overrideName": "ExtensionExtMeshFeatures" }, "Feature ID in EXT_mesh_features": { - "overrideName": "ExtensionExtMeshFeaturesFeatureId" + "overrideName": "FeatureId" }, "Feature ID Texture in EXT_mesh_features": { - "overrideName": "ExtensionExtMeshFeaturesFeatureIdTexture" + "overrideName": "FeatureIdTexture" }, "EXT_mesh_gpu_instancing glTF extension": { "overrideName": "ExtensionExtMeshGpuInstancing" From f82528cc3f42bf4ef8cb0e06e99341fda35cdd6a Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 16 Jun 2023 15:43:02 -0400 Subject: [PATCH 056/121] Formatting, changelog entry, cleanup --- CHANGES.md | 10 +- .../BatchTableToGltfStructuralMetadata.cpp | 2 +- ...gradeBatchTableToExtStructuralMetadata.cpp | 2 +- .../generated/src/GeneratedJsonHandlers.cpp | 3535 +++++++++++++---- 4 files changed, 2689 insertions(+), 860 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5343e5d35..25ce81708 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,12 +4,10 @@ ##### Breaking Changes :mega: -Many classes have been overhauled to support `EXT_mesh_features` and `EXT_structural_metadata`. This includes the following changes: - -- Replaced `FeatureIDTextureView` with `FeatureIdTextureView`, which views a `ExtensionExtMeshFeaturesFeatureIdTexture`. - - Replaced `FeatureIDTextureViewStatus` with `FeatureIdTextureViewStatus`. - - Replaced `getChannel` with `getChannels`. This retrieves the channels as a vector of integers, instead of a single integer. - - Renamed `getTextureCoordinateAttributeId` to `getTexCoordSetIndex`. +- In `CesiumGltf`, all generated classes related to `EXT_feature_metadata` are now prefixed with `ExtensionExtFeatureMetadata`. For example, `ClassProperty` becomes `ExtensionExtFeatureMetadataClassProperty`. 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 `ExtensionExtStructuralMetadataPropertyTable`. - Added `PropertyTableViewStatus` to indicate whether or not `PropertyTableView` is valid. - Renamed `MetadataArrayView` to `PropertyArrayView`. diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 93dce98d2..7010cc286 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -1630,8 +1630,8 @@ ErrorList BatchTableToGltfStructuralMetadata::convertFromB3dm( ExtensionExtMeshFeatures& extension = primitive.addExtension(); - FeatureId& featureID = extension.featureIds.emplace_back(); + // No fast way to count the unique feature IDs in this primitive, so // subtitute the batch table length. featureID.featureCount = batchLength; diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 74c81c281..445416236 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -411,7 +411,7 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { primitive.getExtension(); REQUIRE(pPrimitiveExtension); REQUIRE(pPrimitiveExtension->featureIds.size() == 1); - FeatureId& featureId = pPrimitiveExtension->featureIds[0]; + const FeatureId& featureId = pPrimitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 10); CHECK(featureId.attribute == 0); CHECK(featureId.propertyTable == 0); diff --git a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp index bde0586ff..b65df862c 100644 --- a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp +++ b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp @@ -9,19 +9,30 @@ namespace CesiumGltfReader { -ExtensionCesiumRTCJsonHandler::ExtensionCesiumRTCJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _center() {} +ExtensionCesiumRTCJsonHandler::ExtensionCesiumRTCJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _center() {} -void ExtensionCesiumRTCJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionCesiumRTC* pObject) { +void ExtensionCesiumRTCJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionCesiumRTC* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionCesiumRTCJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionCesiumRTCJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionCesiumRTC(CesiumGltf::ExtensionCesiumRTC::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionCesiumRTC( + CesiumGltf::ExtensionCesiumRTC::TypeName, + str, + *this->_pObject); } -void ExtensionCesiumRTCJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionCesiumRTCJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = o.extensions.emplace(extensionName, CesiumGltf::ExtensionCesiumRTC()) .first->second; @@ -30,10 +41,15 @@ void ExtensionCesiumRTCJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParen &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionCesiumRTCJsonHandler::readObjectKeyExtensionCesiumRTC(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionCesiumRTC& o) { +CesiumJsonReader::IJsonHandler* +ExtensionCesiumRTCJsonHandler::readObjectKeyExtensionCesiumRTC( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionCesiumRTC& o) { using namespace std::string_literals; - if ("center"s == str) return property("center", this->_center, o.center); + if ("center"s == str) + return property("center", this->_center, o.center); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -50,34 +66,59 @@ CesiumJsonReader::IJsonHandler* ExtensionCesiumRTCJsonHandler::readObjectKeyExte namespace CesiumGltfReader { -ExtensionCesiumTileEdgesJsonHandler::ExtensionCesiumTileEdgesJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _left(), _bottom(), _right(), _top() {} - -void ExtensionCesiumTileEdgesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionCesiumTileEdges* pObject) { +ExtensionCesiumTileEdgesJsonHandler::ExtensionCesiumTileEdgesJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _left(), + _bottom(), + _right(), + _top() {} + +void ExtensionCesiumTileEdgesJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionCesiumTileEdges* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionCesiumTileEdgesJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionCesiumTileEdgesJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionCesiumTileEdges(CesiumGltf::ExtensionCesiumTileEdges::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionCesiumTileEdges( + CesiumGltf::ExtensionCesiumTileEdges::TypeName, + str, + *this->_pObject); } -void ExtensionCesiumTileEdgesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionCesiumTileEdgesJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionCesiumTileEdges()) + o.extensions + .emplace(extensionName, CesiumGltf::ExtensionCesiumTileEdges()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionCesiumTileEdgesJsonHandler::readObjectKeyExtensionCesiumTileEdges(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionCesiumTileEdges& o) { +CesiumJsonReader::IJsonHandler* +ExtensionCesiumTileEdgesJsonHandler::readObjectKeyExtensionCesiumTileEdges( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionCesiumTileEdges& o) { using namespace std::string_literals; - if ("left"s == str) return property("left", this->_left, o.left); - if ("bottom"s == str) return property("bottom", this->_bottom, o.bottom); - if ("right"s == str) return property("right", this->_right, o.right); - if ("top"s == str) return property("top", this->_top, o.top); + if ("left"s == str) + return property("left", this->_left, o.left); + if ("bottom"s == str) + return property("bottom", this->_bottom, o.bottom); + if ("right"s == str) + return property("right", this->_right, o.right); + if ("top"s == str) + return property("top", this->_top, o.top); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -94,35 +135,67 @@ CesiumJsonReader::IJsonHandler* ExtensionCesiumTileEdgesJsonHandler::readObjectK namespace CesiumGltfReader { -ExtensionModelExtFeatureMetadataJsonHandler::ExtensionModelExtFeatureMetadataJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _schema(context), _schemaUri(), _statistics(context), _featureTables(context), _featureTextures(context) {} - -void ExtensionModelExtFeatureMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelExtFeatureMetadata* pObject) { +ExtensionModelExtFeatureMetadataJsonHandler:: + ExtensionModelExtFeatureMetadataJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _schema(context), + _schemaUri(), + _statistics(context), + _featureTables(context), + _featureTextures(context) {} + +void ExtensionModelExtFeatureMetadataJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionModelExtFeatureMetadata* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionModelExtFeatureMetadataJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionModelExtFeatureMetadataJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelExtFeatureMetadata(CesiumGltf::ExtensionModelExtFeatureMetadata::TypeName, str, *this->_pObject); -} - -void ExtensionModelExtFeatureMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { - std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionModelExtFeatureMetadata()) - .first->second; + return this->readObjectKeyExtensionModelExtFeatureMetadata( + CesiumGltf::ExtensionModelExtFeatureMetadata::TypeName, + str, + *this->_pObject); +} + +void ExtensionModelExtFeatureMetadataJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { + std::any& value = o.extensions + .emplace( + extensionName, + CesiumGltf::ExtensionModelExtFeatureMetadata()) + .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionModelExtFeatureMetadataJsonHandler::readObjectKeyExtensionModelExtFeatureMetadata(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelExtFeatureMetadata& o) { +CesiumJsonReader::IJsonHandler* ExtensionModelExtFeatureMetadataJsonHandler:: + readObjectKeyExtensionModelExtFeatureMetadata( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionModelExtFeatureMetadata& o) { using namespace std::string_literals; - if ("schema"s == str) return property("schema", this->_schema, o.schema); - if ("schemaUri"s == str) return property("schemaUri", this->_schemaUri, o.schemaUri); - if ("statistics"s == str) return property("statistics", this->_statistics, o.statistics); - if ("featureTables"s == str) return property("featureTables", this->_featureTables, o.featureTables); - if ("featureTextures"s == str) return property("featureTextures", this->_featureTextures, o.featureTextures); + if ("schema"s == str) + return property("schema", this->_schema, o.schema); + if ("schemaUri"s == str) + return property("schemaUri", this->_schemaUri, o.schemaUri); + if ("statistics"s == str) + return property("statistics", this->_statistics, o.statistics); + if ("featureTables"s == str) + return property("featureTables", this->_featureTables, o.featureTables); + if ("featureTextures"s == str) + return property( + "featureTextures", + this->_featureTextures, + o.featureTextures); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -139,33 +212,70 @@ CesiumJsonReader::IJsonHandler* ExtensionModelExtFeatureMetadataJsonHandler::rea namespace CesiumGltfReader { -ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureIdAttributes(context), _featureIdTextures(context), _featureTextures() {} - -void ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata* pObject) { +ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler:: + ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _featureIdAttributes(context), + _featureIdTextures(context), + _featureTextures() {} + +void ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionMeshPrimitiveExtFeatureMetadata(CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionMeshPrimitiveExtFeatureMetadata( + CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata::TypeName, + str, + *this->_pObject); } -void ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata()) + o.extensions + .emplace( + extensionName, + CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata()) .first->second; this->reset( pParentHandler, - &std::any_cast(value)); + &std::any_cast( + value)); } -CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler::readObjectKeyExtensionMeshPrimitiveExtFeatureMetadata(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata& o) { +CesiumJsonReader::IJsonHandler* +ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler:: + readObjectKeyExtensionMeshPrimitiveExtFeatureMetadata( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionMeshPrimitiveExtFeatureMetadata& o) { using namespace std::string_literals; - if ("featureIdAttributes"s == str) return property("featureIdAttributes", this->_featureIdAttributes, o.featureIdAttributes); - if ("featureIdTextures"s == str) return property("featureIdTextures", this->_featureIdTextures, o.featureIdTextures); - if ("featureTextures"s == str) return property("featureTextures", this->_featureTextures, o.featureTextures); + if ("featureIdAttributes"s == str) + return property( + "featureIdAttributes", + this->_featureIdAttributes, + o.featureIdAttributes); + if ("featureIdTextures"s == str) + return property( + "featureIdTextures", + this->_featureIdTextures, + o.featureIdTextures); + if ("featureTextures"s == str) + return property( + "featureTextures", + this->_featureTextures, + o.featureTextures); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -182,31 +292,51 @@ CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveExtFeatureMetadataJsonHand namespace CesiumGltfReader { -ExtensionExtInstanceFeaturesJsonHandler::ExtensionExtInstanceFeaturesJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureIds(context) {} +ExtensionExtInstanceFeaturesJsonHandler:: + ExtensionExtInstanceFeaturesJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _featureIds(context) {} -void ExtensionExtInstanceFeaturesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtInstanceFeatures* pObject) { +void ExtensionExtInstanceFeaturesJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtInstanceFeatures* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtInstanceFeaturesJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtInstanceFeatures(CesiumGltf::ExtensionExtInstanceFeatures::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionExtInstanceFeatures( + CesiumGltf::ExtensionExtInstanceFeatures::TypeName, + str, + *this->_pObject); } -void ExtensionExtInstanceFeaturesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionExtInstanceFeaturesJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionExtInstanceFeatures()) + o.extensions + .emplace(extensionName, CesiumGltf::ExtensionExtInstanceFeatures()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesJsonHandler::readObjectKeyExtensionExtInstanceFeatures(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtInstanceFeatures& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesJsonHandler:: + readObjectKeyExtensionExtInstanceFeatures( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtInstanceFeatures& o) { using namespace std::string_literals; - if ("featureIds"s == str) return property("featureIds", this->_featureIds, o.featureIds); + if ("featureIds"s == str) + return property("featureIds", this->_featureIds, o.featureIds); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -223,31 +353,50 @@ CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesJsonHandler::readObj namespace CesiumGltfReader { -ExtensionExtMeshFeaturesJsonHandler::ExtensionExtMeshFeaturesJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureIds(context) {} +ExtensionExtMeshFeaturesJsonHandler::ExtensionExtMeshFeaturesJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _featureIds(context) {} -void ExtensionExtMeshFeaturesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtMeshFeatures* pObject) { +void ExtensionExtMeshFeaturesJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtMeshFeatures* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtMeshFeaturesJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtMeshFeaturesJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtMeshFeatures(CesiumGltf::ExtensionExtMeshFeatures::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionExtMeshFeatures( + CesiumGltf::ExtensionExtMeshFeatures::TypeName, + str, + *this->_pObject); } -void ExtensionExtMeshFeaturesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionExtMeshFeaturesJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionExtMeshFeatures()) + o.extensions + .emplace(extensionName, CesiumGltf::ExtensionExtMeshFeatures()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionExtMeshFeaturesJsonHandler::readObjectKeyExtensionExtMeshFeatures(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtMeshFeatures& o) { +CesiumJsonReader::IJsonHandler* +ExtensionExtMeshFeaturesJsonHandler::readObjectKeyExtensionExtMeshFeatures( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtMeshFeatures& o) { using namespace std::string_literals; - if ("featureIds"s == str) return property("featureIds", this->_featureIds, o.featureIds); + if ("featureIds"s == str) + return property("featureIds", this->_featureIds, o.featureIds); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -264,31 +413,50 @@ CesiumJsonReader::IJsonHandler* ExtensionExtMeshFeaturesJsonHandler::readObjectK namespace CesiumGltfReader { -ExtensionExtMeshGpuInstancingJsonHandler::ExtensionExtMeshGpuInstancingJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attributes() {} +ExtensionExtMeshGpuInstancingJsonHandler:: + ExtensionExtMeshGpuInstancingJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attributes() {} -void ExtensionExtMeshGpuInstancingJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtMeshGpuInstancing* pObject) { +void ExtensionExtMeshGpuInstancingJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtMeshGpuInstancing* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtMeshGpuInstancingJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtMeshGpuInstancingJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtMeshGpuInstancing(CesiumGltf::ExtensionExtMeshGpuInstancing::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionExtMeshGpuInstancing( + CesiumGltf::ExtensionExtMeshGpuInstancing::TypeName, + str, + *this->_pObject); } -void ExtensionExtMeshGpuInstancingJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionExtMeshGpuInstancingJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionExtMeshGpuInstancing()) + o.extensions + .emplace(extensionName, CesiumGltf::ExtensionExtMeshGpuInstancing()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionExtMeshGpuInstancingJsonHandler::readObjectKeyExtensionExtMeshGpuInstancing(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtMeshGpuInstancing& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtMeshGpuInstancingJsonHandler:: + readObjectKeyExtensionExtMeshGpuInstancing( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtMeshGpuInstancing& o) { using namespace std::string_literals; - if ("attributes"s == str) return property("attributes", this->_attributes, o.attributes); + if ("attributes"s == str) + return property("attributes", this->_attributes, o.attributes); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -305,31 +473,52 @@ CesiumJsonReader::IJsonHandler* ExtensionExtMeshGpuInstancingJsonHandler::readOb namespace CesiumGltfReader { -ExtensionBufferExtMeshoptCompressionJsonHandler::ExtensionBufferExtMeshoptCompressionJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _fallback() {} +ExtensionBufferExtMeshoptCompressionJsonHandler:: + ExtensionBufferExtMeshoptCompressionJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _fallback() {} -void ExtensionBufferExtMeshoptCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionBufferExtMeshoptCompression* pObject) { +void ExtensionBufferExtMeshoptCompressionJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionBufferExtMeshoptCompression* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionBufferExtMeshoptCompressionJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionBufferExtMeshoptCompressionJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionBufferExtMeshoptCompression(CesiumGltf::ExtensionBufferExtMeshoptCompression::TypeName, str, *this->_pObject); -} - -void ExtensionBufferExtMeshoptCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { - std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionBufferExtMeshoptCompression()) - .first->second; + return this->readObjectKeyExtensionBufferExtMeshoptCompression( + CesiumGltf::ExtensionBufferExtMeshoptCompression::TypeName, + str, + *this->_pObject); +} + +void ExtensionBufferExtMeshoptCompressionJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { + std::any& value = o.extensions + .emplace( + extensionName, + CesiumGltf::ExtensionBufferExtMeshoptCompression()) + .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionBufferExtMeshoptCompressionJsonHandler::readObjectKeyExtensionBufferExtMeshoptCompression(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionBufferExtMeshoptCompression& o) { +CesiumJsonReader::IJsonHandler* +ExtensionBufferExtMeshoptCompressionJsonHandler:: + readObjectKeyExtensionBufferExtMeshoptCompression( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionBufferExtMeshoptCompression& o) { using namespace std::string_literals; - if ("fallback"s == str) return property("fallback", this->_fallback, o.fallback); + if ("fallback"s == str) + return property("fallback", this->_fallback, o.fallback); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -346,37 +535,73 @@ CesiumJsonReader::IJsonHandler* ExtensionBufferExtMeshoptCompressionJsonHandler: namespace CesiumGltfReader { -ExtensionBufferViewExtMeshoptCompressionJsonHandler::ExtensionBufferViewExtMeshoptCompressionJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _buffer(), _byteOffset(), _byteLength(), _byteStride(), _count(), _mode(), _filter() {} - -void ExtensionBufferViewExtMeshoptCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionBufferViewExtMeshoptCompression* pObject) { +ExtensionBufferViewExtMeshoptCompressionJsonHandler:: + ExtensionBufferViewExtMeshoptCompressionJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _buffer(), + _byteOffset(), + _byteLength(), + _byteStride(), + _count(), + _mode(), + _filter() {} + +void ExtensionBufferViewExtMeshoptCompressionJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionBufferViewExtMeshoptCompression* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionBufferViewExtMeshoptCompressionJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionBufferViewExtMeshoptCompressionJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionBufferViewExtMeshoptCompression(CesiumGltf::ExtensionBufferViewExtMeshoptCompression::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionBufferViewExtMeshoptCompression( + CesiumGltf::ExtensionBufferViewExtMeshoptCompression::TypeName, + str, + *this->_pObject); } -void ExtensionBufferViewExtMeshoptCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionBufferViewExtMeshoptCompressionJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionBufferViewExtMeshoptCompression()) + o.extensions + .emplace( + extensionName, + CesiumGltf::ExtensionBufferViewExtMeshoptCompression()) .first->second; this->reset( pParentHandler, - &std::any_cast(value)); + &std::any_cast( + value)); } -CesiumJsonReader::IJsonHandler* ExtensionBufferViewExtMeshoptCompressionJsonHandler::readObjectKeyExtensionBufferViewExtMeshoptCompression(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionBufferViewExtMeshoptCompression& o) { +CesiumJsonReader::IJsonHandler* +ExtensionBufferViewExtMeshoptCompressionJsonHandler:: + readObjectKeyExtensionBufferViewExtMeshoptCompression( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionBufferViewExtMeshoptCompression& o) { using namespace std::string_literals; - if ("buffer"s == str) return property("buffer", this->_buffer, o.buffer); - if ("byteOffset"s == str) return property("byteOffset", this->_byteOffset, o.byteOffset); - if ("byteLength"s == str) return property("byteLength", this->_byteLength, o.byteLength); - if ("byteStride"s == str) return property("byteStride", this->_byteStride, o.byteStride); - if ("count"s == str) return property("count", this->_count, o.count); - if ("mode"s == str) return property("mode", this->_mode, o.mode); - if ("filter"s == str) return property("filter", this->_filter, o.filter); + if ("buffer"s == str) + return property("buffer", this->_buffer, o.buffer); + if ("byteOffset"s == str) + return property("byteOffset", this->_byteOffset, o.byteOffset); + if ("byteLength"s == str) + return property("byteLength", this->_byteLength, o.byteLength); + if ("byteStride"s == str) + return property("byteStride", this->_byteStride, o.byteStride); + if ("count"s == str) + return property("count", this->_count, o.count); + if ("mode"s == str) + return property("mode", this->_mode, o.mode); + if ("filter"s == str) + return property("filter", this->_filter, o.filter); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -393,35 +618,70 @@ CesiumJsonReader::IJsonHandler* ExtensionBufferViewExtMeshoptCompressionJsonHand namespace CesiumGltfReader { -ExtensionModelExtStructuralMetadataJsonHandler::ExtensionModelExtStructuralMetadataJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _schema(context), _schemaUri(), _propertyTables(context), _propertyTextures(context), _propertyAttributes(context) {} - -void ExtensionModelExtStructuralMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelExtStructuralMetadata* pObject) { +ExtensionModelExtStructuralMetadataJsonHandler:: + ExtensionModelExtStructuralMetadataJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _schema(context), + _schemaUri(), + _propertyTables(context), + _propertyTextures(context), + _propertyAttributes(context) {} + +void ExtensionModelExtStructuralMetadataJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionModelExtStructuralMetadata* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionModelExtStructuralMetadataJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionModelExtStructuralMetadataJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelExtStructuralMetadata(CesiumGltf::ExtensionModelExtStructuralMetadata::TypeName, str, *this->_pObject); -} - -void ExtensionModelExtStructuralMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { - std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionModelExtStructuralMetadata()) - .first->second; + return this->readObjectKeyExtensionModelExtStructuralMetadata( + CesiumGltf::ExtensionModelExtStructuralMetadata::TypeName, + str, + *this->_pObject); +} + +void ExtensionModelExtStructuralMetadataJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { + std::any& value = o.extensions + .emplace( + extensionName, + CesiumGltf::ExtensionModelExtStructuralMetadata()) + .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionModelExtStructuralMetadataJsonHandler::readObjectKeyExtensionModelExtStructuralMetadata(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelExtStructuralMetadata& o) { +CesiumJsonReader::IJsonHandler* ExtensionModelExtStructuralMetadataJsonHandler:: + readObjectKeyExtensionModelExtStructuralMetadata( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionModelExtStructuralMetadata& o) { using namespace std::string_literals; - if ("schema"s == str) return property("schema", this->_schema, o.schema); - if ("schemaUri"s == str) return property("schemaUri", this->_schemaUri, o.schemaUri); - if ("propertyTables"s == str) return property("propertyTables", this->_propertyTables, o.propertyTables); - if ("propertyTextures"s == str) return property("propertyTextures", this->_propertyTextures, o.propertyTextures); - if ("propertyAttributes"s == str) return property("propertyAttributes", this->_propertyAttributes, o.propertyAttributes); + if ("schema"s == str) + return property("schema", this->_schema, o.schema); + if ("schemaUri"s == str) + return property("schemaUri", this->_schemaUri, o.schemaUri); + if ("propertyTables"s == str) + return property("propertyTables", this->_propertyTables, o.propertyTables); + if ("propertyTextures"s == str) + return property( + "propertyTextures", + this->_propertyTextures, + o.propertyTextures); + if ("propertyAttributes"s == str) + return property( + "propertyAttributes", + this->_propertyAttributes, + o.propertyAttributes); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -438,32 +698,64 @@ CesiumJsonReader::IJsonHandler* ExtensionModelExtStructuralMetadataJsonHandler:: namespace CesiumGltfReader { -ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _propertyTextures(), _propertyAttributes() {} +ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler:: + ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _propertyTextures(), + _propertyAttributes() {} -void ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata* pObject) { +void ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionMeshPrimitiveExtStructuralMetadata(CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionMeshPrimitiveExtStructuralMetadata( + CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata::TypeName, + str, + *this->_pObject); } -void ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata()) + o.extensions + .emplace( + extensionName, + CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata()) .first->second; this->reset( pParentHandler, - &std::any_cast(value)); + &std::any_cast( + value)); } -CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler::readObjectKeyExtensionMeshPrimitiveExtStructuralMetadata(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata& o) { +CesiumJsonReader::IJsonHandler* +ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler:: + readObjectKeyExtensionMeshPrimitiveExtStructuralMetadata( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata& o) { using namespace std::string_literals; - if ("propertyTextures"s == str) return property("propertyTextures", this->_propertyTextures, o.propertyTextures); - if ("propertyAttributes"s == str) return property("propertyAttributes", this->_propertyAttributes, o.propertyAttributes); + if ("propertyTextures"s == str) + return property( + "propertyTextures", + this->_propertyTextures, + o.propertyTextures); + if ("propertyAttributes"s == str) + return property( + "propertyAttributes", + this->_propertyAttributes, + o.propertyAttributes); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -480,32 +772,55 @@ CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveExtStructuralMetadataJsonH namespace CesiumGltfReader { -ExtensionKhrDracoMeshCompressionJsonHandler::ExtensionKhrDracoMeshCompressionJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _bufferView(), _attributes() {} +ExtensionKhrDracoMeshCompressionJsonHandler:: + ExtensionKhrDracoMeshCompressionJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _bufferView(), + _attributes() {} -void ExtensionKhrDracoMeshCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionKhrDracoMeshCompression* pObject) { +void ExtensionKhrDracoMeshCompressionJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionKhrDracoMeshCompression* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionKhrDracoMeshCompressionJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionKhrDracoMeshCompressionJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionKhrDracoMeshCompression(CesiumGltf::ExtensionKhrDracoMeshCompression::TypeName, str, *this->_pObject); -} - -void ExtensionKhrDracoMeshCompressionJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { - std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionKhrDracoMeshCompression()) - .first->second; + return this->readObjectKeyExtensionKhrDracoMeshCompression( + CesiumGltf::ExtensionKhrDracoMeshCompression::TypeName, + str, + *this->_pObject); +} + +void ExtensionKhrDracoMeshCompressionJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { + std::any& value = o.extensions + .emplace( + extensionName, + CesiumGltf::ExtensionKhrDracoMeshCompression()) + .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionKhrDracoMeshCompressionJsonHandler::readObjectKeyExtensionKhrDracoMeshCompression(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionKhrDracoMeshCompression& o) { +CesiumJsonReader::IJsonHandler* ExtensionKhrDracoMeshCompressionJsonHandler:: + readObjectKeyExtensionKhrDracoMeshCompression( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionKhrDracoMeshCompression& o) { using namespace std::string_literals; - if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); - if ("attributes"s == str) return property("attributes", this->_attributes, o.attributes); + if ("bufferView"s == str) + return property("bufferView", this->_bufferView, o.bufferView); + if ("attributes"s == str) + return property("attributes", this->_attributes, o.attributes); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -522,28 +837,45 @@ CesiumJsonReader::IJsonHandler* ExtensionKhrDracoMeshCompressionJsonHandler::rea namespace CesiumGltfReader { -ExtensionKhrMaterialsUnlitJsonHandler::ExtensionKhrMaterialsUnlitJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context) {} +ExtensionKhrMaterialsUnlitJsonHandler::ExtensionKhrMaterialsUnlitJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context) {} -void ExtensionKhrMaterialsUnlitJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionKhrMaterialsUnlit* pObject) { +void ExtensionKhrMaterialsUnlitJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionKhrMaterialsUnlit* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionKhrMaterialsUnlitJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionKhrMaterialsUnlitJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionKhrMaterialsUnlit(CesiumGltf::ExtensionKhrMaterialsUnlit::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionKhrMaterialsUnlit( + CesiumGltf::ExtensionKhrMaterialsUnlit::TypeName, + str, + *this->_pObject); } -void ExtensionKhrMaterialsUnlitJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionKhrMaterialsUnlitJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionKhrMaterialsUnlit()) + o.extensions + .emplace(extensionName, CesiumGltf::ExtensionKhrMaterialsUnlit()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionKhrMaterialsUnlitJsonHandler::readObjectKeyExtensionKhrMaterialsUnlit(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionKhrMaterialsUnlit& o) { +CesiumJsonReader::IJsonHandler* +ExtensionKhrMaterialsUnlitJsonHandler::readObjectKeyExtensionKhrMaterialsUnlit( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionKhrMaterialsUnlit& o) { using namespace std::string_literals; (void)o; @@ -563,31 +895,52 @@ CesiumJsonReader::IJsonHandler* ExtensionKhrMaterialsUnlitJsonHandler::readObjec namespace CesiumGltfReader { -ExtensionModelKhrMaterialsVariantsJsonHandler::ExtensionModelKhrMaterialsVariantsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _variants(context) {} +ExtensionModelKhrMaterialsVariantsJsonHandler:: + ExtensionModelKhrMaterialsVariantsJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _variants(context) {} -void ExtensionModelKhrMaterialsVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelKhrMaterialsVariants* pObject) { +void ExtensionModelKhrMaterialsVariantsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionModelKhrMaterialsVariants* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionModelKhrMaterialsVariantsJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelKhrMaterialsVariants(CesiumGltf::ExtensionModelKhrMaterialsVariants::TypeName, str, *this->_pObject); -} - -void ExtensionModelKhrMaterialsVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { - std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionModelKhrMaterialsVariants()) - .first->second; + return this->readObjectKeyExtensionModelKhrMaterialsVariants( + CesiumGltf::ExtensionModelKhrMaterialsVariants::TypeName, + str, + *this->_pObject); +} + +void ExtensionModelKhrMaterialsVariantsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { + std::any& value = o.extensions + .emplace( + extensionName, + CesiumGltf::ExtensionModelKhrMaterialsVariants()) + .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsJsonHandler::readObjectKeyExtensionModelKhrMaterialsVariants(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelKhrMaterialsVariants& o) { +CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsJsonHandler:: + readObjectKeyExtensionModelKhrMaterialsVariants( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionModelKhrMaterialsVariants& o) { using namespace std::string_literals; - if ("variants"s == str) return property("variants", this->_variants, o.variants); + if ("variants"s == str) + return property("variants", this->_variants, o.variants); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -604,31 +957,55 @@ CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsJsonHandler::r namespace CesiumGltfReader { -ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _mappings(context) {} +ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler:: + ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _mappings(context) {} -void ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants* pObject) { +void ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariants(CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariants( + CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants::TypeName, + str, + *this->_pObject); } -void ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants()) + o.extensions + .emplace( + extensionName, + CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants()) .first->second; this->reset( pParentHandler, - &std::any_cast(value)); + &std::any_cast( + value)); } -CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler::readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariants(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants& o) { +CesiumJsonReader::IJsonHandler* +ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler:: + readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariants( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariants& o) { using namespace std::string_literals; - if ("mappings"s == str) return property("mappings", this->_mappings, o.mappings); + if ("mappings"s == str) + return property("mappings", this->_mappings, o.mappings); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -645,31 +1022,49 @@ CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHa namespace CesiumGltfReader { -ExtensionKhrTextureBasisuJsonHandler::ExtensionKhrTextureBasisuJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _source() {} +ExtensionKhrTextureBasisuJsonHandler::ExtensionKhrTextureBasisuJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _source() {} -void ExtensionKhrTextureBasisuJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionKhrTextureBasisu* pObject) { +void ExtensionKhrTextureBasisuJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionKhrTextureBasisu* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionKhrTextureBasisuJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionKhrTextureBasisuJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionKhrTextureBasisu(CesiumGltf::ExtensionKhrTextureBasisu::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionKhrTextureBasisu( + CesiumGltf::ExtensionKhrTextureBasisu::TypeName, + str, + *this->_pObject); } -void ExtensionKhrTextureBasisuJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionKhrTextureBasisuJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionKhrTextureBasisu()) + o.extensions + .emplace(extensionName, CesiumGltf::ExtensionKhrTextureBasisu()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionKhrTextureBasisuJsonHandler::readObjectKeyExtensionKhrTextureBasisu(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionKhrTextureBasisu& o) { +CesiumJsonReader::IJsonHandler* +ExtensionKhrTextureBasisuJsonHandler::readObjectKeyExtensionKhrTextureBasisu( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionKhrTextureBasisu& o) { using namespace std::string_literals; - if ("source"s == str) return property("source", this->_source, o.source); + if ("source"s == str) + return property("source", this->_source, o.source); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -686,32 +1081,54 @@ CesiumJsonReader::IJsonHandler* ExtensionKhrTextureBasisuJsonHandler::readObject namespace CesiumGltfReader { -ExtensionModelMaxarMeshVariantsJsonHandler::ExtensionModelMaxarMeshVariantsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _defaultProperty(), _variants(context) {} +ExtensionModelMaxarMeshVariantsJsonHandler:: + ExtensionModelMaxarMeshVariantsJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _defaultProperty(), + _variants(context) {} -void ExtensionModelMaxarMeshVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelMaxarMeshVariants* pObject) { +void ExtensionModelMaxarMeshVariantsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionModelMaxarMeshVariants* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionModelMaxarMeshVariantsJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelMaxarMeshVariants(CesiumGltf::ExtensionModelMaxarMeshVariants::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionModelMaxarMeshVariants( + CesiumGltf::ExtensionModelMaxarMeshVariants::TypeName, + str, + *this->_pObject); } -void ExtensionModelMaxarMeshVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionModelMaxarMeshVariantsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionModelMaxarMeshVariants()) + o.extensions + .emplace(extensionName, CesiumGltf::ExtensionModelMaxarMeshVariants()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsJsonHandler::readObjectKeyExtensionModelMaxarMeshVariants(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelMaxarMeshVariants& o) { +CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsJsonHandler:: + readObjectKeyExtensionModelMaxarMeshVariants( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionModelMaxarMeshVariants& o) { using namespace std::string_literals; - if ("default"s == str) return property("default", this->_defaultProperty, o.defaultProperty); - if ("variants"s == str) return property("variants", this->_variants, o.variants); + if ("default"s == str) + return property("default", this->_defaultProperty, o.defaultProperty); + if ("variants"s == str) + return property("variants", this->_variants, o.variants); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -728,31 +1145,51 @@ CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsJsonHandler::read namespace CesiumGltfReader { -ExtensionNodeMaxarMeshVariantsJsonHandler::ExtensionNodeMaxarMeshVariantsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _mappings(context) {} +ExtensionNodeMaxarMeshVariantsJsonHandler:: + ExtensionNodeMaxarMeshVariantsJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _mappings(context) {} -void ExtensionNodeMaxarMeshVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionNodeMaxarMeshVariants* pObject) { +void ExtensionNodeMaxarMeshVariantsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionNodeMaxarMeshVariants* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionNodeMaxarMeshVariantsJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionNodeMaxarMeshVariants(CesiumGltf::ExtensionNodeMaxarMeshVariants::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionNodeMaxarMeshVariants( + CesiumGltf::ExtensionNodeMaxarMeshVariants::TypeName, + str, + *this->_pObject); } -void ExtensionNodeMaxarMeshVariantsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionNodeMaxarMeshVariantsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionNodeMaxarMeshVariants()) + o.extensions + .emplace(extensionName, CesiumGltf::ExtensionNodeMaxarMeshVariants()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsJsonHandler::readObjectKeyExtensionNodeMaxarMeshVariants(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionNodeMaxarMeshVariants& o) { +CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsJsonHandler:: + readObjectKeyExtensionNodeMaxarMeshVariants( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionNodeMaxarMeshVariants& o) { using namespace std::string_literals; - if ("mappings"s == str) return property("mappings", this->_mappings, o.mappings); + if ("mappings"s == str) + return property("mappings", this->_mappings, o.mappings); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -769,34 +1206,60 @@ CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsJsonHandler::readO namespace CesiumGltfReader { -ExtensionKhrTextureTransformJsonHandler::ExtensionKhrTextureTransformJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _offset(), _rotation(), _scale(), _texCoord() {} - -void ExtensionKhrTextureTransformJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionKhrTextureTransform* pObject) { +ExtensionKhrTextureTransformJsonHandler:: + ExtensionKhrTextureTransformJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _offset(), + _rotation(), + _scale(), + _texCoord() {} + +void ExtensionKhrTextureTransformJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionKhrTextureTransform* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionKhrTextureTransformJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionKhrTextureTransformJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionKhrTextureTransform(CesiumGltf::ExtensionKhrTextureTransform::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionKhrTextureTransform( + CesiumGltf::ExtensionKhrTextureTransform::TypeName, + str, + *this->_pObject); } -void ExtensionKhrTextureTransformJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionKhrTextureTransformJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = - o.extensions.emplace(extensionName, CesiumGltf::ExtensionKhrTextureTransform()) + o.extensions + .emplace(extensionName, CesiumGltf::ExtensionKhrTextureTransform()) .first->second; this->reset( pParentHandler, &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionKhrTextureTransformJsonHandler::readObjectKeyExtensionKhrTextureTransform(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionKhrTextureTransform& o) { +CesiumJsonReader::IJsonHandler* ExtensionKhrTextureTransformJsonHandler:: + readObjectKeyExtensionKhrTextureTransform( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionKhrTextureTransform& o) { using namespace std::string_literals; - if ("offset"s == str) return property("offset", this->_offset, o.offset); - if ("rotation"s == str) return property("rotation", this->_rotation, o.rotation); - if ("scale"s == str) return property("scale", this->_scale, o.scale); - if ("texCoord"s == str) return property("texCoord", this->_texCoord, o.texCoord); + if ("offset"s == str) + return property("offset", this->_offset, o.offset); + if ("rotation"s == str) + return property("rotation", this->_rotation, o.rotation); + if ("scale"s == str) + return property("scale", this->_scale, o.scale); + if ("texCoord"s == str) + return property("texCoord", this->_texCoord, o.texCoord); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -813,19 +1276,30 @@ CesiumJsonReader::IJsonHandler* ExtensionKhrTextureTransformJsonHandler::readObj namespace CesiumGltfReader { -ExtensionTextureWebpJsonHandler::ExtensionTextureWebpJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _source() {} +ExtensionTextureWebpJsonHandler::ExtensionTextureWebpJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _source() {} -void ExtensionTextureWebpJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionTextureWebp* pObject) { +void ExtensionTextureWebpJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionTextureWebp* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionTextureWebpJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionTextureWebpJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionTextureWebp(CesiumGltf::ExtensionTextureWebp::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionTextureWebp( + CesiumGltf::ExtensionTextureWebp::TypeName, + str, + *this->_pObject); } -void ExtensionTextureWebpJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumUtility::ExtensibleObject& o, const std::string_view& extensionName) { +void ExtensionTextureWebpJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumUtility::ExtensibleObject& o, + const std::string_view& extensionName) { std::any& value = o.extensions.emplace(extensionName, CesiumGltf::ExtensionTextureWebp()) .first->second; @@ -834,10 +1308,15 @@ void ExtensionTextureWebpJsonHandler::reset(CesiumJsonReader::IJsonHandler* pPar &std::any_cast(value)); } -CesiumJsonReader::IJsonHandler* ExtensionTextureWebpJsonHandler::readObjectKeyExtensionTextureWebp(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionTextureWebp& o) { +CesiumJsonReader::IJsonHandler* +ExtensionTextureWebpJsonHandler::readObjectKeyExtensionTextureWebp( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionTextureWebp& o) { using namespace std::string_literals; - if ("source"s == str) return property("source", this->_source, o.source); + if ("source"s == str) + return property("source", this->_source, o.source); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -854,24 +1333,45 @@ CesiumJsonReader::IJsonHandler* ExtensionTextureWebpJsonHandler::readObjectKeyEx namespace CesiumGltfReader { -ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _variants(), _mesh(), _name() {} - -void ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue* pObject) { +ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler:: + ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _variants(), + _mesh(), + _name() {} + +void ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionNodeMaxarMeshVariantsMappingsValue(CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler::readObjectKeyExtensionNodeMaxarMeshVariantsMappingsValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue& o) { + return this->readObjectKeyExtensionNodeMaxarMeshVariantsMappingsValue( + CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionNodeMaxarMeshVariantsMappingsValueJsonHandler:: + readObjectKeyExtensionNodeMaxarMeshVariantsMappingsValue( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionNodeMaxarMeshVariantsMappingsValue& o) { using namespace std::string_literals; - if ("variants"s == str) return property("variants", this->_variants, o.variants); - if ("mesh"s == str) return property("mesh", this->_mesh, o.mesh); - if ("name"s == str) return property("name", this->_name, o.name); + if ("variants"s == str) + return property("variants", this->_variants, o.variants); + if ("mesh"s == str) + return property("mesh", this->_mesh, o.mesh); + if ("name"s == str) + return property("name", this->_name, o.name); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -888,22 +1388,38 @@ CesiumJsonReader::IJsonHandler* ExtensionNodeMaxarMeshVariantsMappingsValueJsonH namespace CesiumGltfReader { -ExtensionModelMaxarMeshVariantsValueJsonHandler::ExtensionModelMaxarMeshVariantsValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _name() {} +ExtensionModelMaxarMeshVariantsValueJsonHandler:: + ExtensionModelMaxarMeshVariantsValueJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), _name() {} -void ExtensionModelMaxarMeshVariantsValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelMaxarMeshVariantsValue* pObject) { +void ExtensionModelMaxarMeshVariantsValueJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionModelMaxarMeshVariantsValue* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsValueJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionModelMaxarMeshVariantsValueJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelMaxarMeshVariantsValue(CesiumGltf::ExtensionModelMaxarMeshVariantsValue::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsValueJsonHandler::readObjectKeyExtensionModelMaxarMeshVariantsValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelMaxarMeshVariantsValue& o) { + return this->readObjectKeyExtensionModelMaxarMeshVariantsValue( + CesiumGltf::ExtensionModelMaxarMeshVariantsValue::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionModelMaxarMeshVariantsValueJsonHandler:: + readObjectKeyExtensionModelMaxarMeshVariantsValue( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionModelMaxarMeshVariantsValue& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); + if ("name"s == str) + return property("name", this->_name, o.name); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -920,24 +1436,49 @@ CesiumJsonReader::IJsonHandler* ExtensionModelMaxarMeshVariantsValueJsonHandler: namespace CesiumGltfReader { -ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _variants(), _material(), _name() {} - -void ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue* pObject) { +ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler:: + ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _variants(), + _material(), + _name() {} + +void ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue* + pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler:: + readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue(CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler::readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue& o) { + return this + ->readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue( + CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue:: + TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValueJsonHandler:: + readObjectKeyExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue& + o) { using namespace std::string_literals; - if ("variants"s == str) return property("variants", this->_variants, o.variants); - if ("material"s == str) return property("material", this->_material, o.material); - if ("name"s == str) return property("name", this->_name, o.name); + if ("variants"s == str) + return property("variants", this->_variants, o.variants); + if ("material"s == str) + return property("material", this->_material, o.material); + if ("name"s == str) + return property("name", this->_name, o.name); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -954,22 +1495,38 @@ CesiumJsonReader::IJsonHandler* ExtensionMeshPrimitiveKhrMaterialsVariantsMappin namespace CesiumGltfReader { -ExtensionModelKhrMaterialsVariantsValueJsonHandler::ExtensionModelKhrMaterialsVariantsValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _name() {} +ExtensionModelKhrMaterialsVariantsValueJsonHandler:: + ExtensionModelKhrMaterialsVariantsValueJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), _name() {} -void ExtensionModelKhrMaterialsVariantsValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionModelKhrMaterialsVariantsValue* pObject) { +void ExtensionModelKhrMaterialsVariantsValueJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionModelKhrMaterialsVariantsValue* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsValueJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionModelKhrMaterialsVariantsValueJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionModelKhrMaterialsVariantsValue(CesiumGltf::ExtensionModelKhrMaterialsVariantsValue::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsValueJsonHandler::readObjectKeyExtensionModelKhrMaterialsVariantsValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionModelKhrMaterialsVariantsValue& o) { + return this->readObjectKeyExtensionModelKhrMaterialsVariantsValue( + CesiumGltf::ExtensionModelKhrMaterialsVariantsValue::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionModelKhrMaterialsVariantsValueJsonHandler:: + readObjectKeyExtensionModelKhrMaterialsVariantsValue( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionModelKhrMaterialsVariantsValue& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); + if ("name"s == str) + return property("name", this->_name, o.name); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -986,24 +1543,45 @@ CesiumJsonReader::IJsonHandler* ExtensionModelKhrMaterialsVariantsValueJsonHandl namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::ExtensionExtStructuralMetadataPropertyAttributeJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _classProperty(), _properties(context) {} - -void ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute* pObject) { +ExtensionExtStructuralMetadataPropertyAttributeJsonHandler:: + ExtensionExtStructuralMetadataPropertyAttributeJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _classProperty(), + _properties(context) {} + +void ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyAttribute(CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyAttribute(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute& o) { + return this->readObjectKeyExtensionExtStructuralMetadataPropertyAttribute( + CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyAttributeJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataPropertyAttribute( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("class"s == str) return property("class", this->_classProperty, o.classProperty); - if ("properties"s == str) return property("properties", this->_properties, o.properties); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("class"s == str) + return property("class", this->_classProperty, o.classProperty); + if ("properties"s == str) + return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1020,26 +1598,55 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyAttributeJ namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attribute(), _offset(), _scale(), _max(), _min() {} - -void ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty* pObject) { +ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: + ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _attribute(), + _offset(), + _scale(), + _max(), + _min() {} + +void ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty* + pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: + readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty(CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty& o) { + return this + ->readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty( + CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty:: + TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty& + o) { using namespace std::string_literals; - if ("attribute"s == str) return property("attribute", this->_attribute, o.attribute); - if ("offset"s == str) return property("offset", this->_offset, o.offset); - if ("scale"s == str) return property("scale", this->_scale, o.scale); - if ("max"s == str) return property("max", this->_max, o.max); - if ("min"s == str) return property("min", this->_min, o.min); + if ("attribute"s == str) + return property("attribute", this->_attribute, o.attribute); + if ("offset"s == str) + return property("offset", this->_offset, o.offset); + if ("scale"s == str) + return property("scale", this->_scale, o.scale); + if ("max"s == str) + return property("max", this->_max, o.max); + if ("min"s == str) + return property("min", this->_min, o.min); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1056,24 +1663,45 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyAttributeP namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTextureJsonHandler::ExtensionExtStructuralMetadataPropertyTextureJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _classProperty(), _properties(context) {} - -void ExtensionExtStructuralMetadataPropertyTextureJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture* pObject) { +ExtensionExtStructuralMetadataPropertyTextureJsonHandler:: + ExtensionExtStructuralMetadataPropertyTextureJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _classProperty(), + _properties(context) {} + +void ExtensionExtStructuralMetadataPropertyTextureJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTextureJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyTextureJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyTexture(CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTextureJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyTexture(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture& o) { + return this->readObjectKeyExtensionExtStructuralMetadataPropertyTexture( + CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyTextureJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataPropertyTexture( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("class"s == str) return property("class", this->_classProperty, o.classProperty); - if ("properties"s == str) return property("properties", this->_properties, o.properties); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("class"s == str) + return property("class", this->_classProperty, o.classProperty); + if ("properties"s == str) + return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1090,26 +1718,54 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTextureJso namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : TextureInfoJsonHandler(context), _channels(), _offset(), _scale(), _max(), _min() {} - -void ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty* pObject) { +ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler:: + ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : TextureInfoJsonHandler(context), + _channels(), + _offset(), + _scale(), + _max(), + _min() {} + +void ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty* + pObject) { TextureInfoJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty(CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty& o) { + return this + ->readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty( + CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty:: + TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty& o) { using namespace std::string_literals; - if ("channels"s == str) return property("channels", this->_channels, o.channels); - if ("offset"s == str) return property("offset", this->_offset, o.offset); - if ("scale"s == str) return property("scale", this->_scale, o.scale); - if ("max"s == str) return property("max", this->_max, o.max); - if ("min"s == str) return property("min", this->_min, o.min); + if ("channels"s == str) + return property("channels", this->_channels, o.channels); + if ("offset"s == str) + return property("offset", this->_offset, o.offset); + if ("scale"s == str) + return property("scale", this->_scale, o.scale); + if ("max"s == str) + return property("max", this->_max, o.max); + if ("min"s == str) + return property("min", this->_min, o.min); return this->readObjectKeyTextureInfo(objectType, str, *this->_pObject); } @@ -1126,23 +1782,39 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTexturePro namespace CesiumGltfReader { -TextureInfoJsonHandler::TextureInfoJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _index(), _texCoord() {} +TextureInfoJsonHandler::TextureInfoJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _index(), + _texCoord() {} -void TextureInfoJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::TextureInfo* pObject) { +void TextureInfoJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::TextureInfo* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* TextureInfoJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +TextureInfoJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyTextureInfo(CesiumGltf::TextureInfo::TypeName, str, *this->_pObject); + return this->readObjectKeyTextureInfo( + CesiumGltf::TextureInfo::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* TextureInfoJsonHandler::readObjectKeyTextureInfo(const std::string& objectType, const std::string_view& str, CesiumGltf::TextureInfo& o) { +CesiumJsonReader::IJsonHandler* +TextureInfoJsonHandler::readObjectKeyTextureInfo( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::TextureInfo& o) { using namespace std::string_literals; - if ("index"s == str) return property("index", this->_index, o.index); - if ("texCoord"s == str) return property("texCoord", this->_texCoord, o.texCoord); + if ("index"s == str) + return property("index", this->_index, o.index); + if ("texCoord"s == str) + return property("texCoord", this->_texCoord, o.texCoord); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1159,25 +1831,48 @@ CesiumJsonReader::IJsonHandler* TextureInfoJsonHandler::readObjectKeyTextureInfo namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTableJsonHandler::ExtensionExtStructuralMetadataPropertyTableJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _classProperty(), _count(), _properties(context) {} - -void ExtensionExtStructuralMetadataPropertyTableJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyTable* pObject) { +ExtensionExtStructuralMetadataPropertyTableJsonHandler:: + ExtensionExtStructuralMetadataPropertyTableJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _classProperty(), + _count(), + _properties(context) {} + +void ExtensionExtStructuralMetadataPropertyTableJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataPropertyTable* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTableJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyTableJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyTable(CesiumGltf::ExtensionExtStructuralMetadataPropertyTable::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTableJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyTable(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyTable& o) { + return this->readObjectKeyExtensionExtStructuralMetadataPropertyTable( + CesiumGltf::ExtensionExtStructuralMetadataPropertyTable::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyTableJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataPropertyTable( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataPropertyTable& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("class"s == str) return property("class", this->_classProperty, o.classProperty); - if ("count"s == str) return property("count", this->_count, o.count); - if ("properties"s == str) return property("properties", this->_properties, o.properties); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("class"s == str) + return property("class", this->_classProperty, o.classProperty); + if ("count"s == str) + return property("count", this->_count, o.count); + if ("properties"s == str) + return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1194,30 +1889,69 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTableJsonH namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _values(), _arrayOffsets(), _stringOffsets(), _arrayOffsetType(), _stringOffsetType(), _offset(), _scale(), _max(), _min() {} - -void ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty* pObject) { +ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler:: + ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _values(), + _arrayOffsets(), + _stringOffsets(), + _arrayOffsetType(), + _stringOffsetType(), + _offset(), + _scale(), + _max(), + _min() {} + +void ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty(CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty& o) { + return this->readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty( + CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty& o) { using namespace std::string_literals; - if ("values"s == str) return property("values", this->_values, o.values); - if ("arrayOffsets"s == str) return property("arrayOffsets", this->_arrayOffsets, o.arrayOffsets); - if ("stringOffsets"s == str) return property("stringOffsets", this->_stringOffsets, o.stringOffsets); - if ("arrayOffsetType"s == str) return property("arrayOffsetType", this->_arrayOffsetType, o.arrayOffsetType); - if ("stringOffsetType"s == str) return property("stringOffsetType", this->_stringOffsetType, o.stringOffsetType); - if ("offset"s == str) return property("offset", this->_offset, o.offset); - if ("scale"s == str) return property("scale", this->_scale, o.scale); - if ("max"s == str) return property("max", this->_max, o.max); - if ("min"s == str) return property("min", this->_min, o.min); + if ("values"s == str) + return property("values", this->_values, o.values); + if ("arrayOffsets"s == str) + return property("arrayOffsets", this->_arrayOffsets, o.arrayOffsets); + if ("stringOffsets"s == str) + return property("stringOffsets", this->_stringOffsets, o.stringOffsets); + if ("arrayOffsetType"s == str) + return property( + "arrayOffsetType", + this->_arrayOffsetType, + o.arrayOffsetType); + if ("stringOffsetType"s == str) + return property( + "stringOffsetType", + this->_stringOffsetType, + o.stringOffsetType); + if ("offset"s == str) + return property("offset", this->_offset, o.offset); + if ("scale"s == str) + return property("scale", this->_scale, o.scale); + if ("max"s == str) + return property("max", this->_max, o.max); + if ("min"s == str) + return property("min", this->_min, o.min); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1234,27 +1968,54 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataPropertyTablePrope namespace CesiumGltfReader { -ExtensionExtStructuralMetadataSchemaJsonHandler::ExtensionExtStructuralMetadataSchemaJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _id(), _name(), _description(), _version(), _classes(context), _enums(context) {} - -void ExtensionExtStructuralMetadataSchemaJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataSchema* pObject) { +ExtensionExtStructuralMetadataSchemaJsonHandler:: + ExtensionExtStructuralMetadataSchemaJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _id(), + _name(), + _description(), + _version(), + _classes(context), + _enums(context) {} + +void ExtensionExtStructuralMetadataSchemaJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataSchema* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataSchemaJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataSchemaJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataSchema(CesiumGltf::ExtensionExtStructuralMetadataSchema::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataSchemaJsonHandler::readObjectKeyExtensionExtStructuralMetadataSchema(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataSchema& o) { + return this->readObjectKeyExtensionExtStructuralMetadataSchema( + CesiumGltf::ExtensionExtStructuralMetadataSchema::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataSchemaJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataSchema( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataSchema& o) { using namespace std::string_literals; - if ("id"s == str) return property("id", this->_id, o.id); - if ("name"s == str) return property("name", this->_name, o.name); - if ("description"s == str) return property("description", this->_description, o.description); - if ("version"s == str) return property("version", this->_version, o.version); - if ("classes"s == str) return property("classes", this->_classes, o.classes); - if ("enums"s == str) return property("enums", this->_enums, o.enums); + if ("id"s == str) + return property("id", this->_id, o.id); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("description"s == str) + return property("description", this->_description, o.description); + if ("version"s == str) + return property("version", this->_version, o.version); + if ("classes"s == str) + return property("classes", this->_classes, o.classes); + if ("enums"s == str) + return property("enums", this->_enums, o.enums); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1271,25 +2032,47 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataSchemaJsonHandler: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataEnumJsonHandler::ExtensionExtStructuralMetadataEnumJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _valueType(), _values(context) {} - -void ExtensionExtStructuralMetadataEnumJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataEnum* pObject) { +ExtensionExtStructuralMetadataEnumJsonHandler:: + ExtensionExtStructuralMetadataEnumJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _description(), + _valueType(), + _values(context) {} + +void ExtensionExtStructuralMetadataEnumJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataEnum* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataEnumJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataEnum(CesiumGltf::ExtensionExtStructuralMetadataEnum::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionExtStructuralMetadataEnum( + CesiumGltf::ExtensionExtStructuralMetadataEnum::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumJsonHandler::readObjectKeyExtensionExtStructuralMetadataEnum(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataEnum& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataEnum( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataEnum& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("description"s == str) return property("description", this->_description, o.description); - if ("valueType"s == str) return property("valueType", this->_valueType, o.valueType); - if ("values"s == str) return property("values", this->_values, o.values); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("description"s == str) + return property("description", this->_description, o.description); + if ("valueType"s == str) + return property("valueType", this->_valueType, o.valueType); + if ("values"s == str) + return property("values", this->_values, o.values); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1306,24 +2089,45 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumJsonHandler::r namespace CesiumGltfReader { -ExtensionExtStructuralMetadataEnumValueJsonHandler::ExtensionExtStructuralMetadataEnumValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _value() {} - -void ExtensionExtStructuralMetadataEnumValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataEnumValue* pObject) { +ExtensionExtStructuralMetadataEnumValueJsonHandler:: + ExtensionExtStructuralMetadataEnumValueJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _description(), + _value() {} + +void ExtensionExtStructuralMetadataEnumValueJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataEnumValue* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumValueJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataEnumValueJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataEnumValue(CesiumGltf::ExtensionExtStructuralMetadataEnumValue::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumValueJsonHandler::readObjectKeyExtensionExtStructuralMetadataEnumValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataEnumValue& o) { + return this->readObjectKeyExtensionExtStructuralMetadataEnumValue( + CesiumGltf::ExtensionExtStructuralMetadataEnumValue::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataEnumValueJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataEnumValue( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataEnumValue& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("description"s == str) return property("description", this->_description, o.description); - if ("value"s == str) return property("value", this->_value, o.value); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("description"s == str) + return property("description", this->_description, o.description); + if ("value"s == str) + return property("value", this->_value, o.value); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1340,24 +2144,44 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumValueJsonHandl namespace CesiumGltfReader { -ExtensionExtStructuralMetadataClassJsonHandler::ExtensionExtStructuralMetadataClassJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _properties(context) {} - -void ExtensionExtStructuralMetadataClassJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataClass* pObject) { +ExtensionExtStructuralMetadataClassJsonHandler:: + ExtensionExtStructuralMetadataClassJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _description(), + _properties(context) {} + +void ExtensionExtStructuralMetadataClassJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataClass* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataClassJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataClass(CesiumGltf::ExtensionExtStructuralMetadataClass::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionExtStructuralMetadataClass( + CesiumGltf::ExtensionExtStructuralMetadataClass::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassJsonHandler::readObjectKeyExtensionExtStructuralMetadataClass(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataClass& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataClass( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataClass& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("description"s == str) return property("description", this->_description, o.description); - if ("properties"s == str) return property("properties", this->_properties, o.properties); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("description"s == str) + return property("description", this->_description, o.description); + if ("properties"s == str) + return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1374,37 +2198,84 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassJsonHandler:: namespace CesiumGltfReader { -ExtensionExtStructuralMetadataClassPropertyJsonHandler::ExtensionExtStructuralMetadataClassPropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _type(), _componentType(), _enumType(), _array(), _count(), _normalized(), _offset(), _scale(), _max(), _min(), _required(), _noData(), _defaultProperty(), _semantic() {} - -void ExtensionExtStructuralMetadataClassPropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtStructuralMetadataClassProperty* pObject) { +ExtensionExtStructuralMetadataClassPropertyJsonHandler:: + ExtensionExtStructuralMetadataClassPropertyJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _description(), + _type(), + _componentType(), + _enumType(), + _array(), + _count(), + _normalized(), + _offset(), + _scale(), + _max(), + _min(), + _required(), + _noData(), + _defaultProperty(), + _semantic() {} + +void ExtensionExtStructuralMetadataClassPropertyJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtStructuralMetadataClassProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassPropertyJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataClassPropertyJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataClassProperty(CesiumGltf::ExtensionExtStructuralMetadataClassProperty::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassPropertyJsonHandler::readObjectKeyExtensionExtStructuralMetadataClassProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtStructuralMetadataClassProperty& o) { + return this->readObjectKeyExtensionExtStructuralMetadataClassProperty( + CesiumGltf::ExtensionExtStructuralMetadataClassProperty::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtStructuralMetadataClassPropertyJsonHandler:: + readObjectKeyExtensionExtStructuralMetadataClassProperty( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtStructuralMetadataClassProperty& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("description"s == str) return property("description", this->_description, o.description); - if ("type"s == str) return property("type", this->_type, o.type); - if ("componentType"s == str) return property("componentType", this->_componentType, o.componentType); - if ("enumType"s == str) return property("enumType", this->_enumType, o.enumType); - if ("array"s == str) return property("array", this->_array, o.array); - if ("count"s == str) return property("count", this->_count, o.count); - if ("normalized"s == str) return property("normalized", this->_normalized, o.normalized); - if ("offset"s == str) return property("offset", this->_offset, o.offset); - if ("scale"s == str) return property("scale", this->_scale, o.scale); - if ("max"s == str) return property("max", this->_max, o.max); - if ("min"s == str) return property("min", this->_min, o.min); - if ("required"s == str) return property("required", this->_required, o.required); - if ("noData"s == str) return property("noData", this->_noData, o.noData); - if ("default"s == str) return property("default", this->_defaultProperty, o.defaultProperty); - if ("semantic"s == str) return property("semantic", this->_semantic, o.semantic); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("description"s == str) + return property("description", this->_description, o.description); + if ("type"s == str) + return property("type", this->_type, o.type); + if ("componentType"s == str) + return property("componentType", this->_componentType, o.componentType); + if ("enumType"s == str) + return property("enumType", this->_enumType, o.enumType); + if ("array"s == str) + return property("array", this->_array, o.array); + if ("count"s == str) + return property("count", this->_count, o.count); + if ("normalized"s == str) + return property("normalized", this->_normalized, o.normalized); + if ("offset"s == str) + return property("offset", this->_offset, o.offset); + if ("scale"s == str) + return property("scale", this->_scale, o.scale); + if ("max"s == str) + return property("max", this->_max, o.max); + if ("min"s == str) + return property("min", this->_min, o.min); + if ("required"s == str) + return property("required", this->_required, o.required); + if ("noData"s == str) + return property("noData", this->_noData, o.noData); + if ("default"s == str) + return property("default", this->_defaultProperty, o.defaultProperty); + if ("semantic"s == str) + return property("semantic", this->_semantic, o.semantic); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1421,27 +2292,50 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassPropertyJsonH namespace CesiumGltfReader { -FeatureIdJsonHandler::FeatureIdJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureCount(), _nullFeatureId(), _label(), _attribute(), _texture(context), _propertyTable() {} - -void FeatureIdJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::FeatureId* pObject) { +FeatureIdJsonHandler::FeatureIdJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _featureCount(), + _nullFeatureId(), + _label(), + _attribute(), + _texture(context), + _propertyTable() {} + +void FeatureIdJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::FeatureId* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* FeatureIdJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +FeatureIdJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyFeatureId(CesiumGltf::FeatureId::TypeName, str, *this->_pObject); + return this->readObjectKeyFeatureId( + CesiumGltf::FeatureId::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* FeatureIdJsonHandler::readObjectKeyFeatureId(const std::string& objectType, const std::string_view& str, CesiumGltf::FeatureId& o) { +CesiumJsonReader::IJsonHandler* FeatureIdJsonHandler::readObjectKeyFeatureId( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::FeatureId& o) { using namespace std::string_literals; - if ("featureCount"s == str) return property("featureCount", this->_featureCount, o.featureCount); - if ("nullFeatureId"s == str) return property("nullFeatureId", this->_nullFeatureId, o.nullFeatureId); - if ("label"s == str) return property("label", this->_label, o.label); - if ("attribute"s == str) return property("attribute", this->_attribute, o.attribute); - if ("texture"s == str) return property("texture", this->_texture, o.texture); - if ("propertyTable"s == str) return property("propertyTable", this->_propertyTable, o.propertyTable); + if ("featureCount"s == str) + return property("featureCount", this->_featureCount, o.featureCount); + if ("nullFeatureId"s == str) + return property("nullFeatureId", this->_nullFeatureId, o.nullFeatureId); + if ("label"s == str) + return property("label", this->_label, o.label); + if ("attribute"s == str) + return property("attribute", this->_attribute, o.attribute); + if ("texture"s == str) + return property("texture", this->_texture, o.texture); + if ("propertyTable"s == str) + return property("propertyTable", this->_propertyTable, o.propertyTable); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1458,22 +2352,35 @@ CesiumJsonReader::IJsonHandler* FeatureIdJsonHandler::readObjectKeyFeatureId(con namespace CesiumGltfReader { -FeatureIdTextureJsonHandler::FeatureIdTextureJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : TextureInfoJsonHandler(context), _channels() {} +FeatureIdTextureJsonHandler::FeatureIdTextureJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : TextureInfoJsonHandler(context), _channels() {} -void FeatureIdTextureJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::FeatureIdTexture* pObject) { +void FeatureIdTextureJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::FeatureIdTexture* pObject) { TextureInfoJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* FeatureIdTextureJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +FeatureIdTextureJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyFeatureIdTexture(CesiumGltf::FeatureIdTexture::TypeName, str, *this->_pObject); + return this->readObjectKeyFeatureIdTexture( + CesiumGltf::FeatureIdTexture::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* FeatureIdTextureJsonHandler::readObjectKeyFeatureIdTexture(const std::string& objectType, const std::string_view& str, CesiumGltf::FeatureIdTexture& o) { +CesiumJsonReader::IJsonHandler* +FeatureIdTextureJsonHandler::readObjectKeyFeatureIdTexture( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::FeatureIdTexture& o) { using namespace std::string_literals; - if ("channels"s == str) return property("channels", this->_channels, o.channels); + if ("channels"s == str) + return property("channels", this->_channels, o.channels); return this->readObjectKeyTextureInfo(objectType, str, *this->_pObject); } @@ -1490,26 +2397,51 @@ CesiumJsonReader::IJsonHandler* FeatureIdTextureJsonHandler::readObjectKeyFeatur namespace CesiumGltfReader { -ExtensionExtInstanceFeaturesFeatureIdJsonHandler::ExtensionExtInstanceFeaturesFeatureIdJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureCount(), _nullFeatureId(), _label(), _attribute(), _propertyTable() {} - -void ExtensionExtInstanceFeaturesFeatureIdJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtInstanceFeaturesFeatureId* pObject) { +ExtensionExtInstanceFeaturesFeatureIdJsonHandler:: + ExtensionExtInstanceFeaturesFeatureIdJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _featureCount(), + _nullFeatureId(), + _label(), + _attribute(), + _propertyTable() {} + +void ExtensionExtInstanceFeaturesFeatureIdJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtInstanceFeaturesFeatureId* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesFeatureIdJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtInstanceFeaturesFeatureIdJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtInstanceFeaturesFeatureId(CesiumGltf::ExtensionExtInstanceFeaturesFeatureId::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesFeatureIdJsonHandler::readObjectKeyExtensionExtInstanceFeaturesFeatureId(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtInstanceFeaturesFeatureId& o) { + return this->readObjectKeyExtensionExtInstanceFeaturesFeatureId( + CesiumGltf::ExtensionExtInstanceFeaturesFeatureId::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtInstanceFeaturesFeatureIdJsonHandler:: + readObjectKeyExtensionExtInstanceFeaturesFeatureId( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtInstanceFeaturesFeatureId& o) { using namespace std::string_literals; - if ("featureCount"s == str) return property("featureCount", this->_featureCount, o.featureCount); - if ("nullFeatureId"s == str) return property("nullFeatureId", this->_nullFeatureId, o.nullFeatureId); - if ("label"s == str) return property("label", this->_label, o.label); - if ("attribute"s == str) return property("attribute", this->_attribute, o.attribute); - if ("propertyTable"s == str) return property("propertyTable", this->_propertyTable, o.propertyTable); + if ("featureCount"s == str) + return property("featureCount", this->_featureCount, o.featureCount); + if ("nullFeatureId"s == str) + return property("nullFeatureId", this->_nullFeatureId, o.nullFeatureId); + if ("label"s == str) + return property("label", this->_label, o.label); + if ("attribute"s == str) + return property("attribute", this->_attribute, o.attribute); + if ("propertyTable"s == str) + return property("propertyTable", this->_propertyTable, o.propertyTable); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1526,23 +2458,42 @@ CesiumJsonReader::IJsonHandler* ExtensionExtInstanceFeaturesFeatureIdJsonHandler namespace CesiumGltfReader { -ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler::ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureTable(), _featureIds(context) {} +ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler:: + ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _featureTable(), + _featureIds(context) {} -void ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture* pObject) { +void ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataFeatureIDTexture(CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureIDTexture(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture& o) { + return this->readObjectKeyExtensionExtFeatureMetadataFeatureIDTexture( + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureIDTextureJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataFeatureIDTexture( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDTexture& o) { using namespace std::string_literals; - if ("featureTable"s == str) return property("featureTable", this->_featureTable, o.featureTable); - if ("featureIds"s == str) return property("featureIds", this->_featureIds, o.featureIds); + if ("featureTable"s == str) + return property("featureTable", this->_featureTable, o.featureTable); + if ("featureIds"s == str) + return property("featureIds", this->_featureIds, o.featureIds); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1559,23 +2510,42 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDTextureJsonH namespace CesiumGltfReader { -ExtensionExtFeatureMetadataTextureAccessorJsonHandler::ExtensionExtFeatureMetadataTextureAccessorJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _channels(), _texture(context) {} +ExtensionExtFeatureMetadataTextureAccessorJsonHandler:: + ExtensionExtFeatureMetadataTextureAccessorJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _channels(), + _texture(context) {} -void ExtensionExtFeatureMetadataTextureAccessorJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor* pObject) { +void ExtensionExtFeatureMetadataTextureAccessorJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataTextureAccessorJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataTextureAccessorJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataTextureAccessor(CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataTextureAccessorJsonHandler::readObjectKeyExtensionExtFeatureMetadataTextureAccessor(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor& o) { + return this->readObjectKeyExtensionExtFeatureMetadataTextureAccessor( + CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataTextureAccessorJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataTextureAccessor( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataTextureAccessor& o) { using namespace std::string_literals; - if ("channels"s == str) return property("channels", this->_channels, o.channels); - if ("texture"s == str) return property("texture", this->_texture, o.texture); + if ("channels"s == str) + return property("channels", this->_channels, o.channels); + if ("texture"s == str) + return property("texture", this->_texture, o.texture); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1592,23 +2562,42 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataTextureAccessorJsonHa namespace CesiumGltfReader { -ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler::ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _featureTable(), _featureIds(context) {} +ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler:: + ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _featureTable(), + _featureIds(context) {} -void ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute* pObject) { +void ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataFeatureIDAttribute(CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureIDAttribute(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute& o) { + return this->readObjectKeyExtensionExtFeatureMetadataFeatureIDAttribute( + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureIDAttributeJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataFeatureIDAttribute( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDAttribute& o) { using namespace std::string_literals; - if ("featureTable"s == str) return property("featureTable", this->_featureTable, o.featureTable); - if ("featureIds"s == str) return property("featureIds", this->_featureIds, o.featureIds); + if ("featureTable"s == str) + return property("featureTable", this->_featureTable, o.featureTable); + if ("featureIds"s == str) + return property("featureIds", this->_featureIds, o.featureIds); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1625,24 +2614,45 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDAttributeJso namespace CesiumGltfReader { -ExtensionExtFeatureMetadataFeatureIDsJsonHandler::ExtensionExtFeatureMetadataFeatureIDsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attribute(), _constant(), _divisor() {} - -void ExtensionExtFeatureMetadataFeatureIDsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs* pObject) { +ExtensionExtFeatureMetadataFeatureIDsJsonHandler:: + ExtensionExtFeatureMetadataFeatureIDsJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _attribute(), + _constant(), + _divisor() {} + +void ExtensionExtFeatureMetadataFeatureIDsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureIDsJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataFeatureIDs(CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDsJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureIDs(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs& o) { + return this->readObjectKeyExtensionExtFeatureMetadataFeatureIDs( + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureIDsJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataFeatureIDs( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataFeatureIDs& o) { using namespace std::string_literals; - if ("attribute"s == str) return property("attribute", this->_attribute, o.attribute); - if ("constant"s == str) return property("constant", this->_constant, o.constant); - if ("divisor"s == str) return property("divisor", this->_divisor, o.divisor); + if ("attribute"s == str) + return property("attribute", this->_attribute, o.attribute); + if ("constant"s == str) + return property("constant", this->_constant, o.constant); + if ("divisor"s == str) + return property("divisor", this->_divisor, o.divisor); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1659,23 +2669,42 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureIDsJsonHandler namespace CesiumGltfReader { -ExtensionExtFeatureMetadataFeatureTextureJsonHandler::ExtensionExtFeatureMetadataFeatureTextureJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _classProperty(), _properties(context) {} +ExtensionExtFeatureMetadataFeatureTextureJsonHandler:: + ExtensionExtFeatureMetadataFeatureTextureJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _classProperty(), + _properties(context) {} -void ExtensionExtFeatureMetadataFeatureTextureJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture* pObject) { +void ExtensionExtFeatureMetadataFeatureTextureJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTextureJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureTextureJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataFeatureTexture(CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTextureJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureTexture(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture& o) { + return this->readObjectKeyExtensionExtFeatureMetadataFeatureTexture( + CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureTextureJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataFeatureTexture( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTexture& o) { using namespace std::string_literals; - if ("class"s == str) return property("class", this->_classProperty, o.classProperty); - if ("properties"s == str) return property("properties", this->_properties, o.properties); + if ("class"s == str) + return property("class", this->_classProperty, o.classProperty); + if ("properties"s == str) + return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1692,24 +2721,45 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTextureJsonHan namespace CesiumGltfReader { -ExtensionExtFeatureMetadataFeatureTableJsonHandler::ExtensionExtFeatureMetadataFeatureTableJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _classProperty(), _count(), _properties(context) {} - -void ExtensionExtFeatureMetadataFeatureTableJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureTable* pObject) { +ExtensionExtFeatureMetadataFeatureTableJsonHandler:: + ExtensionExtFeatureMetadataFeatureTableJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _classProperty(), + _count(), + _properties(context) {} + +void ExtensionExtFeatureMetadataFeatureTableJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTable* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTableJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureTableJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataFeatureTable(CesiumGltf::ExtensionExtFeatureMetadataFeatureTable::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTableJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureTable(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureTable& o) { + return this->readObjectKeyExtensionExtFeatureMetadataFeatureTable( + CesiumGltf::ExtensionExtFeatureMetadataFeatureTable::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureTableJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataFeatureTable( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTable& o) { using namespace std::string_literals; - if ("class"s == str) return property("class", this->_classProperty, o.classProperty); - if ("count"s == str) return property("count", this->_count, o.count); - if ("properties"s == str) return property("properties", this->_properties, o.properties); + if ("class"s == str) + return property("class", this->_classProperty, o.classProperty); + if ("count"s == str) + return property("count", this->_count, o.count); + if ("properties"s == str) + return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1726,25 +2776,54 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTableJsonHandl namespace CesiumGltfReader { -ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler::ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _bufferView(), _offsetType(), _arrayOffsetBufferView(), _stringOffsetBufferView() {} - -void ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty* pObject) { +ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler:: + ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _bufferView(), + _offsetType(), + _arrayOffsetBufferView(), + _stringOffsetBufferView() {} + +void ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataFeatureTableProperty(CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler::readObjectKeyExtensionExtFeatureMetadataFeatureTableProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty& o) { + return this->readObjectKeyExtensionExtFeatureMetadataFeatureTableProperty( + CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataFeatureTablePropertyJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataFeatureTableProperty( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataFeatureTableProperty& o) { using namespace std::string_literals; - if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); - if ("offsetType"s == str) return property("offsetType", this->_offsetType, o.offsetType); - if ("arrayOffsetBufferView"s == str) return property("arrayOffsetBufferView", this->_arrayOffsetBufferView, o.arrayOffsetBufferView); - if ("stringOffsetBufferView"s == str) return property("stringOffsetBufferView", this->_stringOffsetBufferView, o.stringOffsetBufferView); + if ("bufferView"s == str) + return property("bufferView", this->_bufferView, o.bufferView); + if ("offsetType"s == str) + return property("offsetType", this->_offsetType, o.offsetType); + if ("arrayOffsetBufferView"s == str) + return property( + "arrayOffsetBufferView", + this->_arrayOffsetBufferView, + o.arrayOffsetBufferView); + if ("stringOffsetBufferView"s == str) + return property( + "stringOffsetBufferView", + this->_stringOffsetBufferView, + o.stringOffsetBufferView); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1761,22 +2840,39 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataFeatureTablePropertyJ namespace CesiumGltfReader { -ExtensionExtFeatureMetadataStatisticsJsonHandler::ExtensionExtFeatureMetadataStatisticsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _classes(context) {} +ExtensionExtFeatureMetadataStatisticsJsonHandler:: + ExtensionExtFeatureMetadataStatisticsJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _classes(context) {} -void ExtensionExtFeatureMetadataStatisticsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataStatistics* pObject) { +void ExtensionExtFeatureMetadataStatisticsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataStatistics* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataStatisticsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataStatisticsJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataStatistics(CesiumGltf::ExtensionExtFeatureMetadataStatistics::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataStatisticsJsonHandler::readObjectKeyExtensionExtFeatureMetadataStatistics(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataStatistics& o) { + return this->readObjectKeyExtensionExtFeatureMetadataStatistics( + CesiumGltf::ExtensionExtFeatureMetadataStatistics::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataStatisticsJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataStatistics( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataStatistics& o) { using namespace std::string_literals; - if ("classes"s == str) return property("classes", this->_classes, o.classes); + if ("classes"s == str) + return property("classes", this->_classes, o.classes); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1793,23 +2889,42 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataStatisticsJsonHandler namespace CesiumGltfReader { -ExtensionExtFeatureMetadataClassStatisticsJsonHandler::ExtensionExtFeatureMetadataClassStatisticsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _count(), _properties(context) {} +ExtensionExtFeatureMetadataClassStatisticsJsonHandler:: + ExtensionExtFeatureMetadataClassStatisticsJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _count(), + _properties(context) {} -void ExtensionExtFeatureMetadataClassStatisticsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataClassStatistics* pObject) { +void ExtensionExtFeatureMetadataClassStatisticsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataClassStatistics* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassStatisticsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataClassStatisticsJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataClassStatistics(CesiumGltf::ExtensionExtFeatureMetadataClassStatistics::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassStatisticsJsonHandler::readObjectKeyExtensionExtFeatureMetadataClassStatistics(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataClassStatistics& o) { + return this->readObjectKeyExtensionExtFeatureMetadataClassStatistics( + CesiumGltf::ExtensionExtFeatureMetadataClassStatistics::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataClassStatisticsJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataClassStatistics( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataClassStatistics& o) { using namespace std::string_literals; - if ("count"s == str) return property("count", this->_count, o.count); - if ("properties"s == str) return property("properties", this->_properties, o.properties); + if ("count"s == str) + return property("count", this->_count, o.count); + if ("properties"s == str) + return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1826,29 +2941,63 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassStatisticsJsonHa namespace CesiumGltfReader { -ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler::ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _min(), _max(), _mean(), _median(), _standardDeviation(), _variance(), _sum(), _occurrences() {} - -void ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics* pObject) { +ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler:: + ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _min(), + _max(), + _mean(), + _median(), + _standardDeviation(), + _variance(), + _sum(), + _occurrences() {} + +void ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataPropertyStatistics(CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler::readObjectKeyExtensionExtFeatureMetadataPropertyStatistics(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics& o) { + return this->readObjectKeyExtensionExtFeatureMetadataPropertyStatistics( + CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataPropertyStatisticsJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataPropertyStatistics( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataPropertyStatistics& o) { using namespace std::string_literals; - if ("min"s == str) return property("min", this->_min, o.min); - if ("max"s == str) return property("max", this->_max, o.max); - if ("mean"s == str) return property("mean", this->_mean, o.mean); - if ("median"s == str) return property("median", this->_median, o.median); - if ("standardDeviation"s == str) return property("standardDeviation", this->_standardDeviation, o.standardDeviation); - if ("variance"s == str) return property("variance", this->_variance, o.variance); - if ("sum"s == str) return property("sum", this->_sum, o.sum); - if ("occurrences"s == str) return property("occurrences", this->_occurrences, o.occurrences); + if ("min"s == str) + return property("min", this->_min, o.min); + if ("max"s == str) + return property("max", this->_max, o.max); + if ("mean"s == str) + return property("mean", this->_mean, o.mean); + if ("median"s == str) + return property("median", this->_median, o.median); + if ("standardDeviation"s == str) + return property( + "standardDeviation", + this->_standardDeviation, + o.standardDeviation); + if ("variance"s == str) + return property("variance", this->_variance, o.variance); + if ("sum"s == str) + return property("sum", this->_sum, o.sum); + if ("occurrences"s == str) + return property("occurrences", this->_occurrences, o.occurrences); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1865,26 +3014,50 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataPropertyStatisticsJso namespace CesiumGltfReader { -ExtensionExtFeatureMetadataSchemaJsonHandler::ExtensionExtFeatureMetadataSchemaJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _version(), _classes(context), _enums(context) {} - -void ExtensionExtFeatureMetadataSchemaJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataSchema* pObject) { +ExtensionExtFeatureMetadataSchemaJsonHandler:: + ExtensionExtFeatureMetadataSchemaJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _description(), + _version(), + _classes(context), + _enums(context) {} + +void ExtensionExtFeatureMetadataSchemaJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataSchema* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataSchemaJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataSchemaJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataSchema(CesiumGltf::ExtensionExtFeatureMetadataSchema::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataSchema( + CesiumGltf::ExtensionExtFeatureMetadataSchema::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataSchemaJsonHandler::readObjectKeyExtensionExtFeatureMetadataSchema(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataSchema& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataSchemaJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataSchema( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataSchema& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("description"s == str) return property("description", this->_description, o.description); - if ("version"s == str) return property("version", this->_version, o.version); - if ("classes"s == str) return property("classes", this->_classes, o.classes); - if ("enums"s == str) return property("enums", this->_enums, o.enums); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("description"s == str) + return property("description", this->_description, o.description); + if ("version"s == str) + return property("version", this->_version, o.version); + if ("classes"s == str) + return property("classes", this->_classes, o.classes); + if ("enums"s == str) + return property("enums", this->_enums, o.enums); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1901,25 +3074,47 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataSchemaJsonHandler::re namespace CesiumGltfReader { -ExtensionExtFeatureMetadataEnumJsonHandler::ExtensionExtFeatureMetadataEnumJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _valueType(), _values(context) {} - -void ExtensionExtFeatureMetadataEnumJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataEnum* pObject) { +ExtensionExtFeatureMetadataEnumJsonHandler:: + ExtensionExtFeatureMetadataEnumJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _description(), + _valueType(), + _values(context) {} + +void ExtensionExtFeatureMetadataEnumJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataEnum* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataEnumJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataEnum(CesiumGltf::ExtensionExtFeatureMetadataEnum::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataEnum( + CesiumGltf::ExtensionExtFeatureMetadataEnum::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumJsonHandler::readObjectKeyExtensionExtFeatureMetadataEnum(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataEnum& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataEnum( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataEnum& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("description"s == str) return property("description", this->_description, o.description); - if ("valueType"s == str) return property("valueType", this->_valueType, o.valueType); - if ("values"s == str) return property("values", this->_values, o.values); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("description"s == str) + return property("description", this->_description, o.description); + if ("valueType"s == str) + return property("valueType", this->_valueType, o.valueType); + if ("values"s == str) + return property("values", this->_values, o.values); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1936,24 +3131,45 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumJsonHandler::read namespace CesiumGltfReader { -ExtensionExtFeatureMetadataEnumValueJsonHandler::ExtensionExtFeatureMetadataEnumValueJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _value() {} - -void ExtensionExtFeatureMetadataEnumValueJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataEnumValue* pObject) { +ExtensionExtFeatureMetadataEnumValueJsonHandler:: + ExtensionExtFeatureMetadataEnumValueJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _description(), + _value() {} + +void ExtensionExtFeatureMetadataEnumValueJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataEnumValue* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumValueJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataEnumValueJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataEnumValue(CesiumGltf::ExtensionExtFeatureMetadataEnumValue::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumValueJsonHandler::readObjectKeyExtensionExtFeatureMetadataEnumValue(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataEnumValue& o) { + return this->readObjectKeyExtensionExtFeatureMetadataEnumValue( + CesiumGltf::ExtensionExtFeatureMetadataEnumValue::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataEnumValueJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataEnumValue( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataEnumValue& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("description"s == str) return property("description", this->_description, o.description); - if ("value"s == str) return property("value", this->_value, o.value); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("description"s == str) + return property("description", this->_description, o.description); + if ("value"s == str) + return property("value", this->_value, o.value); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -1970,24 +3186,44 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataEnumValueJsonHandler: namespace CesiumGltfReader { -ExtensionExtFeatureMetadataClassJsonHandler::ExtensionExtFeatureMetadataClassJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _properties(context) {} - -void ExtensionExtFeatureMetadataClassJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataClass* pObject) { +ExtensionExtFeatureMetadataClassJsonHandler:: + ExtensionExtFeatureMetadataClassJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _description(), + _properties(context) {} + +void ExtensionExtFeatureMetadataClassJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataClass* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataClassJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataClass(CesiumGltf::ExtensionExtFeatureMetadataClass::TypeName, str, *this->_pObject); + return this->readObjectKeyExtensionExtFeatureMetadataClass( + CesiumGltf::ExtensionExtFeatureMetadataClass::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassJsonHandler::readObjectKeyExtensionExtFeatureMetadataClass(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataClass& o) { +CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataClass( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataClass& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("description"s == str) return property("description", this->_description, o.description); - if ("properties"s == str) return property("properties", this->_properties, o.properties); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("description"s == str) + return property("description", this->_description, o.description); + if ("properties"s == str) + return property("properties", this->_properties, o.properties); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2004,33 +3240,72 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassJsonHandler::rea namespace CesiumGltfReader { -ExtensionExtFeatureMetadataClassPropertyJsonHandler::ExtensionExtFeatureMetadataClassPropertyJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _type(), _enumType(), _componentType(), _componentCount(), _normalized(), _max(), _min(), _defaultProperty(), _optional(), _semantic() {} - -void ExtensionExtFeatureMetadataClassPropertyJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::ExtensionExtFeatureMetadataClassProperty* pObject) { +ExtensionExtFeatureMetadataClassPropertyJsonHandler:: + ExtensionExtFeatureMetadataClassPropertyJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _name(), + _description(), + _type(), + _enumType(), + _componentType(), + _componentCount(), + _normalized(), + _max(), + _min(), + _defaultProperty(), + _optional(), + _semantic() {} + +void ExtensionExtFeatureMetadataClassPropertyJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::ExtensionExtFeatureMetadataClassProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassPropertyJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataClassPropertyJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtFeatureMetadataClassProperty(CesiumGltf::ExtensionExtFeatureMetadataClassProperty::TypeName, str, *this->_pObject); -} - -CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassPropertyJsonHandler::readObjectKeyExtensionExtFeatureMetadataClassProperty(const std::string& objectType, const std::string_view& str, CesiumGltf::ExtensionExtFeatureMetadataClassProperty& o) { + return this->readObjectKeyExtensionExtFeatureMetadataClassProperty( + CesiumGltf::ExtensionExtFeatureMetadataClassProperty::TypeName, + str, + *this->_pObject); +} + +CesiumJsonReader::IJsonHandler* +ExtensionExtFeatureMetadataClassPropertyJsonHandler:: + readObjectKeyExtensionExtFeatureMetadataClassProperty( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ExtensionExtFeatureMetadataClassProperty& o) { using namespace std::string_literals; - if ("name"s == str) return property("name", this->_name, o.name); - if ("description"s == str) return property("description", this->_description, o.description); - if ("type"s == str) return property("type", this->_type, o.type); - if ("enumType"s == str) return property("enumType", this->_enumType, o.enumType); - if ("componentType"s == str) return property("componentType", this->_componentType, o.componentType); - if ("componentCount"s == str) return property("componentCount", this->_componentCount, o.componentCount); - if ("normalized"s == str) return property("normalized", this->_normalized, o.normalized); - if ("max"s == str) return property("max", this->_max, o.max); - if ("min"s == str) return property("min", this->_min, o.min); - if ("default"s == str) return property("default", this->_defaultProperty, o.defaultProperty); - if ("optional"s == str) return property("optional", this->_optional, o.optional); - if ("semantic"s == str) return property("semantic", this->_semantic, o.semantic); + if ("name"s == str) + return property("name", this->_name, o.name); + if ("description"s == str) + return property("description", this->_description, o.description); + if ("type"s == str) + return property("type", this->_type, o.type); + if ("enumType"s == str) + return property("enumType", this->_enumType, o.enumType); + if ("componentType"s == str) + return property("componentType", this->_componentType, o.componentType); + if ("componentCount"s == str) + return property("componentCount", this->_componentCount, o.componentCount); + if ("normalized"s == str) + return property("normalized", this->_normalized, o.normalized); + if ("max"s == str) + return property("max", this->_max, o.max); + if ("min"s == str) + return property("min", this->_min, o.min); + if ("default"s == str) + return property("default", this->_defaultProperty, o.defaultProperty); + if ("optional"s == str) + return property("optional", this->_optional, o.optional); + if ("semantic"s == str) + return property("semantic", this->_semantic, o.semantic); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2047,38 +3322,86 @@ CesiumJsonReader::IJsonHandler* ExtensionExtFeatureMetadataClassPropertyJsonHand namespace CesiumGltfReader { -ModelJsonHandler::ModelJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _extensionsUsed(), _extensionsRequired(), _accessors(context), _animations(context), _asset(context), _buffers(context), _bufferViews(context), _cameras(context), _images(context), _materials(context), _meshes(context), _nodes(context), _samplers(context), _scene(), _scenes(context), _skins(context), _textures(context) {} - -void ModelJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Model* pObject) { +ModelJsonHandler::ModelJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _extensionsUsed(), + _extensionsRequired(), + _accessors(context), + _animations(context), + _asset(context), + _buffers(context), + _bufferViews(context), + _cameras(context), + _images(context), + _materials(context), + _meshes(context), + _nodes(context), + _samplers(context), + _scene(), + _scenes(context), + _skins(context), + _textures(context) {} + +void ModelJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Model* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ModelJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ModelJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyModel(CesiumGltf::Model::TypeName, str, *this->_pObject); + return this->readObjectKeyModel( + CesiumGltf::Model::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* ModelJsonHandler::readObjectKeyModel(const std::string& objectType, const std::string_view& str, CesiumGltf::Model& o) { +CesiumJsonReader::IJsonHandler* ModelJsonHandler::readObjectKeyModel( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Model& o) { using namespace std::string_literals; - if ("extensionsUsed"s == str) return property("extensionsUsed", this->_extensionsUsed, o.extensionsUsed); - if ("extensionsRequired"s == str) return property("extensionsRequired", this->_extensionsRequired, o.extensionsRequired); - if ("accessors"s == str) return property("accessors", this->_accessors, o.accessors); - if ("animations"s == str) return property("animations", this->_animations, o.animations); - if ("asset"s == str) return property("asset", this->_asset, o.asset); - if ("buffers"s == str) return property("buffers", this->_buffers, o.buffers); - if ("bufferViews"s == str) return property("bufferViews", this->_bufferViews, o.bufferViews); - if ("cameras"s == str) return property("cameras", this->_cameras, o.cameras); - if ("images"s == str) return property("images", this->_images, o.images); - if ("materials"s == str) return property("materials", this->_materials, o.materials); - if ("meshes"s == str) return property("meshes", this->_meshes, o.meshes); - if ("nodes"s == str) return property("nodes", this->_nodes, o.nodes); - if ("samplers"s == str) return property("samplers", this->_samplers, o.samplers); - if ("scene"s == str) return property("scene", this->_scene, o.scene); - if ("scenes"s == str) return property("scenes", this->_scenes, o.scenes); - if ("skins"s == str) return property("skins", this->_skins, o.skins); - if ("textures"s == str) return property("textures", this->_textures, o.textures); + if ("extensionsUsed"s == str) + return property("extensionsUsed", this->_extensionsUsed, o.extensionsUsed); + if ("extensionsRequired"s == str) + return property( + "extensionsRequired", + this->_extensionsRequired, + o.extensionsRequired); + if ("accessors"s == str) + return property("accessors", this->_accessors, o.accessors); + if ("animations"s == str) + return property("animations", this->_animations, o.animations); + if ("asset"s == str) + return property("asset", this->_asset, o.asset); + if ("buffers"s == str) + return property("buffers", this->_buffers, o.buffers); + if ("bufferViews"s == str) + return property("bufferViews", this->_bufferViews, o.bufferViews); + if ("cameras"s == str) + return property("cameras", this->_cameras, o.cameras); + if ("images"s == str) + return property("images", this->_images, o.images); + if ("materials"s == str) + return property("materials", this->_materials, o.materials); + if ("meshes"s == str) + return property("meshes", this->_meshes, o.meshes); + if ("nodes"s == str) + return property("nodes", this->_nodes, o.nodes); + if ("samplers"s == str) + return property("samplers", this->_samplers, o.samplers); + if ("scene"s == str) + return property("scene", this->_scene, o.scene); + if ("scenes"s == str) + return property("scenes", this->_scenes, o.scenes); + if ("skins"s == str) + return property("skins", this->_skins, o.skins); + if ("textures"s == str) + return property("textures", this->_textures, o.textures); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2095,23 +3418,38 @@ CesiumJsonReader::IJsonHandler* ModelJsonHandler::readObjectKeyModel(const std:: namespace CesiumGltfReader { -TextureJsonHandler::TextureJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _sampler(), _source() {} +TextureJsonHandler::TextureJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _sampler(), + _source() {} -void TextureJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Texture* pObject) { +void TextureJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Texture* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* TextureJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +TextureJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyTexture(CesiumGltf::Texture::TypeName, str, *this->_pObject); + return this->readObjectKeyTexture( + CesiumGltf::Texture::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* TextureJsonHandler::readObjectKeyTexture(const std::string& objectType, const std::string_view& str, CesiumGltf::Texture& o) { +CesiumJsonReader::IJsonHandler* TextureJsonHandler::readObjectKeyTexture( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Texture& o) { using namespace std::string_literals; - if ("sampler"s == str) return property("sampler", this->_sampler, o.sampler); - if ("source"s == str) return property("source", this->_source, o.source); + if ("sampler"s == str) + return property("sampler", this->_sampler, o.sampler); + if ("source"s == str) + return property("source", this->_source, o.source); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2128,24 +3466,44 @@ CesiumJsonReader::IJsonHandler* TextureJsonHandler::readObjectKeyTexture(const s namespace CesiumGltfReader { -SkinJsonHandler::SkinJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _inverseBindMatrices(), _skeleton(), _joints() {} +SkinJsonHandler::SkinJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _inverseBindMatrices(), + _skeleton(), + _joints() {} -void SkinJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Skin* pObject) { +void SkinJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Skin* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* SkinJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +SkinJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeySkin(CesiumGltf::Skin::TypeName, str, *this->_pObject); + return this->readObjectKeySkin( + CesiumGltf::Skin::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* SkinJsonHandler::readObjectKeySkin(const std::string& objectType, const std::string_view& str, CesiumGltf::Skin& o) { +CesiumJsonReader::IJsonHandler* SkinJsonHandler::readObjectKeySkin( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Skin& o) { using namespace std::string_literals; - if ("inverseBindMatrices"s == str) return property("inverseBindMatrices", this->_inverseBindMatrices, o.inverseBindMatrices); - if ("skeleton"s == str) return property("skeleton", this->_skeleton, o.skeleton); - if ("joints"s == str) return property("joints", this->_joints, o.joints); + if ("inverseBindMatrices"s == str) + return property( + "inverseBindMatrices", + this->_inverseBindMatrices, + o.inverseBindMatrices); + if ("skeleton"s == str) + return property("skeleton", this->_skeleton, o.skeleton); + if ("joints"s == str) + return property("joints", this->_joints, o.joints); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2162,22 +3520,34 @@ CesiumJsonReader::IJsonHandler* SkinJsonHandler::readObjectKeySkin(const std::st namespace CesiumGltfReader { -SceneJsonHandler::SceneJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _nodes() {} +SceneJsonHandler::SceneJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), _nodes() {} -void SceneJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Scene* pObject) { +void SceneJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Scene* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* SceneJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +SceneJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyScene(CesiumGltf::Scene::TypeName, str, *this->_pObject); + return this->readObjectKeyScene( + CesiumGltf::Scene::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* SceneJsonHandler::readObjectKeyScene(const std::string& objectType, const std::string_view& str, CesiumGltf::Scene& o) { +CesiumJsonReader::IJsonHandler* SceneJsonHandler::readObjectKeyScene( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Scene& o) { using namespace std::string_literals; - if ("nodes"s == str) return property("nodes", this->_nodes, o.nodes); + if ("nodes"s == str) + return property("nodes", this->_nodes, o.nodes); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2194,25 +3564,44 @@ CesiumJsonReader::IJsonHandler* SceneJsonHandler::readObjectKeyScene(const std:: namespace CesiumGltfReader { -SamplerJsonHandler::SamplerJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _magFilter(), _minFilter(), _wrapS(), _wrapT() {} - -void SamplerJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Sampler* pObject) { +SamplerJsonHandler::SamplerJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _magFilter(), + _minFilter(), + _wrapS(), + _wrapT() {} + +void SamplerJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Sampler* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* SamplerJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +SamplerJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeySampler(CesiumGltf::Sampler::TypeName, str, *this->_pObject); + return this->readObjectKeySampler( + CesiumGltf::Sampler::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* SamplerJsonHandler::readObjectKeySampler(const std::string& objectType, const std::string_view& str, CesiumGltf::Sampler& o) { +CesiumJsonReader::IJsonHandler* SamplerJsonHandler::readObjectKeySampler( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Sampler& o) { using namespace std::string_literals; - if ("magFilter"s == str) return property("magFilter", this->_magFilter, o.magFilter); - if ("minFilter"s == str) return property("minFilter", this->_minFilter, o.minFilter); - if ("wrapS"s == str) return property("wrapS", this->_wrapS, o.wrapS); - if ("wrapT"s == str) return property("wrapT", this->_wrapT, o.wrapT); + if ("magFilter"s == str) + return property("magFilter", this->_magFilter, o.magFilter); + if ("minFilter"s == str) + return property("minFilter", this->_minFilter, o.minFilter); + if ("wrapS"s == str) + return property("wrapS", this->_wrapS, o.wrapS); + if ("wrapT"s == str) + return property("wrapT", this->_wrapT, o.wrapT); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2229,30 +3618,59 @@ CesiumJsonReader::IJsonHandler* SamplerJsonHandler::readObjectKeySampler(const s namespace CesiumGltfReader { -NodeJsonHandler::NodeJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _camera(), _children(), _skin(), _matrix(), _mesh(), _rotation(), _scale(), _translation(), _weights() {} - -void NodeJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Node* pObject) { +NodeJsonHandler::NodeJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _camera(), + _children(), + _skin(), + _matrix(), + _mesh(), + _rotation(), + _scale(), + _translation(), + _weights() {} + +void NodeJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Node* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* NodeJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +NodeJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyNode(CesiumGltf::Node::TypeName, str, *this->_pObject); + return this->readObjectKeyNode( + CesiumGltf::Node::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* NodeJsonHandler::readObjectKeyNode(const std::string& objectType, const std::string_view& str, CesiumGltf::Node& o) { +CesiumJsonReader::IJsonHandler* NodeJsonHandler::readObjectKeyNode( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Node& o) { using namespace std::string_literals; - if ("camera"s == str) return property("camera", this->_camera, o.camera); - if ("children"s == str) return property("children", this->_children, o.children); - if ("skin"s == str) return property("skin", this->_skin, o.skin); - if ("matrix"s == str) return property("matrix", this->_matrix, o.matrix); - if ("mesh"s == str) return property("mesh", this->_mesh, o.mesh); - if ("rotation"s == str) return property("rotation", this->_rotation, o.rotation); - if ("scale"s == str) return property("scale", this->_scale, o.scale); - if ("translation"s == str) return property("translation", this->_translation, o.translation); - if ("weights"s == str) return property("weights", this->_weights, o.weights); + if ("camera"s == str) + return property("camera", this->_camera, o.camera); + if ("children"s == str) + return property("children", this->_children, o.children); + if ("skin"s == str) + return property("skin", this->_skin, o.skin); + if ("matrix"s == str) + return property("matrix", this->_matrix, o.matrix); + if ("mesh"s == str) + return property("mesh", this->_mesh, o.mesh); + if ("rotation"s == str) + return property("rotation", this->_rotation, o.rotation); + if ("scale"s == str) + return property("scale", this->_scale, o.scale); + if ("translation"s == str) + return property("translation", this->_translation, o.translation); + if ("weights"s == str) + return property("weights", this->_weights, o.weights); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2269,23 +3687,38 @@ CesiumJsonReader::IJsonHandler* NodeJsonHandler::readObjectKeyNode(const std::st namespace CesiumGltfReader { -MeshJsonHandler::MeshJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _primitives(context), _weights() {} +MeshJsonHandler::MeshJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _primitives(context), + _weights() {} -void MeshJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Mesh* pObject) { +void MeshJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Mesh* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* MeshJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +MeshJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMesh(CesiumGltf::Mesh::TypeName, str, *this->_pObject); + return this->readObjectKeyMesh( + CesiumGltf::Mesh::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* MeshJsonHandler::readObjectKeyMesh(const std::string& objectType, const std::string_view& str, CesiumGltf::Mesh& o) { +CesiumJsonReader::IJsonHandler* MeshJsonHandler::readObjectKeyMesh( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Mesh& o) { using namespace std::string_literals; - if ("primitives"s == str) return property("primitives", this->_primitives, o.primitives); - if ("weights"s == str) return property("weights", this->_weights, o.weights); + if ("primitives"s == str) + return property("primitives", this->_primitives, o.primitives); + if ("weights"s == str) + return property("weights", this->_weights, o.weights); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2302,26 +3735,48 @@ CesiumJsonReader::IJsonHandler* MeshJsonHandler::readObjectKeyMesh(const std::st namespace CesiumGltfReader { -MeshPrimitiveJsonHandler::MeshPrimitiveJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attributes(), _indices(), _material(), _mode(), _targets() {} - -void MeshPrimitiveJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::MeshPrimitive* pObject) { +MeshPrimitiveJsonHandler::MeshPrimitiveJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _attributes(), + _indices(), + _material(), + _mode(), + _targets() {} + +void MeshPrimitiveJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::MeshPrimitive* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* MeshPrimitiveJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +MeshPrimitiveJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMeshPrimitive(CesiumGltf::MeshPrimitive::TypeName, str, *this->_pObject); + return this->readObjectKeyMeshPrimitive( + CesiumGltf::MeshPrimitive::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* MeshPrimitiveJsonHandler::readObjectKeyMeshPrimitive(const std::string& objectType, const std::string_view& str, CesiumGltf::MeshPrimitive& o) { +CesiumJsonReader::IJsonHandler* +MeshPrimitiveJsonHandler::readObjectKeyMeshPrimitive( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::MeshPrimitive& o) { using namespace std::string_literals; - if ("attributes"s == str) return property("attributes", this->_attributes, o.attributes); - if ("indices"s == str) return property("indices", this->_indices, o.indices); - if ("material"s == str) return property("material", this->_material, o.material); - if ("mode"s == str) return property("mode", this->_mode, o.mode); - if ("targets"s == str) return property("targets", this->_targets, o.targets); + if ("attributes"s == str) + return property("attributes", this->_attributes, o.attributes); + if ("indices"s == str) + return property("indices", this->_indices, o.indices); + if ("material"s == str) + return property("material", this->_material, o.material); + if ("mode"s == str) + return property("mode", this->_mode, o.mode); + if ("targets"s == str) + return property("targets", this->_targets, o.targets); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2338,29 +3793,65 @@ CesiumJsonReader::IJsonHandler* MeshPrimitiveJsonHandler::readObjectKeyMeshPrimi namespace CesiumGltfReader { -MaterialJsonHandler::MaterialJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _pbrMetallicRoughness(context), _normalTexture(context), _occlusionTexture(context), _emissiveTexture(context), _emissiveFactor(), _alphaMode(), _alphaCutoff(), _doubleSided() {} - -void MaterialJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Material* pObject) { +MaterialJsonHandler::MaterialJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _pbrMetallicRoughness(context), + _normalTexture(context), + _occlusionTexture(context), + _emissiveTexture(context), + _emissiveFactor(), + _alphaMode(), + _alphaCutoff(), + _doubleSided() {} + +void MaterialJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Material* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* MaterialJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +MaterialJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMaterial(CesiumGltf::Material::TypeName, str, *this->_pObject); + return this->readObjectKeyMaterial( + CesiumGltf::Material::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* MaterialJsonHandler::readObjectKeyMaterial(const std::string& objectType, const std::string_view& str, CesiumGltf::Material& o) { +CesiumJsonReader::IJsonHandler* MaterialJsonHandler::readObjectKeyMaterial( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Material& o) { using namespace std::string_literals; - if ("pbrMetallicRoughness"s == str) return property("pbrMetallicRoughness", this->_pbrMetallicRoughness, o.pbrMetallicRoughness); - if ("normalTexture"s == str) return property("normalTexture", this->_normalTexture, o.normalTexture); - if ("occlusionTexture"s == str) return property("occlusionTexture", this->_occlusionTexture, o.occlusionTexture); - if ("emissiveTexture"s == str) return property("emissiveTexture", this->_emissiveTexture, o.emissiveTexture); - if ("emissiveFactor"s == str) return property("emissiveFactor", this->_emissiveFactor, o.emissiveFactor); - if ("alphaMode"s == str) return property("alphaMode", this->_alphaMode, o.alphaMode); - if ("alphaCutoff"s == str) return property("alphaCutoff", this->_alphaCutoff, o.alphaCutoff); - if ("doubleSided"s == str) return property("doubleSided", this->_doubleSided, o.doubleSided); + if ("pbrMetallicRoughness"s == str) + return property( + "pbrMetallicRoughness", + this->_pbrMetallicRoughness, + o.pbrMetallicRoughness); + if ("normalTexture"s == str) + return property("normalTexture", this->_normalTexture, o.normalTexture); + if ("occlusionTexture"s == str) + return property( + "occlusionTexture", + this->_occlusionTexture, + o.occlusionTexture); + if ("emissiveTexture"s == str) + return property( + "emissiveTexture", + this->_emissiveTexture, + o.emissiveTexture); + if ("emissiveFactor"s == str) + return property("emissiveFactor", this->_emissiveFactor, o.emissiveFactor); + if ("alphaMode"s == str) + return property("alphaMode", this->_alphaMode, o.alphaMode); + if ("alphaCutoff"s == str) + return property("alphaCutoff", this->_alphaCutoff, o.alphaCutoff); + if ("doubleSided"s == str) + return property("doubleSided", this->_doubleSided, o.doubleSided); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2377,22 +3868,37 @@ CesiumJsonReader::IJsonHandler* MaterialJsonHandler::readObjectKeyMaterial(const namespace CesiumGltfReader { -MaterialOcclusionTextureInfoJsonHandler::MaterialOcclusionTextureInfoJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : TextureInfoJsonHandler(context), _strength() {} +MaterialOcclusionTextureInfoJsonHandler:: + MaterialOcclusionTextureInfoJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : TextureInfoJsonHandler(context), _strength() {} -void MaterialOcclusionTextureInfoJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::MaterialOcclusionTextureInfo* pObject) { +void MaterialOcclusionTextureInfoJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::MaterialOcclusionTextureInfo* pObject) { TextureInfoJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* MaterialOcclusionTextureInfoJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +MaterialOcclusionTextureInfoJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMaterialOcclusionTextureInfo(CesiumGltf::MaterialOcclusionTextureInfo::TypeName, str, *this->_pObject); + return this->readObjectKeyMaterialOcclusionTextureInfo( + CesiumGltf::MaterialOcclusionTextureInfo::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* MaterialOcclusionTextureInfoJsonHandler::readObjectKeyMaterialOcclusionTextureInfo(const std::string& objectType, const std::string_view& str, CesiumGltf::MaterialOcclusionTextureInfo& o) { +CesiumJsonReader::IJsonHandler* MaterialOcclusionTextureInfoJsonHandler:: + readObjectKeyMaterialOcclusionTextureInfo( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::MaterialOcclusionTextureInfo& o) { using namespace std::string_literals; - if ("strength"s == str) return property("strength", this->_strength, o.strength); + if ("strength"s == str) + return property("strength", this->_strength, o.strength); return this->readObjectKeyTextureInfo(objectType, str, *this->_pObject); } @@ -2409,22 +3915,36 @@ CesiumJsonReader::IJsonHandler* MaterialOcclusionTextureInfoJsonHandler::readObj namespace CesiumGltfReader { -MaterialNormalTextureInfoJsonHandler::MaterialNormalTextureInfoJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : TextureInfoJsonHandler(context), _scale() {} +MaterialNormalTextureInfoJsonHandler::MaterialNormalTextureInfoJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : TextureInfoJsonHandler(context), _scale() {} -void MaterialNormalTextureInfoJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::MaterialNormalTextureInfo* pObject) { +void MaterialNormalTextureInfoJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::MaterialNormalTextureInfo* pObject) { TextureInfoJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* MaterialNormalTextureInfoJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +MaterialNormalTextureInfoJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMaterialNormalTextureInfo(CesiumGltf::MaterialNormalTextureInfo::TypeName, str, *this->_pObject); + return this->readObjectKeyMaterialNormalTextureInfo( + CesiumGltf::MaterialNormalTextureInfo::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* MaterialNormalTextureInfoJsonHandler::readObjectKeyMaterialNormalTextureInfo(const std::string& objectType, const std::string_view& str, CesiumGltf::MaterialNormalTextureInfo& o) { +CesiumJsonReader::IJsonHandler* +MaterialNormalTextureInfoJsonHandler::readObjectKeyMaterialNormalTextureInfo( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::MaterialNormalTextureInfo& o) { using namespace std::string_literals; - if ("scale"s == str) return property("scale", this->_scale, o.scale); + if ("scale"s == str) + return property("scale", this->_scale, o.scale); return this->readObjectKeyTextureInfo(objectType, str, *this->_pObject); } @@ -2441,26 +3961,62 @@ CesiumJsonReader::IJsonHandler* MaterialNormalTextureInfoJsonHandler::readObject namespace CesiumGltfReader { -MaterialPBRMetallicRoughnessJsonHandler::MaterialPBRMetallicRoughnessJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _baseColorFactor(), _baseColorTexture(context), _metallicFactor(), _roughnessFactor(), _metallicRoughnessTexture(context) {} - -void MaterialPBRMetallicRoughnessJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::MaterialPBRMetallicRoughness* pObject) { +MaterialPBRMetallicRoughnessJsonHandler:: + MaterialPBRMetallicRoughnessJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _baseColorFactor(), + _baseColorTexture(context), + _metallicFactor(), + _roughnessFactor(), + _metallicRoughnessTexture(context) {} + +void MaterialPBRMetallicRoughnessJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::MaterialPBRMetallicRoughness* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* MaterialPBRMetallicRoughnessJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +MaterialPBRMetallicRoughnessJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyMaterialPBRMetallicRoughness(CesiumGltf::MaterialPBRMetallicRoughness::TypeName, str, *this->_pObject); + return this->readObjectKeyMaterialPBRMetallicRoughness( + CesiumGltf::MaterialPBRMetallicRoughness::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* MaterialPBRMetallicRoughnessJsonHandler::readObjectKeyMaterialPBRMetallicRoughness(const std::string& objectType, const std::string_view& str, CesiumGltf::MaterialPBRMetallicRoughness& o) { +CesiumJsonReader::IJsonHandler* MaterialPBRMetallicRoughnessJsonHandler:: + readObjectKeyMaterialPBRMetallicRoughness( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::MaterialPBRMetallicRoughness& o) { using namespace std::string_literals; - if ("baseColorFactor"s == str) return property("baseColorFactor", this->_baseColorFactor, o.baseColorFactor); - if ("baseColorTexture"s == str) return property("baseColorTexture", this->_baseColorTexture, o.baseColorTexture); - if ("metallicFactor"s == str) return property("metallicFactor", this->_metallicFactor, o.metallicFactor); - if ("roughnessFactor"s == str) return property("roughnessFactor", this->_roughnessFactor, o.roughnessFactor); - if ("metallicRoughnessTexture"s == str) return property("metallicRoughnessTexture", this->_metallicRoughnessTexture, o.metallicRoughnessTexture); + if ("baseColorFactor"s == str) + return property( + "baseColorFactor", + this->_baseColorFactor, + o.baseColorFactor); + if ("baseColorTexture"s == str) + return property( + "baseColorTexture", + this->_baseColorTexture, + o.baseColorTexture); + if ("metallicFactor"s == str) + return property("metallicFactor", this->_metallicFactor, o.metallicFactor); + if ("roughnessFactor"s == str) + return property( + "roughnessFactor", + this->_roughnessFactor, + o.roughnessFactor); + if ("metallicRoughnessTexture"s == str) + return property( + "metallicRoughnessTexture", + this->_metallicRoughnessTexture, + o.metallicRoughnessTexture); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2477,24 +4033,41 @@ CesiumJsonReader::IJsonHandler* MaterialPBRMetallicRoughnessJsonHandler::readObj namespace CesiumGltfReader { -ImageJsonHandler::ImageJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _uri(), _mimeType(), _bufferView() {} +ImageJsonHandler::ImageJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _uri(), + _mimeType(), + _bufferView() {} -void ImageJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Image* pObject) { +void ImageJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Image* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* ImageJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +ImageJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyImage(CesiumGltf::Image::TypeName, str, *this->_pObject); + return this->readObjectKeyImage( + CesiumGltf::Image::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* ImageJsonHandler::readObjectKeyImage(const std::string& objectType, const std::string_view& str, CesiumGltf::Image& o) { +CesiumJsonReader::IJsonHandler* ImageJsonHandler::readObjectKeyImage( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Image& o) { using namespace std::string_literals; - if ("uri"s == str) return property("uri", this->_uri, o.uri); - if ("mimeType"s == str) return property("mimeType", this->_mimeType, o.mimeType); - if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); + if ("uri"s == str) + return property("uri", this->_uri, o.uri); + if ("mimeType"s == str) + return property("mimeType", this->_mimeType, o.mimeType); + if ("bufferView"s == str) + return property("bufferView", this->_bufferView, o.bufferView); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2511,24 +4084,41 @@ CesiumJsonReader::IJsonHandler* ImageJsonHandler::readObjectKeyImage(const std:: namespace CesiumGltfReader { -CameraJsonHandler::CameraJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _orthographic(context), _perspective(context), _type() {} +CameraJsonHandler::CameraJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _orthographic(context), + _perspective(context), + _type() {} -void CameraJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Camera* pObject) { +void CameraJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Camera* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* CameraJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +CameraJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyCamera(CesiumGltf::Camera::TypeName, str, *this->_pObject); + return this->readObjectKeyCamera( + CesiumGltf::Camera::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* CameraJsonHandler::readObjectKeyCamera(const std::string& objectType, const std::string_view& str, CesiumGltf::Camera& o) { +CesiumJsonReader::IJsonHandler* CameraJsonHandler::readObjectKeyCamera( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Camera& o) { using namespace std::string_literals; - if ("orthographic"s == str) return property("orthographic", this->_orthographic, o.orthographic); - if ("perspective"s == str) return property("perspective", this->_perspective, o.perspective); - if ("type"s == str) return property("type", this->_type, o.type); + if ("orthographic"s == str) + return property("orthographic", this->_orthographic, o.orthographic); + if ("perspective"s == str) + return property("perspective", this->_perspective, o.perspective); + if ("type"s == str) + return property("type", this->_type, o.type); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2545,25 +4135,45 @@ CesiumJsonReader::IJsonHandler* CameraJsonHandler::readObjectKeyCamera(const std namespace CesiumGltfReader { -CameraPerspectiveJsonHandler::CameraPerspectiveJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _aspectRatio(), _yfov(), _zfar(), _znear() {} - -void CameraPerspectiveJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::CameraPerspective* pObject) { +CameraPerspectiveJsonHandler::CameraPerspectiveJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _aspectRatio(), + _yfov(), + _zfar(), + _znear() {} + +void CameraPerspectiveJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::CameraPerspective* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* CameraPerspectiveJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +CameraPerspectiveJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyCameraPerspective(CesiumGltf::CameraPerspective::TypeName, str, *this->_pObject); + return this->readObjectKeyCameraPerspective( + CesiumGltf::CameraPerspective::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* CameraPerspectiveJsonHandler::readObjectKeyCameraPerspective(const std::string& objectType, const std::string_view& str, CesiumGltf::CameraPerspective& o) { +CesiumJsonReader::IJsonHandler* +CameraPerspectiveJsonHandler::readObjectKeyCameraPerspective( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::CameraPerspective& o) { using namespace std::string_literals; - if ("aspectRatio"s == str) return property("aspectRatio", this->_aspectRatio, o.aspectRatio); - if ("yfov"s == str) return property("yfov", this->_yfov, o.yfov); - if ("zfar"s == str) return property("zfar", this->_zfar, o.zfar); - if ("znear"s == str) return property("znear", this->_znear, o.znear); + if ("aspectRatio"s == str) + return property("aspectRatio", this->_aspectRatio, o.aspectRatio); + if ("yfov"s == str) + return property("yfov", this->_yfov, o.yfov); + if ("zfar"s == str) + return property("zfar", this->_zfar, o.zfar); + if ("znear"s == str) + return property("znear", this->_znear, o.znear); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2580,25 +4190,45 @@ CesiumJsonReader::IJsonHandler* CameraPerspectiveJsonHandler::readObjectKeyCamer namespace CesiumGltfReader { -CameraOrthographicJsonHandler::CameraOrthographicJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _xmag(), _ymag(), _zfar(), _znear() {} - -void CameraOrthographicJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::CameraOrthographic* pObject) { +CameraOrthographicJsonHandler::CameraOrthographicJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _xmag(), + _ymag(), + _zfar(), + _znear() {} + +void CameraOrthographicJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::CameraOrthographic* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* CameraOrthographicJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +CameraOrthographicJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyCameraOrthographic(CesiumGltf::CameraOrthographic::TypeName, str, *this->_pObject); + return this->readObjectKeyCameraOrthographic( + CesiumGltf::CameraOrthographic::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* CameraOrthographicJsonHandler::readObjectKeyCameraOrthographic(const std::string& objectType, const std::string_view& str, CesiumGltf::CameraOrthographic& o) { +CesiumJsonReader::IJsonHandler* +CameraOrthographicJsonHandler::readObjectKeyCameraOrthographic( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::CameraOrthographic& o) { using namespace std::string_literals; - if ("xmag"s == str) return property("xmag", this->_xmag, o.xmag); - if ("ymag"s == str) return property("ymag", this->_ymag, o.ymag); - if ("zfar"s == str) return property("zfar", this->_zfar, o.zfar); - if ("znear"s == str) return property("znear", this->_znear, o.znear); + if ("xmag"s == str) + return property("xmag", this->_xmag, o.xmag); + if ("ymag"s == str) + return property("ymag", this->_ymag, o.ymag); + if ("zfar"s == str) + return property("zfar", this->_zfar, o.zfar); + if ("znear"s == str) + return property("znear", this->_znear, o.znear); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2615,26 +4245,47 @@ CesiumJsonReader::IJsonHandler* CameraOrthographicJsonHandler::readObjectKeyCame namespace CesiumGltfReader { -BufferViewJsonHandler::BufferViewJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _buffer(), _byteOffset(), _byteLength(), _byteStride(), _target() {} - -void BufferViewJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::BufferView* pObject) { +BufferViewJsonHandler::BufferViewJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _buffer(), + _byteOffset(), + _byteLength(), + _byteStride(), + _target() {} + +void BufferViewJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::BufferView* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* BufferViewJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +BufferViewJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyBufferView(CesiumGltf::BufferView::TypeName, str, *this->_pObject); + return this->readObjectKeyBufferView( + CesiumGltf::BufferView::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* BufferViewJsonHandler::readObjectKeyBufferView(const std::string& objectType, const std::string_view& str, CesiumGltf::BufferView& o) { +CesiumJsonReader::IJsonHandler* BufferViewJsonHandler::readObjectKeyBufferView( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::BufferView& o) { using namespace std::string_literals; - if ("buffer"s == str) return property("buffer", this->_buffer, o.buffer); - if ("byteOffset"s == str) return property("byteOffset", this->_byteOffset, o.byteOffset); - if ("byteLength"s == str) return property("byteLength", this->_byteLength, o.byteLength); - if ("byteStride"s == str) return property("byteStride", this->_byteStride, o.byteStride); - if ("target"s == str) return property("target", this->_target, o.target); + if ("buffer"s == str) + return property("buffer", this->_buffer, o.buffer); + if ("byteOffset"s == str) + return property("byteOffset", this->_byteOffset, o.byteOffset); + if ("byteLength"s == str) + return property("byteLength", this->_byteLength, o.byteLength); + if ("byteStride"s == str) + return property("byteStride", this->_byteStride, o.byteStride); + if ("target"s == str) + return property("target", this->_target, o.target); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2651,23 +4302,38 @@ CesiumJsonReader::IJsonHandler* BufferViewJsonHandler::readObjectKeyBufferView(c namespace CesiumGltfReader { -BufferJsonHandler::BufferJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _uri(), _byteLength() {} +BufferJsonHandler::BufferJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _uri(), + _byteLength() {} -void BufferJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Buffer* pObject) { +void BufferJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Buffer* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* BufferJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +BufferJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyBuffer(CesiumGltf::Buffer::TypeName, str, *this->_pObject); + return this->readObjectKeyBuffer( + CesiumGltf::Buffer::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* BufferJsonHandler::readObjectKeyBuffer(const std::string& objectType, const std::string_view& str, CesiumGltf::Buffer& o) { +CesiumJsonReader::IJsonHandler* BufferJsonHandler::readObjectKeyBuffer( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Buffer& o) { using namespace std::string_literals; - if ("uri"s == str) return property("uri", this->_uri, o.uri); - if ("byteLength"s == str) return property("byteLength", this->_byteLength, o.byteLength); + if ("uri"s == str) + return property("uri", this->_uri, o.uri); + if ("byteLength"s == str) + return property("byteLength", this->_byteLength, o.byteLength); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2684,25 +4350,44 @@ CesiumJsonReader::IJsonHandler* BufferJsonHandler::readObjectKeyBuffer(const std namespace CesiumGltfReader { -AssetJsonHandler::AssetJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _copyright(), _generator(), _version(), _minVersion() {} - -void AssetJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Asset* pObject) { +AssetJsonHandler::AssetJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _copyright(), + _generator(), + _version(), + _minVersion() {} + +void AssetJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Asset* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* AssetJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +AssetJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAsset(CesiumGltf::Asset::TypeName, str, *this->_pObject); + return this->readObjectKeyAsset( + CesiumGltf::Asset::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* AssetJsonHandler::readObjectKeyAsset(const std::string& objectType, const std::string_view& str, CesiumGltf::Asset& o) { +CesiumJsonReader::IJsonHandler* AssetJsonHandler::readObjectKeyAsset( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Asset& o) { using namespace std::string_literals; - if ("copyright"s == str) return property("copyright", this->_copyright, o.copyright); - if ("generator"s == str) return property("generator", this->_generator, o.generator); - if ("version"s == str) return property("version", this->_version, o.version); - if ("minVersion"s == str) return property("minVersion", this->_minVersion, o.minVersion); + if ("copyright"s == str) + return property("copyright", this->_copyright, o.copyright); + if ("generator"s == str) + return property("generator", this->_generator, o.generator); + if ("version"s == str) + return property("version", this->_version, o.version); + if ("minVersion"s == str) + return property("minVersion", this->_minVersion, o.minVersion); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2719,23 +4404,38 @@ CesiumJsonReader::IJsonHandler* AssetJsonHandler::readObjectKeyAsset(const std:: namespace CesiumGltfReader { -AnimationJsonHandler::AnimationJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _channels(context), _samplers(context) {} +AnimationJsonHandler::AnimationJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _channels(context), + _samplers(context) {} -void AnimationJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Animation* pObject) { +void AnimationJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Animation* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* AnimationJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +AnimationJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAnimation(CesiumGltf::Animation::TypeName, str, *this->_pObject); + return this->readObjectKeyAnimation( + CesiumGltf::Animation::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* AnimationJsonHandler::readObjectKeyAnimation(const std::string& objectType, const std::string_view& str, CesiumGltf::Animation& o) { +CesiumJsonReader::IJsonHandler* AnimationJsonHandler::readObjectKeyAnimation( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Animation& o) { using namespace std::string_literals; - if ("channels"s == str) return property("channels", this->_channels, o.channels); - if ("samplers"s == str) return property("samplers", this->_samplers, o.samplers); + if ("channels"s == str) + return property("channels", this->_channels, o.channels); + if ("samplers"s == str) + return property("samplers", this->_samplers, o.samplers); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2752,24 +4452,42 @@ CesiumJsonReader::IJsonHandler* AnimationJsonHandler::readObjectKeyAnimation(con namespace CesiumGltfReader { -AnimationSamplerJsonHandler::AnimationSamplerJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _input(), _interpolation(), _output() {} +AnimationSamplerJsonHandler::AnimationSamplerJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _input(), + _interpolation(), + _output() {} -void AnimationSamplerJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AnimationSampler* pObject) { +void AnimationSamplerJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::AnimationSampler* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* AnimationSamplerJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +AnimationSamplerJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAnimationSampler(CesiumGltf::AnimationSampler::TypeName, str, *this->_pObject); + return this->readObjectKeyAnimationSampler( + CesiumGltf::AnimationSampler::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* AnimationSamplerJsonHandler::readObjectKeyAnimationSampler(const std::string& objectType, const std::string_view& str, CesiumGltf::AnimationSampler& o) { +CesiumJsonReader::IJsonHandler* +AnimationSamplerJsonHandler::readObjectKeyAnimationSampler( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::AnimationSampler& o) { using namespace std::string_literals; - if ("input"s == str) return property("input", this->_input, o.input); - if ("interpolation"s == str) return property("interpolation", this->_interpolation, o.interpolation); - if ("output"s == str) return property("output", this->_output, o.output); + if ("input"s == str) + return property("input", this->_input, o.input); + if ("interpolation"s == str) + return property("interpolation", this->_interpolation, o.interpolation); + if ("output"s == str) + return property("output", this->_output, o.output); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2786,23 +4504,39 @@ CesiumJsonReader::IJsonHandler* AnimationSamplerJsonHandler::readObjectKeyAnimat namespace CesiumGltfReader { -AnimationChannelJsonHandler::AnimationChannelJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _sampler(), _target(context) {} +AnimationChannelJsonHandler::AnimationChannelJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _sampler(), + _target(context) {} -void AnimationChannelJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AnimationChannel* pObject) { +void AnimationChannelJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::AnimationChannel* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* AnimationChannelJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +AnimationChannelJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAnimationChannel(CesiumGltf::AnimationChannel::TypeName, str, *this->_pObject); + return this->readObjectKeyAnimationChannel( + CesiumGltf::AnimationChannel::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* AnimationChannelJsonHandler::readObjectKeyAnimationChannel(const std::string& objectType, const std::string_view& str, CesiumGltf::AnimationChannel& o) { +CesiumJsonReader::IJsonHandler* +AnimationChannelJsonHandler::readObjectKeyAnimationChannel( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::AnimationChannel& o) { using namespace std::string_literals; - if ("sampler"s == str) return property("sampler", this->_sampler, o.sampler); - if ("target"s == str) return property("target", this->_target, o.target); + if ("sampler"s == str) + return property("sampler", this->_sampler, o.sampler); + if ("target"s == str) + return property("target", this->_target, o.target); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2819,23 +4553,39 @@ CesiumJsonReader::IJsonHandler* AnimationChannelJsonHandler::readObjectKeyAnimat namespace CesiumGltfReader { -AnimationChannelTargetJsonHandler::AnimationChannelTargetJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _node(), _path() {} +AnimationChannelTargetJsonHandler::AnimationChannelTargetJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _node(), + _path() {} -void AnimationChannelTargetJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AnimationChannelTarget* pObject) { +void AnimationChannelTargetJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::AnimationChannelTarget* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* AnimationChannelTargetJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +AnimationChannelTargetJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAnimationChannelTarget(CesiumGltf::AnimationChannelTarget::TypeName, str, *this->_pObject); + return this->readObjectKeyAnimationChannelTarget( + CesiumGltf::AnimationChannelTarget::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* AnimationChannelTargetJsonHandler::readObjectKeyAnimationChannelTarget(const std::string& objectType, const std::string_view& str, CesiumGltf::AnimationChannelTarget& o) { +CesiumJsonReader::IJsonHandler* +AnimationChannelTargetJsonHandler::readObjectKeyAnimationChannelTarget( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::AnimationChannelTarget& o) { using namespace std::string_literals; - if ("node"s == str) return property("node", this->_node, o.node); - if ("path"s == str) return property("path", this->_path, o.path); + if ("node"s == str) + return property("node", this->_node, o.node); + if ("path"s == str) + return property("path", this->_path, o.path); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2852,30 +4602,59 @@ CesiumJsonReader::IJsonHandler* AnimationChannelTargetJsonHandler::readObjectKey namespace CesiumGltfReader { -AccessorJsonHandler::AccessorJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumGltfReader::NamedObjectJsonHandler(context), _bufferView(), _byteOffset(), _componentType(), _normalized(), _count(), _type(), _max(), _min(), _sparse(context) {} - -void AccessorJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::Accessor* pObject) { +AccessorJsonHandler::AccessorJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumGltfReader::NamedObjectJsonHandler(context), + _bufferView(), + _byteOffset(), + _componentType(), + _normalized(), + _count(), + _type(), + _max(), + _min(), + _sparse(context) {} + +void AccessorJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::Accessor* pObject) { CesiumGltfReader::NamedObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* AccessorJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +AccessorJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAccessor(CesiumGltf::Accessor::TypeName, str, *this->_pObject); + return this->readObjectKeyAccessor( + CesiumGltf::Accessor::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* AccessorJsonHandler::readObjectKeyAccessor(const std::string& objectType, const std::string_view& str, CesiumGltf::Accessor& o) { +CesiumJsonReader::IJsonHandler* AccessorJsonHandler::readObjectKeyAccessor( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Accessor& o) { using namespace std::string_literals; - if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); - if ("byteOffset"s == str) return property("byteOffset", this->_byteOffset, o.byteOffset); - if ("componentType"s == str) return property("componentType", this->_componentType, o.componentType); - if ("normalized"s == str) return property("normalized", this->_normalized, o.normalized); - if ("count"s == str) return property("count", this->_count, o.count); - if ("type"s == str) return property("type", this->_type, o.type); - if ("max"s == str) return property("max", this->_max, o.max); - if ("min"s == str) return property("min", this->_min, o.min); - if ("sparse"s == str) return property("sparse", this->_sparse, o.sparse); + if ("bufferView"s == str) + return property("bufferView", this->_bufferView, o.bufferView); + if ("byteOffset"s == str) + return property("byteOffset", this->_byteOffset, o.byteOffset); + if ("componentType"s == str) + return property("componentType", this->_componentType, o.componentType); + if ("normalized"s == str) + return property("normalized", this->_normalized, o.normalized); + if ("count"s == str) + return property("count", this->_count, o.count); + if ("type"s == str) + return property("type", this->_type, o.type); + if ("max"s == str) + return property("max", this->_max, o.max); + if ("min"s == str) + return property("min", this->_min, o.min); + if ("sparse"s == str) + return property("sparse", this->_sparse, o.sparse); return this->readObjectKeyNamedObject(objectType, str, *this->_pObject); } @@ -2892,24 +4671,42 @@ CesiumJsonReader::IJsonHandler* AccessorJsonHandler::readObjectKeyAccessor(const namespace CesiumGltfReader { -AccessorSparseJsonHandler::AccessorSparseJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _count(), _indices(context), _values(context) {} +AccessorSparseJsonHandler::AccessorSparseJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _count(), + _indices(context), + _values(context) {} -void AccessorSparseJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AccessorSparse* pObject) { +void AccessorSparseJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::AccessorSparse* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* AccessorSparseJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +AccessorSparseJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAccessorSparse(CesiumGltf::AccessorSparse::TypeName, str, *this->_pObject); + return this->readObjectKeyAccessorSparse( + CesiumGltf::AccessorSparse::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* AccessorSparseJsonHandler::readObjectKeyAccessorSparse(const std::string& objectType, const std::string_view& str, CesiumGltf::AccessorSparse& o) { +CesiumJsonReader::IJsonHandler* +AccessorSparseJsonHandler::readObjectKeyAccessorSparse( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::AccessorSparse& o) { using namespace std::string_literals; - if ("count"s == str) return property("count", this->_count, o.count); - if ("indices"s == str) return property("indices", this->_indices, o.indices); - if ("values"s == str) return property("values", this->_values, o.values); + if ("count"s == str) + return property("count", this->_count, o.count); + if ("indices"s == str) + return property("indices", this->_indices, o.indices); + if ("values"s == str) + return property("values", this->_values, o.values); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2926,23 +4723,39 @@ CesiumJsonReader::IJsonHandler* AccessorSparseJsonHandler::readObjectKeyAccessor namespace CesiumGltfReader { -AccessorSparseValuesJsonHandler::AccessorSparseValuesJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _bufferView(), _byteOffset() {} +AccessorSparseValuesJsonHandler::AccessorSparseValuesJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _bufferView(), + _byteOffset() {} -void AccessorSparseValuesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AccessorSparseValues* pObject) { +void AccessorSparseValuesJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::AccessorSparseValues* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* AccessorSparseValuesJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +AccessorSparseValuesJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAccessorSparseValues(CesiumGltf::AccessorSparseValues::TypeName, str, *this->_pObject); + return this->readObjectKeyAccessorSparseValues( + CesiumGltf::AccessorSparseValues::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* AccessorSparseValuesJsonHandler::readObjectKeyAccessorSparseValues(const std::string& objectType, const std::string_view& str, CesiumGltf::AccessorSparseValues& o) { +CesiumJsonReader::IJsonHandler* +AccessorSparseValuesJsonHandler::readObjectKeyAccessorSparseValues( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::AccessorSparseValues& o) { using namespace std::string_literals; - if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); - if ("byteOffset"s == str) return property("byteOffset", this->_byteOffset, o.byteOffset); + if ("bufferView"s == str) + return property("bufferView", this->_bufferView, o.bufferView); + if ("byteOffset"s == str) + return property("byteOffset", this->_byteOffset, o.byteOffset); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } @@ -2959,24 +4772,42 @@ CesiumJsonReader::IJsonHandler* AccessorSparseValuesJsonHandler::readObjectKeyAc namespace CesiumGltfReader { -AccessorSparseIndicesJsonHandler::AccessorSparseIndicesJsonHandler(const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _bufferView(), _byteOffset(), _componentType() {} +AccessorSparseIndicesJsonHandler::AccessorSparseIndicesJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept + : CesiumJsonReader::ExtensibleObjectJsonHandler(context), + _bufferView(), + _byteOffset(), + _componentType() {} -void AccessorSparseIndicesJsonHandler::reset(CesiumJsonReader::IJsonHandler* pParentHandler, CesiumGltf::AccessorSparseIndices* pObject) { +void AccessorSparseIndicesJsonHandler::reset( + CesiumJsonReader::IJsonHandler* pParentHandler, + CesiumGltf::AccessorSparseIndices* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } -CesiumJsonReader::IJsonHandler* AccessorSparseIndicesJsonHandler::readObjectKey(const std::string_view& str) { +CesiumJsonReader::IJsonHandler* +AccessorSparseIndicesJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyAccessorSparseIndices(CesiumGltf::AccessorSparseIndices::TypeName, str, *this->_pObject); + return this->readObjectKeyAccessorSparseIndices( + CesiumGltf::AccessorSparseIndices::TypeName, + str, + *this->_pObject); } -CesiumJsonReader::IJsonHandler* AccessorSparseIndicesJsonHandler::readObjectKeyAccessorSparseIndices(const std::string& objectType, const std::string_view& str, CesiumGltf::AccessorSparseIndices& o) { +CesiumJsonReader::IJsonHandler* +AccessorSparseIndicesJsonHandler::readObjectKeyAccessorSparseIndices( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::AccessorSparseIndices& o) { using namespace std::string_literals; - if ("bufferView"s == str) return property("bufferView", this->_bufferView, o.bufferView); - if ("byteOffset"s == str) return property("byteOffset", this->_byteOffset, o.byteOffset); - if ("componentType"s == str) return property("componentType", this->_componentType, o.componentType); + if ("bufferView"s == str) + return property("bufferView", this->_bufferView, o.bufferView); + if ("byteOffset"s == str) + return property("byteOffset", this->_byteOffset, o.byteOffset); + if ("componentType"s == str) + return property("componentType", this->_componentType, o.componentType); return this->readObjectKeyExtensibleObject(objectType, str, *this->_pObject); } From 55ed63a945fb554940ce84485595beee9f8ab7e6 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 16 Jun 2023 16:08:35 -0400 Subject: [PATCH 057/121] Regenerate EXT_structural_metadata classes without prefix --- ...onExtStructuralMetadataClass.h => Class.h} | 13 +- ...etadataClassProperty.h => ClassProperty.h} | 5 +- ...sionExtStructuralMetadataEnum.h => Enum.h} | 10 +- ...ucturalMetadataEnumValue.h => EnumValue.h} | 6 +- .../ExtensionModelExtStructuralMetadata.h | 19 +- ...ropertyAttribute.h => PropertyAttribute.h} | 11 +- ...Property.h => PropertyAttributeProperty.h} | 7 +- ...etadataPropertyTable.h => PropertyTable.h} | 12 +- ...ableProperty.h => PropertyTableProperty.h} | 5 +- ...ataPropertyTexture.h => PropertyTexture.h} | 11 +- ...reProperty.h => PropertyTextureProperty.h} | 6 +- ...ExtStructuralMetadataSchema.h => Schema.h} | 19 +- .../generated/src/ClassJsonHandler.h | 41 +++ ...onHandler.h => ClassPropertyJsonHandler.h} | 18 +- .../generated/src/EnumJsonHandler.h | 42 +++ ...ueJsonHandler.h => EnumValueJsonHandler.h} | 18 +- ...sionExtStructuralMetadataEnumJsonHandler.h | 46 --- ...uralMetadataPropertyAttributeJsonHandler.h | 46 --- ...onExtStructuralMetadataSchemaJsonHandler.h | 52 --- ...ionModelExtStructuralMetadataJsonHandler.h | 28 +- .../generated/src/GeneratedJsonHandlers.cpp | 337 ++++++++---------- ...ndler.h => PropertyAttributeJsonHandler.h} | 27 +- ...=> PropertyAttributePropertyJsonHandler.h} | 20 +- ...onHandler.h => PropertyTableJsonHandler.h} | 24 +- ...r.h => PropertyTablePropertyJsonHandler.h} | 19 +- ...Handler.h => PropertyTextureJsonHandler.h} | 25 +- ...h => PropertyTexturePropertyJsonHandler.h} | 21 +- .../generated/src/SchemaJsonHandler.h | 45 +++ .../generated/src/registerExtensions.cpp | 123 ++++--- .../generated/src/ModelJsonWriter.cpp | 125 +++---- .../generated/src/ModelJsonWriter.h | 94 +++-- tools/generate-classes/glTF.json | 22 +- 32 files changed, 603 insertions(+), 694 deletions(-) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataClass.h => Class.h} (66%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataClassProperty.h => ClassProperty.h} (97%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataEnum.h => Enum.h} (79%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataEnumValue.h => EnumValue.h} (72%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataPropertyAttribute.h => PropertyAttribute.h} (72%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataPropertyAttributeProperty.h => PropertyAttributeProperty.h} (87%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataPropertyTable.h => PropertyTable.h} (74%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataPropertyTableProperty.h => PropertyTableProperty.h} (96%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataPropertyTexture.h => PropertyTexture.h} (73%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataPropertyTextureProperty.h => PropertyTextureProperty.h} (89%) rename CesiumGltf/generated/include/CesiumGltf/{ExtensionExtStructuralMetadataSchema.h => Schema.h} (70%) create mode 100644 CesiumGltfReader/generated/src/ClassJsonHandler.h rename CesiumGltfReader/generated/src/{ExtensionExtStructuralMetadataClassPropertyJsonHandler.h => ClassPropertyJsonHandler.h} (72%) create mode 100644 CesiumGltfReader/generated/src/EnumJsonHandler.h rename CesiumGltfReader/generated/src/{ExtensionExtStructuralMetadataEnumValueJsonHandler.h => EnumValueJsonHandler.h} (59%) delete mode 100644 CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataEnumJsonHandler.h delete mode 100644 CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyAttributeJsonHandler.h delete mode 100644 CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataSchemaJsonHandler.h rename CesiumGltfReader/generated/src/{ExtensionExtStructuralMetadataClassJsonHandler.h => PropertyAttributeJsonHandler.h} (50%) rename CesiumGltfReader/generated/src/{ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler.h => PropertyAttributePropertyJsonHandler.h} (59%) rename CesiumGltfReader/generated/src/{ExtensionExtStructuralMetadataPropertyTableJsonHandler.h => PropertyTableJsonHandler.h} (53%) rename CesiumGltfReader/generated/src/{ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler.h => PropertyTablePropertyJsonHandler.h} (66%) rename CesiumGltfReader/generated/src/{ExtensionExtStructuralMetadataPropertyTextureJsonHandler.h => PropertyTextureJsonHandler.h} (50%) rename CesiumGltfReader/generated/src/{ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler.h => PropertyTexturePropertyJsonHandler.h} (59%) create mode 100644 CesiumGltfReader/generated/src/SchemaJsonHandler.h diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataClass.h b/CesiumGltf/generated/include/CesiumGltf/Class.h similarity index 66% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataClass.h rename to CesiumGltf/generated/include/CesiumGltf/Class.h index caaed0ddf..ac548d150 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataClass.h +++ b/CesiumGltf/generated/include/CesiumGltf/Class.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" +#include "CesiumGltf/ClassProperty.h" #include "CesiumGltf/Library.h" #include @@ -15,10 +15,8 @@ namespace CesiumGltf { /** * @brief A class containing a set of properties. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataClass final - : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataClass"; +struct CESIUMGLTF_API Class final : public CesiumUtility::ExtensibleObject { + static inline constexpr const char* TypeName = "Class"; /** * @brief The name of the class, e.g. for display purposes. @@ -35,9 +33,6 @@ struct CESIUMGLTF_API ExtensionExtStructuralMetadataClass final * object defining the property. Property IDs must be alphanumeric identifiers * matching the regular expression `^[a-zA-Z_][a-zA-Z0-9_]*$`. */ - std::unordered_map< - std::string, - CesiumGltf::ExtensionExtStructuralMetadataClassProperty> - properties; + std::unordered_map properties; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h b/CesiumGltf/generated/include/CesiumGltf/ClassProperty.h similarity index 97% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h rename to CesiumGltf/generated/include/CesiumGltf/ClassProperty.h index 245866180..fe07dfca3 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h +++ b/CesiumGltf/generated/include/CesiumGltf/ClassProperty.h @@ -15,10 +15,9 @@ namespace CesiumGltf { /** * @brief A class property. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataClassProperty final +struct CESIUMGLTF_API ClassProperty final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataClassProperty"; + static inline constexpr const char* TypeName = "ClassProperty"; /** * @brief Known values for The element type. diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataEnum.h b/CesiumGltf/generated/include/CesiumGltf/Enum.h similarity index 79% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataEnum.h rename to CesiumGltf/generated/include/CesiumGltf/Enum.h index a9c95a7df..2aac09e6a 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataEnum.h +++ b/CesiumGltf/generated/include/CesiumGltf/Enum.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ExtensionExtStructuralMetadataEnumValue.h" +#include "CesiumGltf/EnumValue.h" #include "CesiumGltf/Library.h" #include @@ -15,10 +15,8 @@ namespace CesiumGltf { /** * @brief An object defining the values of an enum. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataEnum final - : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataEnum"; +struct CESIUMGLTF_API Enum final : public CesiumUtility::ExtensibleObject { + static inline constexpr const char* TypeName = "Enum"; /** * @brief Known values for The type of the integer enum value. @@ -63,6 +61,6 @@ struct CESIUMGLTF_API ExtensionExtStructuralMetadataEnum final * @brief An array of enum values. Duplicate names or duplicate integer values * are not allowed. */ - std::vector values; + std::vector values; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataEnumValue.h b/CesiumGltf/generated/include/CesiumGltf/EnumValue.h similarity index 72% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataEnumValue.h rename to CesiumGltf/generated/include/CesiumGltf/EnumValue.h index 57bc28339..d1c505a4e 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataEnumValue.h +++ b/CesiumGltf/generated/include/CesiumGltf/EnumValue.h @@ -14,10 +14,8 @@ namespace CesiumGltf { /** * @brief An enum value. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataEnumValue final - : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataEnumValue"; +struct CESIUMGLTF_API EnumValue final : public CesiumUtility::ExtensibleObject { + static inline constexpr const char* TypeName = "EnumValue"; /** * @brief The name of the enum value. diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionModelExtStructuralMetadata.h b/CesiumGltf/generated/include/CesiumGltf/ExtensionModelExtStructuralMetadata.h index 270019b92..f78ace942 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionModelExtStructuralMetadata.h +++ b/CesiumGltf/generated/include/CesiumGltf/ExtensionModelExtStructuralMetadata.h @@ -2,11 +2,11 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyAttribute.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTable.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTexture.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataSchema.h" #include "CesiumGltf/Library.h" +#include "CesiumGltf/PropertyAttribute.h" +#include "CesiumGltf/PropertyTable.h" +#include "CesiumGltf/PropertyTexture.h" +#include "CesiumGltf/Schema.h" #include @@ -28,7 +28,7 @@ struct CESIUMGLTF_API ExtensionModelExtStructuralMetadata final /** * @brief An object defining classes and enums. */ - std::optional schema; + std::optional schema; /** * @brief The URI (or IRI) of the external schema file. @@ -39,21 +39,18 @@ struct CESIUMGLTF_API ExtensionModelExtStructuralMetadata final * @brief An array of property table definitions, which may be referenced by * index. */ - std::vector - propertyTables; + std::vector propertyTables; /** * @brief An array of property texture definitions, which may be referenced by * index. */ - std::vector - propertyTextures; + std::vector propertyTextures; /** * @brief An array of property attribute definitions, which may be referenced * by index. */ - std::vector - propertyAttributes; + std::vector propertyAttributes; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyAttribute.h b/CesiumGltf/generated/include/CesiumGltf/PropertyAttribute.h similarity index 72% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyAttribute.h rename to CesiumGltf/generated/include/CesiumGltf/PropertyAttribute.h index 9222d9571..c7256721b 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyAttribute.h +++ b/CesiumGltf/generated/include/CesiumGltf/PropertyAttribute.h @@ -2,8 +2,8 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyAttributeProperty.h" #include "CesiumGltf/Library.h" +#include "CesiumGltf/PropertyAttributeProperty.h" #include @@ -16,10 +16,9 @@ namespace CesiumGltf { * @brief Properties conforming to a class, organized as property values stored * in attributes. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataPropertyAttribute final +struct CESIUMGLTF_API PropertyAttribute final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataPropertyAttribute"; + static inline constexpr const char* TypeName = "PropertyAttribute"; /** * @brief The name of the property attribute, e.g. for display purposes. @@ -38,9 +37,7 @@ struct CESIUMGLTF_API ExtensionExtStructuralMetadataPropertyAttribute final * property values are stored. Required properties must be included in this * dictionary. */ - std::unordered_map< - std::string, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty> + std::unordered_map properties; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyAttributeProperty.h b/CesiumGltf/generated/include/CesiumGltf/PropertyAttributeProperty.h similarity index 87% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyAttributeProperty.h rename to CesiumGltf/generated/include/CesiumGltf/PropertyAttributeProperty.h index 25405e9f3..25c6391ff 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyAttributeProperty.h +++ b/CesiumGltf/generated/include/CesiumGltf/PropertyAttributeProperty.h @@ -14,10 +14,9 @@ namespace CesiumGltf { /** * @brief An attribute containing property values. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataPropertyAttributeProperty - final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataPropertyAttributeProperty"; +struct CESIUMGLTF_API PropertyAttributeProperty final + : public CesiumUtility::ExtensibleObject { + static inline constexpr const char* TypeName = "PropertyAttributeProperty"; /** * @brief The name of the attribute containing property values. diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTable.h b/CesiumGltf/generated/include/CesiumGltf/PropertyTable.h similarity index 74% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTable.h rename to CesiumGltf/generated/include/CesiumGltf/PropertyTable.h index 004f3a206..4a4130cd6 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTable.h +++ b/CesiumGltf/generated/include/CesiumGltf/PropertyTable.h @@ -2,8 +2,8 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTableProperty.h" #include "CesiumGltf/Library.h" +#include "CesiumGltf/PropertyTableProperty.h" #include @@ -17,10 +17,9 @@ namespace CesiumGltf { * @brief Properties conforming to a class, organized as property values stored * in binary columnar arrays. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataPropertyTable final +struct CESIUMGLTF_API PropertyTable final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataPropertyTable"; + static inline constexpr const char* TypeName = "PropertyTable"; /** * @brief The name of the property table, e.g. for display purposes. @@ -44,9 +43,6 @@ struct CESIUMGLTF_API ExtensionExtStructuralMetadataPropertyTable final * property values are stored. Required properties must be included in this * dictionary. */ - std::unordered_map< - std::string, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty> - properties; + std::unordered_map properties; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTableProperty.h b/CesiumGltf/generated/include/CesiumGltf/PropertyTableProperty.h similarity index 96% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTableProperty.h rename to CesiumGltf/generated/include/CesiumGltf/PropertyTableProperty.h index 7d5751a4d..5b9cf839d 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTableProperty.h +++ b/CesiumGltf/generated/include/CesiumGltf/PropertyTableProperty.h @@ -15,10 +15,9 @@ namespace CesiumGltf { /** * @brief An array of binary property values. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataPropertyTableProperty final +struct CESIUMGLTF_API PropertyTableProperty final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataPropertyTableProperty"; + static inline constexpr const char* TypeName = "PropertyTableProperty"; /** * @brief Known values for The type of values in `arrayOffsets`. diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTexture.h b/CesiumGltf/generated/include/CesiumGltf/PropertyTexture.h similarity index 73% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTexture.h rename to CesiumGltf/generated/include/CesiumGltf/PropertyTexture.h index 2b1ab5c32..6ea853c30 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTexture.h +++ b/CesiumGltf/generated/include/CesiumGltf/PropertyTexture.h @@ -2,8 +2,8 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTextureProperty.h" #include "CesiumGltf/Library.h" +#include "CesiumGltf/PropertyTextureProperty.h" #include @@ -16,10 +16,9 @@ namespace CesiumGltf { * @brief Properties conforming to a class, organized as property values stored * in textures. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataPropertyTexture final +struct CESIUMGLTF_API PropertyTexture final : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataPropertyTexture"; + static inline constexpr const char* TypeName = "PropertyTexture"; /** * @brief The name of the property texture, e.g. for display purposes. @@ -38,9 +37,7 @@ struct CESIUMGLTF_API ExtensionExtStructuralMetadataPropertyTexture final * property values are stored. Required properties must be included in this * dictionary. */ - std::unordered_map< - std::string, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty> + std::unordered_map properties; }; } // namespace CesiumGltf diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTextureProperty.h b/CesiumGltf/generated/include/CesiumGltf/PropertyTextureProperty.h similarity index 89% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTextureProperty.h rename to CesiumGltf/generated/include/CesiumGltf/PropertyTextureProperty.h index faa50b189..04ec656fc 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataPropertyTextureProperty.h +++ b/CesiumGltf/generated/include/CesiumGltf/PropertyTextureProperty.h @@ -15,10 +15,8 @@ namespace CesiumGltf { /** * @brief A texture containing property values. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataPropertyTextureProperty - final : public TextureInfo { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataPropertyTextureProperty"; +struct CESIUMGLTF_API PropertyTextureProperty final : public TextureInfo { + static inline constexpr const char* TypeName = "PropertyTextureProperty"; /** * @brief Texture channels containing property values, identified by index. diff --git a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataSchema.h b/CesiumGltf/generated/include/CesiumGltf/Schema.h similarity index 70% rename from CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataSchema.h rename to CesiumGltf/generated/include/CesiumGltf/Schema.h index 8b92f94af..7930d4f91 100644 --- a/CesiumGltf/generated/include/CesiumGltf/ExtensionExtStructuralMetadataSchema.h +++ b/CesiumGltf/generated/include/CesiumGltf/Schema.h @@ -2,8 +2,8 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "CesiumGltf/ExtensionExtStructuralMetadataClass.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataEnum.h" +#include "CesiumGltf/Class.h" +#include "CesiumGltf/Enum.h" #include "CesiumGltf/Library.h" #include @@ -16,10 +16,8 @@ namespace CesiumGltf { /** * @brief An object defining classes and enums. */ -struct CESIUMGLTF_API ExtensionExtStructuralMetadataSchema final - : public CesiumUtility::ExtensibleObject { - static inline constexpr const char* TypeName = - "ExtensionExtStructuralMetadataSchema"; +struct CESIUMGLTF_API Schema final : public CesiumUtility::ExtensibleObject { + static inline constexpr const char* TypeName = "Schema"; /** * @brief Unique identifier for the schema. Schema IDs must be alphanumeric @@ -47,18 +45,13 @@ struct CESIUMGLTF_API ExtensionExtStructuralMetadataSchema final * object defining the class. Class IDs must be alphanumeric identifiers * matching the regular expression `^[a-zA-Z_][a-zA-Z0-9_]*$`. */ - std::unordered_map< - std::string, - CesiumGltf::ExtensionExtStructuralMetadataClass> - classes; + std::unordered_map classes; /** * @brief A dictionary, where each key is an enum ID and each value is an * object defining the values for the enum. Enum IDs must be alphanumeric * identifiers matching the regular expression `^[a-zA-Z_][a-zA-Z0-9_]*$`. */ - std:: - unordered_map - enums; + std::unordered_map enums; }; } // namespace CesiumGltf diff --git a/CesiumGltfReader/generated/src/ClassJsonHandler.h b/CesiumGltfReader/generated/src/ClassJsonHandler.h new file mode 100644 index 000000000..580791944 --- /dev/null +++ b/CesiumGltfReader/generated/src/ClassJsonHandler.h @@ -0,0 +1,41 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include "ClassPropertyJsonHandler.h" + +#include +#include +#include +#include + +namespace CesiumJsonReader { +class ExtensionReaderContext; +} + +namespace CesiumGltfReader { +class ClassJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { +public: + using ValueType = CesiumGltf::Class; + + ClassJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept; + void reset(IJsonHandler* pParentHandler, CesiumGltf::Class* pObject); + + virtual IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeyClass( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Class& o); + +private: + CesiumGltf::Class* _pObject = nullptr; + CesiumJsonReader::StringJsonHandler _name; + CesiumJsonReader::StringJsonHandler _description; + CesiumJsonReader:: + DictionaryJsonHandler + _properties; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataClassPropertyJsonHandler.h b/CesiumGltfReader/generated/src/ClassPropertyJsonHandler.h similarity index 72% rename from CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataClassPropertyJsonHandler.h rename to CesiumGltfReader/generated/src/ClassPropertyJsonHandler.h index 5b4f30f29..8eab7a7e6 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataClassPropertyJsonHandler.h +++ b/CesiumGltfReader/generated/src/ClassPropertyJsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include #include @@ -14,27 +14,25 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataClassPropertyJsonHandler +class ClassPropertyJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataClassProperty; + using ValueType = CesiumGltf::ClassProperty; - ExtensionExtStructuralMetadataClassPropertyJsonHandler( + ClassPropertyJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset( - IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataClassProperty* pObject); + void reset(IJsonHandler* pParentHandler, CesiumGltf::ClassProperty* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyExtensionExtStructuralMetadataClassProperty( + IJsonHandler* readObjectKeyClassProperty( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataClassProperty& o); + CesiumGltf::ClassProperty& o); private: - CesiumGltf::ExtensionExtStructuralMetadataClassProperty* _pObject = nullptr; + CesiumGltf::ClassProperty* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _name; CesiumJsonReader::StringJsonHandler _description; CesiumJsonReader::StringJsonHandler _type; diff --git a/CesiumGltfReader/generated/src/EnumJsonHandler.h b/CesiumGltfReader/generated/src/EnumJsonHandler.h new file mode 100644 index 000000000..355e88790 --- /dev/null +++ b/CesiumGltfReader/generated/src/EnumJsonHandler.h @@ -0,0 +1,42 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include "EnumValueJsonHandler.h" + +#include +#include +#include +#include + +namespace CesiumJsonReader { +class ExtensionReaderContext; +} + +namespace CesiumGltfReader { +class EnumJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { +public: + using ValueType = CesiumGltf::Enum; + + EnumJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept; + void reset(IJsonHandler* pParentHandler, CesiumGltf::Enum* pObject); + + virtual IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeyEnum( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Enum& o); + +private: + CesiumGltf::Enum* _pObject = nullptr; + CesiumJsonReader::StringJsonHandler _name; + CesiumJsonReader::StringJsonHandler _description; + CesiumJsonReader::StringJsonHandler _valueType; + CesiumJsonReader:: + ArrayJsonHandler + _values; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataEnumValueJsonHandler.h b/CesiumGltfReader/generated/src/EnumValueJsonHandler.h similarity index 59% rename from CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataEnumValueJsonHandler.h rename to CesiumGltfReader/generated/src/EnumValueJsonHandler.h index 477f0bd4b..d56d90722 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataEnumValueJsonHandler.h +++ b/CesiumGltfReader/generated/src/EnumValueJsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include #include @@ -12,27 +12,25 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataEnumValueJsonHandler +class EnumValueJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataEnumValue; + using ValueType = CesiumGltf::EnumValue; - ExtensionExtStructuralMetadataEnumValueJsonHandler( + EnumValueJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset( - IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataEnumValue* pObject); + void reset(IJsonHandler* pParentHandler, CesiumGltf::EnumValue* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyExtensionExtStructuralMetadataEnumValue( + IJsonHandler* readObjectKeyEnumValue( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataEnumValue& o); + CesiumGltf::EnumValue& o); private: - CesiumGltf::ExtensionExtStructuralMetadataEnumValue* _pObject = nullptr; + CesiumGltf::EnumValue* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _name; CesiumJsonReader::StringJsonHandler _description; CesiumJsonReader::IntegerJsonHandler _value; diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataEnumJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataEnumJsonHandler.h deleted file mode 100644 index dad293d8e..000000000 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataEnumJsonHandler.h +++ /dev/null @@ -1,46 +0,0 @@ -// This file was generated by generate-classes. -// DO NOT EDIT THIS FILE! -#pragma once - -#include "ExtensionExtStructuralMetadataEnumValueJsonHandler.h" - -#include -#include -#include -#include - -namespace CesiumJsonReader { -class ExtensionReaderContext; -} - -namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataEnumJsonHandler - : public CesiumJsonReader::ExtensibleObjectJsonHandler { -public: - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataEnum; - - ExtensionExtStructuralMetadataEnumJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset( - IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataEnum* pObject); - - virtual IJsonHandler* readObjectKey(const std::string_view& str) override; - -protected: - IJsonHandler* readObjectKeyExtensionExtStructuralMetadataEnum( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataEnum& o); - -private: - CesiumGltf::ExtensionExtStructuralMetadataEnum* _pObject = nullptr; - CesiumJsonReader::StringJsonHandler _name; - CesiumJsonReader::StringJsonHandler _description; - CesiumJsonReader::StringJsonHandler _valueType; - CesiumJsonReader::ArrayJsonHandler< - CesiumGltf::ExtensionExtStructuralMetadataEnumValue, - ExtensionExtStructuralMetadataEnumValueJsonHandler> - _values; -}; -} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyAttributeJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyAttributeJsonHandler.h deleted file mode 100644 index c195cae56..000000000 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyAttributeJsonHandler.h +++ /dev/null @@ -1,46 +0,0 @@ -// This file was generated by generate-classes. -// DO NOT EDIT THIS FILE! -#pragma once - -#include "ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler.h" - -#include -#include -#include -#include - -namespace CesiumJsonReader { -class ExtensionReaderContext; -} - -namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataPropertyAttributeJsonHandler - : public CesiumJsonReader::ExtensibleObjectJsonHandler { -public: - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute; - - ExtensionExtStructuralMetadataPropertyAttributeJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset( - IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute* pObject); - - virtual IJsonHandler* readObjectKey(const std::string_view& str) override; - -protected: - IJsonHandler* readObjectKeyExtensionExtStructuralMetadataPropertyAttribute( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute& o); - -private: - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute* _pObject = - nullptr; - CesiumJsonReader::StringJsonHandler _name; - CesiumJsonReader::StringJsonHandler _classProperty; - CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty, - ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler> - _properties; -}; -} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataSchemaJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataSchemaJsonHandler.h deleted file mode 100644 index 78ba70d0c..000000000 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataSchemaJsonHandler.h +++ /dev/null @@ -1,52 +0,0 @@ -// This file was generated by generate-classes. -// DO NOT EDIT THIS FILE! -#pragma once - -#include "ExtensionExtStructuralMetadataClassJsonHandler.h" -#include "ExtensionExtStructuralMetadataEnumJsonHandler.h" - -#include -#include -#include -#include - -namespace CesiumJsonReader { -class ExtensionReaderContext; -} - -namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataSchemaJsonHandler - : public CesiumJsonReader::ExtensibleObjectJsonHandler { -public: - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataSchema; - - ExtensionExtStructuralMetadataSchemaJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset( - IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataSchema* pObject); - - virtual IJsonHandler* readObjectKey(const std::string_view& str) override; - -protected: - IJsonHandler* readObjectKeyExtensionExtStructuralMetadataSchema( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataSchema& o); - -private: - CesiumGltf::ExtensionExtStructuralMetadataSchema* _pObject = nullptr; - CesiumJsonReader::StringJsonHandler _id; - CesiumJsonReader::StringJsonHandler _name; - CesiumJsonReader::StringJsonHandler _description; - CesiumJsonReader::StringJsonHandler _version; - CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::ExtensionExtStructuralMetadataClass, - ExtensionExtStructuralMetadataClassJsonHandler> - _classes; - CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::ExtensionExtStructuralMetadataEnum, - ExtensionExtStructuralMetadataEnumJsonHandler> - _enums; -}; -} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionModelExtStructuralMetadataJsonHandler.h b/CesiumGltfReader/generated/src/ExtensionModelExtStructuralMetadataJsonHandler.h index 4d4ce5e18..3def01e1a 100644 --- a/CesiumGltfReader/generated/src/ExtensionModelExtStructuralMetadataJsonHandler.h +++ b/CesiumGltfReader/generated/src/ExtensionModelExtStructuralMetadataJsonHandler.h @@ -2,10 +2,10 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "ExtensionExtStructuralMetadataPropertyAttributeJsonHandler.h" -#include "ExtensionExtStructuralMetadataPropertyTableJsonHandler.h" -#include "ExtensionExtStructuralMetadataPropertyTextureJsonHandler.h" -#include "ExtensionExtStructuralMetadataSchemaJsonHandler.h" +#include "PropertyAttributeJsonHandler.h" +#include "PropertyTableJsonHandler.h" +#include "PropertyTextureJsonHandler.h" +#include "SchemaJsonHandler.h" #include #include @@ -91,19 +91,17 @@ class ExtensionModelExtStructuralMetadataJsonHandler private: CesiumGltf::ExtensionModelExtStructuralMetadata* _pObject = nullptr; - ExtensionExtStructuralMetadataSchemaJsonHandler _schema; + SchemaJsonHandler _schema; CesiumJsonReader::StringJsonHandler _schemaUri; + CesiumJsonReader:: + ArrayJsonHandler + _propertyTables; + CesiumJsonReader:: + ArrayJsonHandler + _propertyTextures; CesiumJsonReader::ArrayJsonHandler< - CesiumGltf::ExtensionExtStructuralMetadataPropertyTable, - ExtensionExtStructuralMetadataPropertyTableJsonHandler> - _propertyTables; - CesiumJsonReader::ArrayJsonHandler< - CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture, - ExtensionExtStructuralMetadataPropertyTextureJsonHandler> - _propertyTextures; - CesiumJsonReader::ArrayJsonHandler< - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute, - ExtensionExtStructuralMetadataPropertyAttributeJsonHandler> + CesiumGltf::PropertyAttribute, + PropertyAttributeJsonHandler> _propertyAttributes; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp index b65df862c..f7b8c5076 100644 --- a/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp +++ b/CesiumGltfReader/generated/src/GeneratedJsonHandlers.cpp @@ -1534,46 +1534,43 @@ ExtensionModelKhrMaterialsVariantsValueJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataPropertyAttributeJsonHandler.h" +#include "PropertyAttributeJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyAttributeJsonHandler:: - ExtensionExtStructuralMetadataPropertyAttributeJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +PropertyAttributeJsonHandler::PropertyAttributeJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _classProperty(), _properties(context) {} -void ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::reset( +void PropertyAttributeJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute* pObject) { + CesiumGltf::PropertyAttribute* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyAttributeJsonHandler::readObjectKey( - const std::string_view& str) { +PropertyAttributeJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyAttribute( - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute::TypeName, + return this->readObjectKeyPropertyAttribute( + CesiumGltf::PropertyAttribute::TypeName, str, *this->_pObject); } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyAttributeJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyAttribute( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute& o) { +PropertyAttributeJsonHandler::readObjectKeyPropertyAttribute( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::PropertyAttribute& o) { using namespace std::string_literals; if ("name"s == str) @@ -1589,18 +1586,17 @@ ExtensionExtStructuralMetadataPropertyAttributeJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler.h" +#include "PropertyAttributePropertyJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: - ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +PropertyAttributePropertyJsonHandler::PropertyAttributePropertyJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _attribute(), _offset(), @@ -1608,33 +1604,28 @@ ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: _max(), _min() {} -void ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler::reset( +void PropertyAttributePropertyJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty* - pObject) { + CesiumGltf::PropertyAttributeProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: - readObjectKey(const std::string_view& str) { +PropertyAttributePropertyJsonHandler::readObjectKey( + const std::string_view& str) { assert(this->_pObject); - return this - ->readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty( - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty:: - TypeName, - str, - *this->_pObject); + return this->readObjectKeyPropertyAttributeProperty( + CesiumGltf::PropertyAttributeProperty::TypeName, + str, + *this->_pObject); } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty& - o) { +PropertyAttributePropertyJsonHandler::readObjectKeyPropertyAttributeProperty( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::PropertyAttributeProperty& o) { using namespace std::string_literals; if ("attribute"s == str) @@ -1654,46 +1645,43 @@ ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataPropertyTextureJsonHandler.h" +#include "PropertyTextureJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTextureJsonHandler:: - ExtensionExtStructuralMetadataPropertyTextureJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +PropertyTextureJsonHandler::PropertyTextureJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _classProperty(), _properties(context) {} -void ExtensionExtStructuralMetadataPropertyTextureJsonHandler::reset( +void PropertyTextureJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture* pObject) { + CesiumGltf::PropertyTexture* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTextureJsonHandler::readObjectKey( - const std::string_view& str) { +PropertyTextureJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyTexture( - CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture::TypeName, + return this->readObjectKeyPropertyTexture( + CesiumGltf::PropertyTexture::TypeName, str, *this->_pObject); } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTextureJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyTexture( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture& o) { +PropertyTextureJsonHandler::readObjectKeyPropertyTexture( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::PropertyTexture& o) { using namespace std::string_literals; if ("name"s == str) @@ -1709,18 +1697,17 @@ ExtensionExtStructuralMetadataPropertyTextureJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler.h" +#include "PropertyTexturePropertyJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler:: - ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +PropertyTexturePropertyJsonHandler::PropertyTexturePropertyJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : TextureInfoJsonHandler(context), _channels(), _offset(), @@ -1728,32 +1715,27 @@ ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler:: _max(), _min() {} -void ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::reset( +void PropertyTexturePropertyJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty* - pObject) { + CesiumGltf::PropertyTextureProperty* pObject) { TextureInfoJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler::readObjectKey( - const std::string_view& str) { +PropertyTexturePropertyJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this - ->readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty( - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty:: - TypeName, - str, - *this->_pObject); + return this->readObjectKeyPropertyTextureProperty( + CesiumGltf::PropertyTextureProperty::TypeName, + str, + *this->_pObject); } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty& o) { +PropertyTexturePropertyJsonHandler::readObjectKeyPropertyTextureProperty( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::PropertyTextureProperty& o) { using namespace std::string_literals; if ("channels"s == str) @@ -1822,47 +1804,44 @@ TextureInfoJsonHandler::readObjectKeyTextureInfo( } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataPropertyTableJsonHandler.h" +#include "PropertyTableJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTableJsonHandler:: - ExtensionExtStructuralMetadataPropertyTableJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +PropertyTableJsonHandler::PropertyTableJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _classProperty(), _count(), _properties(context) {} -void ExtensionExtStructuralMetadataPropertyTableJsonHandler::reset( +void PropertyTableJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTable* pObject) { + CesiumGltf::PropertyTable* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTableJsonHandler::readObjectKey( - const std::string_view& str) { +PropertyTableJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyTable( - CesiumGltf::ExtensionExtStructuralMetadataPropertyTable::TypeName, + return this->readObjectKeyPropertyTable( + CesiumGltf::PropertyTable::TypeName, str, *this->_pObject); } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTableJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyTable( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTable& o) { +PropertyTableJsonHandler::readObjectKeyPropertyTable( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::PropertyTable& o) { using namespace std::string_literals; if ("name"s == str) @@ -1880,18 +1859,17 @@ ExtensionExtStructuralMetadataPropertyTableJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler.h" +#include "PropertyTablePropertyJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler:: - ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +PropertyTablePropertyJsonHandler::PropertyTablePropertyJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _values(), _arrayOffsets(), @@ -1903,29 +1881,27 @@ ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler:: _max(), _min() {} -void ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::reset( +void PropertyTablePropertyJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty* pObject) { + CesiumGltf::PropertyTableProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler::readObjectKey( - const std::string_view& str) { +PropertyTablePropertyJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty( - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty::TypeName, + return this->readObjectKeyPropertyTableProperty( + CesiumGltf::PropertyTableProperty::TypeName, str, *this->_pObject); } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty& o) { +PropertyTablePropertyJsonHandler::readObjectKeyPropertyTableProperty( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::PropertyTableProperty& o) { using namespace std::string_literals; if ("values"s == str) @@ -1959,18 +1935,17 @@ ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataSchemaJsonHandler.h" +#include "SchemaJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataSchemaJsonHandler:: - ExtensionExtStructuralMetadataSchemaJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +SchemaJsonHandler::SchemaJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _id(), _name(), @@ -1979,29 +1954,26 @@ ExtensionExtStructuralMetadataSchemaJsonHandler:: _classes(context), _enums(context) {} -void ExtensionExtStructuralMetadataSchemaJsonHandler::reset( +void SchemaJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataSchema* pObject) { + CesiumGltf::Schema* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataSchemaJsonHandler::readObjectKey( - const std::string_view& str) { +SchemaJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataSchema( - CesiumGltf::ExtensionExtStructuralMetadataSchema::TypeName, + return this->readObjectKeySchema( + CesiumGltf::Schema::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataSchemaJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataSchema( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataSchema& o) { +CesiumJsonReader::IJsonHandler* SchemaJsonHandler::readObjectKeySchema( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Schema& o) { using namespace std::string_literals; if ("id"s == str) @@ -2023,46 +1995,43 @@ ExtensionExtStructuralMetadataSchemaJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataEnumJsonHandler.h" +#include "EnumJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataEnumJsonHandler:: - ExtensionExtStructuralMetadataEnumJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +EnumJsonHandler::EnumJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _valueType(), _values(context) {} -void ExtensionExtStructuralMetadataEnumJsonHandler::reset( +void EnumJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataEnum* pObject) { + CesiumGltf::Enum* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataEnumJsonHandler::readObjectKey( - const std::string_view& str) { +EnumJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataEnum( - CesiumGltf::ExtensionExtStructuralMetadataEnum::TypeName, + return this->readObjectKeyEnum( + CesiumGltf::Enum::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataEnum( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataEnum& o) { +CesiumJsonReader::IJsonHandler* EnumJsonHandler::readObjectKeyEnum( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Enum& o) { using namespace std::string_literals; if ("name"s == str) @@ -2080,46 +2049,42 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataEnumJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataEnumValueJsonHandler.h" +#include "EnumValueJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataEnumValueJsonHandler:: - ExtensionExtStructuralMetadataEnumValueJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +EnumValueJsonHandler::EnumValueJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _value() {} -void ExtensionExtStructuralMetadataEnumValueJsonHandler::reset( +void EnumValueJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataEnumValue* pObject) { + CesiumGltf::EnumValue* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataEnumValueJsonHandler::readObjectKey( - const std::string_view& str) { +EnumValueJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataEnumValue( - CesiumGltf::ExtensionExtStructuralMetadataEnumValue::TypeName, + return this->readObjectKeyEnumValue( + CesiumGltf::EnumValue::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataEnumValueJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataEnumValue( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataEnumValue& o) { +CesiumJsonReader::IJsonHandler* EnumValueJsonHandler::readObjectKeyEnumValue( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::EnumValue& o) { using namespace std::string_literals; if ("name"s == str) @@ -2135,45 +2100,42 @@ ExtensionExtStructuralMetadataEnumValueJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataClassJsonHandler.h" +#include "ClassJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataClassJsonHandler:: - ExtensionExtStructuralMetadataClassJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +ClassJsonHandler::ClassJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), _properties(context) {} -void ExtensionExtStructuralMetadataClassJsonHandler::reset( +void ClassJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataClass* pObject) { + CesiumGltf::Class* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataClassJsonHandler::readObjectKey( - const std::string_view& str) { +ClassJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataClass( - CesiumGltf::ExtensionExtStructuralMetadataClass::TypeName, + return this->readObjectKeyClass( + CesiumGltf::Class::TypeName, str, *this->_pObject); } -CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataClass( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataClass& o) { +CesiumJsonReader::IJsonHandler* ClassJsonHandler::readObjectKeyClass( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Class& o) { using namespace std::string_literals; if ("name"s == str) @@ -2189,18 +2151,17 @@ CesiumJsonReader::IJsonHandler* ExtensionExtStructuralMetadataClassJsonHandler:: } // namespace CesiumGltfReader // This file was generated by generate-classes. // DO NOT EDIT THIS FILE! -#include "ExtensionExtStructuralMetadataClassPropertyJsonHandler.h" +#include "ClassPropertyJsonHandler.h" -#include +#include #include #include namespace CesiumGltfReader { -ExtensionExtStructuralMetadataClassPropertyJsonHandler:: - ExtensionExtStructuralMetadataClassPropertyJsonHandler( - const CesiumJsonReader::ExtensionReaderContext& context) noexcept +ClassPropertyJsonHandler::ClassPropertyJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept : CesiumJsonReader::ExtensibleObjectJsonHandler(context), _name(), _description(), @@ -2219,29 +2180,27 @@ ExtensionExtStructuralMetadataClassPropertyJsonHandler:: _defaultProperty(), _semantic() {} -void ExtensionExtStructuralMetadataClassPropertyJsonHandler::reset( +void ClassPropertyJsonHandler::reset( CesiumJsonReader::IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataClassProperty* pObject) { + CesiumGltf::ClassProperty* pObject) { CesiumJsonReader::ExtensibleObjectJsonHandler::reset(pParentHandler, pObject); this->_pObject = pObject; } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataClassPropertyJsonHandler::readObjectKey( - const std::string_view& str) { +ClassPropertyJsonHandler::readObjectKey(const std::string_view& str) { assert(this->_pObject); - return this->readObjectKeyExtensionExtStructuralMetadataClassProperty( - CesiumGltf::ExtensionExtStructuralMetadataClassProperty::TypeName, + return this->readObjectKeyClassProperty( + CesiumGltf::ClassProperty::TypeName, str, *this->_pObject); } CesiumJsonReader::IJsonHandler* -ExtensionExtStructuralMetadataClassPropertyJsonHandler:: - readObjectKeyExtensionExtStructuralMetadataClassProperty( - const std::string& objectType, - const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataClassProperty& o) { +ClassPropertyJsonHandler::readObjectKeyClassProperty( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::ClassProperty& o) { using namespace std::string_literals; if ("name"s == str) diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataClassJsonHandler.h b/CesiumGltfReader/generated/src/PropertyAttributeJsonHandler.h similarity index 50% rename from CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataClassJsonHandler.h rename to CesiumGltfReader/generated/src/PropertyAttributeJsonHandler.h index ba06f5973..8f870958c 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataClassJsonHandler.h +++ b/CesiumGltfReader/generated/src/PropertyAttributeJsonHandler.h @@ -2,9 +2,9 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "ExtensionExtStructuralMetadataClassPropertyJsonHandler.h" +#include "PropertyAttributePropertyJsonHandler.h" -#include +#include #include #include #include @@ -14,32 +14,31 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataClassJsonHandler +class PropertyAttributeJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataClass; + using ValueType = CesiumGltf::PropertyAttribute; - ExtensionExtStructuralMetadataClassJsonHandler( + PropertyAttributeJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset( - IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataClass* pObject); + void + reset(IJsonHandler* pParentHandler, CesiumGltf::PropertyAttribute* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyExtensionExtStructuralMetadataClass( + IJsonHandler* readObjectKeyPropertyAttribute( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataClass& o); + CesiumGltf::PropertyAttribute& o); private: - CesiumGltf::ExtensionExtStructuralMetadataClass* _pObject = nullptr; + CesiumGltf::PropertyAttribute* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _name; - CesiumJsonReader::StringJsonHandler _description; + CesiumJsonReader::StringJsonHandler _classProperty; CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::ExtensionExtStructuralMetadataClassProperty, - ExtensionExtStructuralMetadataClassPropertyJsonHandler> + CesiumGltf::PropertyAttributeProperty, + PropertyAttributePropertyJsonHandler> _properties; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler.h b/CesiumGltfReader/generated/src/PropertyAttributePropertyJsonHandler.h similarity index 59% rename from CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler.h rename to CesiumGltfReader/generated/src/PropertyAttributePropertyJsonHandler.h index 4a91ba0b8..8851411be 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler.h +++ b/CesiumGltfReader/generated/src/PropertyAttributePropertyJsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include #include @@ -12,31 +12,27 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler +class PropertyAttributePropertyJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty; + using ValueType = CesiumGltf::PropertyAttributeProperty; - ExtensionExtStructuralMetadataPropertyAttributePropertyJsonHandler( + PropertyAttributePropertyJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; void reset( IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty* - pObject); + CesiumGltf::PropertyAttributeProperty* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* - readObjectKeyExtensionExtStructuralMetadataPropertyAttributeProperty( + IJsonHandler* readObjectKeyPropertyAttributeProperty( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty& o); + CesiumGltf::PropertyAttributeProperty& o); private: - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty* - _pObject = nullptr; + CesiumGltf::PropertyAttributeProperty* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _attribute; CesiumJsonReader::JsonObjectJsonHandler _offset; CesiumJsonReader::JsonObjectJsonHandler _scale; diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTableJsonHandler.h b/CesiumGltfReader/generated/src/PropertyTableJsonHandler.h similarity index 53% rename from CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTableJsonHandler.h rename to CesiumGltfReader/generated/src/PropertyTableJsonHandler.h index f4f3ee112..3fa49ed20 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTableJsonHandler.h +++ b/CesiumGltfReader/generated/src/PropertyTableJsonHandler.h @@ -2,9 +2,9 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler.h" +#include "PropertyTablePropertyJsonHandler.h" -#include +#include #include #include #include @@ -15,33 +15,31 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataPropertyTableJsonHandler +class PropertyTableJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataPropertyTable; + using ValueType = CesiumGltf::PropertyTable; - ExtensionExtStructuralMetadataPropertyTableJsonHandler( + PropertyTableJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset( - IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTable* pObject); + void reset(IJsonHandler* pParentHandler, CesiumGltf::PropertyTable* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyExtensionExtStructuralMetadataPropertyTable( + IJsonHandler* readObjectKeyPropertyTable( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTable& o); + CesiumGltf::PropertyTable& o); private: - CesiumGltf::ExtensionExtStructuralMetadataPropertyTable* _pObject = nullptr; + CesiumGltf::PropertyTable* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _name; CesiumJsonReader::StringJsonHandler _classProperty; CesiumJsonReader::IntegerJsonHandler _count; CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty, - ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler> + CesiumGltf::PropertyTableProperty, + PropertyTablePropertyJsonHandler> _properties; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler.h b/CesiumGltfReader/generated/src/PropertyTablePropertyJsonHandler.h similarity index 66% rename from CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler.h rename to CesiumGltfReader/generated/src/PropertyTablePropertyJsonHandler.h index 6051f6973..20951fbc1 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler.h +++ b/CesiumGltfReader/generated/src/PropertyTablePropertyJsonHandler.h @@ -2,7 +2,7 @@ // DO NOT EDIT THIS FILE! #pragma once -#include +#include #include #include #include @@ -13,30 +13,27 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler +class PropertyTablePropertyJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty; + using ValueType = CesiumGltf::PropertyTableProperty; - ExtensionExtStructuralMetadataPropertyTablePropertyJsonHandler( + PropertyTablePropertyJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; void reset( IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty* pObject); + CesiumGltf::PropertyTableProperty* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* - readObjectKeyExtensionExtStructuralMetadataPropertyTableProperty( + IJsonHandler* readObjectKeyPropertyTableProperty( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty& o); + CesiumGltf::PropertyTableProperty& o); private: - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty* _pObject = - nullptr; + CesiumGltf::PropertyTableProperty* _pObject = nullptr; CesiumJsonReader::IntegerJsonHandler _values; CesiumJsonReader::IntegerJsonHandler _arrayOffsets; CesiumJsonReader::IntegerJsonHandler _stringOffsets; diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTextureJsonHandler.h b/CesiumGltfReader/generated/src/PropertyTextureJsonHandler.h similarity index 50% rename from CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTextureJsonHandler.h rename to CesiumGltfReader/generated/src/PropertyTextureJsonHandler.h index aa8e3c513..16c7b9c45 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTextureJsonHandler.h +++ b/CesiumGltfReader/generated/src/PropertyTextureJsonHandler.h @@ -2,9 +2,9 @@ // DO NOT EDIT THIS FILE! #pragma once -#include "ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler.h" +#include "PropertyTexturePropertyJsonHandler.h" -#include +#include #include #include #include @@ -14,32 +14,31 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataPropertyTextureJsonHandler +class PropertyTextureJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { public: - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture; + using ValueType = CesiumGltf::PropertyTexture; - ExtensionExtStructuralMetadataPropertyTextureJsonHandler( + PropertyTextureJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; - void reset( - IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture* pObject); + void + reset(IJsonHandler* pParentHandler, CesiumGltf::PropertyTexture* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* readObjectKeyExtensionExtStructuralMetadataPropertyTexture( + IJsonHandler* readObjectKeyPropertyTexture( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture& o); + CesiumGltf::PropertyTexture& o); private: - CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture* _pObject = nullptr; + CesiumGltf::PropertyTexture* _pObject = nullptr; CesiumJsonReader::StringJsonHandler _name; CesiumJsonReader::StringJsonHandler _classProperty; CesiumJsonReader::DictionaryJsonHandler< - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty, - ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler> + CesiumGltf::PropertyTextureProperty, + PropertyTexturePropertyJsonHandler> _properties; }; } // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler.h b/CesiumGltfReader/generated/src/PropertyTexturePropertyJsonHandler.h similarity index 59% rename from CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler.h rename to CesiumGltfReader/generated/src/PropertyTexturePropertyJsonHandler.h index 2b2527250..1b30d241c 100644 --- a/CesiumGltfReader/generated/src/ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler.h +++ b/CesiumGltfReader/generated/src/PropertyTexturePropertyJsonHandler.h @@ -4,7 +4,7 @@ #include "TextureInfoJsonHandler.h" -#include +#include #include #include #include @@ -14,31 +14,26 @@ class ExtensionReaderContext; } namespace CesiumGltfReader { -class ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler - : public TextureInfoJsonHandler { +class PropertyTexturePropertyJsonHandler : public TextureInfoJsonHandler { public: - using ValueType = - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty; + using ValueType = CesiumGltf::PropertyTextureProperty; - ExtensionExtStructuralMetadataPropertyTexturePropertyJsonHandler( + PropertyTexturePropertyJsonHandler( const CesiumJsonReader::ExtensionReaderContext& context) noexcept; void reset( IJsonHandler* pParentHandler, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty* - pObject); + CesiumGltf::PropertyTextureProperty* pObject); virtual IJsonHandler* readObjectKey(const std::string_view& str) override; protected: - IJsonHandler* - readObjectKeyExtensionExtStructuralMetadataPropertyTextureProperty( + IJsonHandler* readObjectKeyPropertyTextureProperty( const std::string& objectType, const std::string_view& str, - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty& o); + CesiumGltf::PropertyTextureProperty& o); private: - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty* _pObject = - nullptr; + CesiumGltf::PropertyTextureProperty* _pObject = nullptr; CesiumJsonReader:: ArrayJsonHandler> _channels; diff --git a/CesiumGltfReader/generated/src/SchemaJsonHandler.h b/CesiumGltfReader/generated/src/SchemaJsonHandler.h new file mode 100644 index 000000000..ffc2ca7eb --- /dev/null +++ b/CesiumGltfReader/generated/src/SchemaJsonHandler.h @@ -0,0 +1,45 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include "ClassJsonHandler.h" +#include "EnumJsonHandler.h" + +#include +#include +#include +#include + +namespace CesiumJsonReader { +class ExtensionReaderContext; +} + +namespace CesiumGltfReader { +class SchemaJsonHandler : public CesiumJsonReader::ExtensibleObjectJsonHandler { +public: + using ValueType = CesiumGltf::Schema; + + SchemaJsonHandler( + const CesiumJsonReader::ExtensionReaderContext& context) noexcept; + void reset(IJsonHandler* pParentHandler, CesiumGltf::Schema* pObject); + + virtual IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeySchema( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::Schema& o); + +private: + CesiumGltf::Schema* _pObject = nullptr; + CesiumJsonReader::StringJsonHandler _id; + CesiumJsonReader::StringJsonHandler _name; + CesiumJsonReader::StringJsonHandler _description; + CesiumJsonReader::StringJsonHandler _version; + CesiumJsonReader::DictionaryJsonHandler + _classes; + CesiumJsonReader::DictionaryJsonHandler + _enums; +}; +} // namespace CesiumGltfReader diff --git a/CesiumGltfReader/generated/src/registerExtensions.cpp b/CesiumGltfReader/generated/src/registerExtensions.cpp index 1c46f4ba9..15deefecc 100644 --- a/CesiumGltfReader/generated/src/registerExtensions.cpp +++ b/CesiumGltfReader/generated/src/registerExtensions.cpp @@ -3,61 +3,98 @@ #include "registerExtensions.h" -#include - -#include -#include -#include -#include -#include -#include -#include -#include - +#include "ExtensionBufferExtMeshoptCompressionJsonHandler.h" +#include "ExtensionBufferViewExtMeshoptCompressionJsonHandler.h" #include "ExtensionCesiumRTCJsonHandler.h" -#include "ExtensionModelExtFeatureMetadataJsonHandler.h" -#include "ExtensionModelExtStructuralMetadataJsonHandler.h" -#include "ExtensionModelKhrMaterialsVariantsJsonHandler.h" -#include "ExtensionModelMaxarMeshVariantsJsonHandler.h" #include "ExtensionCesiumTileEdgesJsonHandler.h" -#include "ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler.h" -#include "ExtensionExtMeshFeaturesJsonHandler.h" -#include "ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler.h" -#include "ExtensionKhrDracoMeshCompressionJsonHandler.h" -#include "ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler.h" #include "ExtensionExtInstanceFeaturesJsonHandler.h" +#include "ExtensionExtMeshFeaturesJsonHandler.h" #include "ExtensionExtMeshGpuInstancingJsonHandler.h" -#include "ExtensionNodeMaxarMeshVariantsJsonHandler.h" -#include "ExtensionBufferExtMeshoptCompressionJsonHandler.h" -#include "ExtensionBufferViewExtMeshoptCompressionJsonHandler.h" +#include "ExtensionKhrDracoMeshCompressionJsonHandler.h" #include "ExtensionKhrMaterialsUnlitJsonHandler.h" #include "ExtensionKhrTextureBasisuJsonHandler.h" +#include "ExtensionKhrTextureTransformJsonHandler.h" +#include "ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler.h" +#include "ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler.h" +#include "ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler.h" +#include "ExtensionModelExtFeatureMetadataJsonHandler.h" +#include "ExtensionModelExtStructuralMetadataJsonHandler.h" +#include "ExtensionModelKhrMaterialsVariantsJsonHandler.h" +#include "ExtensionModelMaxarMeshVariantsJsonHandler.h" +#include "ExtensionNodeMaxarMeshVariantsJsonHandler.h" #include "ExtensionTextureWebpJsonHandler.h" -#include "ExtensionKhrTextureTransformJsonHandler.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace CesiumGltfReader { void registerExtensions(CesiumJsonReader::ExtensionReaderContext& context) { (void)context; context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); + context.registerExtension< + CesiumGltf::Model, + ExtensionModelExtFeatureMetadataJsonHandler>(); + context.registerExtension< + CesiumGltf::Model, + ExtensionModelExtStructuralMetadataJsonHandler>(); + context.registerExtension< + CesiumGltf::Model, + ExtensionModelKhrMaterialsVariantsJsonHandler>(); + context.registerExtension< + CesiumGltf::Model, + ExtensionModelMaxarMeshVariantsJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionCesiumTileEdgesJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionExtMeshFeaturesJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionKhrDracoMeshCompressionJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler>(); + context.registerExtension< + CesiumGltf::Node, + ExtensionExtInstanceFeaturesJsonHandler>(); + context.registerExtension< + CesiumGltf::Node, + ExtensionExtMeshGpuInstancingJsonHandler>(); + context.registerExtension< + CesiumGltf::Node, + ExtensionNodeMaxarMeshVariantsJsonHandler>(); + context.registerExtension< + CesiumGltf::Buffer, + ExtensionBufferExtMeshoptCompressionJsonHandler>(); + context.registerExtension< + CesiumGltf::BufferView, + ExtensionBufferViewExtMeshoptCompressionJsonHandler>(); + context.registerExtension< + CesiumGltf::Material, + ExtensionKhrMaterialsUnlitJsonHandler>(); + context.registerExtension< + CesiumGltf::Texture, + ExtensionKhrTextureBasisuJsonHandler>(); + context.registerExtension< + CesiumGltf::Texture, + ExtensionTextureWebpJsonHandler>(); + context.registerExtension< + CesiumGltf::TextureInfo, + ExtensionKhrTextureTransformJsonHandler>(); } } // namespace CesiumGltfReader diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp index a008e3e3c..2d2e38fc2 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.cpp @@ -17,6 +17,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -40,17 +44,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -79,8 +72,15 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include +#include #include #include #include @@ -216,24 +216,22 @@ void writeJson( const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute& obj, + const CesiumGltf::PropertyAttribute& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty& - obj, + const CesiumGltf::PropertyAttributeProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture& obj, + const CesiumGltf::PropertyTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty& - obj, + const CesiumGltf::PropertyTextureProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); @@ -243,37 +241,37 @@ void writeJson( const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTable& obj, + const CesiumGltf::PropertyTable& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty& obj, + const CesiumGltf::PropertyTableProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataSchema& obj, + const CesiumGltf::Schema& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataEnum& obj, + const CesiumGltf::Enum& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataEnumValue& obj, + const CesiumGltf::EnumValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataClass& obj, + const CesiumGltf::Class& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataClassProperty& obj, + const CesiumGltf::ClassProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); @@ -1168,7 +1166,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute& obj, + const CesiumGltf::PropertyAttribute& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1192,8 +1190,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty& - obj, + const CesiumGltf::PropertyAttributeProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1227,7 +1224,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture& obj, + const CesiumGltf::PropertyTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1251,8 +1248,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty& - obj, + const CesiumGltf::PropertyTextureProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1300,7 +1296,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTable& obj, + const CesiumGltf::PropertyTable& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1327,7 +1323,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty& obj, + const CesiumGltf::PropertyTableProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1348,15 +1344,13 @@ void writeJson( } if (obj.arrayOffsetType != - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT32) { + CesiumGltf::PropertyTableProperty::ArrayOffsetType::UINT32) { jsonWriter.Key("arrayOffsetType"); writeJson(obj.arrayOffsetType, jsonWriter, context); } if (obj.stringOffsetType != - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT32) { + CesiumGltf::PropertyTableProperty::StringOffsetType::UINT32) { jsonWriter.Key("stringOffsetType"); writeJson(obj.stringOffsetType, jsonWriter, context); } @@ -1387,7 +1381,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataSchema& obj, + const CesiumGltf::Schema& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1426,7 +1420,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataEnum& obj, + const CesiumGltf::Enum& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1441,8 +1435,7 @@ void writeJson( writeJson(obj.description, jsonWriter, context); } - if (obj.valueType != - CesiumGltf::ExtensionExtStructuralMetadataEnum::ValueType::UINT16) { + if (obj.valueType != CesiumGltf::Enum::ValueType::UINT16) { jsonWriter.Key("valueType"); writeJson(obj.valueType, jsonWriter, context); } @@ -1458,7 +1451,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataEnumValue& obj, + const CesiumGltf::EnumValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1480,7 +1473,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataClass& obj, + const CesiumGltf::Class& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -1506,7 +1499,7 @@ void writeJson( } void writeJson( - const CesiumGltf::ExtensionExtStructuralMetadataClassProperty& obj, + const CesiumGltf::ClassProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { jsonWriter.StartObject(); @@ -3091,31 +3084,29 @@ void ExtensionModelKhrMaterialsVariantsValueJsonWriter::write( writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataPropertyAttributeJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute& obj, +void PropertyAttributeJsonWriter::write( + const CesiumGltf::PropertyAttribute& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataPropertyAttributePropertyJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty& - obj, +void PropertyAttributePropertyJsonWriter::write( + const CesiumGltf::PropertyAttributeProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataPropertyTextureJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture& obj, +void PropertyTextureJsonWriter::write( + const CesiumGltf::PropertyTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataPropertyTexturePropertyJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty& - obj, +void PropertyTexturePropertyJsonWriter::write( + const CesiumGltf::PropertyTextureProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); @@ -3128,50 +3119,50 @@ void TextureInfoJsonWriter::write( writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataPropertyTableJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTable& obj, +void PropertyTableJsonWriter::write( + const CesiumGltf::PropertyTable& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataPropertyTablePropertyJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty& obj, +void PropertyTablePropertyJsonWriter::write( + const CesiumGltf::PropertyTableProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataSchemaJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataSchema& obj, +void SchemaJsonWriter::write( + const CesiumGltf::Schema& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataEnumJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataEnum& obj, +void EnumJsonWriter::write( + const CesiumGltf::Enum& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataEnumValueJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataEnumValue& obj, +void EnumValueJsonWriter::write( + const CesiumGltf::EnumValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataClassJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataClass& obj, +void ClassJsonWriter::write( + const CesiumGltf::Class& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); } -void ExtensionExtStructuralMetadataClassPropertyJsonWriter::write( - const CesiumGltf::ExtensionExtStructuralMetadataClassProperty& obj, +void ClassPropertyJsonWriter::write( + const CesiumGltf::ClassProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context) { writeJson(obj, jsonWriter, context); diff --git a/CesiumGltfWriter/generated/src/ModelJsonWriter.h b/CesiumGltfWriter/generated/src/ModelJsonWriter.h index 6ea76be94..e60717f4d 100644 --- a/CesiumGltfWriter/generated/src/ModelJsonWriter.h +++ b/CesiumGltfWriter/generated/src/ModelJsonWriter.h @@ -34,18 +34,18 @@ struct ExtensionNodeMaxarMeshVariantsMappingsValue; struct ExtensionModelMaxarMeshVariantsValue; struct ExtensionMeshPrimitiveKhrMaterialsVariantsMappingsValue; struct ExtensionModelKhrMaterialsVariantsValue; -struct ExtensionExtStructuralMetadataPropertyAttribute; -struct ExtensionExtStructuralMetadataPropertyAttributeProperty; -struct ExtensionExtStructuralMetadataPropertyTexture; -struct ExtensionExtStructuralMetadataPropertyTextureProperty; +struct PropertyAttribute; +struct PropertyAttributeProperty; +struct PropertyTexture; +struct PropertyTextureProperty; struct TextureInfo; -struct ExtensionExtStructuralMetadataPropertyTable; -struct ExtensionExtStructuralMetadataPropertyTableProperty; -struct ExtensionExtStructuralMetadataSchema; -struct ExtensionExtStructuralMetadataEnum; -struct ExtensionExtStructuralMetadataEnumValue; -struct ExtensionExtStructuralMetadataClass; -struct ExtensionExtStructuralMetadataClassProperty; +struct PropertyTable; +struct PropertyTableProperty; +struct Schema; +struct Enum; +struct EnumValue; +struct Class; +struct ClassProperty; struct FeatureId; struct FeatureIdTexture; struct ExtensionExtInstanceFeaturesFeatureId; @@ -354,42 +354,38 @@ struct ExtensionModelKhrMaterialsVariantsValueJsonWriter { const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataPropertyAttributeJsonWriter { - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute; +struct PropertyAttributeJsonWriter { + using ValueType = CesiumGltf::PropertyAttribute; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyAttribute& obj, + const CesiumGltf::PropertyAttribute& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataPropertyAttributePropertyJsonWriter { - using ValueType = - CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty; +struct PropertyAttributePropertyJsonWriter { + using ValueType = CesiumGltf::PropertyAttributeProperty; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyAttributeProperty& - obj, + const CesiumGltf::PropertyAttributeProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataPropertyTextureJsonWriter { - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture; +struct PropertyTextureJsonWriter { + using ValueType = CesiumGltf::PropertyTexture; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTexture& obj, + const CesiumGltf::PropertyTexture& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataPropertyTexturePropertyJsonWriter { - using ValueType = - CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty; +struct PropertyTexturePropertyJsonWriter { + using ValueType = CesiumGltf::PropertyTextureProperty; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTextureProperty& - obj, + const CesiumGltf::PropertyTextureProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; @@ -403,67 +399,65 @@ struct TextureInfoJsonWriter { const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataPropertyTableJsonWriter { - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataPropertyTable; +struct PropertyTableJsonWriter { + using ValueType = CesiumGltf::PropertyTable; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTable& obj, + const CesiumGltf::PropertyTable& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataPropertyTablePropertyJsonWriter { - using ValueType = - CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty; +struct PropertyTablePropertyJsonWriter { + using ValueType = CesiumGltf::PropertyTableProperty; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataPropertyTableProperty& - obj, + const CesiumGltf::PropertyTableProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataSchemaJsonWriter { - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataSchema; +struct SchemaJsonWriter { + using ValueType = CesiumGltf::Schema; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataSchema& obj, + const CesiumGltf::Schema& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataEnumJsonWriter { - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataEnum; +struct EnumJsonWriter { + using ValueType = CesiumGltf::Enum; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataEnum& obj, + const CesiumGltf::Enum& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataEnumValueJsonWriter { - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataEnumValue; +struct EnumValueJsonWriter { + using ValueType = CesiumGltf::EnumValue; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataEnumValue& obj, + const CesiumGltf::EnumValue& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataClassJsonWriter { - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataClass; +struct ClassJsonWriter { + using ValueType = CesiumGltf::Class; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataClass& obj, + const CesiumGltf::Class& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; -struct ExtensionExtStructuralMetadataClassPropertyJsonWriter { - using ValueType = CesiumGltf::ExtensionExtStructuralMetadataClassProperty; +struct ClassPropertyJsonWriter { + using ValueType = CesiumGltf::ClassProperty; static void write( - const CesiumGltf::ExtensionExtStructuralMetadataClassProperty& obj, + const CesiumGltf::ClassProperty& obj, CesiumJsonWriter::JsonWriter& jsonWriter, const CesiumJsonWriter::ExtensionWriterContext& context); }; diff --git a/tools/generate-classes/glTF.json b/tools/generate-classes/glTF.json index e6b7e699a..c08c9f865 100644 --- a/tools/generate-classes/glTF.json +++ b/tools/generate-classes/glTF.json @@ -118,37 +118,37 @@ "overrideName": "ExtensionMeshPrimitiveExtStructuralMetadata" }, "Class Property in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataClassProperty" + "overrideName": "ClassProperty" }, "Class in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataClass" + "overrideName": "Class" }, "Enum in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataEnum" + "overrideName": "Enum" }, "Enum Value in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataEnumValue" + "overrideName": "EnumValue" }, "Property Attribute Property in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataPropertyAttributeProperty" + "overrideName": "PropertyAttributeProperty" }, "Property Attribute in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataPropertyAttribute" + "overrideName": "PropertyAttribute" }, "Property Table Property in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataPropertyTableProperty" + "overrideName": "PropertyTableProperty" }, "Property Table in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataPropertyTable" + "overrideName": "PropertyTable" }, "Property Texture Property in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataPropertyTextureProperty" + "overrideName": "PropertyTextureProperty" }, "Property Texture in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataPropertyTexture" + "overrideName": "PropertyTexture" }, "Schema in EXT_structural_metadata": { - "overrideName": "ExtensionExtStructuralMetadataSchema" + "overrideName": "Schema" }, "Any Value": { "overrideName": "CesiumUtility::JsonValue" From c329a8d407aa683b67fdd88c6e653dc304cccdf0 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 16 Jun 2023 16:25:39 -0400 Subject: [PATCH 058/121] Replace class names in metadata implementation files --- .../BatchTableToGltfStructuralMetadata.cpp | 191 ++-- .../src/upsampleGltfForRasterOverlays.cpp | 3 +- ...gradeBatchTableToExtStructuralMetadata.cpp | 450 ++++------ .../include/CesiumGltf/PropertyArrayView.h | 3 +- .../CesiumGltf/PropertyTablePropertyView.h | 53 +- .../include/CesiumGltf/PropertyTableView.h | 92 +- .../CesiumGltf/PropertyTexturePropertyView.h | 22 +- .../include/CesiumGltf/PropertyTextureView.h | 24 +- CesiumGltf/src/PropertyTableView.cpp | 23 +- .../src/PropertyTexturePropertyView.cpp | 5 +- CesiumGltf/src/PropertyTextureView.cpp | 5 +- CesiumGltf/src/PropertyType.cpp | 117 ++- CesiumGltf/test/TestPropertyTableView.cpp | 815 +++++++----------- .../test/TestPropertyTexturePropertyView.cpp | 135 ++- CesiumGltf/test/TestPropertyTextureView.cpp | 89 +- CesiumGltf/test/TestPropertyType.cpp | 145 ++-- 16 files changed, 873 insertions(+), 1299 deletions(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 7010cc286..b78b73764 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -241,22 +241,10 @@ struct GltfPropertyTableType { }; const std::map batchTableTypeToGltfType = { - {"SCALAR", - GltfPropertyTableType{ - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - 1}}, - {"VEC2", - GltfPropertyTableType{ - ExtensionExtStructuralMetadataClassProperty::Type::VEC2, - 2}}, - {"VEC3", - GltfPropertyTableType{ - ExtensionExtStructuralMetadataClassProperty::Type::VEC3, - 3}}, - {"VEC4", - GltfPropertyTableType{ - ExtensionExtStructuralMetadataClassProperty::Type::VEC4, - 4}}, + {"SCALAR", GltfPropertyTableType{ClassProperty::Type::SCALAR, 1}}, + {"VEC2", GltfPropertyTableType{ClassProperty::Type::VEC2, 2}}, + {"VEC3", GltfPropertyTableType{ClassProperty::Type::VEC3, 3}}, + {"VEC4", GltfPropertyTableType{ClassProperty::Type::VEC4, 4}}, }; struct GltfPropertyTableComponentType { @@ -268,37 +256,35 @@ const std::map batchTableComponentTypeToGltfComponentType = { {"BYTE", GltfPropertyTableComponentType{ - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + ClassProperty::ComponentType::INT8, sizeof(int8_t)}}, {"UNSIGNED_BYTE", GltfPropertyTableComponentType{ - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8, + ClassProperty::ComponentType::UINT8, sizeof(uint8_t)}}, {"SHORT", GltfPropertyTableComponentType{ - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16, + ClassProperty::ComponentType::INT16, sizeof(int16_t)}}, {"UNSIGNED_SHORT", GltfPropertyTableComponentType{ - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16, + ClassProperty::ComponentType::UINT16, sizeof(uint16_t)}}, {"INT", GltfPropertyTableComponentType{ - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32, + ClassProperty::ComponentType::INT32, sizeof(int32_t)}}, {"UNSIGNED_INT", GltfPropertyTableComponentType{ - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32, + ClassProperty::ComponentType::UINT32, sizeof(uint32_t)}}, {"FLOAT", GltfPropertyTableComponentType{ - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - FLOAT32, + ClassProperty::ComponentType::FLOAT32, sizeof(float)}}, {"DOUBLE", GltfPropertyTableComponentType{ - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - FLOAT64, + ClassProperty::ComponentType::FLOAT64, sizeof(double)}}, }; @@ -466,9 +452,9 @@ int32_t addBufferToGltf(Model& gltf, std::vector&& buffer) { template void updateExtensionWithJsonStringProperty( Model& gltf, - ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, + ClassProperty& classProperty, + const PropertyTable& propertyTable, + PropertyTableProperty& propertyTableProperty, const TValueGetter& propertyValue) { rapidjson::StringBuffer rapidjsonStrBuffer; @@ -511,8 +497,7 @@ void updateExtensionWithJsonStringProperty( buffer, offsetBuffer); propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT8; + PropertyTableProperty::StringOffsetType::UINT8; } else if (isInRangeForUnsignedInteger(totalSize)) { copyStringBuffer( rapidjsonStrBuffer, @@ -520,8 +505,7 @@ void updateExtensionWithJsonStringProperty( buffer, offsetBuffer); propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT16; + PropertyTableProperty::StringOffsetType::UINT16; } else if (isInRangeForUnsignedInteger(totalSize)) { copyStringBuffer( rapidjsonStrBuffer, @@ -529,8 +513,7 @@ void updateExtensionWithJsonStringProperty( buffer, offsetBuffer); propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT32; + PropertyTableProperty::StringOffsetType::UINT32; } else { copyStringBuffer( rapidjsonStrBuffer, @@ -538,12 +521,10 @@ void updateExtensionWithJsonStringProperty( buffer, offsetBuffer); propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT64; + PropertyTableProperty::StringOffsetType::UINT64; } - classProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::STRING; + classProperty.type = ClassProperty::Type::STRING; propertyTableProperty.values = addBufferToGltf(gltf, std::move(buffer)); propertyTableProperty.stringOffsets = @@ -553,15 +534,14 @@ void updateExtensionWithJsonStringProperty( template void updateExtensionWithJsonScalarProperty( Model& gltf, - ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, + ClassProperty& classProperty, + const PropertyTable& propertyTable, + PropertyTableProperty& propertyTableProperty, const TValueGetter& propertyValue, const std::string& componentTypeName) { assert(propertyValue.size() >= propertyTable.count); - classProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = componentTypeName; // Create a new buffer for this property. @@ -581,9 +561,9 @@ void updateExtensionWithJsonScalarProperty( template void updateExtensionWithJsonBooleanProperty( Model& gltf, - ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, + ClassProperty& classProperty, + const PropertyTable& propertyTable, + PropertyTableProperty& propertyTableProperty, const TValueGetter& propertyValue) { assert(propertyValue.size() >= propertyTable.count); @@ -601,8 +581,7 @@ void updateExtensionWithJsonBooleanProperty( ++it; } - classProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + classProperty.type = ClassProperty::Type::BOOLEAN; propertyTableProperty.values = addBufferToGltf(gltf, std::move(buffer)); } @@ -615,7 +594,7 @@ void copyVariableLengthScalarArraysToBuffers( std::vector& valueBuffer, std::vector& offsetBuffer, size_t numOfElements, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + const PropertyTable& propertyTable, const TValueGetter& propertyValue) { valueBuffer.resize(sizeof(ValueType) * numOfElements); offsetBuffer.resize( @@ -645,15 +624,14 @@ void copyVariableLengthScalarArraysToBuffers( template void updateScalarArrayProperty( Model& gltf, - ExtensionExtStructuralMetadataClassProperty& classProperty, - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + ClassProperty& classProperty, + PropertyTableProperty& propertyTableProperty, + const PropertyTable& propertyTable, const MaskedArrayType& arrayType, const TValueGetter& propertyValue) { assert(propertyValue.size() >= propertyTable.count); - classProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = convertPropertyComponentTypeToString(static_cast( TypeToPropertyType::component)); @@ -744,7 +722,7 @@ void copyStringsToBuffers( std::vector& offsetBuffer, size_t totalByteLength, size_t numOfString, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + const PropertyTable& propertyTable, const TValueGetter& propertyValue) { valueBuffer.resize(totalByteLength); offsetBuffer.resize((numOfString + 1) * sizeof(OffsetType)); @@ -776,7 +754,7 @@ void copyStringsToBuffers( template void copyArrayOffsetsForStringArraysToBuffer( std::vector& offsetBuffer, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + const PropertyTable& propertyTable, const TValueGetter& propertyValue) { OffsetType prevOffset = 0; offsetBuffer.resize( @@ -798,9 +776,9 @@ void copyArrayOffsetsForStringArraysToBuffer( template void updateStringArrayProperty( Model& gltf, - ExtensionExtStructuralMetadataClassProperty& classProperty, - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + ClassProperty& classProperty, + PropertyTableProperty& propertyTableProperty, + const PropertyTable& propertyTable, const MaskedArrayType& arrayType, const TValueGetter& propertyValue) { assert(propertyValue.size() >= propertyTable.count); @@ -860,8 +838,7 @@ void updateStringArrayProperty( stringOffsetType = PropertyComponentType::Uint64; } - classProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::STRING; + classProperty.type = ClassProperty::Type::STRING; classProperty.array = true; propertyTableProperty.stringOffsetType = convertPropertyComponentTypeToString(stringOffsetType); @@ -918,7 +895,7 @@ void copyVariableLengthBooleanArraysToBuffers( std::vector& valueBuffer, std::vector& offsetBuffer, size_t numOfElements, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + const PropertyTable& propertyTable, const TValueGetter& propertyValue) { size_t currentIndex = 0; const size_t totalByteLength = @@ -953,15 +930,14 @@ void copyVariableLengthBooleanArraysToBuffers( template void updateBooleanArrayProperty( Model& gltf, - ExtensionExtStructuralMetadataClassProperty& classProperty, - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + ClassProperty& classProperty, + PropertyTableProperty& propertyTableProperty, + const PropertyTable& propertyTable, const MaskedArrayType& arrayType, const TValueGetter& propertyValue) { assert(propertyValue.size() >= propertyTable.count); - classProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.array = true; // Fixed-length array of booleans @@ -1050,9 +1026,9 @@ void updateBooleanArrayProperty( template void updateExtensionWithArrayProperty( Model& gltf, - ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, + ClassProperty& classProperty, + const PropertyTable& propertyTable, + PropertyTableProperty& propertyTableProperty, const MaskedArrayType& arrayType, const TValueGetter& propertyValue) { assert(propertyValue.size() >= propertyTable.count); @@ -1162,9 +1138,9 @@ void updateExtensionWithArrayProperty( template void updateExtensionWithJsonProperty( Model& gltf, - ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, + ClassProperty& classProperty, + const PropertyTable& propertyTable, + PropertyTableProperty& propertyTableProperty, const TValueGetter& propertyValue) { if (propertyValue.size() == 0 || propertyValue.size() < propertyTable.count) { @@ -1208,7 +1184,7 @@ void updateExtensionWithJsonProperty( propertyTable, propertyTableProperty, propertyValue, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8); + ClassProperty::ComponentType::INT8); } else if (type.isUint8) { updateExtensionWithJsonScalarProperty( gltf, @@ -1216,7 +1192,7 @@ void updateExtensionWithJsonProperty( propertyTable, propertyTableProperty, propertyValue, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8); + ClassProperty::ComponentType::UINT8); } else if (type.isInt16) { updateExtensionWithJsonScalarProperty( gltf, @@ -1224,7 +1200,7 @@ void updateExtensionWithJsonProperty( propertyTable, propertyTableProperty, propertyValue, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16); + ClassProperty::ComponentType::INT16); } else if (type.isUint16) { updateExtensionWithJsonScalarProperty( gltf, @@ -1232,7 +1208,7 @@ void updateExtensionWithJsonProperty( propertyTable, propertyTableProperty, propertyValue, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); + ClassProperty::ComponentType::UINT16); } else if (type.isInt32) { updateExtensionWithJsonScalarProperty( gltf, @@ -1240,7 +1216,7 @@ void updateExtensionWithJsonProperty( propertyTable, propertyTableProperty, propertyValue, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + ClassProperty::ComponentType::INT32); } else if (type.isUint32) { updateExtensionWithJsonScalarProperty( gltf, @@ -1248,7 +1224,7 @@ void updateExtensionWithJsonProperty( propertyTable, propertyTableProperty, propertyValue, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + ClassProperty::ComponentType::UINT32); } else if (type.isInt64) { updateExtensionWithJsonScalarProperty( gltf, @@ -1256,7 +1232,7 @@ void updateExtensionWithJsonProperty( propertyTable, propertyTableProperty, propertyValue, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64); + ClassProperty::ComponentType::INT64); } else if (type.isUint64) { updateExtensionWithJsonScalarProperty( gltf, @@ -1264,7 +1240,7 @@ void updateExtensionWithJsonProperty( propertyTable, propertyTableProperty, propertyValue, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64); + ClassProperty::ComponentType::UINT64); } else if (type.isFloat32) { updateExtensionWithJsonScalarProperty( gltf, @@ -1272,7 +1248,7 @@ void updateExtensionWithJsonProperty( propertyTable, propertyTableProperty, propertyValue, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); + ClassProperty::ComponentType::FLOAT32); } else if (type.isFloat64) { updateExtensionWithJsonScalarProperty( gltf, @@ -1280,7 +1256,7 @@ void updateExtensionWithJsonProperty( propertyTable, propertyTableProperty, propertyValue, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); + ClassProperty::ComponentType::FLOAT64); } else { updateExtensionWithJsonStringProperty( gltf, @@ -1296,9 +1272,9 @@ void updateExtensionWithBinaryProperty( int32_t gltfBufferIndex, int64_t gltfBufferOffset, BinaryProperty& binaryProperty, - ExtensionExtStructuralMetadataClassProperty& classProperty, - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, + ClassProperty& classProperty, + PropertyTableProperty& propertyTableProperty, + const PropertyTable& propertyTable, const std::string& propertyName, const rapidjson::Value& propertyValue, ErrorList& result) { @@ -1385,8 +1361,8 @@ void updateExtensionWithBinaryProperty( void updateExtensionWithBatchTableHierarchy( Model& gltf, - ExtensionExtStructuralMetadataClass& classDefinition, - ExtensionExtStructuralMetadataPropertyTable& propertyTable, + Class& classDefinition, + PropertyTable& propertyTable, ErrorList& result, const rapidjson::Value& batchTableHierarchy) { // EXT_structural_metadata can't support hierarchy, so we need to flatten it. @@ -1442,17 +1418,12 @@ void updateExtensionWithBatchTableHierarchy( propertyTable.count); for (const std::string& name : properties) { - ExtensionExtStructuralMetadataClassProperty& classProperty = - classDefinition.properties - .emplace(name, ExtensionExtStructuralMetadataClassProperty()) - .first->second; + ClassProperty& classProperty = + classDefinition.properties.emplace(name, ClassProperty()).first->second; classProperty.name = name; - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = - propertyTable.properties - .emplace( - name, - ExtensionExtStructuralMetadataPropertyTableProperty()) + PropertyTableProperty& propertyTableProperty = + propertyTable.properties.emplace(name, PropertyTableProperty()) .first->second; batchTableHierarchyValues.setProperty(name); @@ -1485,16 +1456,13 @@ void convertBatchTableToGltfStructuralMetadataExtension( ExtensionModelExtStructuralMetadata& modelExtension = gltf.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = - modelExtension.schema.emplace(); + Schema& schema = modelExtension.schema.emplace(); schema.id = "default"; // Required by the spec. - ExtensionExtStructuralMetadataClass& classDefinition = - schema.classes.emplace("default", ExtensionExtStructuralMetadataClass()) - .first->second; + Class& classDefinition = + schema.classes.emplace("default", Class()).first->second; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - modelExtension.propertyTables.emplace_back(); + PropertyTable& propertyTable = modelExtension.propertyTables.emplace_back(); propertyTable.name = "default"; propertyTable.count = featureCount; propertyTable.classProperty = "default"; @@ -1510,17 +1478,12 @@ void convertBatchTableToGltfStructuralMetadataExtension( continue; } - ExtensionExtStructuralMetadataClassProperty& classProperty = - classDefinition.properties - .emplace(name, ExtensionExtStructuralMetadataClassProperty()) - .first->second; + ClassProperty& classProperty = + classDefinition.properties.emplace(name, ClassProperty()).first->second; classProperty.name = name; - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = - propertyTable.properties - .emplace( - name, - ExtensionExtStructuralMetadataPropertyTableProperty()) + PropertyTableProperty& propertyTableProperty = + propertyTable.properties.emplace(name, PropertyTableProperty()) .first->second; const rapidjson::Value& propertyValue = propertyIt->value; if (propertyValue.IsArray()) { diff --git a/Cesium3DTilesSelection/src/upsampleGltfForRasterOverlays.cpp b/Cesium3DTilesSelection/src/upsampleGltfForRasterOverlays.cpp index 8469f1134..e198912e9 100644 --- a/Cesium3DTilesSelection/src/upsampleGltfForRasterOverlays.cpp +++ b/Cesium3DTilesSelection/src/upsampleGltfForRasterOverlays.cpp @@ -1252,8 +1252,7 @@ static void copyMetadataTables(const Model& parentModel, Model& result) { if (pMetadata) { for (auto& propertyTable : pMetadata->propertyTables) { for (auto& propertyPair : propertyTable.properties) { - ExtensionExtStructuralMetadataPropertyTableProperty& property = - propertyPair.second; + PropertyTableProperty& property = propertyPair.second; property.values = copyBufferView(parentModel, property.values, result); property.arrayOffsets = copyBufferView(parentModel, property.arrayOffsets, result); diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 445416236..46dc79b45 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -24,15 +24,14 @@ using namespace CesiumUtility; template static void checkNonArrayProperty( const Model& model, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, - const ExtensionExtStructuralMetadataClass& metaClass, + const PropertyTable& propertyTable, + const Class& metaClass, const std::string& propertyName, const std::string& expectedType, const std::optional& expectedComponentType, const std::vector& expected, size_t expectedTotalInstances) { - const ExtensionExtStructuralMetadataClassProperty& property = - metaClass.properties.at(propertyName); + const ClassProperty& property = metaClass.properties.at(propertyName); REQUIRE(property.type == expectedType); REQUIRE(property.componentType == expectedComponentType); REQUIRE(!property.array); @@ -68,16 +67,15 @@ static void checkNonArrayProperty( template static void checkArrayProperty( const Model& model, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable, - const ExtensionExtStructuralMetadataClass& metaClass, + const PropertyTable& propertyTable, + const Class& metaClass, const std::string& propertyName, int64_t expectedCount, const std::string& expectedType, const std::optional& expectedComponentType, const std::vector>& expected, size_t expectedTotalInstances) { - const ExtensionExtStructuralMetadataClassProperty& property = - metaClass.properties.at(propertyName); + const ClassProperty& property = metaClass.properties.at(propertyName); REQUIRE(property.type == expectedType); REQUIRE(property.componentType == expectedComponentType); REQUIRE(property.array); @@ -161,26 +159,20 @@ static void createTestForNonArrayJson( model.getExtension(); REQUIRE(pMetadata); - const std::optional schema = - pMetadata->schema; + const std::optional schema = pMetadata->schema; REQUIRE(schema); - const std::unordered_map& - classes = schema->classes; + const std::unordered_map& classes = schema->classes; REQUIRE(classes.size() == 1); - const ExtensionExtStructuralMetadataClass& defaultClass = - classes.at("default"); - const std::unordered_map< - std::string, - ExtensionExtStructuralMetadataClassProperty>& properties = + const Class& defaultClass = classes.at("default"); + const std::unordered_map& properties = defaultClass.properties; REQUIRE(properties.size() == 1); REQUIRE(pMetadata->propertyTables.size() == 1); - const ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pMetadata->propertyTables[0]; + const PropertyTable& propertyTable = pMetadata->propertyTables[0]; checkNonArrayProperty( model, propertyTable, @@ -247,18 +239,15 @@ static void createTestForArrayJson( model.getExtension(); REQUIRE(pMetadata); - const std::optional& schema = - pMetadata->schema; + const std::optional& schema = pMetadata->schema; REQUIRE(schema); REQUIRE(schema->classes.find("default") != schema->classes.end()); - const ExtensionExtStructuralMetadataClass& defaultClass = - schema->classes.at("default"); + const Class& defaultClass = schema->classes.at("default"); REQUIRE(defaultClass.properties.size() == 1); REQUIRE(pMetadata->propertyTables.size() == 1); - const ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pMetadata->propertyTables[0]; + const PropertyTable& propertyTable = pMetadata->propertyTables[0]; checkArrayProperty( model, @@ -274,7 +263,7 @@ static void createTestForArrayJson( std::set getUniqueBufferViewIds( const std::vector& accessors, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable) { + const PropertyTable& propertyTable) { std::set result; for (auto it = accessors.begin(); it != accessors.end(); it++) { result.insert(it->bufferView); @@ -316,7 +305,7 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - ExtensionExtStructuralMetadataClass& defaultClass = firstClassIt->second; + Class& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 4); auto idIt = defaultClass.properties.find("id"); @@ -328,36 +317,24 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { auto heightIt = defaultClass.properties.find("Height"); REQUIRE(heightIt != defaultClass.properties.end()); - CHECK( - idIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - CHECK( - longitudeIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - CHECK( - latitudeIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - CHECK( - heightIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + CHECK(idIt->second.type == ClassProperty::Type::SCALAR); + CHECK(longitudeIt->second.type == ClassProperty::Type::SCALAR); + CHECK(latitudeIt->second.type == ClassProperty::Type::SCALAR); + CHECK(heightIt->second.type == ClassProperty::Type::SCALAR); - CHECK( - idIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8); + CHECK(idIt->second.componentType == ClassProperty::ComponentType::INT8); CHECK( longitudeIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); + ClassProperty::ComponentType::FLOAT64); CHECK( latitudeIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); + ClassProperty::ComponentType::FLOAT64); CHECK( - heightIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); + heightIt->second.componentType == ClassProperty::ComponentType::FLOAT64); // Check the property table REQUIRE(pExtension->propertyTables.size() == 1); - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pExtension->propertyTables[0]; + PropertyTable& propertyTable = pExtension->propertyTables[0]; CHECK(propertyTable.classProperty == "default"); REQUIRE(propertyTable.properties.size() == 4); @@ -426,8 +403,8 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { propertyTable, defaultClass, "id", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT8, expected, expected.size()); } @@ -449,8 +426,8 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { propertyTable, defaultClass, "Height", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -472,8 +449,8 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { propertyTable, defaultClass, "Longitude", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -495,8 +472,8 @@ TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { propertyTable, defaultClass, "Latitude", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -518,24 +495,19 @@ TEST_CASE("Convert binary B3DM batch table to EXT_structural_metadata") { model.getExtension(); REQUIRE(metadata); - std::optional schema = metadata->schema; + std::optional schema = metadata->schema; REQUIRE(schema); - const std::unordered_map& - classes = schema->classes; + const std::unordered_map& classes = schema->classes; REQUIRE(classes.size() == 1); - const ExtensionExtStructuralMetadataClass& defaultClass = - classes.at("default"); - const std::unordered_map< - std::string, - ExtensionExtStructuralMetadataClassProperty>& properties = + const Class& defaultClass = classes.at("default"); + const std::unordered_map& properties = defaultClass.properties; REQUIRE(properties.size() == 6); REQUIRE(metadata->propertyTables.size() == 1); - const ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata->propertyTables[0]; + const PropertyTable& propertyTable = metadata->propertyTables[0]; // Check that batch IDs were converted to EXT_mesh_features CHECK(!model.meshes.empty()); @@ -570,8 +542,8 @@ TEST_CASE("Convert binary B3DM batch table to EXT_structural_metadata") { propertyTable, defaultClass, "id", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT8, expected, expected.size()); } @@ -593,8 +565,8 @@ TEST_CASE("Convert binary B3DM batch table to EXT_structural_metadata") { propertyTable, defaultClass, "Height", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -616,8 +588,8 @@ TEST_CASE("Convert binary B3DM batch table to EXT_structural_metadata") { propertyTable, defaultClass, "Longitude", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -639,8 +611,8 @@ TEST_CASE("Convert binary B3DM batch table to EXT_structural_metadata") { propertyTable, defaultClass, "Latitude", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -652,8 +624,8 @@ TEST_CASE("Convert binary B3DM batch table to EXT_structural_metadata") { propertyTable, defaultClass, "code", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT8, expected, expected.size()); } @@ -678,8 +650,8 @@ TEST_CASE("Convert binary B3DM batch table to EXT_structural_metadata") { propertyTable, defaultClass, "cartographic", - ExtensionExtStructuralMetadataClassProperty::Type::VEC3, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + ClassProperty::Type::VEC3, + ClassProperty::ComponentType::FLOAT64, expected, expected.size()); } @@ -705,8 +677,7 @@ TEST_CASE("Converts batched PNTS batch table to EXT_structural_metadata") { auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - const ExtensionExtStructuralMetadataClass& defaultClass = - firstClassIt->second; + const Class& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 3); { @@ -717,27 +688,18 @@ TEST_CASE("Converts batched PNTS batch table to EXT_structural_metadata") { auto idIt = defaultClass.properties.find("id"); REQUIRE(idIt != defaultClass.properties.end()); - CHECK( - nameIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::STRING); - CHECK( - dimensionsIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + CHECK(nameIt->second.type == ClassProperty::Type::STRING); + CHECK(dimensionsIt->second.type == ClassProperty::Type::VEC3); CHECK( dimensionsIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); - CHECK( - idIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - CHECK( - idIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + ClassProperty::ComponentType::FLOAT32); + CHECK(idIt->second.type == ClassProperty::Type::SCALAR); + CHECK(idIt->second.componentType == ClassProperty::ComponentType::UINT32); } // Check the property table REQUIRE(pExtension->propertyTables.size() == 1); - const ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pExtension->propertyTables[0]; + const PropertyTable& propertyTable = pExtension->propertyTables[0]; CHECK(propertyTable.classProperty == "default"); REQUIRE(propertyTable.properties.size() == 3); @@ -799,7 +761,7 @@ TEST_CASE("Converts batched PNTS batch table to EXT_structural_metadata") { propertyTable, defaultClass, "name", - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, expected, expected.size()); @@ -820,8 +782,8 @@ TEST_CASE("Converts batched PNTS batch table to EXT_structural_metadata") { propertyTable, defaultClass, "dimensions", - ExtensionExtStructuralMetadataClassProperty::Type::VEC3, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, + ClassProperty::Type::VEC3, + ClassProperty::ComponentType::FLOAT32, expected, expected.size()); } @@ -833,8 +795,8 @@ TEST_CASE("Converts batched PNTS batch table to EXT_structural_metadata") { propertyTable, defaultClass, "id", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT32, expected, expected.size()); } @@ -861,8 +823,7 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_structural_metadata") { auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - const ExtensionExtStructuralMetadataClass& defaultClass = - firstClassIt->second; + const Class& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 3); { @@ -873,31 +834,22 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_structural_metadata") { auto idIt = defaultClass.properties.find("id"); REQUIRE(idIt != defaultClass.properties.end()); - CHECK( - temperatureIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + CHECK(temperatureIt->second.type == ClassProperty::Type::SCALAR); CHECK( temperatureIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); - CHECK( - secondaryColorIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + ClassProperty::ComponentType::FLOAT32); + CHECK(secondaryColorIt->second.type == ClassProperty::Type::VEC3); REQUIRE(secondaryColorIt->second.componentType); CHECK( secondaryColorIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); - CHECK( - idIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - CHECK( - idIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); + ClassProperty::ComponentType::FLOAT32); + CHECK(idIt->second.type == ClassProperty::Type::SCALAR); + CHECK(idIt->second.componentType == ClassProperty::ComponentType::UINT16); } // Check the property table REQUIRE(pExtension->propertyTables.size() == 1); - const ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pExtension->propertyTables[0]; + const PropertyTable& propertyTable = pExtension->propertyTables[0]; CHECK(propertyTable.classProperty == "default"); REQUIRE(propertyTable.properties.size() == 3); @@ -960,8 +912,8 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_structural_metadata") { propertyTable, defaultClass, "temperature", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT32, expected, expected.size()); } @@ -981,8 +933,8 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_structural_metadata") { propertyTable, defaultClass, "secondaryColor", - ExtensionExtStructuralMetadataClassProperty::Type::VEC3, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, + ClassProperty::Type::VEC3, + ClassProperty::ComponentType::FLOAT32, expected, expected.size()); } @@ -994,8 +946,8 @@ TEST_CASE("Converts per-point PNTS batch table to EXT_structural_metadata") { propertyTable, defaultClass, "id", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT16, expected, expected.size()); } @@ -1022,8 +974,7 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - const ExtensionExtStructuralMetadataClass& defaultClass = - firstClassIt->second; + const Class& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 3); { @@ -1034,31 +985,22 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " auto idIt = defaultClass.properties.find("id"); REQUIRE(idIt != defaultClass.properties.end()); - CHECK( - temperatureIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + CHECK(temperatureIt->second.type == ClassProperty::Type::SCALAR); CHECK( temperatureIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); - CHECK( - secondaryColorIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + ClassProperty::ComponentType::FLOAT32); + CHECK(secondaryColorIt->second.type == ClassProperty::Type::VEC3); REQUIRE(secondaryColorIt->second.componentType); CHECK( secondaryColorIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); - CHECK( - idIt->second.type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - CHECK( - idIt->second.componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); + ClassProperty::ComponentType::FLOAT32); + CHECK(idIt->second.type == ClassProperty::Type::SCALAR); + CHECK(idIt->second.componentType == ClassProperty::ComponentType::UINT16); } // Check the property table REQUIRE(pExtension->propertyTables.size() == 1); - const ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pExtension->propertyTables[0]; + const PropertyTable& propertyTable = pExtension->propertyTables[0]; CHECK(propertyTable.classProperty == "default"); REQUIRE(propertyTable.properties.size() == 3); @@ -1121,8 +1063,8 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " propertyTable, defaultClass, "temperature", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT32, expected, expected.size()); } @@ -1142,8 +1084,8 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " propertyTable, defaultClass, "secondaryColor", - ExtensionExtStructuralMetadataClassProperty::Type::VEC3, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, + ClassProperty::Type::VEC3, + ClassProperty::ComponentType::FLOAT32, expected, expected.size()); } @@ -1155,8 +1097,8 @@ TEST_CASE("Converts Draco per-point PNTS batch table to " propertyTable, defaultClass, "id", - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT16, expected, expected.size()); } @@ -1177,25 +1119,19 @@ TEST_CASE("Upgrade nested JSON metadata to string") { result.model->getExtension(); REQUIRE(pMetadata); - const std::optional& schema = - pMetadata->schema; + const std::optional& schema = pMetadata->schema; REQUIRE(schema); - const std::unordered_map& - classes = schema->classes; + const std::unordered_map& classes = schema->classes; REQUIRE(classes.size() == 1); - const ExtensionExtStructuralMetadataClass& defaultClass = - classes.at("default"); - const std::unordered_map< - std::string, - ExtensionExtStructuralMetadataClassProperty>& properties = + const Class& defaultClass = classes.at("default"); + const std::unordered_map& properties = defaultClass.properties; REQUIRE(properties.size() == 6); REQUIRE(pMetadata->propertyTables.size() == 1); - const ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pMetadata->propertyTables[0]; + const PropertyTable& propertyTable = pMetadata->propertyTables[0]; REQUIRE(propertyTable.count == 10); { @@ -1210,7 +1146,7 @@ TEST_CASE("Upgrade nested JSON metadata to string") { propertyTable, defaultClass, "info", - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, expected, expected.size()); @@ -1231,7 +1167,7 @@ TEST_CASE("Upgrade nested JSON metadata to string") { defaultClass, "rooms", 3, - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, expected, expected.size()); @@ -1275,35 +1211,28 @@ TEST_CASE("Upgrade JSON booleans to binary") { model.getExtension(); REQUIRE(pMetadata); - const std::optional& schema = - pMetadata->schema; + const std::optional& schema = pMetadata->schema; REQUIRE(schema); - const std::unordered_map& - classes = schema->classes; + const std::unordered_map& classes = schema->classes; REQUIRE(classes.size() == 1); - const ExtensionExtStructuralMetadataClass& defaultClass = - classes.at("default"); - const std::unordered_map< - std::string, - ExtensionExtStructuralMetadataClassProperty>& properties = + const Class& defaultClass = classes.at("default"); + const std::unordered_map& properties = defaultClass.properties; REQUIRE(properties.size() == 1); - const ExtensionExtStructuralMetadataClassProperty& propertyClass = - properties.at("boolProp"); + const ClassProperty& propertyClass = properties.at("boolProp"); REQUIRE(propertyClass.type == "BOOLEAN"); REQUIRE(pMetadata->propertyTables.size() == 1); - const ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pMetadata->propertyTables[0]; + const PropertyTable& propertyTable = pMetadata->propertyTables[0]; checkNonArrayProperty( model, propertyTable, defaultClass, "boolProp", - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + ClassProperty::Type::BOOLEAN, std::nullopt, expected, expected.size()); @@ -1322,8 +1251,8 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT8, 4, expected.size()); } @@ -1340,8 +1269,8 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT8, 5, expected.size()); } @@ -1358,8 +1287,8 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT16, 4, expected.size()); } @@ -1376,8 +1305,8 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT16, 4, expected.size()); } @@ -1394,8 +1323,8 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT32, 4, expected.size()); } @@ -1412,8 +1341,8 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT32, 4, expected.size()); } @@ -1432,8 +1361,8 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT64, 4, expected.size()); } @@ -1450,8 +1379,8 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT64, 4, expected.size()); } @@ -1468,8 +1397,8 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT32, 4, expected.size()); } @@ -1486,8 +1415,8 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT64, 4, expected.size()); } @@ -1504,7 +1433,7 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, 4, expected.size()); @@ -1522,7 +1451,7 @@ TEST_CASE("Upgrade fixed-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + ClassProperty::Type::BOOLEAN, std::nullopt, 6, expected.size()); @@ -1542,8 +1471,8 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT8, 0, expected.size()); } @@ -1560,8 +1489,8 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT8, 0, expected.size()); } @@ -1578,8 +1507,8 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT16, 0, expected.size()); } @@ -1596,8 +1525,8 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT16, 0, expected.size()); } @@ -1614,8 +1543,8 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT32, 0, expected.size()); } @@ -1632,8 +1561,8 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT32, 0, expected.size()); } @@ -1650,8 +1579,8 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT64, 0, expected.size()); } @@ -1668,8 +1597,8 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT64, 0, expected.size()); } @@ -1686,8 +1615,8 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT32, 0, expected.size()); } @@ -1704,8 +1633,8 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::FLOAT64, 0, expected.size()); } @@ -1722,7 +1651,7 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, 0, expected.size()); @@ -1741,7 +1670,7 @@ TEST_CASE("Upgrade variable-length JSON arrays") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + ClassProperty::Type::BOOLEAN, std::nullopt, 0, expected.size()); @@ -1755,8 +1684,8 @@ TEST_CASE("Upgrade JSON values") { std::vector expected{32, 45, 21, 65, 78}; createTestForNonArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT8, expected.size()); } @@ -1764,7 +1693,7 @@ TEST_CASE("Upgrade JSON values") { std::vector expected{true, false, true, false, true, true, false}; createTestForNonArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + ClassProperty::Type::BOOLEAN, std::nullopt, expected.size()); } @@ -1773,7 +1702,7 @@ TEST_CASE("Upgrade JSON values") { std::vector expected{"Test 0", "Test 1", "Test 2", "Test 3"}; createTestForNonArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, expected.size()); } @@ -1784,8 +1713,8 @@ TEST_CASE("Cannot write past batch table length") { std::vector expected{32, 45, 21, 65, 78, 20, 33, 12}; createTestForNonArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT8, 4); } @@ -1793,7 +1722,7 @@ TEST_CASE("Cannot write past batch table length") { std::vector expected{true, false, true, false, true, true, false}; createTestForNonArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + ClassProperty::Type::BOOLEAN, std::nullopt, 4); } @@ -1803,7 +1732,7 @@ TEST_CASE("Cannot write past batch table length") { expected{"Test 0", "Test 1", "Test 2", "Test 3", "Test 4"}; createTestForNonArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, 3); } @@ -1820,8 +1749,8 @@ TEST_CASE("Cannot write past batch table length") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::UINT64, 4, 2); } @@ -1838,7 +1767,7 @@ TEST_CASE("Cannot write past batch table length") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + ClassProperty::Type::BOOLEAN, std::nullopt, 3, 2); @@ -1856,7 +1785,7 @@ TEST_CASE("Cannot write past batch table length") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, 4, 2); @@ -1874,8 +1803,8 @@ TEST_CASE("Cannot write past batch table length") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR, - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT32, 0, 3); } @@ -1893,7 +1822,7 @@ TEST_CASE("Cannot write past batch table length") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN, + ClassProperty::Type::BOOLEAN, std::nullopt, 0, 2); @@ -1911,7 +1840,7 @@ TEST_CASE("Cannot write past batch table length") { createTestForArrayJson( expected, - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, 0, 2); @@ -1990,13 +1919,12 @@ TEST_CASE("Converts \"Feature Classes\" 3DTILES_batch_table_hierarchy example " auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - ExtensionExtStructuralMetadataClass& defaultClass = firstClassIt->second; + Class& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 6); // Check the property table REQUIRE(pExtension->propertyTables.size() == 1); - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pExtension->propertyTables[0]; + PropertyTable& propertyTable = pExtension->propertyTables[0]; CHECK(propertyTable.classProperty == "default"); REQUIRE(propertyTable.properties.size() == 6); @@ -2012,27 +1940,27 @@ TEST_CASE("Converts \"Feature Classes\" 3DTILES_batch_table_hierarchy example " std::vector expectedProperties{ {"lampStrength", - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, {"10", "5", "7", "null", "null", "null", "null", "null"}}, {"lampColor", - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, {"yellow", "white", "white", "null", "null", "null", "null", "null"}}, {"carType", - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, {"null", "null", "null", "truck", "bus", "sedan", "null", "null"}}, {"carColor", - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, {"null", "null", "null", "green", "blue", "red", "null", "null"}}, {"treeHeight", - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, {"null", "null", "null", "null", "null", "null", "10", "15"}}, {"treeAge", - ExtensionExtStructuralMetadataClassProperty::Type::STRING, + ClassProperty::Type::STRING, std::nullopt, {"null", "null", "null", "null", "null", "null", "5", "8"}}}; @@ -2128,22 +2056,19 @@ TEST_CASE( auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - ExtensionExtStructuralMetadataClass& defaultClass = firstClassIt->second; + Class& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 7); // Check the property table REQUIRE(pExtension->propertyTables.size() == 1); - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pExtension->propertyTables[0]; + PropertyTable& propertyTable = pExtension->propertyTables[0]; CHECK(propertyTable.classProperty == "default"); REQUIRE(propertyTable.properties.size() == 7); struct ExpectedString { std::string name; std::vector values; - std::string type() const { - return ExtensionExtStructuralMetadataClassProperty::Type::STRING; - } + std::string type() const { return ClassProperty::Type::STRING; } std::optional componentType() const { return std::nullopt; } }; @@ -2186,11 +2111,9 @@ TEST_CASE( struct ExpectedInt8Properties { std::string name; std::vector values; - std::string type() const { - return ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - } + std::string type() const { return ClassProperty::Type::SCALAR; } std::optional componentType() const { - return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8; + return ClassProperty::ComponentType::INT8; } }; @@ -2220,12 +2143,9 @@ TEST_CASE( std::string name; int64_t count; std::vector> values; - std::string type() const { - return ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - } + std::string type() const { return ClassProperty::Type::SCALAR; } std::optional componentType() const { - return ExtensionExtStructuralMetadataClassProperty::ComponentType:: - FLOAT64; + return ClassProperty::ComponentType::FLOAT64; } }; @@ -2340,14 +2260,12 @@ TEST_CASE("3DTILES_batch_table_hierarchy with parentCounts is okay if all " auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - const ExtensionExtStructuralMetadataClass& defaultClass = - firstClassIt->second; + const Class& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 3); // Check the property table REQUIRE(pExtension->propertyTables.size() == 1); - const ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pExtension->propertyTables[0]; + const PropertyTable& propertyTable = pExtension->propertyTables[0]; CHECK(propertyTable.classProperty == "default"); REQUIRE(propertyTable.properties.size() == 3); } @@ -2431,14 +2349,12 @@ TEST_CASE("3DTILES_batch_table_hierarchy with parentCounts values != 1 is " auto firstClassIt = pExtension->schema->classes.begin(); CHECK(firstClassIt->first == "default"); - const ExtensionExtStructuralMetadataClass& defaultClass = - firstClassIt->second; + const Class& defaultClass = firstClassIt->second; REQUIRE(defaultClass.properties.size() == 0); // Check the property table REQUIRE(pExtension->propertyTables.size() == 1); - const ExtensionExtStructuralMetadataPropertyTable& propertyTable = - pExtension->propertyTables[0]; + const PropertyTable& propertyTable = pExtension->propertyTables[0]; CHECK(propertyTable.classProperty == "default"); REQUIRE(propertyTable.properties.size() == 0); diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index 9f3ea6d2f..ef89f5766 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -12,8 +12,7 @@ namespace CesiumGltf { /** - * @brief A view on an array element of a - * {@link ExtensionExtStructuralMetadataPropertyTableProperty}. + * @brief A view on an array element of a {@link PropertyTableProperty}. * * Provides utility to retrieve the data stored in the array of * elements via the array index operator. diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 451c5f14d..05b1adcd5 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -16,10 +16,9 @@ namespace CesiumGltf { * @brief Indicates the status of a property table property view. * * The {@link PropertyTablePropertyView} constructor always completes successfully. - * However, it may not always reflect the actual content of the - * {@link ExtensionExtStructuralMetadataPropertyTableProperty}, but instead - * indicate that its {@link PropertyTablePropertyView::size} is 0. This enumeration - * provides the reason. + * However, it may not always reflect the actual content of the {@link PropertyTableProperty}, + * but instead indicate that its {@link PropertyTablePropertyView::size} is 0. + * This enumeration provides the reason. */ enum class PropertyTablePropertyViewStatus { /** @@ -29,32 +28,31 @@ enum class PropertyTablePropertyViewStatus { /** * @brief This property view was attempting to view an invalid - * {@link ExtensionExtStructuralMetadataPropertyTable}. + * {@link PropertyTable}. */ ErrorInvalidPropertyTable, /** * @brief This property view is trying to view a property that does not exist - * in the - * {@link ExtensionExtStructuralMetadataPropertyTable}. + * in the {@link PropertyTable}. */ ErrorPropertyDoesNotExist, /** * @brief This property view's type does not match what is - * specified in {@link ExtensionExtStructuralMetadataClassProperty::type}. + * specified in {@link ClassProperty::type}. */ ErrorTypeMismatch, /** * @brief This property view's component type does not match what - * is specified in {@link ExtensionExtStructuralMetadataClassProperty::componentType}. + * is specified in {@link ClassProperty::componentType}. */ ErrorComponentTypeMismatch, /** * @brief This property view differs from what is specified in - * {@link ExtensionExtStructuralMetadataClassProperty::array}. + * {@link ClassProperty::array}. */ ErrorArrayTypeMismatch, @@ -157,13 +155,12 @@ enum class PropertyTablePropertyViewStatus { }; /** - * @brief A view on the data of the - * {@link ExtensionExtStructuralMetadataPropertyTableProperty that is created by - * a {@link PropertyTableView}. + * @brief A view on the data of the {@link PropertyTableProperty that is created + * by a {@link PropertyTableView}. * * It provides utility to retrieve the actual data stored in the - * {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} like an array of elements. - * Data of each instance can be accessed through the {@link get(int64_t instance)} method. + * {@link PropertyTableProperty::values} like an array of elements. Data of each + * instance can be accessed through the {@link get(int64_t instance)} method. * * @param ElementType must be one of the following: a scalar (uint8_t, int8_t, * uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double), a @@ -185,9 +182,9 @@ template class PropertyTablePropertyView { /** * @brief Construct a new instance pointing to non-array data specified by - * {@link ExtensionExtStructuralMetadataPropertyTableProperty}. - * @param values The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} - * @param size The number of elements in the property table specified by {@link ExtensionExtStructuralMetadataPropertyTable::count} + * {@link PropertyTableProperty}. + * @param values The raw buffer specified by {@link PropertyTableProperty::values} + * @param size The number of elements in the property table specified by {@link PropertyTable::count} * @param normalized Whether this property has a normalized integer type. */ PropertyTablePropertyView( @@ -209,14 +206,14 @@ template class PropertyTablePropertyView { /** * @brief Construct a new instance pointing to the data specified by - * {@link ExtensionExtStructuralMetadataPropertyTableProperty}. - * @param values The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::values} - * @param arrayOffsets The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::arrayOffsets} - * @param stringOffsets The raw buffer specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::stringOffsets} - * @param offsetType The offset type of arrayOffsets specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::arrayOffsetType} - * @param offsetType The offset type of stringOffsets specified by {@link ExtensionExtStructuralMetadataPropertyTableProperty::stringOffsetType} - * @param arrayCount The number of elements in each array value specified by {@link ExtensionExtStructuralMetadataClassProperty::count} - * @param size The number of elements in the property table specified by {@link ExtensionExtStructuralMetadataPropertyTable::count} + * {@link PropertyTableProperty}. + * @param values The raw buffer specified by {@link PropertyTableProperty::values} + * @param arrayOffsets The raw buffer specified by {@link PropertyTableProperty::arrayOffsets} + * @param stringOffsets The raw buffer specified by {@link PropertyTableProperty::stringOffsets} + * @param offsetType The offset type of arrayOffsets specified by {@link PropertyTableProperty::arrayOffsetType} + * @param offsetType The offset type of stringOffsets specified by {@link PropertyTableProperty::stringOffsetType} + * @param arrayCount The number of elements in each array value specified by {@link ClassProperty::count} + * @param size The number of elements in the property table specified by {@link PropertyTable::count} * @param normalized Whether this property has a normalized integer type. */ PropertyTablePropertyView( @@ -252,7 +249,7 @@ template class PropertyTablePropertyView { PropertyTablePropertyViewStatus status() const noexcept { return _status; } /** - * @brief Get the value of an element of the {@link ExtensionExtStructuralMetadataPropertyTable}. + * @brief Get the value of an element of the {@link PropertyTable}. * @param index The element index * @return The value of the element */ @@ -295,7 +292,7 @@ template class PropertyTablePropertyView { /** * @brief Get the number of elements in this * PropertyTablePropertyView. If the view is valid, this returns - * {@link ExtensionExtStructuralMetadataPropertyTable::count}. Otherwise, this returns 0. + * {@link PropertyTable::count}. Otherwise, this returns 0. * * @return The number of elements in this PropertyTablePropertyView. */ diff --git a/CesiumGltf/include/CesiumGltf/PropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h index 84757d07f..210ecd0c5 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -14,9 +14,9 @@ namespace CesiumGltf { * @brief Indicates the status of a property table view. * * The {@link PropertyTableView} constructor always completes successfully. - * However, it may not always reflect the actual content of the - * {@link ExtensionExtStructuralMetadataPropertyTable}, but instead indicate that its - * {@link PropertyTableView::size} is 0. This enumeration provides the reason. + * However, it may not always reflect the actual content of the {@link PropertyTable}, + * but instead indicate that its {@link PropertyTableView::size} is 0. + * This enumeration provides the reason. */ enum class PropertyTableViewStatus { /** @@ -44,8 +44,7 @@ enum class PropertyTableViewStatus { }; /** - * @brief Utility to retrieve the data of - * {@link ExtensionExtStructuralMetadataPropertyTable}. + * @brief Utility to retrieve the data of {@link PropertyTable}. * * This should be used to get a {@link PropertyTablePropertyView} of a property in the property table. * It will validate the EXT_structural_metadata format and ensure {@link PropertyTablePropertyView} @@ -56,12 +55,10 @@ class PropertyTableView { /** * @brief Creates an instance of PropertyTableView. * @param model The Gltf Model that contains property table data. - * @param propertyTable The {@link ExtensionExtStructuralMetadataPropertyTable} + * @param propertyTable The {@link PropertyTable} * from which the view will retrieve data. */ - PropertyTableView( - const Model& model, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable); + PropertyTableView(const Model& model, const PropertyTable& propertyTable); /** * @brief Gets the status of this property table view. @@ -75,8 +72,7 @@ class PropertyTableView { /** * @brief Get the number of elements in this PropertyTableView. If the - * view is valid, this returns - * {@link ExtensionExtStructuralMetadataPropertyTable::count}. Otherwise, this returns 0. + * view is valid, this returns {@link PropertyTable::count}. Otherwise, this returns 0. * * @return The number of elements in this PropertyTableView. */ @@ -86,19 +82,18 @@ class PropertyTableView { } /** - * @brief Finds the {@link ExtensionExtStructuralMetadataClassProperty} that + * @brief Finds the {@link ClassProperty} that * describes the type information of the property with the specified name. * @param propertyName The name of the property to retrieve the class for. - * @return A pointer to the {@link ExtensionExtStructuralMetadataClassProperty}. + * @return A pointer to the {@link ClassProperty}. * Return nullptr if the PropertyTableView is invalid or if no class * property was found. */ - const ExtensionExtStructuralMetadataClassProperty* - getClassProperty(const std::string& propertyName) const; + const ClassProperty* getClassProperty(const std::string& propertyName) const; /** * @brief Gets a {@link PropertyTablePropertyView} that views the data of a property stored - * in the {@link ExtensionExtStructuralMetadataPropertyTable}. + * in the {@link PropertyTable}. * * This method will validate the EXT_structural_metadata format to ensure * {@link PropertyTablePropertyView} retrieves the correct data. T must be one of the @@ -120,8 +115,7 @@ class PropertyTableView { PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); } - const ExtensionExtStructuralMetadataClassProperty* pClassProperty = - getClassProperty(propertyName); + const ClassProperty* pClassProperty = getClassProperty(propertyName); if (!pClassProperty) { return createInvalidPropertyView( PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist); @@ -160,8 +154,7 @@ class PropertyTableView { return; } - const ExtensionExtStructuralMetadataClassProperty* pClassProperty = - getClassProperty(propertyName); + const ClassProperty* pClassProperty = getClassProperty(propertyName); if (!pClassProperty) { callback( propertyName, @@ -221,10 +214,9 @@ class PropertyTableView { } /** - * @brief Iterates over each property in the - * {@link ExtensionExtStructuralMetadataPropertyTable} with a callback that accepts a - * property name and a {@link PropertyTablePropertyView} to view the data - * stored in the {@link ExtensionExtStructuralMetadataPropertyTableProperty}. + * @brief Iterates over each property in the {@link PropertyTable} with a callback + * that accepts a property name and a {@link PropertyTablePropertyView} to view + * the data stored in the {@link PropertyTableProperty}. * * This method will validate the EXT_structural_metadata format to ensure * {@link PropertyTablePropertyView} retrieves the correct data. T must be one of the @@ -267,7 +259,7 @@ class PropertyTableView { template void getScalarArrayPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyComponentType componentType, Callback&& callback) const { switch (componentType) { @@ -353,7 +345,7 @@ class PropertyTableView { template void getVecNArrayPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyComponentType componentType, Callback&& callback) const { switch (componentType) { @@ -439,7 +431,7 @@ class PropertyTableView { template void getVecNArrayPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyType type, PropertyComponentType componentType, Callback&& callback) const { @@ -478,7 +470,7 @@ class PropertyTableView { template void getMatNArrayPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyComponentType componentType, Callback&& callback) const { switch (componentType) { @@ -564,7 +556,7 @@ class PropertyTableView { template void getMatNArrayPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyType type, PropertyComponentType componentType, Callback&& callback) const { @@ -603,7 +595,7 @@ class PropertyTableView { template void getArrayPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyType type, PropertyComponentType componentType, Callback&& callback) const { @@ -651,7 +643,7 @@ class PropertyTableView { template void getVecNPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyComponentType componentType, Callback&& callback) const { @@ -736,7 +728,7 @@ class PropertyTableView { template void getVecNPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyType type, PropertyComponentType componentType, Callback&& callback) const { @@ -775,7 +767,7 @@ class PropertyTableView { template void getMatNPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyComponentType componentType, Callback&& callback) const { switch (componentType) { @@ -861,7 +853,7 @@ class PropertyTableView { template void getMatNPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyType type, PropertyComponentType componentType, Callback&& callback) const { @@ -900,7 +892,7 @@ class PropertyTableView { template void getScalarPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty, + const ClassProperty& classProperty, PropertyComponentType componentType, Callback&& callback) const { switch (componentType) { @@ -966,7 +958,7 @@ class PropertyTableView { template PropertyTablePropertyView getPropertyViewImpl( const std::string& propertyName, - const ExtensionExtStructuralMetadataClassProperty& classProperty) const { + const ClassProperty& classProperty) const { auto propertyTablePropertyIter = _pPropertyTable->properties.find(propertyName); if (propertyTablePropertyIter == _pPropertyTable->properties.end()) { @@ -974,8 +966,8 @@ class PropertyTableView { PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist); } - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty = propertyTablePropertyIter->second; + const PropertyTableProperty& propertyTableProperty = + propertyTablePropertyIter->second; if constexpr (IsMetadataNumeric::value || IsMetadataBoolean::value) { return getNumericOrBooleanPropertyValues( @@ -1002,9 +994,8 @@ class PropertyTableView { template PropertyTablePropertyView getNumericOrBooleanPropertyValues( - const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty) const { + const ClassProperty& classProperty, + const PropertyTableProperty& propertyTableProperty) const { if (classProperty.array) { return createInvalidPropertyView( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); @@ -1057,16 +1048,14 @@ class PropertyTableView { } PropertyTablePropertyView getStringPropertyValues( - const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty) const; + const ClassProperty& classProperty, + const PropertyTableProperty& propertyTableProperty) const; template PropertyTablePropertyView> getPrimitiveArrayPropertyValues( - const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty) const { + const ClassProperty& classProperty, + const PropertyTableProperty& propertyTableProperty) const { if (!classProperty.array) { return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); @@ -1178,9 +1167,8 @@ class PropertyTableView { PropertyTablePropertyView> getStringArrayPropertyValues( - const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty) const; + const ClassProperty& classProperty, + const PropertyTableProperty& propertyTableProperty) const; PropertyTablePropertyViewStatus getBufferSafe( int32_t bufferView, @@ -1212,8 +1200,8 @@ class PropertyTableView { } const Model* _pModel; - const ExtensionExtStructuralMetadataPropertyTable* _pPropertyTable; - const ExtensionExtStructuralMetadataClass* _pClass; + const PropertyTable* _pPropertyTable; + const Class* _pClass; PropertyTableViewStatus _status; }; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index a6b97ccd1..425ad1f58 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -1,11 +1,11 @@ #pragma once -#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTexture.h" +#include "CesiumGltf/ClassProperty.h" #include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" #include "CesiumGltf/Image.h" #include "CesiumGltf/ImageCesium.h" #include "CesiumGltf/Model.h" +#include "CesiumGltf/PropertyTexture.h" #include "CesiumGltf/Sampler.h" #include "CesiumGltf/Texture.h" @@ -89,11 +89,12 @@ enum class PropertyTexturePropertyComponentType { * @tparam T The component type, must correspond to a valid * {@link PropertyTexturePropertyComponentType}. */ -template struct PropertyTexturePropertyValue { T components[4]; }; +template struct PropertyTexturePropertyValue { + T components[4]; +}; /** - * @brief A view of the data specified by a - * {@link ExtensionExtStructuralMetadataPropertyTextureProperty}. + * @brief A view of the data specified by a {@link PropertyTextureProperty}. * * Provides utilities to sample the property texture property using texture * coordinates. @@ -107,8 +108,8 @@ class PropertyTexturePropertyView { /** * @brief Construct a view of the data specified by the given property texture - * property. Assumes the model has already been validated by - * PropertyTextureView. + * property. Assumes the model has already been validated by the + * {@link PropertyTextureView} that invoked this constructor. * * @param model The glTF in which to look for the data specified by the * property texture property. @@ -117,9 +118,8 @@ class PropertyTexturePropertyView { */ PropertyTexturePropertyView( const Model& model, - const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty) noexcept; + const ClassProperty& classProperty, + const PropertyTextureProperty& propertyTextureProperty) noexcept; /** * @brief Gets the unswizzled property for the given texture coordinates. @@ -229,7 +229,7 @@ class PropertyTexturePropertyView { private: PropertyTexturePropertyViewStatus _status; - const ExtensionExtStructuralMetadataClassProperty* _pClassProperty; + const ClassProperty* _pClassProperty; const Sampler* _pSampler; const ImageCesium* _pImage; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 8fc438670..53189aa31 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -1,9 +1,9 @@ #pragma once -#include "CesiumGltf/ExtensionExtStructuralMetadataClass.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTexture.h" +#include "CesiumGltf/Class.h" +#include "CesiumGltf/ClassProperty.h" #include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" +#include "CesiumGltf/PropertyTexture.h" #include "CesiumGltf/PropertyTexturePropertyView.h" #include "CesiumGltf/Texture.h" #include "Image.h" @@ -16,7 +16,7 @@ namespace CesiumGltf { * * The {@link PropertyTextureView} constructor always completes successfully. * However it may not always reflect the actual content of the - * {@link ExtensionExtStructuralMetadataPropertyTexture}. This enumeration provides the reason. + * {@link PropertyTexture}. This enumeration provides the reason. */ enum class PropertyTextureViewStatus { /** @@ -60,7 +60,7 @@ enum class PropertyTextureViewStatus { }; /** - * @brief A view on the {@link ExtensionExtStructuralMetadataPropertyTexture}. + * @brief A view on the {@link PropertyTexture}. * * Provides access to views on the property texture properties. */ @@ -79,8 +79,7 @@ class PropertyTextureView { */ PropertyTextureView( const Model& model, - const ExtensionExtStructuralMetadataPropertyTexture& - propertyTexture) noexcept; + const PropertyTexture& propertyTexture) noexcept; /** * @brief Gets the status of this property texture view. @@ -91,15 +90,14 @@ class PropertyTextureView { PropertyTextureViewStatus status() const noexcept { return this->_status; } /** - * @brief Finds the {@link ExtensionExtStructuralMetadataClassProperty} that + * @brief Finds the {@link ClassProperty} that * describes the type information of the property with the specified name. * @param propertyName The name of the property to retrieve the class for. - * @return A pointer to the {@link ExtensionExtStructuralMetadataClassProperty}. + * @return A pointer to the {@link ClassProperty}. * Return nullptr if the PropertyTextureView is invalid or if no class * property was found. */ - const ExtensionExtStructuralMetadataClassProperty* - getClassProperty(const std::string& propertyName) const; + const ClassProperty* getClassProperty(const std::string& propertyName) const; /** * @brief Get the views for this property texture's properties. @@ -111,8 +109,8 @@ class PropertyTextureView { private: const Model* _pModel; - const ExtensionExtStructuralMetadataPropertyTexture* _pPropertyTexture; - const ExtensionExtStructuralMetadataClass* _pClass; + const PropertyTexture* _pPropertyTexture; + const Class* _pClass; std::unordered_map _propertyViews; PropertyTextureViewStatus _status; }; diff --git a/CesiumGltf/src/PropertyTableView.cpp b/CesiumGltf/src/PropertyTableView.cpp index 0e06b7d0f..a280527f6 100644 --- a/CesiumGltf/src/PropertyTableView.cpp +++ b/CesiumGltf/src/PropertyTableView.cpp @@ -106,7 +106,7 @@ static PropertyTablePropertyViewStatus checkStringAndArrayOffsetsBuffers( PropertyTableView::PropertyTableView( const Model& model, - const ExtensionExtStructuralMetadataPropertyTable& propertyTable) + const PropertyTable& propertyTable) : _pModel{&model}, _pPropertyTable{&propertyTable}, _pClass{nullptr}, @@ -118,8 +118,7 @@ PropertyTableView::PropertyTableView( return; } - const std::optional& schema = - pMetadata->schema; + const std::optional& schema = pMetadata->schema; if (!schema) { _status = PropertyTableViewStatus::ErrorMissingSchema; return; @@ -135,7 +134,7 @@ PropertyTableView::PropertyTableView( } } -const ExtensionExtStructuralMetadataClassProperty* +const ClassProperty* PropertyTableView::getClassProperty(const std::string& propertyName) const { if (_status != PropertyTableViewStatus::Valid) { return nullptr; @@ -280,16 +279,14 @@ PropertyTablePropertyViewStatus PropertyTableView::getStringOffsetsBufferSafe( PropertyTablePropertyView PropertyTableView::getStringPropertyValues( - const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty) const { + const ClassProperty& classProperty, + const PropertyTableProperty& propertyTableProperty) const { if (classProperty.array) { return createInvalidPropertyView( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } - if (classProperty.type != - ExtensionExtStructuralMetadataClassProperty::Type::STRING) { + if (classProperty.type != ClassProperty::Type::STRING) { return createInvalidPropertyView( PropertyTablePropertyViewStatus::ErrorTypeMismatch); } @@ -333,16 +330,14 @@ PropertyTableView::getStringPropertyValues( PropertyTablePropertyView> PropertyTableView::getStringArrayPropertyValues( - const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTableProperty& - propertyTableProperty) const { + const ClassProperty& classProperty, + const PropertyTableProperty& propertyTableProperty) const { if (!classProperty.array) { return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } - if (classProperty.type != - ExtensionExtStructuralMetadataClassProperty::Type::STRING) { + if (classProperty.type != ClassProperty::Type::STRING) { return createInvalidPropertyView>( PropertyTablePropertyViewStatus::ErrorTypeMismatch); } diff --git a/CesiumGltf/src/PropertyTexturePropertyView.cpp b/CesiumGltf/src/PropertyTexturePropertyView.cpp index d854468d2..253fdecb9 100644 --- a/CesiumGltf/src/PropertyTexturePropertyView.cpp +++ b/CesiumGltf/src/PropertyTexturePropertyView.cpp @@ -16,9 +16,8 @@ PropertyTexturePropertyView::PropertyTexturePropertyView() noexcept PropertyTexturePropertyView::PropertyTexturePropertyView( const Model& model, - const ExtensionExtStructuralMetadataClassProperty& classProperty, - const ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty) noexcept + const ClassProperty& classProperty, + const PropertyTextureProperty& propertyTextureProperty) noexcept : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), _pClassProperty(&classProperty), _pSampler(nullptr), diff --git a/CesiumGltf/src/PropertyTextureView.cpp b/CesiumGltf/src/PropertyTextureView.cpp index 7f917c8a9..90dc0d6f7 100644 --- a/CesiumGltf/src/PropertyTextureView.cpp +++ b/CesiumGltf/src/PropertyTextureView.cpp @@ -10,8 +10,7 @@ PropertyTextureView::PropertyTextureView() noexcept PropertyTextureView::PropertyTextureView( const Model& model, - const ExtensionExtStructuralMetadataPropertyTexture& - propertyTexture) noexcept + const PropertyTexture& propertyTexture) noexcept : _pModel(&model), _pPropertyTexture(&propertyTexture), _pClass(nullptr), @@ -66,7 +65,7 @@ PropertyTextureView::PropertyTextureView( this->_status = PropertyTextureViewStatus::Valid; } -const ExtensionExtStructuralMetadataClassProperty* +const ClassProperty* PropertyTextureView::getClassProperty(const std::string& propertyName) const { if (_status != PropertyTextureViewStatus::Valid) { return nullptr; diff --git a/CesiumGltf/src/PropertyType.cpp b/CesiumGltf/src/PropertyType.cpp index 826997cf8..1e5e4ed62 100644 --- a/CesiumGltf/src/PropertyType.cpp +++ b/CesiumGltf/src/PropertyType.cpp @@ -1,74 +1,74 @@ #include "CesiumGltf/PropertyType.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTable.h" +#include "CesiumGltf/ClassProperty.h" +#include "CesiumGltf/PropertyTable.h" namespace CesiumGltf { std::string convertPropertyTypeToString(PropertyType type) { switch (type) { case PropertyType::Scalar: - return ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; + return ClassProperty::Type::SCALAR; case PropertyType::Vec2: - return ExtensionExtStructuralMetadataClassProperty::Type::VEC2; + return ClassProperty::Type::VEC2; case PropertyType::Vec3: - return ExtensionExtStructuralMetadataClassProperty::Type::VEC3; + return ClassProperty::Type::VEC3; case PropertyType::Vec4: - return ExtensionExtStructuralMetadataClassProperty::Type::VEC4; + return ClassProperty::Type::VEC4; case PropertyType::Mat2: - return ExtensionExtStructuralMetadataClassProperty::Type::MAT2; + return ClassProperty::Type::MAT2; case PropertyType::Mat3: - return ExtensionExtStructuralMetadataClassProperty::Type::MAT3; + return ClassProperty::Type::MAT3; case PropertyType::Mat4: - return ExtensionExtStructuralMetadataClassProperty::Type::MAT4; + return ClassProperty::Type::MAT4; case PropertyType::Boolean: - return ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + return ClassProperty::Type::BOOLEAN; case PropertyType::Enum: - return ExtensionExtStructuralMetadataClassProperty::Type::ENUM; + return ClassProperty::Type::ENUM; case PropertyType::String: - return ExtensionExtStructuralMetadataClassProperty::Type::STRING; + return ClassProperty::Type::STRING; default: return "INVALID"; } } PropertyType convertStringToPropertyType(const std::string& str) { - if (str == ExtensionExtStructuralMetadataClassProperty::Type::SCALAR) { + if (str == ClassProperty::Type::SCALAR) { return PropertyType::Scalar; } - if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC2) { + if (str == ClassProperty::Type::VEC2) { return PropertyType::Vec2; } - if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC3) { + if (str == ClassProperty::Type::VEC3) { return PropertyType::Vec3; } - if (str == ExtensionExtStructuralMetadataClassProperty::Type::VEC4) { + if (str == ClassProperty::Type::VEC4) { return PropertyType::Vec4; } - if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT2) { + if (str == ClassProperty::Type::MAT2) { return PropertyType::Mat2; } - if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT3) { + if (str == ClassProperty::Type::MAT3) { return PropertyType::Mat3; } - if (str == ExtensionExtStructuralMetadataClassProperty::Type::MAT4) { + if (str == ClassProperty::Type::MAT4) { return PropertyType::Mat4; } - if (str == ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN) { + if (str == ClassProperty::Type::BOOLEAN) { return PropertyType::Boolean; } - if (str == ExtensionExtStructuralMetadataClassProperty::Type::STRING) { + if (str == ClassProperty::Type::STRING) { return PropertyType::String; } - if (str == ExtensionExtStructuralMetadataClassProperty::Type::ENUM) { + if (str == ClassProperty::Type::ENUM) { return PropertyType::Enum; } @@ -80,25 +80,25 @@ std::string convertPropertyComponentTypeToString(PropertyComponentType type) { case PropertyComponentType::None: return "NONE"; case PropertyComponentType::Uint8: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + return ClassProperty::ComponentType::UINT8; case PropertyComponentType::Int8: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8; + return ClassProperty::ComponentType::INT8; case PropertyComponentType::Uint16: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16; + return ClassProperty::ComponentType::UINT16; case PropertyComponentType::Int16: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16; + return ClassProperty::ComponentType::INT16; case PropertyComponentType::Uint32: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + return ClassProperty::ComponentType::UINT32; case PropertyComponentType::Int32: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + return ClassProperty::ComponentType::INT32; case PropertyComponentType::Uint64: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64; + return ClassProperty::ComponentType::UINT64; case PropertyComponentType::Int64: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64; + return ClassProperty::ComponentType::INT64; case PropertyComponentType::Float32: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32; + return ClassProperty::ComponentType::FLOAT32; case PropertyComponentType::Float64: - return ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64; + return ClassProperty::ComponentType::FLOAT64; default: return "NONE"; } @@ -106,52 +106,43 @@ std::string convertPropertyComponentTypeToString(PropertyComponentType type) { PropertyComponentType convertStringToPropertyComponentType(const std::string& str) { - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8) { + if (str == ClassProperty::ComponentType::UINT8) { return PropertyComponentType::Uint8; } - if (str == ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8) { + if (str == ClassProperty::ComponentType::INT8) { return PropertyComponentType::Int8; } - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16) { + if (str == ClassProperty::ComponentType::UINT16) { return PropertyComponentType::Uint16; } - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16) { + if (str == ClassProperty::ComponentType::INT16) { return PropertyComponentType::Int16; } - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32) { + if (str == ClassProperty::ComponentType::UINT32) { return PropertyComponentType::Uint32; } - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32) { + if (str == ClassProperty::ComponentType::INT32) { return PropertyComponentType::Int32; } - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64) { + if (str == ClassProperty::ComponentType::UINT64) { return PropertyComponentType::Uint64; } - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64) { + if (str == ClassProperty::ComponentType::INT64) { return PropertyComponentType::Int64; } - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32) { + if (str == ClassProperty::ComponentType::FLOAT32) { return PropertyComponentType::Float32; } - if (str == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64) { + if (str == ClassProperty::ComponentType::FLOAT64) { return PropertyComponentType::Float64; } @@ -160,23 +151,19 @@ convertStringToPropertyComponentType(const std::string& str) { PropertyComponentType convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str) { - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT8) { + if (str == PropertyTableProperty::ArrayOffsetType::UINT8) { return PropertyComponentType::Uint8; } - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT16) { + if (str == PropertyTableProperty::ArrayOffsetType::UINT16) { return PropertyComponentType::Uint16; } - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT32) { + if (str == PropertyTableProperty::ArrayOffsetType::UINT32) { return PropertyComponentType::Uint32; } - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT64) { + if (str == PropertyTableProperty::ArrayOffsetType::UINT64) { return PropertyComponentType::Uint64; } @@ -185,23 +172,19 @@ convertArrayOffsetTypeStringToPropertyComponentType(const std::string& str) { PropertyComponentType convertStringOffsetTypeStringToPropertyComponentType(const std::string& str) { - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT8) { + if (str == PropertyTableProperty::StringOffsetType::UINT8) { return PropertyComponentType::Uint8; } - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT16) { + if (str == PropertyTableProperty::StringOffsetType::UINT16) { return PropertyComponentType::Uint16; } - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT32) { + if (str == PropertyTableProperty::StringOffsetType::UINT32) { return PropertyComponentType::Uint32; } - if (str == ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT64) { + if (str == PropertyTableProperty::StringOffsetType::UINT64) { return PropertyComponentType::Uint64; } diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index cfadc098b..d1984cd67 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -11,11 +11,11 @@ TEST_CASE("Test PropertyTableView on model without EXT_structural_metadata " Model model; // Create an erroneously isolated property table. - ExtensionExtStructuralMetadataPropertyTable propertyTable; + PropertyTable propertyTable; propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(10); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(0); @@ -24,7 +24,7 @@ TEST_CASE("Test PropertyTableView on model without EXT_structural_metadata " view.status() == PropertyTableViewStatus::ErrorMissingMetadataExtension); REQUIRE(view.size() == 0); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(!classProperty); } @@ -35,12 +35,11 @@ TEST_CASE("Test PropertyTableView on model without metadata schema") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(10); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(0); @@ -48,7 +47,7 @@ TEST_CASE("Test PropertyTableView on model without metadata schema") { REQUIRE(view.status() == PropertyTableViewStatus::ErrorMissingSchema); REQUIRE(view.size() == 0); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(!classProperty); } @@ -59,21 +58,17 @@ TEST_CASE("Test property table with nonexistent class") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; - - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "I Don't Exist"; propertyTable.count = static_cast(10); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(0); @@ -81,7 +76,7 @@ TEST_CASE("Test property table with nonexistent class") { REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); REQUIRE(view.size() == 0); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(!classProperty); } @@ -117,21 +112,17 @@ TEST_CASE("Test scalar property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; - - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(values.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); @@ -139,15 +130,11 @@ TEST_CASE("Test scalar property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); @@ -299,21 +286,17 @@ TEST_CASE("Test vecN property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::VEC3; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; - - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(values.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); @@ -321,15 +304,11 @@ TEST_CASE("Test vecN property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::VEC3); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); @@ -498,21 +477,17 @@ TEST_CASE("Test matN property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::MAT2; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; - - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(values.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); @@ -520,15 +495,11 @@ TEST_CASE("Test matN property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::MAT2); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); @@ -698,19 +669,16 @@ TEST_CASE("Test boolean property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(instanceCount); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); @@ -719,12 +687,10 @@ TEST_CASE("Test boolean property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); REQUIRE(classProperty->componentType == std::nullopt); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); @@ -809,23 +775,19 @@ TEST_CASE("Test string property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::STRING; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(expected.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT32; + PropertyTableProperty::StringOffsetType::UINT32; propertyTableProperty.values = static_cast(valueBufferViewIndex); propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); @@ -834,12 +796,10 @@ TEST_CASE("Test string property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::STRING); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); REQUIRE(classProperty->componentType == std::nullopt); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); @@ -865,8 +825,7 @@ TEST_CASE("Test string property") { SECTION("Wrong offset type") { propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT8; + PropertyTableProperty::StringOffsetType::UINT8; PropertyTablePropertyView stringProperty = view.getPropertyView("TestClassProperty"); REQUIRE( @@ -875,8 +834,7 @@ TEST_CASE("Test string property") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT64; + PropertyTableProperty::StringOffsetType::UINT64; stringProperty = view.getPropertyView("TestClassProperty"); REQUIRE( @@ -893,8 +851,7 @@ TEST_CASE("Test string property") { propertyTableProperty.stringOffsetType = ""; propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT32; + PropertyTableProperty::StringOffsetType::UINT32; stringProperty = view.getPropertyView("TestClassProperty"); REQUIRE( @@ -954,24 +911,20 @@ TEST_CASE("Test fixed-length scalar array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; testClassProperty.array = true; testClassProperty.count = 3; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( values.size() / static_cast(testClassProperty.count.value())); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); @@ -980,15 +933,11 @@ TEST_CASE("Test fixed-length scalar array") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 3); @@ -1127,43 +1076,34 @@ TEST_CASE("Test variable-length scalar array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16; + 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; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(expected.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); propertyTableProperty.arrayOffsets = static_cast(offsetBufferViewIndex); propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT64; + PropertyTableProperty::ArrayOffsetType::UINT64; PropertyTableView view(model, propertyTable); REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT16); REQUIRE(classProperty->array); REQUIRE(!classProperty->count); @@ -1182,8 +1122,7 @@ TEST_CASE("Test variable-length scalar array") { } SECTION("Wrong offset type") { propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT8; + PropertyTableProperty::ArrayOffsetType::UINT8; PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( @@ -1192,8 +1131,7 @@ TEST_CASE("Test variable-length scalar array") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT16; + PropertyTableProperty::ArrayOffsetType::UINT16; arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( @@ -1210,8 +1148,7 @@ TEST_CASE("Test variable-length scalar array") { propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT64; + PropertyTableProperty::StringOffsetType::UINT64; arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( @@ -1221,8 +1158,7 @@ TEST_CASE("Test variable-length scalar array") { SECTION("Offset values are not sorted ascending") { propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT64; + PropertyTableProperty::ArrayOffsetType::UINT64; uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; @@ -1288,24 +1224,20 @@ TEST_CASE("Test fixed-length vecN array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::VEC3; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; testClassProperty.array = true; testClassProperty.count = 2; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( values.size() / static_cast(testClassProperty.count.value())); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); @@ -1314,15 +1246,11 @@ TEST_CASE("Test fixed-length vecN array") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::VEC3); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); @@ -1468,43 +1396,34 @@ TEST_CASE("Test variable-length vecN array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::VEC3; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; testClassProperty.array = true; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(expected.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); propertyTableProperty.arrayOffsets = static_cast(offsetBufferViewIndex); propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT64; + PropertyTableProperty::ArrayOffsetType::UINT64; PropertyTableView view(model, propertyTable); REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::VEC3); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(!classProperty->count); @@ -1525,8 +1444,7 @@ TEST_CASE("Test variable-length vecN array") { SECTION("Wrong offset type") { propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT8; + PropertyTableProperty::ArrayOffsetType::UINT8; PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); @@ -1536,8 +1454,7 @@ TEST_CASE("Test variable-length vecN array") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT16; + PropertyTableProperty::ArrayOffsetType::UINT16; arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( @@ -1554,8 +1471,7 @@ TEST_CASE("Test variable-length vecN array") { propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT64; + PropertyTableProperty::StringOffsetType::UINT64; arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( @@ -1565,8 +1481,7 @@ TEST_CASE("Test variable-length vecN array") { SECTION("Offset values are not sorted ascending") { propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT64; + PropertyTableProperty::ArrayOffsetType::UINT64; uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; @@ -1649,24 +1564,20 @@ TEST_CASE("Test fixed-length matN array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::MAT2; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; testClassProperty.array = true; testClassProperty.count = 2; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( values.size() / static_cast(testClassProperty.count.value())); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); @@ -1675,15 +1586,11 @@ TEST_CASE("Test fixed-length matN array") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::MAT2); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); @@ -1850,43 +1757,34 @@ TEST_CASE("Test variable-length matN array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::MAT2; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; testClassProperty.array = true; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(expected.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); propertyTableProperty.arrayOffsets = static_cast(offsetBufferViewIndex); propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT64; + PropertyTableProperty::ArrayOffsetType::UINT64; PropertyTableView view(model, propertyTable); REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::MAT2); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(!classProperty->count); @@ -1907,8 +1805,7 @@ TEST_CASE("Test variable-length matN array") { SECTION("Wrong offset type") { propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT8; + PropertyTableProperty::ArrayOffsetType::UINT8; PropertyTablePropertyView> arrayProperty = view.getPropertyView>( "TestClassProperty"); @@ -1918,8 +1815,7 @@ TEST_CASE("Test variable-length matN array") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT16; + PropertyTableProperty::ArrayOffsetType::UINT16; arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( @@ -1936,8 +1832,7 @@ TEST_CASE("Test variable-length matN array") { propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT64; + PropertyTableProperty::StringOffsetType::UINT64; arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( @@ -1947,8 +1842,7 @@ TEST_CASE("Test variable-length matN array") { SECTION("Offset values are not sorted ascending") { propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT64; + PropertyTableProperty::ArrayOffsetType::UINT64; uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; @@ -2031,22 +1925,19 @@ TEST_CASE("Test fixed-length boolean array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; testClassProperty.array = true; testClassProperty.count = 3; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( expected.size() / static_cast(testClassProperty.count.value())); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); @@ -2055,12 +1946,10 @@ TEST_CASE("Test fixed-length boolean array") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 3); @@ -2184,38 +2073,32 @@ TEST_CASE("Test variable-length boolean array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; testClassProperty.array = true; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(expected.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); propertyTableProperty.arrayOffsets = static_cast(offsetBufferViewIndex); propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT64; + PropertyTableProperty::ArrayOffsetType::UINT64; PropertyTableView view(model, propertyTable); REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); REQUIRE(classProperty->array); REQUIRE(!classProperty->count); @@ -2236,8 +2119,7 @@ TEST_CASE("Test variable-length boolean array") { SECTION("Wrong offset type") { propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT8; + PropertyTableProperty::ArrayOffsetType::UINT8; PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( @@ -2246,8 +2128,7 @@ TEST_CASE("Test variable-length boolean array") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT16; + PropertyTableProperty::ArrayOffsetType::UINT16; arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( @@ -2264,8 +2145,7 @@ TEST_CASE("Test variable-length boolean array") { propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT64; + PropertyTableProperty::StringOffsetType::UINT64; arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( @@ -2275,8 +2155,7 @@ TEST_CASE("Test variable-length boolean array") { SECTION("Offset values are not sorted ascending") { propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT64; + PropertyTableProperty::ArrayOffsetType::UINT64; uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; @@ -2367,26 +2246,22 @@ TEST_CASE("Test fixed-length arrays of strings") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::STRING; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; testClassProperty.array = true; testClassProperty.count = 2; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( expected.size() / static_cast(testClassProperty.count.value())); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT32; + PropertyTableProperty::StringOffsetType::UINT32; propertyTableProperty.values = static_cast(valueBufferViewIndex); propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); @@ -2395,12 +2270,10 @@ TEST_CASE("Test fixed-length arrays of strings") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::STRING); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); @@ -2459,8 +2332,7 @@ TEST_CASE("Test fixed-length arrays of strings") { propertyTableProperty.stringOffsetType = ""; propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT32; + PropertyTableProperty::ArrayOffsetType::UINT32; stringProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( @@ -2573,27 +2445,22 @@ TEST_CASE("Test variable-length arrays of strings") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::STRING; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; testClassProperty.array = true; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(expected.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT32; + PropertyTableProperty::ArrayOffsetType::UINT32; propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT32; + PropertyTableProperty::StringOffsetType::UINT32; propertyTableProperty.values = static_cast(valueBufferViewIndex); propertyTableProperty.arrayOffsets = static_cast(arrayOffsetBufferView); @@ -2604,12 +2471,10 @@ TEST_CASE("Test variable-length arrays of strings") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::STRING); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); REQUIRE(classProperty->array); REQUIRE(!classProperty->componentType); REQUIRE(!classProperty->count); @@ -2631,8 +2496,7 @@ TEST_CASE("Test variable-length arrays of strings") { SECTION("Wrong array offset type") { propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT8; + PropertyTableProperty::ArrayOffsetType::UINT8; PropertyTablePropertyView> arrayProperty = view.getPropertyView>( @@ -2643,8 +2507,7 @@ TEST_CASE("Test variable-length arrays of strings") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT16; + PropertyTableProperty::ArrayOffsetType::UINT16; arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( @@ -2659,14 +2522,12 @@ TEST_CASE("Test variable-length arrays of strings") { arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); propertyTableProperty.arrayOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::ArrayOffsetType:: - UINT32; + PropertyTableProperty::ArrayOffsetType::UINT32; } SECTION("Wrong string offset type") { propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT8; + PropertyTableProperty::StringOffsetType::UINT8; PropertyTablePropertyView> arrayProperty = view.getPropertyView>( @@ -2677,8 +2538,7 @@ TEST_CASE("Test variable-length arrays of strings") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT16; + PropertyTableProperty::StringOffsetType::UINT16; arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( @@ -2693,8 +2553,7 @@ TEST_CASE("Test variable-length arrays of strings") { arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT32; + PropertyTableProperty::StringOffsetType::UINT32; } SECTION("Array offset values are not sorted ascending") { @@ -2774,12 +2633,11 @@ TEST_CASE("Test callback on invalid property table view") { metadata.schema.emplace(); // Property table has a nonexistent class. - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(5); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(-1); @@ -2787,7 +2645,7 @@ TEST_CASE("Test callback on invalid property table view") { REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); REQUIRE(view.size() == 0); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(!classProperty); @@ -2812,21 +2670,17 @@ TEST_CASE("Test callback for invalid property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["InvalidProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; - - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["InvalidProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(5); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["InvalidProperty"]; propertyTableProperty.values = static_cast(-1); @@ -2834,8 +2688,7 @@ TEST_CASE("Test callback for invalid property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = - view.getClassProperty("InvalidProperty"); + const ClassProperty* classProperty = view.getClassProperty("InvalidProperty"); REQUIRE(classProperty); classProperty = view.getClassProperty("NonexistentProperty"); @@ -2884,21 +2737,17 @@ TEST_CASE("Test callback for scalar property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; - - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(values.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); @@ -2906,15 +2755,11 @@ TEST_CASE("Test callback for scalar property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(!classProperty->array); REQUIRE(classProperty->count == std::nullopt); @@ -2980,21 +2825,17 @@ TEST_CASE("Test callback for vecN property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::VEC3; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; - - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(values.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); @@ -3002,15 +2843,11 @@ TEST_CASE("Test callback for vecN property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::VEC3); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); @@ -3086,21 +2923,17 @@ TEST_CASE("Test callback for matN property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::MAT2; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; - - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(values.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); @@ -3108,15 +2941,11 @@ TEST_CASE("Test callback for matN property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::MAT2); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); @@ -3191,19 +3020,16 @@ TEST_CASE("Test callback for boolean property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(instanceCount); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); @@ -3212,12 +3038,10 @@ TEST_CASE("Test callback for boolean property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); REQUIRE(classProperty->componentType == std::nullopt); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); @@ -3310,23 +3134,19 @@ TEST_CASE("Test callback for string property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::STRING; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast(expected.size()); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT32; + PropertyTableProperty::StringOffsetType::UINT32; propertyTableProperty.values = static_cast(valueBufferViewIndex); propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); @@ -3335,12 +3155,10 @@ TEST_CASE("Test callback for string property") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::STRING); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); REQUIRE(classProperty->componentType == std::nullopt); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); @@ -3399,24 +3217,20 @@ TEST_CASE("Test callback for scalar array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; testClassProperty.array = true; testClassProperty.count = 3; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( values.size() / static_cast(testClassProperty.count.value())); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); @@ -3425,15 +3239,11 @@ TEST_CASE("Test callback for scalar array") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 3); @@ -3499,24 +3309,20 @@ TEST_CASE("Test callback for vecN array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::VEC3; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; testClassProperty.array = true; testClassProperty.count = 2; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( values.size() / static_cast(testClassProperty.count.value())); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); @@ -3525,15 +3331,11 @@ TEST_CASE("Test callback for vecN array") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::VEC3); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); @@ -3613,24 +3415,20 @@ TEST_CASE("Test callback for matN array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::MAT2; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; testClassProperty.array = true; testClassProperty.count = 2; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( values.size() / static_cast(testClassProperty.count.value())); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); @@ -3639,15 +3437,11 @@ TEST_CASE("Test callback for matN array") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::MAT2); - REQUIRE( - classProperty->componentType == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); @@ -3729,22 +3523,19 @@ TEST_CASE("Test callback for boolean array") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; testClassProperty.array = true; testClassProperty.count = 3; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( expected.size() / static_cast(testClassProperty.count.value())); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(model.bufferViews.size() - 1); @@ -3753,12 +3544,10 @@ TEST_CASE("Test callback for boolean array") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 3); @@ -3850,26 +3639,22 @@ TEST_CASE("Test callback for array of strings") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::STRING; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; testClassProperty.array = true; testClassProperty.count = 2; - ExtensionExtStructuralMetadataPropertyTable& propertyTable = - metadata.propertyTables.emplace_back(); + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( expected.size() / static_cast(testClassProperty.count.value())); - ExtensionExtStructuralMetadataPropertyTableProperty& propertyTableProperty = + PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; propertyTableProperty.stringOffsetType = - ExtensionExtStructuralMetadataPropertyTableProperty::StringOffsetType:: - UINT32; + PropertyTableProperty::StringOffsetType::UINT32; propertyTableProperty.values = static_cast(valueBufferViewIndex); propertyTableProperty.stringOffsets = static_cast(offsetBufferViewIndex); @@ -3878,12 +3663,10 @@ TEST_CASE("Test callback for array of strings") { REQUIRE(view.status() == PropertyTableViewStatus::Valid); REQUIRE(view.size() == propertyTable.count); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE( - classProperty->type == - ExtensionExtStructuralMetadataClassProperty::Type::STRING); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index e6d96520e..12ddfd3bf 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -17,20 +17,17 @@ TEST_CASE( ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; - - ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + + PropertyTexture propertyTexture; propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = -1; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; @@ -49,14 +46,11 @@ TEST_CASE( ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; Image& image = model.images.emplace_back(); image.cesium.width = 1; @@ -65,11 +59,11 @@ TEST_CASE( texture.sampler = -1; texture.source = 0; - ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + PropertyTexture propertyTexture; propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; @@ -89,14 +83,11 @@ TEST_CASE( ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; model.samplers.emplace_back(); @@ -104,11 +95,11 @@ TEST_CASE( texture.sampler = 0; texture.source = -1; - ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + PropertyTexture propertyTexture; propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; @@ -126,14 +117,11 @@ TEST_CASE("Test PropertyTexturePropertyView on property with empty image") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; Image& image = model.images.emplace_back(); image.cesium.width = 0; @@ -145,11 +133,11 @@ TEST_CASE("Test PropertyTexturePropertyView on property with empty image") { texture.sampler = 0; texture.source = 0; - ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + PropertyTexture propertyTexture; propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; @@ -167,14 +155,11 @@ TEST_CASE("Test PropertyTextureView on property table property with negative " ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; Image& image = model.images.emplace_back(); image.cesium.width = 1; @@ -186,11 +171,11 @@ TEST_CASE("Test PropertyTextureView on property table property with negative " texture.sampler = 0; texture.source = 0; - ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + PropertyTexture propertyTexture; propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = -1; propertyTextureProperty.channels = {0}; @@ -210,14 +195,11 @@ TEST_CASE("Test PropertyTextureView on property texture property with zero " ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; Image& image = model.images.emplace_back(); image.cesium.width = 1; @@ -230,11 +212,11 @@ TEST_CASE("Test PropertyTextureView on property texture property with zero " texture.sampler = 0; texture.source = 0; - ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + PropertyTexture propertyTexture; propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {}; @@ -253,14 +235,11 @@ TEST_CASE("Test PropertyTextureView on property texture property with too many " ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; Image& image = model.images.emplace_back(); image.cesium.width = 1; @@ -273,11 +252,11 @@ TEST_CASE("Test PropertyTextureView on property texture property with too many " texture.sampler = 0; texture.source = 0; - ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + PropertyTexture propertyTexture; propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0, 1}; diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index 6ca05cad2..514a979e6 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -16,11 +16,11 @@ TEST_CASE("Test PropertyTextureView on model without EXT_structural_metadata " Model model; // Create an erroneously isolated property texture. - ExtensionExtStructuralMetadataPropertyTexture propertyTexture; + PropertyTexture propertyTexture; propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; @@ -31,7 +31,7 @@ TEST_CASE("Test PropertyTextureView on model without EXT_structural_metadata " PropertyTextureViewStatus::ErrorMissingMetadataExtension); REQUIRE(view.getProperties().empty()); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(!classProperty); } @@ -42,12 +42,11 @@ TEST_CASE("Test PropertyTextureView on model without metadata schema") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataPropertyTexture& propertyTexture = - metadata.propertyTextures.emplace_back(); + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; @@ -56,7 +55,7 @@ TEST_CASE("Test PropertyTextureView on model without metadata schema") { REQUIRE(view.status() == PropertyTextureViewStatus::ErrorMissingSchema); REQUIRE(view.getProperties().empty()); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(!classProperty); } @@ -67,21 +66,17 @@ TEST_CASE("Test property texture with nonexistent class") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; - - ExtensionExtStructuralMetadataPropertyTexture& propertyTexture = - metadata.propertyTextures.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); propertyTexture.classProperty = "I Don't Exist"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; @@ -90,7 +85,7 @@ TEST_CASE("Test property texture with nonexistent class") { REQUIRE(view.status() == PropertyTextureViewStatus::ErrorClassNotFound); REQUIRE(view.getProperties().empty()); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(!classProperty); } @@ -101,21 +96,17 @@ TEST_CASE("Test property texture with nonexistent class property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; - - ExtensionExtStructuralMetadataPropertyTexture& propertyTexture = - metadata.propertyTextures.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["I Don't Exist"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["I Don't Exist"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; @@ -125,7 +116,7 @@ TEST_CASE("Test property texture with nonexistent class property") { view.status() == PropertyTextureViewStatus::ErrorClassPropertyNotFound); REQUIRE(view.getProperties().empty()); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(!classProperty); } @@ -136,21 +127,17 @@ TEST_CASE("Test property texture with invalid property") { ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); - ExtensionExtStructuralMetadataSchema& schema = metadata.schema.emplace(); - ExtensionExtStructuralMetadataClass& testClass = schema.classes["TestClass"]; - ExtensionExtStructuralMetadataClassProperty& testClassProperty = - testClass.properties["TestClassProperty"]; - testClassProperty.type = - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR; - testClassProperty.componentType = - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8; - - ExtensionExtStructuralMetadataPropertyTexture& propertyTexture = - metadata.propertyTextures.emplace_back(); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); propertyTexture.classProperty = "TestClass"; - ExtensionExtStructuralMetadataPropertyTextureProperty& - propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = -1; PropertyTextureView view(model, propertyTexture); @@ -162,7 +149,7 @@ TEST_CASE("Test property texture with invalid property") { PropertyTexturePropertyView& propertyView = properties["TestClassProperty"]; REQUIRE(propertyView.status() != PropertyTexturePropertyViewStatus::Valid); - const ExtensionExtStructuralMetadataClassProperty* classProperty = + const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(!classProperty); } diff --git a/CesiumGltf/test/TestPropertyType.cpp b/CesiumGltf/test/TestPropertyType.cpp index 9f345f6aa..539d01a3b 100644 --- a/CesiumGltf/test/TestPropertyType.cpp +++ b/CesiumGltf/test/TestPropertyType.cpp @@ -1,5 +1,5 @@ -#include "CesiumGltf/ExtensionExtStructuralMetadataClassProperty.h" -#include "CesiumGltf/ExtensionExtStructuralMetadataPropertyTableProperty.h" +#include "CesiumGltf/ClassProperty.h" +#include "CesiumGltf/PropertyTableProperty.h" #include "CesiumGltf/PropertyType.h" #include @@ -9,53 +9,43 @@ using namespace CesiumGltf; TEST_CASE("Test PropertyType utilities function") { SECTION("Convert string to PropertyType") { REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR) == + convertStringToPropertyType(ClassProperty::Type::SCALAR) == PropertyType::Scalar); REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::VEC2) == + convertStringToPropertyType(ClassProperty::Type::VEC2) == PropertyType::Vec2); REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::VEC3) == + convertStringToPropertyType(ClassProperty::Type::VEC3) == PropertyType::Vec3); REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::VEC4) == + convertStringToPropertyType(ClassProperty::Type::VEC4) == PropertyType::Vec4); REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::MAT2) == + convertStringToPropertyType(ClassProperty::Type::MAT2) == PropertyType::Mat2); REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::MAT3) == + convertStringToPropertyType(ClassProperty::Type::MAT3) == PropertyType::Mat3); REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::MAT4) == + convertStringToPropertyType(ClassProperty::Type::MAT4) == PropertyType::Mat4); REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN) == + convertStringToPropertyType(ClassProperty::Type::BOOLEAN) == PropertyType::Boolean); REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::STRING) == + convertStringToPropertyType(ClassProperty::Type::STRING) == PropertyType::String); REQUIRE( - convertStringToPropertyType( - ExtensionExtStructuralMetadataClassProperty::Type::ENUM) == + convertStringToPropertyType(ClassProperty::Type::ENUM) == PropertyType::Enum); REQUIRE(convertStringToPropertyType("invalid") == PropertyType::Invalid); @@ -64,50 +54,49 @@ TEST_CASE("Test PropertyType utilities function") { SECTION("Convert string to PropertyComponentType") { REQUIRE( convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - UINT8) == PropertyComponentType::Uint8); + ClassProperty::ComponentType::UINT8) == + PropertyComponentType::Uint8); REQUIRE( convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8) == - PropertyComponentType::Int8); + ClassProperty::ComponentType::INT8) == PropertyComponentType::Int8); REQUIRE( convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - UINT16) == PropertyComponentType::Uint16); + ClassProperty::ComponentType::UINT16) == + PropertyComponentType::Uint16); REQUIRE( convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - INT16) == PropertyComponentType::Int16); + ClassProperty::ComponentType::INT16) == + PropertyComponentType::Int16); REQUIRE( convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - UINT32) == PropertyComponentType::Uint32); + ClassProperty::ComponentType::UINT32) == + PropertyComponentType::Uint32); REQUIRE( convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - INT32) == PropertyComponentType::Int32); + ClassProperty::ComponentType::INT32) == + PropertyComponentType::Int32); REQUIRE( convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - UINT64) == PropertyComponentType::Uint64); + ClassProperty::ComponentType::UINT64) == + PropertyComponentType::Uint64); REQUIRE( convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - INT64) == PropertyComponentType::Int64); + ClassProperty::ComponentType::INT64) == + PropertyComponentType::Int64); REQUIRE( convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - FLOAT32) == PropertyComponentType::Float32); + ClassProperty::ComponentType::FLOAT32) == + PropertyComponentType::Float32); REQUIRE( convertStringToPropertyComponentType( - ExtensionExtStructuralMetadataClassProperty::ComponentType:: - FLOAT64) == PropertyComponentType::Float64); + ClassProperty::ComponentType::FLOAT64) == + PropertyComponentType::Float64); REQUIRE( convertStringToPropertyComponentType("invalid") == @@ -117,107 +106,107 @@ TEST_CASE("Test PropertyType utilities function") { SECTION("Convert PropertyType to string") { REQUIRE( convertPropertyTypeToString(PropertyType::Scalar) == - ExtensionExtStructuralMetadataClassProperty::Type::SCALAR); + ClassProperty::Type::SCALAR); REQUIRE( convertPropertyTypeToString(PropertyType::Vec2) == - ExtensionExtStructuralMetadataClassProperty::Type::VEC2); + ClassProperty::Type::VEC2); REQUIRE( convertPropertyTypeToString(PropertyType::Vec3) == - ExtensionExtStructuralMetadataClassProperty::Type::VEC3); + ClassProperty::Type::VEC3); REQUIRE( convertPropertyTypeToString(PropertyType::Vec4) == - ExtensionExtStructuralMetadataClassProperty::Type::VEC4); + ClassProperty::Type::VEC4); REQUIRE( convertPropertyTypeToString(PropertyType::Mat2) == - ExtensionExtStructuralMetadataClassProperty::Type::MAT2); + ClassProperty::Type::MAT2); REQUIRE( convertPropertyTypeToString(PropertyType::Mat3) == - ExtensionExtStructuralMetadataClassProperty::Type::MAT3); + ClassProperty::Type::MAT3); REQUIRE( convertPropertyTypeToString(PropertyType::Mat4) == - ExtensionExtStructuralMetadataClassProperty::Type::MAT4); + ClassProperty::Type::MAT4); REQUIRE( convertPropertyTypeToString(PropertyType::Boolean) == - ExtensionExtStructuralMetadataClassProperty::Type::BOOLEAN); + ClassProperty::Type::BOOLEAN); REQUIRE( convertPropertyTypeToString(PropertyType::String) == - ExtensionExtStructuralMetadataClassProperty::Type::STRING); + ClassProperty::Type::STRING); REQUIRE( convertPropertyTypeToString(PropertyType::Enum) == - ExtensionExtStructuralMetadataClassProperty::Type::ENUM); + ClassProperty::Type::ENUM); } SECTION("Convert PropertyComponentType to string") { REQUIRE( convertPropertyComponentTypeToString(PropertyComponentType::Uint8) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT8); + ClassProperty::ComponentType::UINT8); REQUIRE( convertPropertyComponentTypeToString(PropertyComponentType::Int8) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT8); + ClassProperty::ComponentType::INT8); REQUIRE( convertPropertyComponentTypeToString(PropertyComponentType::Uint16) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT16); + ClassProperty::ComponentType::UINT16); REQUIRE( convertPropertyComponentTypeToString(PropertyComponentType::Int16) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT16); + ClassProperty::ComponentType::INT16); REQUIRE( convertPropertyComponentTypeToString(PropertyComponentType::Uint32) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT32); + ClassProperty::ComponentType::UINT32); REQUIRE( convertPropertyComponentTypeToString(PropertyComponentType::Int32) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT32); + ClassProperty::ComponentType::INT32); REQUIRE( convertPropertyComponentTypeToString(PropertyComponentType::Uint64) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::UINT64); + ClassProperty::ComponentType::UINT64); REQUIRE( convertPropertyComponentTypeToString(PropertyComponentType::Int64) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::INT64); + ClassProperty::ComponentType::INT64); REQUIRE( convertPropertyComponentTypeToString(PropertyComponentType::Float32) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT32); + ClassProperty::ComponentType::FLOAT32); REQUIRE( convertPropertyComponentTypeToString(PropertyComponentType::Float64) == - ExtensionExtStructuralMetadataClassProperty::ComponentType::FLOAT64); + ClassProperty::ComponentType::FLOAT64); } SECTION("Convert array offset type string to PropertyComponentType") { REQUIRE( convertArrayOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT8) == PropertyComponentType::Uint8); + PropertyTableProperty::ArrayOffsetType::UINT8) == + PropertyComponentType::Uint8); REQUIRE( convertArrayOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT16) == PropertyComponentType::Uint16); + PropertyTableProperty::ArrayOffsetType::UINT16) == + PropertyComponentType::Uint16); REQUIRE( convertArrayOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT32) == PropertyComponentType::Uint32); + PropertyTableProperty::ArrayOffsetType::UINT32) == + PropertyComponentType::Uint32); REQUIRE( convertArrayOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - ArrayOffsetType::UINT64) == PropertyComponentType::Uint64); + PropertyTableProperty::ArrayOffsetType::UINT64) == + PropertyComponentType::Uint64); REQUIRE( convertArrayOffsetTypeStringToPropertyComponentType("invalid") == @@ -227,23 +216,23 @@ TEST_CASE("Test PropertyType utilities function") { SECTION("Convert string offset type string to PropertyComponentType") { REQUIRE( convertStringOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT8) == PropertyComponentType::Uint8); + PropertyTableProperty::StringOffsetType::UINT8) == + PropertyComponentType::Uint8); REQUIRE( convertStringOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT16) == PropertyComponentType::Uint16); + PropertyTableProperty::StringOffsetType::UINT16) == + PropertyComponentType::Uint16); REQUIRE( convertStringOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT32) == PropertyComponentType::Uint32); + PropertyTableProperty::StringOffsetType::UINT32) == + PropertyComponentType::Uint32); REQUIRE( convertStringOffsetTypeStringToPropertyComponentType( - ExtensionExtStructuralMetadataPropertyTableProperty:: - StringOffsetType::UINT64) == PropertyComponentType::Uint64); + PropertyTableProperty::StringOffsetType::UINT64) == + PropertyComponentType::Uint64); REQUIRE( convertStringOffsetTypeStringToPropertyComponentType("invalid") == From 0b8aecf710f0245059cda7a09a50fd69777f4e15 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 16 Jun 2023 16:41:07 -0400 Subject: [PATCH 059/121] Update changelog --- CHANGES.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 25ce81708..307298603 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,19 +4,20 @@ ##### Breaking Changes :mega: -- In `CesiumGltf`, all generated classes related to `EXT_feature_metadata` are now prefixed with `ExtensionExtFeatureMetadata`. For example, `ClassProperty` becomes `ExtensionExtFeatureMetadataClassProperty`. This also extends to the glTF reader and writer. +- 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 `ExtensionExtStructuralMetadataPropertyTable`. - - Added `PropertyTableViewStatus` to indicate whether or not `PropertyTableView` is valid. +- 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 `ExtensionExtMeshFeaturesPropertyTexture`. - - Replaced `FeatureTextureViewStatus` with `PropertyTextureViewStatus`. -- Replaced `FeatureTexturePropertyView` with `PropertyTexturePropertyView`, which views a `ExtensionExtMeshFeaturesPropertyTextureProperty`. - - Replaced `FeatureTexturePropertyViewStatus` with `PropertyTexturePropertyViewStatus`. -- Refactored the `PropertyType` enum to reflect the values of `type` in an `ExtensionExtStructuralMetadataClassProperty`. -- Added the `PropertyComponentType` enum to reflect the values of `componentType` in an `ExtensionExtStructuralMetadataClassProperty`. +- 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`. +- 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`. From 037a718eb830d7b5224c189fd70f51bea26f18c9 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 16 Jun 2023 16:44:43 -0400 Subject: [PATCH 060/121] Formatting --- .../generated/src/registerExtensions.cpp | 123 ++++++++++++------ 1 file changed, 80 insertions(+), 43 deletions(-) diff --git a/CesiumGltfReader/generated/src/registerExtensions.cpp b/CesiumGltfReader/generated/src/registerExtensions.cpp index 1c46f4ba9..15deefecc 100644 --- a/CesiumGltfReader/generated/src/registerExtensions.cpp +++ b/CesiumGltfReader/generated/src/registerExtensions.cpp @@ -3,61 +3,98 @@ #include "registerExtensions.h" -#include - -#include -#include -#include -#include -#include -#include -#include -#include - +#include "ExtensionBufferExtMeshoptCompressionJsonHandler.h" +#include "ExtensionBufferViewExtMeshoptCompressionJsonHandler.h" #include "ExtensionCesiumRTCJsonHandler.h" -#include "ExtensionModelExtFeatureMetadataJsonHandler.h" -#include "ExtensionModelExtStructuralMetadataJsonHandler.h" -#include "ExtensionModelKhrMaterialsVariantsJsonHandler.h" -#include "ExtensionModelMaxarMeshVariantsJsonHandler.h" #include "ExtensionCesiumTileEdgesJsonHandler.h" -#include "ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler.h" -#include "ExtensionExtMeshFeaturesJsonHandler.h" -#include "ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler.h" -#include "ExtensionKhrDracoMeshCompressionJsonHandler.h" -#include "ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler.h" #include "ExtensionExtInstanceFeaturesJsonHandler.h" +#include "ExtensionExtMeshFeaturesJsonHandler.h" #include "ExtensionExtMeshGpuInstancingJsonHandler.h" -#include "ExtensionNodeMaxarMeshVariantsJsonHandler.h" -#include "ExtensionBufferExtMeshoptCompressionJsonHandler.h" -#include "ExtensionBufferViewExtMeshoptCompressionJsonHandler.h" +#include "ExtensionKhrDracoMeshCompressionJsonHandler.h" #include "ExtensionKhrMaterialsUnlitJsonHandler.h" #include "ExtensionKhrTextureBasisuJsonHandler.h" +#include "ExtensionKhrTextureTransformJsonHandler.h" +#include "ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler.h" +#include "ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler.h" +#include "ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler.h" +#include "ExtensionModelExtFeatureMetadataJsonHandler.h" +#include "ExtensionModelExtStructuralMetadataJsonHandler.h" +#include "ExtensionModelKhrMaterialsVariantsJsonHandler.h" +#include "ExtensionModelMaxarMeshVariantsJsonHandler.h" +#include "ExtensionNodeMaxarMeshVariantsJsonHandler.h" #include "ExtensionTextureWebpJsonHandler.h" -#include "ExtensionKhrTextureTransformJsonHandler.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace CesiumGltfReader { void registerExtensions(CesiumJsonReader::ExtensionReaderContext& context) { (void)context; context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); -context.registerExtension(); + context.registerExtension< + CesiumGltf::Model, + ExtensionModelExtFeatureMetadataJsonHandler>(); + context.registerExtension< + CesiumGltf::Model, + ExtensionModelExtStructuralMetadataJsonHandler>(); + context.registerExtension< + CesiumGltf::Model, + ExtensionModelKhrMaterialsVariantsJsonHandler>(); + context.registerExtension< + CesiumGltf::Model, + ExtensionModelMaxarMeshVariantsJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionCesiumTileEdgesJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionMeshPrimitiveExtFeatureMetadataJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionExtMeshFeaturesJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionMeshPrimitiveExtStructuralMetadataJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionKhrDracoMeshCompressionJsonHandler>(); + context.registerExtension< + CesiumGltf::MeshPrimitive, + ExtensionMeshPrimitiveKhrMaterialsVariantsJsonHandler>(); + context.registerExtension< + CesiumGltf::Node, + ExtensionExtInstanceFeaturesJsonHandler>(); + context.registerExtension< + CesiumGltf::Node, + ExtensionExtMeshGpuInstancingJsonHandler>(); + context.registerExtension< + CesiumGltf::Node, + ExtensionNodeMaxarMeshVariantsJsonHandler>(); + context.registerExtension< + CesiumGltf::Buffer, + ExtensionBufferExtMeshoptCompressionJsonHandler>(); + context.registerExtension< + CesiumGltf::BufferView, + ExtensionBufferViewExtMeshoptCompressionJsonHandler>(); + context.registerExtension< + CesiumGltf::Material, + ExtensionKhrMaterialsUnlitJsonHandler>(); + context.registerExtension< + CesiumGltf::Texture, + ExtensionKhrTextureBasisuJsonHandler>(); + context.registerExtension< + CesiumGltf::Texture, + ExtensionTextureWebpJsonHandler>(); + context.registerExtension< + CesiumGltf::TextureInfo, + ExtensionKhrTextureTransformJsonHandler>(); } } // namespace CesiumGltfReader From ffc1ca8f65b9dd7034e9b53f33a125b6144acbae Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 16 Jun 2023 17:33:40 -0400 Subject: [PATCH 061/121] Use helper function in PropertyTableView tests --- CesiumGltf/test/TestPropertyTableView.cpp | 654 ++++------------------ 1 file changed, 94 insertions(+), 560 deletions(-) diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index d1984cd67..9516c72a6 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -6,6 +6,22 @@ using namespace CesiumGltf; +template +void addBufferToModel(Model& model, std::vector& values) { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(T)); + valueBuffer.byteLength = static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; +} + TEST_CASE("Test PropertyTableView on model without EXT_structural_metadata " "extension") { Model model; @@ -83,31 +99,11 @@ TEST_CASE("Test property table with nonexistent class") { TEST_CASE("Test scalar property") { Model model; - std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; - size_t valueBufferIndex = 0; - size_t valueBufferViewIndex = 0; - - // Buffers are constructed in scope to ensure that the tests don't use their - // temporary variables. - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - valueBufferIndex = model.buffers.size() - 1; - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -253,35 +249,15 @@ TEST_CASE("Test scalar property") { TEST_CASE("Test vecN property") { Model model; - std::vector values = { glm::ivec3(-12, 34, 30), glm::ivec3(11, 73, 0), glm::ivec3(-2, 6, 12), glm::ivec3(-4, 8, -13)}; - size_t valueBufferIndex = 0; - size_t valueBufferViewIndex = 0; - - // Buffers are constructed in scope to ensure that the tests don't use their - // temporary variables. - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(glm::ivec3)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - valueBufferIndex = model.buffers.size() - 1; - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -434,7 +410,6 @@ TEST_CASE("Test vecN property") { TEST_CASE("Test matN property") { Model model; - // clang-format off std::vector values = { glm::u32mat2x2( @@ -451,28 +426,9 @@ TEST_CASE("Test matN property") { 3, 23)}; // clang-format on - size_t valueBufferIndex = 0; - size_t valueBufferViewIndex = 0; - - // Buffers are constructed in scope to ensure that the tests don't use their - // temporary variables. - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(glm::u32mat2x2)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - valueBufferIndex = model.buffers.size() - 1; - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -647,24 +603,7 @@ TEST_CASE("Test boolean property") { values[static_cast(byteIndex)] = static_cast( (expectedValue << bitIndex) | values[static_cast(byteIndex)]); } - - // Buffers are constructed in scope to ensure that the tests don't use their - // temporary variables. - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size()); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - } + addBufferToModel(model, values); ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -740,37 +679,13 @@ TEST_CASE("Test string property") { offsetValue[i] + static_cast(expectedValue.size()); } - // Buffers are constructed in scope to ensure that the tests don't use their - // temporary variables. - size_t valueBufferIndex = 0; - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - valueBufferIndex = model.buffers.size() - 1; + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(valueBufferIndex); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - size_t offsetBufferIndex = 0; - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(stringOffsets.size()); - offsetBuffer.cesium.data = std::move(stringOffsets); - offsetBufferIndex = model.buffers.size() - 1; - - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(offsetBufferIndex); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, stringOffsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -886,27 +801,11 @@ TEST_CASE("Test string property") { TEST_CASE("Test fixed-length scalar array") { Model model; - std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -1043,35 +942,13 @@ TEST_CASE("Test variable-length scalar array") { offsetValue[i + 1] = offsetValue[i] + expected[i].size() * sizeof(uint16_t); } - size_t valueBufferIndex = 0; - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - valueBufferIndex = model.buffers.size() - 1; - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; - size_t offsetBufferIndex = 0; - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); - offsetBufferIndex = model.buffers.size() - 1; - - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(model.buffers.size() - 1); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -1193,7 +1070,6 @@ TEST_CASE("Test variable-length scalar array") { TEST_CASE("Test fixed-length vecN array") { Model model; - std::vector values = { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1), @@ -1203,23 +1079,8 @@ TEST_CASE("Test fixed-length vecN array") { glm::ivec3(40, 61, 3), }; - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(glm::ivec3)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -1335,7 +1196,6 @@ TEST_CASE("Test fixed-length vecN array") { TEST_CASE("Test variable-length vecN array") { Model model; - // clang-format off std::vector> expected{ { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1) }, @@ -1363,35 +1223,13 @@ TEST_CASE("Test variable-length vecN array") { offsetValue[i] + expected[i].size() * sizeof(glm::ivec3); } - size_t valueBufferIndex = 0; - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - valueBufferIndex = model.buffers.size() - 1; + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - size_t offsetBufferIndex = 0; - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); - offsetBufferIndex = model.buffers.size() - 1; - - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(model.buffers.size() - 1); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -1519,7 +1357,6 @@ TEST_CASE("Test variable-length vecN array") { TEST_CASE("Test fixed-length matN array") { Model model; - // clang-format off std::vector values = { glm::i32mat2x2( @@ -1543,23 +1380,8 @@ TEST_CASE("Test fixed-length matN array") { }; // clang-format on - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(glm::i32mat2x2)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -1676,7 +1498,6 @@ TEST_CASE("Test fixed-length matN array") { TEST_CASE("Test variable-length matN array") { Model model; - // clang-format off std::vector data0{ glm::i32mat2x2( @@ -1724,35 +1545,13 @@ TEST_CASE("Test variable-length matN array") { offsetValue[i] + expected[i].size() * sizeof(glm::i32mat2x2); } - size_t valueBufferIndex = 0; - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - valueBufferIndex = model.buffers.size() - 1; + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - size_t offsetBufferIndex = 0; - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); - offsetBufferIndex = model.buffers.size() - 1; - - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(model.buffers.size() - 1); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -1906,21 +1705,7 @@ TEST_CASE("Test fixed-length boolean array") { static_cast((expectedValue << bitIndex) | values[byteIndex]); } - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size()); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - } + addBufferToModel(model, values); ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2040,35 +1825,13 @@ TEST_CASE("Test variable-length boolean array") { offsetValue[i + 1] = offsetValue[i] + expected[i].size(); } - size_t valueBufferViewIndex = 0; - size_t valueBufferIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - valueBufferIndex = model.buffers.size() - 1; + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(valueBufferIndex); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - size_t offsetBufferIndex = 0; - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); - offsetBufferIndex = model.buffers.size() - 1; - - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(offsetBufferIndex); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2217,31 +1980,11 @@ TEST_CASE("Test fixed-length arrays of strings") { offsetValue[i] + static_cast(expectedValue.size()); } - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(model.buffers.size() - 1); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, offsets); + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2399,48 +2142,16 @@ TEST_CASE("Test variable-length arrays of strings") { static_cast(expected[i].size() * sizeof(uint32_t)); } - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; - size_t arrayOffsetBuffer = 0; - size_t arrayOffsetBufferView = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); - arrayOffsetBuffer = model.buffers.size() - 1; + addBufferToModel(model, offsets); + size_t arrayOffsetBuffer = model.buffers.size() - 1; + size_t arrayOffsetBufferView = model.bufferViews.size() - 1; - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(arrayOffsetBuffer); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - arrayOffsetBufferView = model.bufferViews.size() - 1; - } - - size_t stringOffsetBuffer = 0; - size_t stringOffsetBufferView = 0; - { - Buffer& strOffsetBuffer = model.buffers.emplace_back(); - strOffsetBuffer.byteLength = static_cast(stringOffsets.size()); - strOffsetBuffer.cesium.data = std::move(stringOffsets); - stringOffsetBuffer = model.buffers.size() - 1; - - BufferView& strOffsetBufferView = model.bufferViews.emplace_back(); - strOffsetBufferView.buffer = static_cast(stringOffsetBuffer); - strOffsetBufferView.byteOffset = 0; - strOffsetBufferView.byteLength = strOffsetBuffer.byteLength; - stringOffsetBufferView = model.bufferViews.size() - 1; - } + addBufferToModel(model, stringOffsets); + size_t stringOffsetBuffer = model.buffers.size() - 1; + size_t stringOffsetBufferView = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2713,26 +2424,8 @@ TEST_CASE("Test callback for scalar property") { Model model; std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; - size_t valueBufferViewIndex = 0; - - // Buffers are constructed in scope to ensure that the tests don't use their - // temporary variables. - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2794,33 +2487,14 @@ TEST_CASE("Test callback for scalar property") { TEST_CASE("Test callback for vecN property") { Model model; - std::vector values = { glm::ivec3(-12, 34, 30), glm::ivec3(11, 73, 0), glm::ivec3(-2, 6, 12), glm::ivec3(-4, 8, -13)}; - size_t valueBufferViewIndex = 0; - - // Buffers are constructed in scope to ensure that the tests don't use their - // temporary variables. - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(glm::ivec3)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2882,7 +2556,6 @@ TEST_CASE("Test callback for vecN property") { TEST_CASE("Test callback for matN property") { Model model; - // clang-format off std::vector values = { glm::u32mat2x2( @@ -2899,26 +2572,8 @@ TEST_CASE("Test callback for matN property") { 3, 23)}; // clang-format on - size_t valueBufferViewIndex = 0; - - // Buffers are constructed in scope to ensure that the tests don't use their - // temporary variables. - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(glm::u32mat2x2)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2999,23 +2654,7 @@ TEST_CASE("Test callback for boolean property") { (expectedValue << bitIndex) | values[static_cast(byteIndex)]); } - // Buffers are constructed in scope to ensure that the tests don't use their - // temporary variables. - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size()); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - } + addBufferToModel(model, values); ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -3099,37 +2738,11 @@ TEST_CASE("Test callback for string property") { offsetValue[i] + static_cast(expectedValue.size()); } - // Buffers are constructed in scope to ensure that the tests don't use their - // temporary variables. - size_t valueBufferIndex = 0; - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - valueBufferIndex = model.buffers.size() - 1; - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(valueBufferIndex); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - size_t offsetBufferIndex = 0; - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(stringOffsets.size()); - offsetBuffer.cesium.data = std::move(stringOffsets); - offsetBufferIndex = model.buffers.size() - 1; + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(offsetBufferIndex); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, stringOffsets); + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -3194,25 +2807,10 @@ TEST_CASE("Test callback for string property") { TEST_CASE("Test callback for scalar array") { Model model; - std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(uint32_t)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - } + addBufferToModel(model, values); ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -3280,7 +2878,6 @@ TEST_CASE("Test callback for scalar array") { TEST_CASE("Test callback for vecN array") { Model model; - std::vector values = { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1), @@ -3290,21 +2887,7 @@ TEST_CASE("Test callback for vecN array") { glm::ivec3(40, 61, 3), }; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(glm::ivec3)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - } + addBufferToModel(model, values); ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -3372,7 +2955,6 @@ TEST_CASE("Test callback for vecN array") { TEST_CASE("Test callback for matN array") { Model model; - // clang-format off std::vector values = { glm::i32mat2x2( @@ -3396,21 +2978,7 @@ TEST_CASE("Test callback for matN array") { }; // clang-format on - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(glm::i32mat2x2)); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - } + addBufferToModel(model, values); ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -3504,21 +3072,7 @@ TEST_CASE("Test callback for boolean array") { static_cast((expectedValue << bitIndex) | values[byteIndex]); } - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size()); - valueBuffer.byteLength = - static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - } + addBufferToModel(model, values); ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -3610,31 +3164,11 @@ TEST_CASE("Test callback for array of strings") { offsetValue[i] + static_cast(expectedValue.size()); } - size_t valueBufferViewIndex = 0; - { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.byteLength = static_cast(values.size()); - valueBuffer.cesium.data = std::move(values); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; - valueBufferViewIndex = model.bufferViews.size() - 1; - } - - size_t offsetBufferViewIndex = 0; - { - Buffer& offsetBuffer = model.buffers.emplace_back(); - offsetBuffer.byteLength = static_cast(offsets.size()); - offsetBuffer.cesium.data = std::move(offsets); + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; - BufferView& offsetBufferView = model.bufferViews.emplace_back(); - offsetBufferView.buffer = static_cast(model.buffers.size() - 1); - offsetBufferView.byteOffset = 0; - offsetBufferView.byteLength = offsetBuffer.byteLength; - offsetBufferViewIndex = model.bufferViews.size() - 1; - } + addBufferToModel(model, offsets); + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); From 59549893c7038b343008950e9362774e1476da31 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 16 Jun 2023 17:35:26 -0400 Subject: [PATCH 062/121] Formatting --- CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 425ad1f58..eea7425e4 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -89,9 +89,7 @@ enum class PropertyTexturePropertyComponentType { * @tparam T The component type, must correspond to a valid * {@link PropertyTexturePropertyComponentType}. */ -template struct PropertyTexturePropertyValue { - T components[4]; -}; +template struct PropertyTexturePropertyValue { T components[4]; }; /** * @brief A view of the data specified by a {@link PropertyTextureProperty}. From 1694a9ad3e731f4e3d047c85996206e57e0689de Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 20 Jun 2023 10:26:32 -0400 Subject: [PATCH 063/121] Fix typo --- CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 05b1adcd5..e1987a5a2 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -155,12 +155,12 @@ enum class PropertyTablePropertyViewStatus { }; /** - * @brief A view on the data of the {@link PropertyTableProperty that is created + * @brief A view on the data of the {@link PropertyTableProperty} that is created * by a {@link PropertyTableView}. * * It provides utility to retrieve the actual data stored in the * {@link PropertyTableProperty::values} like an array of elements. Data of each - * instance can be accessed through the {@link get(int64_t instance)} method. + * instance can be accessed through the {@link PropertyTablePropertyView::get} method. * * @param ElementType must be one of the following: a scalar (uint8_t, int8_t, * uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double), a From 76d5d260513388678f98a6bea2a879d982ef449d Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 23 Jun 2023 12:06:25 -0400 Subject: [PATCH 064/121] Rework PropertyTexturePropertyView, begin reworking PropertyTextureView --- .../include/CesiumGltf/FeatureIdTextureView.h | 3 +- .../include/CesiumGltf/PropertyArrayView.h | 60 +- .../CesiumGltf/PropertyTablePropertyView.h | 28 +- .../include/CesiumGltf/PropertyTableView.h | 108 +- .../CesiumGltf/PropertyTexturePropertyView.h | 466 ++++-- .../include/CesiumGltf/PropertyTextureView.h | 289 +++- CesiumGltf/include/CesiumGltf/PropertyType.h | 7 + CesiumGltf/src/PropertyTableView.cpp | 48 +- .../src/PropertyTexturePropertyView.cpp | 145 -- CesiumGltf/src/PropertyTextureView.cpp | 95 +- CesiumGltf/src/PropertyType.cpp | 39 + .../test/TestPropertyTablePropertyView.cpp | 37 +- CesiumGltf/test/TestPropertyTableView.cpp | 2 +- .../test/TestPropertyTexturePropertyView.cpp | 1428 ++++++++++++----- CesiumGltf/test/TestPropertyTextureView.cpp | 461 +++++- CesiumGltf/test/TestPropertyType.cpp | 501 +++--- 16 files changed, 2594 insertions(+), 1123 deletions(-) delete mode 100644 CesiumGltf/src/PropertyTexturePropertyView.cpp diff --git a/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h b/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h index 8b6e28eef..9834c0f3c 100644 --- a/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h +++ b/CesiumGltf/include/CesiumGltf/FeatureIdTextureView.h @@ -49,8 +49,7 @@ enum class FeatureIdTextureViewStatus { /** * @brief The image for this feature ID texture has channels that take up more - * than a byte. The feature ID texture's channels should represent the bytes - * of the actual feature ID. + * than a byte. Only single-byte channels are supported. */ ErrorInvalidImageBytesPerChannel, diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index ef89f5766..b921c13f3 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -9,35 +9,76 @@ #include #include +#include +#include namespace CesiumGltf { /** - * @brief A view on an array element of a {@link PropertyTableProperty}. + * @brief A view on an array element of a {@link PropertyTableProperty} + * or {@link PropertyTextureProperty}. * * Provides utility to retrieve the data stored in the array of * elements via the array index operator. */ template class PropertyArrayView { public: + /** + * @brief Constructs an empty array view. + */ PropertyArrayView() : _values{} {} + /** + * @brief Constructs an array view from a buffer. + * + * @param buffer The buffer containing the values. + */ PropertyArrayView(const gsl::span& buffer) noexcept : _values{CesiumUtility::reintepretCastSpan(buffer)} {} + /** + * @brief Constructs an array view from a vector of values. This is mainly + * used by PropertyTextureProperty -- since the values are swizzled from the + * texture, the values cannot be viewed in place, and must passed in through a + * correctly ordered vector. + * + * @param values The vector containing the values. + */ + PropertyArrayView(const std::vector&& values) + : _values{std::move(values)} {} + const ElementType& operator[](int64_t index) const noexcept { - return _values[index]; + return std::visit( + [index](auto const& values) -> auto const& { return values[index]; }, + _values); } - int64_t size() const noexcept { return static_cast(_values.size()); } + int64_t size() const noexcept { + return std::visit( + [](auto const& values) { return static_cast(values.size()); }, + _values); + } private: - gsl::span _values; + using ArrayType = + std::variant, std::vector>; + ArrayType _values; }; template <> class PropertyArrayView { public: + /** + * @brief Constructs an empty array view. + */ PropertyArrayView() : _values{}, _bitOffset{0}, _size{0} {} + /** + * @brief Constructs an array view from a buffer. + * + * @param buffer The buffer containing the values. + * @param bitOffset The offset into the buffer where the values actually + * begin. + * @param size The number of values in the array. + */ PropertyArrayView( const gsl::span& buffer, int64_t bitOffset, @@ -62,9 +103,20 @@ template <> class PropertyArrayView { template <> class PropertyArrayView { public: + /** + * @brief Constructs an empty array view. + */ PropertyArrayView() : _values{}, _stringOffsets{}, _stringOffsetType{}, _size{0} {} + /** + * @brief Constructs an array view from buffers and their information. + * + * @param values The buffer containing the values. + * @param stringOffsets The buffer containing the string offsets. + * @param stringOffsetType The component type of the string offsets. + * @param size The number of values in the array. + */ PropertyArrayView( const gsl::span& values, const gsl::span& stringOffsets, diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 912dba62f..977ccc995 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -171,7 +171,7 @@ enum class PropertyTablePropertyViewStatus { template class PropertyTablePropertyView { public: /** - * @brief Constructs a new instance with a non-existent property. + * @brief Constructs an invalid instance for a non-existent property. */ PropertyTablePropertyView() : _status{PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist}, @@ -181,18 +181,29 @@ template class PropertyTablePropertyView { _normalized{} {} /** - * @brief Construct a new instance pointing to non-array data specified by - * {@link PropertyTableProperty}. + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The {@link PropertyTablePropertyViewStatus} indicating the error with the property. + */ + PropertyTablePropertyView(PropertyTablePropertyViewStatus status) + : _status{status}, _values{}, _arrayCount{}, _size{}, _normalized{} { + assert( + _status != PropertyTablePropertyViewStatus::Valid && + "An empty property view should not be constructed with a valid status"); + } + + /** + * @brief Construct a valid instance pointing to non-array data specified by + * a {@link PropertyTableProperty}. * @param values The raw buffer specified by {@link PropertyTableProperty::values} * @param size The number of elements in the property table specified by {@link PropertyTable::count} * @param normalized Whether this property has a normalized integer type. */ PropertyTablePropertyView( - PropertyTablePropertyViewStatus status, gsl::span values, int64_t size, bool normalized) noexcept - : _status{status}, + : _status{PropertyTablePropertyViewStatus::Valid}, _values{values}, _arrayOffsets{}, _arrayOffsetType{PropertyComponentType::None}, @@ -205,8 +216,8 @@ template class PropertyTablePropertyView { _normalized{normalized} {} /** - * @brief Construct a new instance pointing to the data specified by - * {@link PropertyTableProperty}. + * @brief Construct a valid instance pointing to the data specified by + * a {@link PropertyTableProperty}. * @param values The raw buffer specified by {@link PropertyTableProperty::values} * @param arrayOffsets The raw buffer specified by {@link PropertyTableProperty::arrayOffsets} * @param stringOffsets The raw buffer specified by {@link PropertyTableProperty::stringOffsets} @@ -217,7 +228,6 @@ template class PropertyTablePropertyView { * @param normalized Whether this property has a normalized integer type. */ PropertyTablePropertyView( - PropertyTablePropertyViewStatus status, gsl::span values, gsl::span arrayOffsets, gsl::span stringOffsets, @@ -226,7 +236,7 @@ template class PropertyTablePropertyView { int64_t arrayCount, int64_t size, bool normalized) noexcept - : _status{status}, + : _status{PropertyTablePropertyViewStatus::Valid}, _values{values}, _arrayOffsets{arrayOffsets}, _arrayOffsetType{arrayOffsetType}, diff --git a/CesiumGltf/include/CesiumGltf/PropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h index 4c255439e..6af76ce7f 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -54,7 +54,7 @@ class PropertyTableView { public: /** * @brief Creates an instance of PropertyTableView. - * @param model The Gltf Model that contains property table data. + * @param model The glTF Model that contains the property table data. * @param propertyTable The {@link PropertyTable} * from which the view will retrieve data. */ @@ -111,15 +111,14 @@ class PropertyTableView { PropertyTablePropertyView getPropertyView(const std::string& propertyName) const { if (this->size() <= 0) { - return createInvalidPropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); } const ClassProperty* pClassProperty = getClassProperty(propertyName); if (!pClassProperty) { - return createInvalidPropertyView( - StructuralMetadata::PropertyTablePropertyViewStatus:: - ErrorNonexistentProperty); + return PropertyTablePropertyView( + PropertyTablePropertyViewStatus::ErrorNonexistentProperty); } return getPropertyViewImpl(propertyName, *pClassProperty); @@ -150,7 +149,7 @@ class PropertyTableView { if (this->size() <= 0) { callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable)); return; } @@ -159,7 +158,7 @@ class PropertyTableView { if (!pClassProperty) { callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorNonexistentProperty)); return; } @@ -209,7 +208,7 @@ class PropertyTableView { } else { callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorTypeMismatch)); } } @@ -241,22 +240,6 @@ class PropertyTableView { } private: - glm::length_t getDimensionsFromType(PropertyType type) const { - switch (type) { - case PropertyType::Vec2: - case PropertyType::Mat2: - return 2; - case PropertyType::Vec3: - case PropertyType::Mat3: - return 3; - case PropertyType::Vec4: - case PropertyType::Mat4: - return 4; - default: - return 0; - } - } - template void getScalarArrayPropertyViewImpl( const std::string& propertyName, @@ -337,7 +320,7 @@ class PropertyTableView { default: callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } @@ -423,7 +406,7 @@ class PropertyTableView { default: callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } @@ -436,7 +419,7 @@ class PropertyTableView { PropertyType type, PropertyComponentType componentType, Callback&& callback) const { - glm::length_t N = getDimensionsFromType(type); + glm::length_t N = getDimensionsFromPropertyType(type); switch (N) { case 2: getVecNArrayPropertyViewImpl( @@ -462,7 +445,7 @@ class PropertyTableView { default: callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorTypeMismatch)); break; } @@ -548,7 +531,7 @@ class PropertyTableView { default: callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } @@ -561,7 +544,7 @@ class PropertyTableView { PropertyType type, PropertyComponentType componentType, Callback&& callback) const { - const glm::length_t N = getDimensionsFromType(type); + const glm::length_t N = getDimensionsFromPropertyType(type); switch (N) { case 2: getMatNArrayPropertyViewImpl( @@ -587,7 +570,7 @@ class PropertyTableView { default: callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorTypeMismatch)); break; } @@ -636,7 +619,7 @@ class PropertyTableView { } else { callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorTypeMismatch)); } } @@ -720,7 +703,7 @@ class PropertyTableView { default: callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } @@ -733,7 +716,7 @@ class PropertyTableView { PropertyType type, PropertyComponentType componentType, Callback&& callback) const { - const glm::length_t N = getDimensionsFromType(type); + const glm::length_t N = getDimensionsFromPropertyType(type); switch (N) { case 2: getVecNPropertyViewImpl( @@ -759,7 +742,7 @@ class PropertyTableView { default: callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorTypeMismatch)); break; } @@ -845,7 +828,7 @@ class PropertyTableView { default: callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } @@ -858,7 +841,7 @@ class PropertyTableView { PropertyType type, PropertyComponentType componentType, Callback&& callback) const { - glm::length_t N = getDimensionsFromType(type); + glm::length_t N = getDimensionsFromPropertyType(type); switch (N) { case 2: getMatNPropertyViewImpl( @@ -884,7 +867,7 @@ class PropertyTableView { default: callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorTypeMismatch)); break; } @@ -950,7 +933,7 @@ class PropertyTableView { default: callback( propertyName, - createInvalidPropertyView( + PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch)); break; } @@ -963,7 +946,7 @@ class PropertyTableView { auto propertyTablePropertyIter = _pPropertyTable->properties.find(propertyName); if (propertyTablePropertyIter == _pPropertyTable->properties.end()) { - return createInvalidPropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorNonexistentProperty); } @@ -998,31 +981,31 @@ class PropertyTableView { const ClassProperty& classProperty, const PropertyTableProperty& propertyTableProperty) const { if (classProperty.array) { - return createInvalidPropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { - return createInvalidPropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorTypeMismatch); } const PropertyComponentType componentType = convertStringToPropertyComponentType( classProperty.componentType.value_or("")); if (TypeToPropertyType::component != componentType) { - return createInvalidPropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } gsl::span values; const auto status = getBufferSafe(propertyTableProperty.values, values); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView(status); + return PropertyTablePropertyView(status); } if (values.size() % sizeof(T) != 0) { - return createInvalidPropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize); } @@ -1036,13 +1019,12 @@ class PropertyTableView { } if (values.size() < maxRequiredBytes) { - return createInvalidPropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } return PropertyTablePropertyView( - PropertyTablePropertyViewStatus::Valid, values, _pPropertyTable->count, classProperty.normalized); @@ -1058,13 +1040,13 @@ class PropertyTableView { const ClassProperty& classProperty, const PropertyTableProperty& propertyTableProperty) const { if (!classProperty.array) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorTypeMismatch); } @@ -1072,31 +1054,31 @@ class PropertyTableView { convertStringToPropertyComponentType( classProperty.componentType.value_or("")); if (TypeToPropertyType::component != componentType) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } gsl::span values; auto status = getBufferSafe(propertyTableProperty.values, values); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>(status); + return PropertyTablePropertyView>(status); } if (values.size() % sizeof(T) != 0) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize); } const int64_t fixedLengthArrayCount = classProperty.count.value_or(0); if (fixedLengthArrayCount > 0 && propertyTableProperty.arrayOffsets >= 0) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus:: ErrorArrayCountAndOffsetBufferCoexist); } if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus:: ErrorArrayCountAndOffsetBufferDontExist); } @@ -1115,13 +1097,12 @@ class PropertyTableView { } if (values.size() < maxRequiredBytes) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } return PropertyTablePropertyView>( - PropertyTablePropertyViewStatus::Valid, values, gsl::span(), gsl::span(), @@ -1137,7 +1118,7 @@ class PropertyTableView { convertArrayOffsetTypeStringToPropertyComponentType( propertyTableProperty.arrayOffsetType); if (arrayOffsetType == PropertyComponentType::None) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } @@ -1151,11 +1132,10 @@ class PropertyTableView { checkBitsSize, arrayOffsets); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>(status); + return PropertyTablePropertyView>(status); } return PropertyTablePropertyView>( - PropertyTablePropertyViewStatus::Valid, values, arrayOffsets, gsl::span(), @@ -1190,16 +1170,6 @@ class PropertyTableView { size_t propertyTableCount, gsl::span& stringOffsetsBuffer) const noexcept; - template - static PropertyTablePropertyView createInvalidPropertyView( - PropertyTablePropertyViewStatus invalidStatus) noexcept { - return PropertyTablePropertyView( - invalidStatus, - gsl::span(), - 0, - false); - } - const Model* _pModel; const PropertyTable* _pPropertyTable; const Class* _pClass; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index f388d2c6e..c843781d2 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -1,17 +1,12 @@ #pragma once -#include "CesiumGltf/ClassProperty.h" -#include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" -#include "CesiumGltf/Image.h" #include "CesiumGltf/ImageCesium.h" -#include "CesiumGltf/Model.h" -#include "CesiumGltf/PropertyTexture.h" +#include "CesiumGltf/PropertyTextureProperty.h" +#include "CesiumGltf/PropertyTypeTraits.h" #include "CesiumGltf/Sampler.h" -#include "CesiumGltf/Texture.h" #include #include -#include namespace CesiumGltf { /** @@ -24,74 +19,93 @@ namespace CesiumGltf { */ enum class PropertyTexturePropertyViewStatus { /** - * @brief This view is valid and ready to use. + * @brief This property view is valid and ready to use. */ Valid, /** - * @brief This view has not been initialized. + * @brief This property view was initialized from an invalid + * {@link PropertyTexture}. */ - ErrorUninitialized, + ErrorInvalidPropertyTexture, /** - * @brief This property texture property is associated with a class property - * with an invalid or unsupported type. + * @brief This property view is trying to view a property that does not exist + * in the {@link PropertyTexture}. */ - ErrorInvalidClassProperty, + ErrorNonexistentProperty, /** - * @brief This property texture property has a texture index that does not - * exist in the glTF. + * @brief This property view is associated with a {@link ClassProperty} of an + * unsupported type. + */ + ErrorUnsupportedProperty, + + /** + * @brief This property view's type does not match what is + * specified in {@link ClassProperty::type}. + */ + ErrorTypeMismatch, + + /** + * @brief This property view's component type does not match what + * is specified in {@link ClassProperty::componentType}. + */ + ErrorComponentTypeMismatch, + + /** + * @brief This property view differs from what is specified in + * {@link ClassProperty::array}. + */ + ErrorArrayTypeMismatch, + + /** + * @brief This property view does not have a valid texture index. */ ErrorInvalidTexture, /** - * @brief This property texture property has a texture sampler index that does - * not exist in the glTF. + * @brief This property view does not have a valid sampler index. */ - ErrorInvalidTextureSampler, + ErrorInvalidSampler, /** - * @brief This property texture property has an image index that does not - * exist in the glTF. + * @brief This property view does not have a valid image index. */ ErrorInvalidImage, /** - * @brief This property texture property points to an empty image. + * @brief This property is viewing an empty image. */ ErrorEmptyImage, + /** + * @brief This property uses an image with multi-byte channels. Only + * single-byte channels are supported. + */ + ErrorInvalidBytesPerChannel, + /** * @brief The channels of this property texture property are invalid. * Channels must be in the range 0-3, with a minimum of one channel. Although * more than four channels can be defined for specialized texture * formats, this view only supports a maximum of four channels. */ - ErrorInvalidChannels -}; + ErrorInvalidChannels, -/** - * @brief The supported component types that can exist in property id textures. - */ -enum class PropertyTexturePropertyComponentType { - Uint8 - // TODO: add more types. Currently this is the only one outputted by stb, - // so change stb call to output more of the original types. -}; + /** + * @brief This property texture property is trying to sample channels that + * don't exist in the image. + */ + ErrorTooManyChannels, -/** - * @brief The property texture property value for a pixel. This will contain - * four channels of the specified type. - * - * Only the first n components will be valid, where n is the number of channels - * in this property texture property. - * - * @tparam T The component type, must correspond to a valid - * {@link PropertyTexturePropertyComponentType}. - */ -template struct PropertyTexturePropertyValue { - T components[4]; + /** + * @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. + */ + ErrorChannelsAndTypeMismatch, }; /** @@ -100,144 +114,142 @@ template struct PropertyTexturePropertyValue { * Provides utilities to sample the property texture property using texture * coordinates. */ -class PropertyTexturePropertyView { +template class PropertyTexturePropertyView { public: /** - * @brief Construct an uninitialized, invalid view. + * @brief Constructs an invalid instance for a non-existent property. */ - PropertyTexturePropertyView() noexcept; + PropertyTexturePropertyView() noexcept + : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), + _pSampler(nullptr), + _pImage(nullptr), + _texCoordSetIndex(0), + _channels(), + _swizzle(""), + _normalized(false) {} /** - * @brief Construct a view of the data specified by the given property texture - * property. Assumes the model has already been validated by the - * {@link PropertyTextureView} that invoked this constructor. + * @brief Constructs an invalid instance for an erroneous property. * - * @param model The glTF in which to look for the data specified by the - * property texture property. - * @param classProperty The property description. - * @param propertyTextureProperty The property texture property + * @param status The {@link PropertyTexturePropertyViewStatus} indicating the error with the property. + */ + PropertyTexturePropertyView(PropertyTexturePropertyViewStatus status) noexcept + : _status(status), + _pSampler(nullptr), + _pImage(nullptr), + _texCoordSetIndex(0), + _channels(), + _swizzle(""), + _normalized(false) {} + + /** + * @brief Construct a valid view of the data specified by a {@link PropertyTextureProperty}. + * + * @param pSampler A pointer to the sampler used by the property. + * @param pImage A pointer to the image used by the property. + * @param texCoordSetIndex The value of {@link PropertyTextureProperty::texcoord}. + * @param channels The value of {@link PropertyTextureProperty::channels}. + * @param normalized Whether this property has a normalized integer type. */ PropertyTexturePropertyView( - const Model& model, - const ClassProperty& classProperty, - const PropertyTextureProperty& propertyTextureProperty) noexcept; + const Sampler& sampler, + const ImageCesium& image, + int64_t texCoordSetIndex, + const std::vector& channels, + bool normalized) noexcept + : _status(PropertyTexturePropertyViewStatus::Valid), + _pSampler(&sampler), + _pImage(&image), + _texCoordSetIndex(texCoordSetIndex), + _channels(channels), + _swizzle(""), + _normalized(normalized) { + 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: + assert(false && "A valid channels vector must be passed to the view."); + } + } + } /** - * @brief Gets the unswizzled property value for the given texture - * coordinates. + * @brief Gets the property value for the given texture coordinates. The + * sampler's wrapping mode will be used when sampling the texture. * - * Will return 0s when the status is not Valid or when the templated - * component type doesn't match the image's channel byte-size. + * @param u The u-component of the texture coordinates. + * @param v The v-component of the texture coordinates. * - * @tparam T The component type to use when interpreting the channels of the - * property's pixel value. - * @param u The u-component of the texture coordinates. Must be within - * [0.0, 1.0]. - * @param v The v-component of the texture coordinates. Must be within - * [0.0, 1.0]. - * @return The property at the nearest pixel to the texture coordinates. + * @return The value at the nearest pixel to the texture coordinates. */ - template - PropertyTexturePropertyValue get(double u, double v) const noexcept { - PropertyTexturePropertyValue property; - property.components[0] = 0; - property.components[1] = 0; - property.components[2] = 0; - property.components[3] = 0; - - if (this->_status != PropertyTexturePropertyViewStatus::Valid || - sizeof(T) != this->_pImage->bytesPerChannel) { - return property; - } - double fraction = 0, integral = 0; - int64_t integer = 0; - switch (this->_pSampler->wrapS) { - case Sampler::WrapS::REPEAT: - fraction = std::modf(u, &integral); - // Wrap negative values. - u = fraction < 0 ? 1.0 - fraction : fraction; - break; - case Sampler::WrapS::MIRRORED_REPEAT: - fraction = std::abs(std::modf(u, &integral)); - integer = static_cast(std::abs(integral)); - // If the integer part is odd, the direction is reversed. - u = integer % 2 == 1 ? 1.0 - fraction : fraction; - break; - case Sampler::WrapS::CLAMP_TO_EDGE: - default: - u = std::clamp(u, 0.0, 1.0); - break; - } + ElementType get(double u, double v) const noexcept { + assert( + _status == PropertyTexturePropertyViewStatus::Valid && + "Check the status() first to make sure view is valid"); - switch (this->_pSampler->wrapT) { - case Sampler::WrapT::REPEAT: - fraction = std::modf(v, &integral); - // Wrap negative values. - v = fraction < 0 ? 1.0 - fraction : fraction; - break; - case Sampler::WrapT::MIRRORED_REPEAT: - fraction = std::abs(std::modf(v, &integral)); - integer = static_cast(std::abs(integral)); - // If the integer part is odd, the direction is reversed. - v = integer % 2 == 1 ? 1.0 - fraction : fraction; - break; - case Sampler::WrapT::CLAMP_TO_EDGE: - default: - v = std::clamp(u, 0.0, 1.0); - break; - } + double wrappedU = applySamplerWrapS(u, this->_pSampler->wrapS); + double wrappedV = applySamplerWrapT(v, this->_pSampler->wrapT); - // Clamp here to ensure no out-of-bounds data access. + // TODO: account for sampler's filter (can be nearest or linear) + + // For nearest filtering, std::floor is used instead of std::round. + // This is because filtering is supposed to consider the pixel centers. But + // memory access here acts as sampling the beginning of the pixel. Example: + // 0.4 * 2 = 0.8. In a 2x1 pixel image, that should be closer to the left + // pixel's center. But it will round to 1.0 which corresponds to the right + // pixel. So the right pixel has a bigger range than the left one, which is + // incorrect. + double xCoord = std::floor(wrappedU * this->_pImage->width); + double yCoord = std::floor(wrappedV * this->_pImage->height); + + // Clamp to ensure no out-of-bounds data access int64_t x = std::clamp( - std::llround(u * this->_pImage->width), + static_cast(xCoord), 0LL, static_cast(this->_pImage->width) - 1); int64_t y = std::clamp( - std::llround(v * this->_pImage->height), + static_cast(yCoord), 0LL, static_cast(this->_pImage->height) - 1); - int64_t pixelOffset = this->_pImage->bytesPerChannel * - this->_pImage->channels * - (y * this->_pImage->width + x); - const T* pRedChannel = reinterpret_cast( - this->_pImage->pixelData.data() + pixelOffset); + int64_t pixelIndex = this->_pImage->bytesPerChannel * + this->_pImage->channels * + (y * this->_pImage->width + x); + + // TODO: Currently stb only outputs uint8 pixel types. If that + // changes this should account for additional pixel byte sizes. + const uint8_t* pValue = reinterpret_cast( + this->_pImage->pixelData.data() + pixelIndex); - // TODO: account for the sampler filter. - // TODO: it is possible for channels to represent multi-byte values for a - // property. But we only support uint8 property types at the moment. + std::vector channelValues(this->_channels.size()); for (size_t i = 0; i < this->_channels.size(); i++) { - const size_t channel = static_cast(this->_channels[i]); - property.components[channel] = *(pRedChannel + channel); + channelValues[i] = *(pValue + this->_channels[i]); } - return property; + return assembleValueFromChannels(channelValues); } /** * @brief Get the status of this view. * - * If invalid, it will not be safe to sample from this view. + * If invalid, this view cannot be sampled. */ PropertyTexturePropertyViewStatus status() const noexcept { return this->_status; } - /** - * @brief Get the component type for this property. - */ - PropertyTexturePropertyComponentType - getPropertyComponentType() const noexcept { - return this->_componentType; - } - - /** - * @brief Get the component count of this property. This is equivalent to how - * many channels a pixel value for this property will use. - */ - int64_t getComponentCount() const noexcept { return this->_componentCount; } - /** * @brief Get the texture coordinate set index for this property. */ @@ -271,16 +283,176 @@ class PropertyTexturePropertyView { const std::string& getSwizzle() const noexcept { return this->_swizzle; } private: + ElementType + assembleValueFromChannels(const std::vector& bytes) const noexcept { + assert(bytes.size() > 0 && "Channel input must have at least one value."); + + if constexpr (IsMetadataScalar::value) { + return assembleScalarValue(bytes); + } + + if constexpr (IsMetadataVecN::value) { + return assembleVecNValue(bytes); + } + + if constexpr (IsMetadataArray::value) { + return assembleArrayValue::type>( + bytes); + } + } + + ElementType + assembleScalarValue(const std::vector& bytes) const noexcept { + if constexpr (std::is_same_v) { + 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(bytes[i]) << i * 8; + } + + // Reinterpret the bits as a float. + return *reinterpret_cast(&resultAsUint); + } + + if constexpr ( + IsMetadataInteger::value && + std::is_signed_v) { + using UintType = std::make_unsigned_t; + UintType resultAsUint = 0; + for (size_t i = 0; i < bytes.size(); i++) { + resultAsUint |= static_cast(bytes[i]) << i * 8; + } + // Reinterpret the bits as a signed integer. + return *reinterpret_cast(&resultAsUint); + } else if constexpr (IsMetadataInteger::value) { + ElementType result = 0; + for (size_t i = 0; i < bytes.size(); i++) { + result |= static_cast(bytes[i]) << i * 8; + } + return result; + } + } + + ElementType + assembleVecNValue(const std::vector& bytes) const noexcept { + ElementType result = ElementType(); + + PropertyComponentType componentType = + TypeToPropertyType::component; + size_t componentSize = getSizeOfComponentType(componentType); + assert( + componentSize <= 2 && + "Components cannot be larger than two bytes in size."); + + if (componentSize == 2) { + assert( + TypeToPropertyType::value == PropertyType::Vec2 && + "Only vec2s can contain two-byte integer components."); + uint16_t x = static_cast(bytes[0]) | + (static_cast(bytes[1]) << 8); + uint16_t y = static_cast(bytes[2]) | + (static_cast(bytes[3]) << 8); + + if (componentType == PropertyComponentType::Int16) { + result[0] = *reinterpret_cast(&x); + result[1] = *reinterpret_cast(&y); + } else { + result[0] = x; + result[1] = y; + } + + return result; + } + + if (componentType == PropertyComponentType::Int8) { + for (size_t i = 0; i < bytes.size(); i++) { + result[i] = *reinterpret_cast(&bytes[i]); + } + } else { + for (size_t i = 0; i < bytes.size(); i++) { + result[i] = bytes[i]; + } + } + + return result; + } + + template + PropertyArrayView + assembleArrayValue(const std::vector& bytes) const noexcept { + if (sizeof(T) == 2) { + std::vector result(bytes.size() / sizeof(T)); + for (int i = 0, b = 0; i < result.size(); i++, b += 2) { + if constexpr (std::is_signed_v) { + using UintType = std::make_unsigned_t; + UintType resultAsUint = static_cast(bytes[b]) | + (static_cast(bytes[b + 1]) << 8); + result[i] = *reinterpret_cast(&resultAsUint); + } else { + result[i] = + static_cast(bytes[b]) | (static_cast(bytes[b + 1]) << 8); + } + } + + return PropertyArrayView(std::move(result)); + } + + std::vector result(bytes.size()); + for (size_t i = 0; i < bytes.size(); i++) { + if constexpr (std::is_signed_v) { + result[i] = *reinterpret_cast(&bytes[i]); + } else { + result[i] = bytes[i]; + } + } + return PropertyArrayView(std::move(result)); + } + + double applySamplerWrapS(const double u, const int32_t wrapS) const noexcept { + if (wrapS == Sampler::WrapS::REPEAT) { + double integral = 0; + double fraction = std::modf(u, &integral); + return fraction < 0 ? 1.0 - fraction : fraction; + } + + if (wrapS == Sampler::WrapS::MIRRORED_REPEAT) { + double integral = 0; + double fraction = std::abs(std::modf(u, &integral)); + int64_t integer = static_cast(std::abs(integral)); + // If the integer part is odd, the direction is reversed. + return integer % 2 == 1 ? 1.0 - fraction : fraction; + } + + return glm::clamp(u, 0.0, 1.0); + } + + double applySamplerWrapT(const double v, const int32_t wrapT) const noexcept { + if (wrapT == Sampler::WrapT::REPEAT) { + double integral = 0; + double fraction = std::modf(v, &integral); + return fraction < 0 ? 1.0 - fraction : fraction; + } + + if (wrapT == Sampler::WrapT::MIRRORED_REPEAT) { + double integral = 0; + double fraction = std::abs(std::modf(v, &integral)); + int64_t integer = static_cast(std::abs(integral)); + // If the integer part is odd, the direction is reversed. + return integer % 2 == 1 ? 1.0 - fraction : fraction; + } + + return glm::clamp(v, 0.0, 1.0); + } + PropertyTexturePropertyViewStatus _status; - const ClassProperty* _pClassProperty; const Sampler* _pSampler; const ImageCesium* _pImage; int64_t _texCoordSetIndex; std::vector _channels; std::string _swizzle; - PropertyTexturePropertyComponentType _componentType; - int64_t _componentCount; bool _normalized; }; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 22eeeb1c4..1ac63f84d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -6,8 +6,6 @@ #include "CesiumGltf/PropertyTexture.h" #include "CesiumGltf/PropertyTexturePropertyView.h" #include "CesiumGltf/Texture.h" -#include "Image.h" -#include "ImageCesium.h" #include "Model.h" namespace CesiumGltf { @@ -24,11 +22,6 @@ enum class PropertyTextureViewStatus { */ Valid, - /** - * @brief This property texture view is not initialized. - */ - ErrorUninitialized, - /** * @brief The glTF is missing the EXT_structural_metadata extension. */ @@ -43,32 +36,24 @@ enum class PropertyTextureViewStatus { * @brief The property texture's specified class could not be found in the * extension. */ - ErrorClassNotFound, - - /** - * @brief A property name specified in the property texture could not be found - * in the class. - */ - ErrorClassPropertyNotFound + ErrorClassNotFound }; /** - * @brief A view on the {@link PropertyTexture}. + * @brief A view on a {@link PropertyTexture}. * - * Provides access to views on the property texture properties. + * This should be used to get a {@link PropertyTexturePropertyView} of a property in the property texture. + * It will validate the EXT_structural_metadata format and ensure {@link PropertyTexturePropertyView} + * does not access out of bounds. */ class PropertyTextureView { public: /** - * @brief Construct an uninitialized, invalid property texture view. - */ - PropertyTextureView() noexcept; - - /** - * @brief Construct a view for the property texture. + * @brief Construct a PropertyTextureView. * - * @param model The glTF in which to look for the property texture's data. - * @param propertyTexture The property texture to create a view for. + * @param model The glTF that contains the property texture's data. + * @param propertyTexture The {@link PropertyTexture} + * from which the view will retrieve data. */ PropertyTextureView( const Model& model, @@ -93,18 +78,264 @@ class PropertyTextureView { const ClassProperty* getClassProperty(const std::string& propertyName) const; /** - * @brief Get the views for this property texture's properties. + * @brief Gets a {@link PropertyTexturePropertyView} that views the data of a + * property stored in the {@link PropertyTexture}. + * + * 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. + * + * @param propertyName The name of the property to retrieve data from + * @return A {@link PropertyTablePropertyView} of the property. If no valid property is + * found, the property view will be invalid. */ - const std::unordered_map& - getProperties() const noexcept { - return this->_propertyViews; + template + PropertyTexturePropertyView + getPropertyView(const std::string& propertyName) const { + if (this->_status != PropertyTextureViewStatus::Valid) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorInvalidPropertyTexture); + } + + const ClassProperty* pClassProperty = getClassProperty(propertyName); + if (!pClassProperty) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorNonexistentProperty); + } + + return getPropertyViewImpl(propertyName, *pClassProperty); } private: + template + PropertyTexturePropertyView getPropertyViewImpl( + const std::string& propertyName, + const ClassProperty& classProperty) const { + auto propertyTexturePropertyIter = + _pPropertyTexture->properties.find(propertyName); + if (propertyTexturePropertyIter == _pPropertyTexture->properties.end()) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorNonexistentProperty); + } + + const PropertyTextureProperty& propertyTextureProperty = + propertyTexturePropertyIter->second; + + if constexpr (IsMetadataScalar::value) { + return createScalarPropertyView( + classProperty, + propertyTextureProperty); + } else if constexpr (IsMetadataVecN::value) { + } else if constexpr (IsMetadataArray::value) { + return createArrayPropertyView::type>( + classProperty, + propertyTextureProperty); + } else { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } + } + + template + PropertyTexturePropertyView createScalarPropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& propertyTextureProperty) const { + if (classProperty.array) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } + + const PropertyType type = convertStringToPropertyType(classProperty.type); + if (TypeToPropertyType::value != type) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorTypeMismatch); + } + + const PropertyComponentType componentType = + convertStringToPropertyComponentType( + classProperty.componentType.value_or("")); + if (TypeToPropertyType::component != componentType) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + } + + // Eight-byte scalar types are unsupported. + if constexpr ( + std::is_same_v || std::is_same_v || + std::is_same_v) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } + + return createPropertyViewImpl( + classProperty, + propertyTextureProperty, + sizeof(T)); + } + + template + PropertyTexturePropertyView createVecNPropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& propertyTextureProperty) const { + if (classProperty.array) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } + + const PropertyType type = convertStringToPropertyType(classProperty.type); + if (TypeToPropertyType::value != type) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorTypeMismatch); + } + + const PropertyComponentType componentType = + convertStringToPropertyComponentType( + classProperty.componentType.value_or("")); + if (TypeToPropertyType::component != componentType) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + } + + // Only uint8 and uint16s are supported. + if (componentType != PropertyComponentType::Uint8 && + componentType != PropertyComponentType::Uint16) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } + + // Only up to four bytes of image data are supported. + if (sizeof(T) > 4) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } + + return createPropertyViewImpl( + classProperty, + propertyTextureProperty, + sizeof(T)); + } + + template + PropertyTexturePropertyView> createArrayPropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& propertyTextureProperty) const { + if (!classProperty.array) { + return PropertyTexturePropertyView>( + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } + + const PropertyType type = convertStringToPropertyType(classProperty.type); + if (TypeToPropertyType::value != type) { + return PropertyTexturePropertyView>( + PropertyTexturePropertyViewStatus::ErrorTypeMismatch); + } + + // Only scalar arrays are supported. + if (type != PropertyType::Scalar) { + return PropertyTexturePropertyView>( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } + + // Only up to four elements are supported. + int64_t count = classProperty.count.value_or(0); + if (count <= 0 || count > 4) { + return PropertyTexturePropertyView>( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } + + const PropertyComponentType componentType = + convertStringToPropertyComponentType( + classProperty.componentType.value_or("")); + if (TypeToPropertyType::component != componentType) { + return PropertyTexturePropertyView>( + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + } + + // Only uint8 and uint16s are supported. + if (componentType != PropertyComponentType::Uint8 && + componentType != PropertyComponentType::Uint16) { + return PropertyTexturePropertyView>( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } + + if (componentType == PropertyComponentType::Uint16 && count > 2) { + return PropertyTexturePropertyView>( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } + + return createPropertyViewImpl>( + classProperty, + propertyTextureProperty, + count * sizeof(T)); + } + + template + PropertyTexturePropertyView createPropertyViewImpl( + const ClassProperty& classProperty, + const PropertyTextureProperty& propertyTextureProperty, + size_t elementSize) const { + int32_t samplerIndex; + int32_t imageIndex; + + auto status = + getTextureSafe(propertyTextureProperty.index, samplerIndex, imageIndex); + + if (status != PropertyTexturePropertyViewStatus::Valid) { + return PropertyTexturePropertyView(status); + } + + status = checkSampler(samplerIndex); + if (status != PropertyTexturePropertyViewStatus::Valid) { + return PropertyTexturePropertyView(status); + } + + status = checkImage(samplerIndex); + if (status != PropertyTexturePropertyViewStatus::Valid) { + return PropertyTexturePropertyView(status); + } + + const ImageCesium& image = _pModel->images[imageIndex].cesium; + const std::vector& channels = propertyTextureProperty.channels; + + status = checkChannels(channels, image); + if (status != PropertyTexturePropertyViewStatus::Valid) { + return PropertyTexturePropertyView(status); + } + + if (channels.size() * image.bytesPerChannel != elementSize) { + return PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch; + } + + return PropertyTexturePropertyView( + _pModel->samplers[samplerIndex], + image, + propertyTextureProperty.texCoord, + channels, + classProperty.normalized); + } + + PropertyTexturePropertyViewStatus getTextureSafe( + const int32_t textureIndex, + int32_t& samplerIndex, + int32_t& imageIndex) const noexcept; + + PropertyTexturePropertyViewStatus + checkSampler(const int32_t samplerIndex) const noexcept; + + PropertyTexturePropertyViewStatus + checkImage(const int32_t imageIndex) const noexcept; + + PropertyTexturePropertyViewStatus checkChannels( + const std::vector& channels, + const ImageCesium& image) const noexcept; + const Model* _pModel; const PropertyTexture* _pPropertyTexture; const Class* _pClass; - std::unordered_map _propertyViews; + PropertyTextureViewStatus _status; }; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyType.h b/CesiumGltf/include/CesiumGltf/PropertyType.h index e5771a015..e5c964ec8 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyType.h +++ b/CesiumGltf/include/CesiumGltf/PropertyType.h @@ -4,6 +4,8 @@ #include #include +#include + namespace CesiumGltf { enum class PropertyType { Invalid, @@ -52,4 +54,9 @@ convertStringOffsetTypeStringToPropertyComponentType(const std::string& str); bool isPropertyTypeVecN(PropertyType type); bool isPropertyTypeMatN(PropertyType type); + +glm::length_t getDimensionsFromPropertyType(PropertyType type); + +size_t getSizeOfComponentType(PropertyComponentType componentType); + } // namespace CesiumGltf diff --git a/CesiumGltf/src/PropertyTableView.cpp b/CesiumGltf/src/PropertyTableView.cpp index a280527f6..0e861151e 100644 --- a/CesiumGltf/src/PropertyTableView.cpp +++ b/CesiumGltf/src/PropertyTableView.cpp @@ -125,13 +125,12 @@ PropertyTableView::PropertyTableView( } auto classIter = schema->classes.find(_pPropertyTable->classProperty); - if (classIter != schema->classes.end()) { - _pClass = &classIter->second; - } - - if (!_pClass) { + if (classIter == schema->classes.end()) { _status = PropertyTableViewStatus::ErrorClassNotFound; + return; } + + _pClass = &classIter->second; } const ClassProperty* @@ -282,26 +281,26 @@ PropertyTableView::getStringPropertyValues( const ClassProperty& classProperty, const PropertyTableProperty& propertyTableProperty) const { if (classProperty.array) { - return createInvalidPropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } if (classProperty.type != ClassProperty::Type::STRING) { - return createInvalidPropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorTypeMismatch); } gsl::span values; auto status = getBufferSafe(propertyTableProperty.values, values); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView(status); + return PropertyTablePropertyView(status); } const PropertyComponentType offsetType = convertStringOffsetTypeStringToPropertyComponentType( propertyTableProperty.stringOffsetType); if (offsetType == PropertyComponentType::None) { - return createInvalidPropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); } @@ -313,11 +312,10 @@ PropertyTableView::getStringPropertyValues( static_cast(_pPropertyTable->count), stringOffsets); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView(status); + return PropertyTablePropertyView(status); } return PropertyTablePropertyView( - PropertyTablePropertyViewStatus::Valid, values, gsl::span(), stringOffsets, @@ -333,31 +331,31 @@ PropertyTableView::getStringArrayPropertyValues( const ClassProperty& classProperty, const PropertyTableProperty& propertyTableProperty) const { if (!classProperty.array) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } if (classProperty.type != ClassProperty::Type::STRING) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorTypeMismatch); } gsl::span values; auto status = getBufferSafe(propertyTableProperty.values, values); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( status); } // Check if array is fixed or variable length const int64_t fixedLengthArrayCount = classProperty.count.value_or(0); if (fixedLengthArrayCount > 0 && propertyTableProperty.arrayOffsets >= 0) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus:: ErrorArrayCountAndOffsetBufferDontExist); } @@ -367,12 +365,12 @@ PropertyTableView::getStringArrayPropertyValues( convertStringOffsetTypeStringToPropertyComponentType( propertyTableProperty.stringOffsetType); if (stringOffsetType == PropertyComponentType::None) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); } if (propertyTableProperty.stringOffsets < 0) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetBufferView); } @@ -386,12 +384,11 @@ PropertyTableView::getStringArrayPropertyValues( static_cast(_pPropertyTable->count * fixedLengthArrayCount), stringOffsets); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( status); } return PropertyTablePropertyView>( - PropertyTablePropertyViewStatus::Valid, values, gsl::span(), stringOffsets, @@ -407,12 +404,12 @@ PropertyTableView::getStringArrayPropertyValues( convertArrayOffsetTypeStringToPropertyComponentType( propertyTableProperty.arrayOffsetType); if (arrayOffsetType == PropertyComponentType::None) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } if (propertyTableProperty.arrayOffsets < 0) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetBufferView); } @@ -420,14 +417,14 @@ PropertyTableView::getStringArrayPropertyValues( gsl::span stringOffsets; status = getBufferSafe(propertyTableProperty.stringOffsets, stringOffsets); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( status); } gsl::span arrayOffsets; status = getBufferSafe(propertyTableProperty.arrayOffsets, arrayOffsets); if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( status); } @@ -470,12 +467,11 @@ PropertyTableView::getStringArrayPropertyValues( } if (status != PropertyTablePropertyViewStatus::Valid) { - return createInvalidPropertyView>( + return PropertyTablePropertyView>( status); } return PropertyTablePropertyView>( - PropertyTablePropertyViewStatus::Valid, values, arrayOffsets, stringOffsets, diff --git a/CesiumGltf/src/PropertyTexturePropertyView.cpp b/CesiumGltf/src/PropertyTexturePropertyView.cpp deleted file mode 100644 index a779a73ee..000000000 --- a/CesiumGltf/src/PropertyTexturePropertyView.cpp +++ /dev/null @@ -1,145 +0,0 @@ - -#include "CesiumGltf/PropertyTexturePropertyView.h" - -#include - -namespace CesiumGltf { -namespace { -static std::unordered_set supportedTypes{ - ClassProperty::Type::SCALAR, - ClassProperty::Type::VEC2, - ClassProperty::Type::VEC3, - ClassProperty::Type::VEC4}; - -bool isValidClassProperty(const ClassProperty& classProperty) { - if (supportedTypes.find(classProperty.type) == supportedTypes.end()) { - return false; - } - - // Non-arrays don't need further validation. - if (!classProperty.array) { - return true; - } - - if (classProperty.type != ClassProperty::Type::SCALAR) { - return false; - } - - int64_t count = classProperty.count.value_or(0); - return count > 0 && count <= 4; -} -} // namespace - -PropertyTexturePropertyView::PropertyTexturePropertyView() noexcept - : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), - _pClassProperty(nullptr), - _pSampler(nullptr), - _pImage(nullptr), - _texCoordSetIndex(0), - _channels(), - _swizzle(""), - _componentType(PropertyTexturePropertyComponentType::Uint8), - _componentCount(0), - _normalized(false) {} - -PropertyTexturePropertyView::PropertyTexturePropertyView( - const Model& model, - const ClassProperty& classProperty, - const PropertyTextureProperty& propertyTextureProperty) noexcept - : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), - _pClassProperty(&classProperty), - _pSampler(nullptr), - _pImage(nullptr), - _texCoordSetIndex(propertyTextureProperty.texCoord), - _channels(), - _swizzle(""), - _componentType(PropertyTexturePropertyComponentType::Uint8), - _componentCount(0), - _normalized(false) { - - if (!isValidClassProperty(classProperty)) { - this->_status = - PropertyTexturePropertyViewStatus::ErrorInvalidClassProperty; - return; - } - - if (classProperty.array) { - this->_componentCount = *classProperty.count; - } else if (classProperty.type == ClassProperty::Type::SCALAR) { - this->_componentCount = 1; - } else if (classProperty.type == ClassProperty::Type::VEC2) { - this->_componentCount = 2; - } else if (classProperty.type == ClassProperty::Type::VEC3) { - this->_componentCount = 3; - } else if (classProperty.type == ClassProperty::Type::VEC4) { - this->_componentCount = 4; - } - - const int64_t index = propertyTextureProperty.index; - if (index < 0 || static_cast(index) >= model.textures.size()) { - this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidTexture; - return; - } - - const Texture& texture = model.textures[static_cast(index)]; - if (texture.sampler < 0 || - static_cast(texture.sampler) >= model.samplers.size()) { - this->_status = - PropertyTexturePropertyViewStatus::ErrorInvalidTextureSampler; - return; - } - - this->_pSampler = &model.samplers[static_cast(texture.sampler)]; - - if (texture.source < 0 || - static_cast(texture.source) >= model.images.size()) { - this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidImage; - return; - } - - this->_pImage = &model.images[static_cast(texture.source)].cesium; - if (this->_pImage->width < 1 || this->_pImage->height < 1) { - this->_status = PropertyTexturePropertyViewStatus::ErrorEmptyImage; - return; - } - - // TODO: support more component types - // this->_componentType = ... - - this->_normalized = this->_pClassProperty->normalized; - - // TODO: channels can represent a multi-byte value, so the last check will - // need to change. - const std::vector& channels = propertyTextureProperty.channels; - if (channels.size() == 0 || channels.size() > 4 || - channels.size() > static_cast(this->_pImage->channels) || - channels.size() != static_cast(this->_componentCount)) { - this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidChannels; - return; - } - - for (size_t i = 0; i < channels.size(); ++i) { - switch (channels[i]) { - case 0: - this->_swizzle += "r"; - break; - case 1: - this->_swizzle += "g"; - break; - case 2: - this->_swizzle += "b"; - break; - case 3: - this->_swizzle += "a"; - break; - default: - this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidChannels; - return; - } - } - - this->_channels = channels; - - this->_status = PropertyTexturePropertyViewStatus::Valid; -} -} // namespace CesiumGltf diff --git a/CesiumGltf/src/PropertyTextureView.cpp b/CesiumGltf/src/PropertyTextureView.cpp index c5c67de05..24c9d10ff 100644 --- a/CesiumGltf/src/PropertyTextureView.cpp +++ b/CesiumGltf/src/PropertyTextureView.cpp @@ -1,22 +1,13 @@ #include "CesiumGltf/PropertyTextureView.h" namespace CesiumGltf { -PropertyTextureView::PropertyTextureView() noexcept - : _pModel(nullptr), - _pPropertyTexture(nullptr), - _pClass(nullptr), - _propertyViews(), - _status(PropertyTextureViewStatus::ErrorUninitialized) {} - PropertyTextureView::PropertyTextureView( const Model& model, const PropertyTexture& propertyTexture) noexcept : _pModel(&model), _pPropertyTexture(&propertyTexture), _pClass(nullptr), - _propertyViews(), - _status(PropertyTextureViewStatus::ErrorUninitialized) { - + _status() { const ExtensionModelExtStructuralMetadata* pMetadata = model.getExtension(); @@ -38,23 +29,6 @@ PropertyTextureView::PropertyTextureView( } this->_pClass = &classIt->second; - - this->_propertyViews.reserve(propertyTexture.properties.size()); - for (const auto& property : propertyTexture.properties) { - auto classPropertyIt = this->_pClass->properties.find(property.first); - - if (classPropertyIt == this->_pClass->properties.end()) { - this->_status = PropertyTextureViewStatus::ErrorClassPropertyNotFound; - return; - } - - this->_propertyViews[property.first] = PropertyTexturePropertyView( - model, - classPropertyIt->second, - property.second); - } - - this->_status = PropertyTextureViewStatus::Valid; } const ClassProperty* @@ -70,4 +44,71 @@ PropertyTextureView::getClassProperty(const std::string& propertyName) const { return &propertyIter->second; } + +PropertyTexturePropertyViewStatus PropertyTextureView::getTextureSafe( + const int32_t textureIndex, + int32_t& samplerIndex, + int32_t& imageIndex) const noexcept { + if (textureIndex < 0 || + static_cast(textureIndex) >= _pModel->textures.size()) { + return PropertyTexturePropertyViewStatus::ErrorInvalidTexture; + } + + const Texture& texture = _pModel->textures[static_cast(textureIndex)]; + samplerIndex = texture.sampler; + imageIndex = texture.source; + + return PropertyTexturePropertyViewStatus::Valid; +} + +PropertyTexturePropertyViewStatus +PropertyTextureView::checkSampler(const int32_t samplerIndex) const noexcept { + if (samplerIndex < 0 || + static_cast(samplerIndex) >= _pModel->samplers.size()) { + return PropertyTexturePropertyViewStatus::ErrorInvalidSampler; + } + + // TODO: check if sampler filter values are supported + + return PropertyTexturePropertyViewStatus::Valid; +} + +PropertyTexturePropertyViewStatus +PropertyTextureView::checkImage(const int32_t imageIndex) const noexcept { + if (imageIndex < 0 || + static_cast(imageIndex) >= _pModel->images.size()) { + return PropertyTexturePropertyViewStatus::ErrorInvalidImage; + } + + const ImageCesium& image = + _pModel->images[static_cast(imageIndex)].cesium; + + if (image.width < 1 || image.height < 1) { + return PropertyTexturePropertyViewStatus::ErrorEmptyImage; + } + + if (image.bytesPerChannel > 1) { + return PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel; + } + + return PropertyTexturePropertyViewStatus::Valid; +} + +PropertyTexturePropertyViewStatus PropertyTextureView::checkChannels( + const std::vector& channels, + const ImageCesium& image) const noexcept { + int64_t imageChannelCount = static_cast(image.channels); + for (size_t i = 0; i < channels.size(); i++) { + if (channels[i] < 0 || channels[i] >= imageChannelCount) { + return PropertyTexturePropertyViewStatus::ErrorInvalidChannels; + } + } + + if (static_cast(imageChannelCount) < channels.size()) { + return PropertyTexturePropertyViewStatus::ErrorTooManyChannels; + } + + return PropertyTexturePropertyViewStatus::Valid; +} + } // namespace CesiumGltf diff --git a/CesiumGltf/src/PropertyType.cpp b/CesiumGltf/src/PropertyType.cpp index 1e5e4ed62..f30be7931 100644 --- a/CesiumGltf/src/PropertyType.cpp +++ b/CesiumGltf/src/PropertyType.cpp @@ -200,4 +200,43 @@ bool isPropertyTypeMatN(PropertyType type) { return type == PropertyType::Mat2 || type == PropertyType::Mat3 || type == PropertyType::Mat4; } + +glm::length_t getDimensionsFromPropertyType(PropertyType type) { + switch (type) { + case PropertyType::Scalar: + return 1; + case PropertyType::Vec2: + case PropertyType::Mat2: + return 2; + case PropertyType::Vec3: + case PropertyType::Mat3: + return 3; + case PropertyType::Vec4: + case PropertyType::Mat4: + return 4; + default: + return 0; + } +} + +size_t getSizeOfComponentType(PropertyComponentType componentType) { + switch (componentType) { + case PropertyComponentType::Int8: + case PropertyComponentType::Uint8: + return 1; + case PropertyComponentType::Int16: + case PropertyComponentType::Uint16: + return 2; + case PropertyComponentType::Int32: + case PropertyComponentType::Uint32: + case PropertyComponentType::Float32: + return 4; + case PropertyComponentType::Int64: + case PropertyComponentType::Uint64: + case PropertyComponentType::Float64: + return 8; + default: + return 0; + } +} } // namespace CesiumGltf diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index ae1075ec3..8fc0a28c1 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -17,7 +17,6 @@ template static void checkNumeric(const std::vector& expected) { std::memcpy(data.data(), expected.data(), data.size()); PropertyTablePropertyView property( - PropertyTablePropertyViewStatus::Valid, gsl::span(data.data(), data.size()), static_cast(expected.size()), false); @@ -47,7 +46,6 @@ static void checkVariableLengthArray( offsets.size() * sizeof(OffsetType)); PropertyTablePropertyView> property( - PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(offsetBuffer.data(), offsetBuffer.size()), gsl::span(), @@ -79,7 +77,6 @@ static void checkFixedLengthArray( std::memcpy(buffer.data(), data.data(), data.size() * sizeof(T)); PropertyTablePropertyView> property( - PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(), @@ -101,7 +98,7 @@ static void checkFixedLengthArray( REQUIRE(expectedIdx == data.size()); } -TEST_CASE("Check scalar numeric property view") { +TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Uint8 Scalar") { std::vector data{12, 33, 56, 67}; checkNumeric(data); @@ -127,7 +124,7 @@ TEST_CASE("Check scalar numeric property view") { } } -TEST_CASE("Check vecN numeric property view") { +TEST_CASE("Check vecN PropertyTablePropertyView") { SECTION("Float Vec2") { std::vector data{ glm::vec2(10.001f, 0.005f), @@ -156,7 +153,7 @@ TEST_CASE("Check vecN numeric property view") { } } -TEST_CASE("Check matN numeric property view") { +TEST_CASE("Check matN PropertyTablePropertyView") { SECTION("Float Mat2") { // clang-format off std::vector data{ @@ -218,7 +215,7 @@ TEST_CASE("Check matN numeric property view") { } } -TEST_CASE("Check boolean property") { +TEST_CASE("Check boolean PropertyTablePropertyView") { std::bitset bits = 0b11110101; unsigned long val = bits.to_ulong(); std::vector data(sizeof(val)); @@ -226,7 +223,6 @@ TEST_CASE("Check boolean property") { size_t instanceCount = sizeof(unsigned long) * CHAR_BIT; PropertyTablePropertyView property( - PropertyTablePropertyViewStatus::Valid, gsl::span(data.data(), data.size()), static_cast(instanceCount), false); @@ -235,7 +231,7 @@ TEST_CASE("Check boolean property") { } } -TEST_CASE("Check string property") { +TEST_CASE("Check string PropertyTablePropertyView") { std::vector strings{ "This is a fine test", "What's going on", @@ -273,7 +269,6 @@ TEST_CASE("Check string property") { sizeof(uint32_t)); PropertyTablePropertyView property( - PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(offsetBuffer.data(), offsetBuffer.size()), @@ -287,7 +282,7 @@ TEST_CASE("Check string property") { } } -TEST_CASE("Check fixed-length scalar array property") { +TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { SECTION("Fixed-length array of 4 uint8_ts") { // clang-format off std::vector data{ @@ -376,7 +371,7 @@ TEST_CASE("Check fixed-length scalar array property") { } } -TEST_CASE("Check fixed-length vecN array property") { +TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { SECTION("Fixed-length array of 4 u8vec2s") { // clang-format off std::vector data{ @@ -419,7 +414,7 @@ TEST_CASE("Check fixed-length vecN array property") { } } -TEST_CASE("Check fixed-length matN array property") { +TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { SECTION("Fixed-length array of 4 i8mat2x2") { // clang-format off std::vector data{ @@ -520,7 +515,7 @@ TEST_CASE("Check fixed-length matN array property") { } } -TEST_CASE("Check variable-length scalar array property") { +TEST_CASE("Check variable-length scalar array PropertyTablePropertyView") { SECTION("Variable-length array of uint8_t") { // clang-format off std::vector data{ @@ -572,7 +567,7 @@ TEST_CASE("Check variable-length scalar array property") { } } -TEST_CASE("Check variable-length vecN array property") { +TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { SECTION("Variable-length array of ivec2") { // clang-format off std::vector data{ @@ -636,7 +631,7 @@ TEST_CASE("Check variable-length vecN array property") { } } -TEST_CASE("Check variable-length matN array property") { +TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { SECTION("Variable-length array of dmat2") { // clang-format off std::vector data0{ @@ -832,7 +827,6 @@ TEST_CASE("Check fixed-length array of string") { sizeof(uint32_t)); PropertyTablePropertyView> property( - PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(stringOffsets.data(), stringOffsets.size()), @@ -855,7 +849,7 @@ TEST_CASE("Check fixed-length array of string") { REQUIRE(expectedIdx == stringCount); } -TEST_CASE("Check variable-length array of strings property") { +TEST_CASE("Check variable-length string array PropertyTablePropertyView") { // clang-format off std::vector arrayOffsets{ 0, @@ -904,7 +898,6 @@ TEST_CASE("Check variable-length array of strings property") { sizeof(uint32_t)); PropertyTablePropertyView> property( - PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span( reinterpret_cast(arrayOffsets.data()), @@ -929,14 +922,13 @@ TEST_CASE("Check variable-length array of strings property") { REQUIRE(expectedIdx == stringCount); } -TEST_CASE("Check fixed-length boolean array property") { +TEST_CASE("Check fixed-length boolean array PropertyTablePropertyView") { std::vector buffer{ static_cast(0b10101111), static_cast(0b11111010), static_cast(0b11100111)}; PropertyTablePropertyView> property( - PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(), @@ -978,7 +970,7 @@ TEST_CASE("Check fixed-length boolean array property") { REQUIRE(static_cast(val1[11]) == 1); } -TEST_CASE("Check variable-length boolean array property") { +TEST_CASE("Check variable-length boolean array PropertyTablePropertyView") { std::vector buffer{ static_cast(0b10101111), static_cast(0b11111010), @@ -988,7 +980,6 @@ TEST_CASE("Check variable-length boolean array property") { std::vector offsetBuffer{0, 3, 12, 28}; PropertyTablePropertyView> property( - PropertyTablePropertyViewStatus::Valid, gsl::span(buffer.data(), buffer.size()), gsl::span( reinterpret_cast(offsetBuffer.data()), diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index 9516c72a6..df8fc0a28 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -7,7 +7,7 @@ using namespace CesiumGltf; template -void addBufferToModel(Model& model, std::vector& values) { +void addBufferToModel(Model& model, const std::vector& values) { Buffer& valueBuffer = model.buffers.emplace_back(); valueBuffer.cesium.data.resize(values.size() * sizeof(T)); valueBuffer.byteLength = static_cast(valueBuffer.cesium.data.size()); diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index 60035721a..4b54c49b8 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -11,401 +11,1063 @@ using namespace CesiumGltf; -TEST_CASE( - "Test PropertyTexturePropertyView on property with invalid texture index") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - - PropertyTexture propertyTexture; - propertyTexture.classProperty = "TestClass"; - - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = -1; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0}; - - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE( - view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidTexture); -} +TEST_CASE("Check scalar PropertyTexturePropertyView") { + SECTION("uint8_t") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 1; + image.bytesPerChannel = 1; + + std::vector data{12, 33, 56, 67}; + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "r"); + + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == data[i]); + } + } -TEST_CASE( - "Test PropertyTexturePropertyView on property with invalid sampler index") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - - Image& image = model.images.emplace_back(); - image.cesium.width = 1; - image.cesium.height = 1; - Texture& texture = model.textures.emplace_back(); - texture.sampler = -1; - texture.source = 0; - - PropertyTexture propertyTexture; - propertyTexture.classProperty = "TestClass"; - - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0}; - - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE( - view.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidTextureSampler); -} + SECTION("int8_t") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 1; + image.bytesPerChannel = 1; + + std::vector data{255, 0, 223, 67}; + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "r"); + + std::vector expected{-1, 0, -33, 67}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } -TEST_CASE( - "Test PropertyTexturePropertyView on property with invalid image index") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - - model.samplers.emplace_back(); - - Texture& texture = model.textures.emplace_back(); - texture.sampler = 0; - texture.source = -1; - - PropertyTexture propertyTexture; - propertyTexture.classProperty = "TestClass"; - - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0}; - - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE( - view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidImage); -} + SECTION("uint16_t") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 2; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 28, 0, + 1, 1, + 0, 3, + 182, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rg"); + + std::vector expected{28, 257, 768, 438}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } -TEST_CASE("Test PropertyTexturePropertyView on property with empty image") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - - Image& image = model.images.emplace_back(); - image.cesium.width = 0; - image.cesium.height = 0; - - model.samplers.emplace_back(); - - Texture& texture = model.textures.emplace_back(); - texture.sampler = 0; - texture.source = 0; - - PropertyTexture propertyTexture; - propertyTexture.classProperty = "TestClass"; - - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0}; - - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE(view.status() == PropertyTexturePropertyViewStatus::ErrorEmptyImage); -} + SECTION("int16_t") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 2; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 255, 255, + 1, 129, + 0, 3, + 182, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rg"); + + std::vector expected{-1, -32511, 768, 438}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } -TEST_CASE("Test PropertyTextureView on property texture property with zero " - "channels") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - - Image& image = model.images.emplace_back(); - image.cesium.width = 1; - image.cesium.height = 1; - image.cesium.channels = 1; - - model.samplers.emplace_back(); - - Texture& texture = model.textures.emplace_back(); - texture.sampler = 0; - texture.source = 0; - - PropertyTexture propertyTexture; - propertyTexture.classProperty = "TestClass"; - - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {}; - - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE( - view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidChannels); -} + SECTION("uint32_t") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 0, 0, 0, 1, + 9, 0, 1, 0, + 20, 2, 2, 0, + 8, 1, 0, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + + std::vector expected{16777216, 65545, 131604, 16777480}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("int32_t") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 255, 255, 255, 255, + 9, 0, 1, 0, + 20, 2, 2, 255, + 8, 1, 0, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + std::vector expected{-1, 65545, -16645612, 16777480}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } -TEST_CASE("Test PropertyTextureView on property texture property with too many " - "channels") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - - Image& image = model.images.emplace_back(); - image.cesium.width = 1; - image.cesium.height = 1; - image.cesium.channels = 1; - - model.samplers.emplace_back(); - - Texture& texture = model.textures.emplace_back(); - texture.sampler = 0; - texture.source = 0; - - PropertyTexture propertyTexture; - propertyTexture.classProperty = "TestClass"; - - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0, 1}; - - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE( - view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidChannels); + SECTION("float") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 0, 0, 0, 1, + 9, 0, 1, 0, + 20, 2, 2, 0, + 8, 1, 0, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + + std::vector expectedUint{16777216, 65545, 131604, 16777480}; + std::vector expected(expectedUint.size()); + for (size_t i = 0; i < expectedUint.size(); i++) { + float value = *reinterpret_cast(&expectedUint[i]); + expected[i] = value; + } + + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } } -TEST_CASE("Test PropertyTexturePropertyView on valid property texture") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - - Image& image = model.images.emplace_back(); - image.cesium.width = 1; - image.cesium.height = 1; - image.cesium.channels = 1; - - model.samplers.emplace_back(); - - Texture& texture = model.textures.emplace_back(); - texture.sampler = 0; - texture.source = 0; - - PropertyTexture propertyTexture; - propertyTexture.classProperty = "TestClass"; - - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0}; - - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE(view.status() == PropertyTexturePropertyViewStatus::Valid); +TEST_CASE("Check vecN PropertyTexturePropertyView") { + SECTION("glm::u8vec2") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 2; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 28, 0, + 1, 1, + 0, 3, + 182, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rg"); + + std::vector expected{ + glm::u8vec2(28, 0), + glm::u8vec2(1, 1), + glm::u8vec2(0, 3), + glm::u8vec2(182, 1)}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("glm::i8vec2") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 2; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 28, 255, + 254, 1, + 0, 3, + 182, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rg"); + + std::vector expected{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(-74, 1)}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("glm::u8vec3") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 3; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 1, 2, 3, + 4, 5, 6, + 7, 8, 9, + 0, 5, 2}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgb"); + + std::vector expected{ + glm::u8vec3(1, 2, 3), + glm::u8vec3(4, 5, 6), + glm::u8vec3(7, 8, 9), + glm::u8vec3(0, 5, 2)}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("glm::i8vec3") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 3; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 255, 2, 3, + 4, 254, 6, + 7, 8, 159, + 0, 5, 2}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgb"); + + std::vector expected{ + glm::i8vec3(-1, 2, 3), + glm::i8vec3(4, -2, 6), + glm::i8vec3(7, 8, -97), + glm::i8vec3(0, 5, 2)}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("glm::u8vec4") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 1, 2, 3, 0, + 4, 5, 6, 11, + 7, 8, 9, 3, + 0, 5, 2, 27}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + + std::vector expected{ + glm::u8vec4(1, 2, 3, 0), + glm::u8vec4(4, 5, 6, 11), + glm::u8vec4(7, 8, 9, 3), + glm::u8vec4(0, 5, 2, 27)}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("glm::i8vec4") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 1, 200, 3, 0, + 4, 5, 6, 251, + 129, 8, 9, 3, + 0, 155, 2, 27}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + + std::vector expected{ + glm::i8vec4(1, -56, 3, 0), + glm::i8vec4(4, 5, 6, -5), + glm::i8vec4(-127, 8, 9, 3), + glm::i8vec4(0, -101, 2, 27)}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("glm::u16vec2") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 0, 0, 0, 1, + 9, 0, 1, 0, + 20, 2, 2, 0, + 8, 1, 0, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + + std::vector expected{ + glm::u16vec2(0, 256), + glm::u16vec2(9, 1), + glm::u16vec2(532, 2), + glm::u16vec2(264, 256)}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("glm::i16vec2") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 255, 255, 0, 1, + 9, 0, 146, 195, + 20, 2, 2, 0, + 8, 1, 255, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + + std::vector expected{ + glm::i16vec2(-1, 256), + glm::i16vec2(9, -15470), + glm::i16vec2(532, 2), + glm::i16vec2(264, 511)}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } } -TEST_CASE("Test getSwizzle") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - testClassProperty.count = 4; - - Image& image = model.images.emplace_back(); - image.cesium.width = 1; - image.cesium.height = 1; - image.cesium.channels = 4; - - model.samplers.emplace_back(); - - Texture& texture = model.textures.emplace_back(); - texture.sampler = 0; - texture.source = 0; - - PropertyTexture propertyTexture; - propertyTexture.classProperty = "TestClass"; - - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0, 2, 3, 1}; - - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE(view.status() == PropertyTexturePropertyViewStatus::Valid); - REQUIRE(view.getCount() == 4); - REQUIRE(view.getSwizzle() == "rbag"); +TEST_CASE("Check array PropertyTexturePropertyView") { + SECTION("uint8_t array") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 1, 2, 3, 0, + 4, 5, 6, 11, + 7, 8, 9, 3, + 0, 5, 2, 27}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView> + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + + std::vector> values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + + for (size_t i = 0; i < 4; i++) { + auto dataStart = data.begin() + i * 4; + std::vector expected(dataStart, dataStart + 4); + const PropertyArrayView& value = values[i]; + REQUIRE(static_cast(value.size()) == expected.size()); + for (size_t j = 0; j < expected.size(); j++) { + REQUIRE(value[j] == expected[j]); + } + } + } + + SECTION("int8_t array") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 1, 200, 3, 0, + 4, 5, 6, 251, + 129, 8, 9, 3, + 0, 155, 2, 27}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView> + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + + std::vector> expected{ + {1, -56, 3, 0}, + {4, 5, 6, -5}, + {-127, 8, 9, 3}, + {0, -101, 2, 27}}; + std::vector> values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + std::vector& expectedValue = expected[i]; + const PropertyArrayView& value = values[i]; + REQUIRE(static_cast(value.size()) == expected.size()); + for (size_t j = 0; j < expected.size(); j++) { + REQUIRE(value[j] == expectedValue[j]); + } + } + } + + SECTION("uint16_t array") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 0, 0, 0, 1, + 9, 0, 1, 0, + 20, 2, 2, 0, + 8, 1, 0, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView> + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + + std::vector> values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + + std::vector> expected{ + {0, 256}, + {9, 1}, + {532, 2}, + {264, 256}}; + + for (size_t i = 0; i < expected.size(); i++) { + std::vector& expectedValue = expected[i]; + const PropertyArrayView& value = values[i]; + REQUIRE(static_cast(value.size()) == expectedValue.size()); + for (size_t j = 0; j < expectedValue.size(); j++) { + REQUIRE(value[j] == expectedValue[j]); + } + } + } + + SECTION("int16_t array") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 255, 255, 0, 1, + 9, 0, 146, 195, + 20, 2, 2, 0, + 8, 255, 0, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTexturePropertyView> + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "rgba"); + + std::vector> expected{ + {-1, 256}, + {9, -15470}, + {532, 2}, + {-248, 256}}; + std::vector> values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + std::vector& expectedValue = expected[i]; + const PropertyArrayView& value = values[i]; + REQUIRE(static_cast(value.size()) == expectedValue.size()); + for (size_t j = 0; j < expectedValue.size(); j++) { + REQUIRE(value[j] == expectedValue[j]); + } + } + } } -TEST_CASE("Test getting value from invalid view") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - - Image& image = model.images.emplace_back(); - image.cesium.width = 0; - image.cesium.height = 1; - image.cesium.channels = 1; - - model.samplers.emplace_back(); - - Texture& texture = model.textures.emplace_back(); - texture.sampler = 0; - texture.source = 0; - - PropertyTexture propertyTexture; - propertyTexture.classProperty = "TestClass"; - - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0}; - - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE(view.status() != PropertyTexturePropertyViewStatus::Valid); - PropertyTexturePropertyValue value = view.get(0, 0); - REQUIRE(value.components[0] == 0); - REQUIRE(value.components[1] == 0); - REQUIRE(value.components[2] == 0); - REQUIRE(value.components[3] == 0); +TEST_CASE("Check that non-adjacent channels resolve to expected output") { + SECTION("single-byte scalar") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 0, 1, 2, 3, + 1, 2, 3, 4, + 1, 0, 1, 0, + 2, 3, 8, 1}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{3}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "a"); + + std::vector expected{3, 4, 0, 1}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("multi-byte scalar") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 0, 1, 2, 3, + 1, 2, 3, 4, + 1, 0, 1, 0, + 2, 3, 8, 1}; + // clang-format on + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{2, 0}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "br"); + + std::vector expected{2, 259, 257, 520}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("vecN") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 0, 1, 2, 3, + 1, 2, 3, 4, + 1, 0, 1, 0, + 2, 3, 8, 1}; + // clang-format on + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{3, 2, 1}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "abg"); + + std::vector expected{ + glm::u8vec3(3, 2, 1), + glm::u8vec3(4, 3, 2), + glm::u8vec3(0, 1, 0), + glm::u8vec3(1, 8, 3)}; + std::vector values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("array") { + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 1, 2, 3, 0, + 4, 5, 6, 11, + 7, 8, 9, 3, + 0, 5, 2, 27}; + // clang-format on + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{1, 0, 3, 2}; + + PropertyTexturePropertyView> + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "grab"); + + std::vector> values{ + view.get(0, 0), + view.get(0.5, 0), + view.get(0, 0.5), + view.get(0.5, 0.5)}; + + std::vector> expected{ + {2, 1, 0, 3}, + {5, 4, 11, 6}, + {8, 7, 3, 9}, + {5, 0, 27, 2}}; + + for (size_t i = 0; i < expected.size(); i++) { + std::vector& expectedValue = expected[i]; + const PropertyArrayView& value = values[i]; + REQUIRE(static_cast(value.size()) == expectedValue.size()); + for (size_t j = 0; j < expectedValue.size(); j++) { + REQUIRE(value[j] == expectedValue[j]); + } + } + } } -TEST_CASE("Test getting value from valid view") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - - std::vector values{10, 8, 4, 22}; - - Image& image = model.images.emplace_back(); - image.cesium.width = 2; - image.cesium.height = 2; - image.cesium.channels = 1; - image.cesium.bytesPerChannel = 1; - image.cesium.pixelData.resize(values.size()); - std::memcpy(image.cesium.pixelData.data(), values.data(), values.size()); - - Sampler& sampler = model.samplers.emplace_back(); - sampler.wrapS = Sampler::WrapS::CLAMP_TO_EDGE; - sampler.wrapT = Sampler::WrapT::CLAMP_TO_EDGE; - - Texture& texture = model.textures.emplace_back(); - texture.sampler = 0; - texture.source = 0; - - PropertyTexture propertyTexture; - propertyTexture.classProperty = "TestClass"; - - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0}; - - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE(view.status() == PropertyTexturePropertyViewStatus::Valid); - - std::vector> viewValues{ - view.get(0, 0), - view.get(1.0, 0), - view.get(0, 1.0), - view.get(1.0, 1.0)}; - - for (size_t i = 0; i < viewValues.size(); i++) { - PropertyTexturePropertyValue& actual = viewValues[i]; - REQUIRE(actual.components[0] == values[i]); - REQUIRE(actual.components[1] == 0); - REQUIRE(actual.components[2] == 0); - REQUIRE(actual.components[3] == 0); +TEST_CASE("Check sampling with different sampler values") { + SECTION("REPEAT") { + Sampler sampler; + sampler.wrapS = Sampler::WrapS::REPEAT; + sampler.wrapT = Sampler::WrapT::REPEAT; + + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 1; + image.bytesPerChannel = 1; + + std::vector data{12, 33, 56, 67}; + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "r"); + + std::vector values{ + view.get(1.0, 0), + view.get(-1.5, 0), + view.get(0, -0.5), + view.get(1.5, -0.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == data[i]); + } + } + + SECTION("MIRRORED_REPEAT") { + Sampler sampler; + sampler.wrapS = Sampler::WrapS::MIRRORED_REPEAT; + sampler.wrapT = Sampler::WrapT::MIRRORED_REPEAT; + // REPEAT: | 1 2 3 | 1 2 3 | + // MIRRORED: | 1 2 3 | 3 2 1 | + // Sampling 0.6 is equal to sampling 1.4 or -0.6. + + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 1; + image.bytesPerChannel = 1; + + std::vector data{12, 33, 56, 67}; + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "r"); + + std::vector values{ + view.get(2.0, 0), + view.get(-0.75, 0), + view.get(0, 1.25), + view.get(-1.25, 2.75)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == data[i]); + } + } + + SECTION("CLAMP_TO_EDGE") { + Sampler sampler; + sampler.wrapS = Sampler::WrapS::CLAMP_TO_EDGE; + sampler.wrapT = Sampler::WrapT::CLAMP_TO_EDGE; + + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 1; + image.bytesPerChannel = 1; + + std::vector data{12, 33, 56, 67}; + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "r"); + + std::vector values{ + view.get(-1.0, 0), + view.get(1.4, 0), + view.get(0, 2.0), + view.get(1.5, 1.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == data[i]); + } + } + + SECTION("Mismatched wrap values") { + Sampler sampler; + sampler.wrapS = Sampler::WrapS::REPEAT; + sampler.wrapT = Sampler::WrapT::CLAMP_TO_EDGE; + + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 1; + image.bytesPerChannel = 1; + + std::vector data{12, 33, 56, 67}; + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0}; + + PropertyTexturePropertyView + view(sampler, image, 0, channels, false); + CHECK(view.getSwizzle() == "r"); + + std::vector values{ + view.get(1.0, 0), + view.get(-1.5, -1.0), + view.get(0, 1.5), + view.get(1.5, 1.5)}; + for (size_t i = 0; i < values.size(); i++) { + REQUIRE(values[i] == data[i]); + } } } diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index 34dc8112d..f14306282 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -11,6 +11,35 @@ using namespace CesiumGltf; +namespace { +void addTextureToModel( + Model& model, + int32_t wrapS, + int32_t wrapT, + int32_t width, + int32_t height, + int32_t channels, + const std::vector& data) { + Image& image = model.images.emplace_back(); + image.cesium.width = width; + image.cesium.height = height; + image.cesium.channels = channels; + image.cesium.bytesPerChannel = 1; + + std::vector& imageData = image.cesium.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + Sampler& sampler = model.samplers.emplace_back(); + sampler.wrapS = wrapS; + sampler.wrapT = wrapT; + + Texture& texture = model.textures.emplace_back(); + texture.sampler = static_cast(model.samplers.size() - 1); + texture.source = static_cast(model.images.size() - 1); +} +} // namespace + TEST_CASE("Test PropertyTextureView on model without EXT_structural_metadata " "extension") { Model model; @@ -29,7 +58,6 @@ TEST_CASE("Test PropertyTextureView on model without EXT_structural_metadata " REQUIRE( view.status() == PropertyTextureViewStatus::ErrorMissingMetadataExtension); - REQUIRE(view.getProperties().empty()); const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); @@ -53,7 +81,6 @@ TEST_CASE("Test PropertyTextureView on model without metadata schema") { PropertyTextureView view(model, propertyTexture); REQUIRE(view.status() == PropertyTextureViewStatus::ErrorMissingSchema); - REQUIRE(view.getProperties().empty()); const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); @@ -83,15 +110,24 @@ TEST_CASE("Test property texture with nonexistent class") { PropertyTextureView view(model, propertyTexture); REQUIRE(view.status() == PropertyTextureViewStatus::ErrorClassNotFound); - REQUIRE(view.getProperties().empty()); const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(!classProperty); } -TEST_CASE("Test property texture with nonexistent class property") { +TEST_CASE("Test scalar PropertyTextureProperty") { Model model; + std::vector data = {12, 34, 30, 11}; + + addTextureToModel( + model, + Sampler::WrapS::CLAMP_TO_EDGE, + Sampler::WrapS::CLAMP_TO_EDGE, + 2, + 2, + 1, + data); ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -106,50 +142,423 @@ TEST_CASE("Test property texture with nonexistent class property") { propertyTexture.classProperty = "TestClass"; PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["I Don't Exist"]; + propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = 0; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; PropertyTextureView view(model, propertyTexture); - REQUIRE( - view.status() == PropertyTextureViewStatus::ErrorClassPropertyNotFound); - REQUIRE(view.getProperties().empty()); + REQUIRE(view.status() == PropertyTextureViewStatus::Valid); const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); - REQUIRE(!classProperty); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(uint8Property.status() == PropertyTexturePropertyViewStatus::Valid); + + std::vector values{ + uint8Property.get(0.0, 0.0), + uint8Property.get(0.5, 0.0), + uint8Property.get(0.0, 0.5), + uint8Property.get(0.5, 0.5), + }; + + for (size_t i = 0; i < values.size(); ++i) { + REQUIRE(values[i] == data[i]); + } + } + + SECTION("Access wrong component type") { + PropertyTexturePropertyView uint16Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint16Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTexturePropertyView int32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + int32Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTexturePropertyView uint64Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint64Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + PropertyTexturePropertyView> arrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } } -TEST_CASE("Test property texture with invalid property is still valid") { +// TEST_CASE( +// "Test PropertyTexturePropertyView on property with invalid texture +// index") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; +// +// PropertyTexture propertyTexture; +// propertyTexture.classProperty = "TestClass"; +// +// PropertyTextureProperty& propertyTextureProperty = +// propertyTexture.properties["TestClassProperty"]; +// propertyTextureProperty.index = -1; +// propertyTextureProperty.texCoord = 0; +// propertyTextureProperty.channels = {0}; +// +// PropertyTexturePropertyView view( +// model, +// testClassProperty, +// propertyTextureProperty); +// REQUIRE( +// view.status() == +// PropertyTexturePropertyViewStatus::ErrorInvalidTexture); +//} +// +// TEST_CASE( +// "Test PropertyTexturePropertyView on property with invalid sampler index") +// { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; +// +// Image& image = model.images.emplace_back(); +// image.cesium.width = 1; +// image.cesium.height = 1; +// Texture& texture = model.textures.emplace_back(); +// texture.sampler = -1; +// texture.source = 0; +// +// PropertyTexture propertyTexture; +// propertyTexture.classProperty = "TestClass"; +// +// PropertyTextureProperty& propertyTextureProperty = +// propertyTexture.properties["TestClassProperty"]; +// propertyTextureProperty.index = 0; +// propertyTextureProperty.texCoord = 0; +// propertyTextureProperty.channels = {0}; +// +// PropertyTexturePropertyView view( +// model, +// testClassProperty, +// propertyTextureProperty); +// REQUIRE( +// view.status() == +// PropertyTexturePropertyViewStatus::ErrorInvalidTextureSampler); +//} +// +// TEST_CASE( +// "Test PropertyTexturePropertyView on property with invalid image index") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; +// +// model.samplers.emplace_back(); +// +// Texture& texture = model.textures.emplace_back(); +// texture.sampler = 0; +// texture.source = -1; +// +// PropertyTexture propertyTexture; +// propertyTexture.classProperty = "TestClass"; +// +// PropertyTextureProperty& propertyTextureProperty = +// propertyTexture.properties["TestClassProperty"]; +// propertyTextureProperty.index = 0; +// propertyTextureProperty.texCoord = 0; +// propertyTextureProperty.channels = {0}; +// +// PropertyTexturePropertyView view( +// model, +// testClassProperty, +// propertyTextureProperty); +// REQUIRE( +// view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidImage); +//} +// +// TEST_CASE("Test PropertyTexturePropertyView on property with empty image") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; +// +// Image& image = model.images.emplace_back(); +// image.cesium.width = 0; +// image.cesium.height = 0; +// +// model.samplers.emplace_back(); +// +// Texture& texture = model.textures.emplace_back(); +// texture.sampler = 0; +// texture.source = 0; +// +// PropertyTexture propertyTexture; +// propertyTexture.classProperty = "TestClass"; +// +// PropertyTextureProperty& propertyTextureProperty = +// propertyTexture.properties["TestClassProperty"]; +// propertyTextureProperty.index = 0; +// propertyTextureProperty.texCoord = 0; +// propertyTextureProperty.channels = {0}; +// +// PropertyTexturePropertyView view( +// model, +// testClassProperty, +// propertyTextureProperty); +// REQUIRE(view.status() == +// PropertyTexturePropertyViewStatus::ErrorEmptyImage); +//} +// +// TEST_CASE("Test PropertyTextureView on property texture property with zero " +// "channels") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; +// +// Image& image = model.images.emplace_back(); +// image.cesium.width = 1; +// image.cesium.height = 1; +// image.cesium.channels = 1; +// +// model.samplers.emplace_back(); +// +// Texture& texture = model.textures.emplace_back(); +// texture.sampler = 0; +// texture.source = 0; +// +// PropertyTexture propertyTexture; +// propertyTexture.classProperty = "TestClass"; +// +// PropertyTextureProperty& propertyTextureProperty = +// propertyTexture.properties["TestClassProperty"]; +// propertyTextureProperty.index = 0; +// propertyTextureProperty.texCoord = 0; +// propertyTextureProperty.channels = {}; +// +// PropertyTexturePropertyView view( +// model, +// testClassProperty, +// propertyTextureProperty); +// REQUIRE( +// view.status() == +// PropertyTexturePropertyViewStatus::ErrorInvalidChannels); +//} +// +// TEST_CASE("Test PropertyTextureView on property texture property with too +// many " +// "channels") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; +// +// Image& image = model.images.emplace_back(); +// image.cesium.width = 1; +// image.cesium.height = 1; +// image.cesium.channels = 1; +// +// model.samplers.emplace_back(); +// +// Texture& texture = model.textures.emplace_back(); +// texture.sampler = 0; +// texture.source = 0; +// +// PropertyTexture propertyTexture; +// propertyTexture.classProperty = "TestClass"; +// +// PropertyTextureProperty& propertyTextureProperty = +// propertyTexture.properties["TestClassProperty"]; +// propertyTextureProperty.index = 0; +// propertyTextureProperty.texCoord = 0; +// propertyTextureProperty.channels = {0, 1}; +// +// PropertyTexturePropertyView view( +// model, +// testClassProperty, +// propertyTextureProperty); +// REQUIRE( +// view.status() == +// PropertyTexturePropertyViewStatus::ErrorInvalidChannels); +//} +// +// TEST_CASE("Test PropertyTextureView on property texture property with " +// "unsupported class property") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; +// +// Image& image = model.images.emplace_back(); +// image.cesium.width = 1; +// image.cesium.height = 1; +// image.cesium.channels = 1; +// +// model.samplers.emplace_back(); +// +// Texture& texture = model.textures.emplace_back(); +// texture.sampler = 0; +// texture.source = 0; +// +// PropertyTexture propertyTexture; +// propertyTexture.classProperty = "TestClass"; +// +// PropertyTextureProperty& propertyTextureProperty = +// propertyTexture.properties["TestClassProperty"]; +// propertyTextureProperty.index = 0; +// propertyTextureProperty.texCoord = 0; +// propertyTextureProperty.channels = {0, 1}; +// +// PropertyTexturePropertyView view( +// model, +// testClassProperty, +// propertyTextureProperty); +// REQUIRE( +// view.status() == +// PropertyTexturePropertyViewStatus::ErrorInvalidChannels); +//} +/* +TEST_CASE("Test PropertyTexturePropertyView on valid property texture") { Model model; - ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + ClassProperty& testClassProperty = +testClass.properties["TestClassProperty"]; testClassProperty.type = +ClassProperty::Type::SCALAR; testClassProperty.componentType = +ClassProperty::ComponentType::UINT8; - PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + Image& image = model.images.emplace_back(); + image.cesium.width = 1; + image.cesium.height = 1; + image.cesium.channels = 1; + + model.samplers.emplace_back(); + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + PropertyTexture propertyTexture; propertyTexture.classProperty = "TestClass"; PropertyTextureProperty& propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = -1; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; - PropertyTextureView view(model, propertyTexture); - REQUIRE(view.status() == PropertyTextureViewStatus::Valid); + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + REQUIRE(view.status() == PropertyTexturePropertyViewStatus::Valid); +} - auto properties = view.getProperties(); - REQUIRE(properties.size() == 1); +TEST_CASE("Test getting value from valid view") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); - PropertyTexturePropertyView& propertyView = properties["TestClassProperty"]; - REQUIRE(propertyView.status() != PropertyTexturePropertyViewStatus::Valid); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = +testClass.properties["TestClassProperty"]; testClassProperty.type = +ClassProperty::Type::SCALAR; testClassProperty.componentType = +ClassProperty::ComponentType::UINT8; - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty == &testClassProperty); -} + std::vector values{10, 8, 4, 22}; + + Image& image = model.images.emplace_back(); + image.cesium.width = 2; + image.cesium.height = 2; + image.cesium.channels = 1; + image.cesium.bytesPerChannel = 1; + image.cesium.pixelData.resize(values.size()); + std::memcpy(image.cesium.pixelData.data(), values.data(), values.size()); + + Sampler& sampler = model.samplers.emplace_back(); + sampler.wrapS = Sampler::WrapS::CLAMP_TO_EDGE; + sampler.wrapT = Sampler::WrapT::CLAMP_TO_EDGE; + + Texture& texture = model.textures.emplace_back(); + texture.sampler = 0; + texture.source = 0; + + PropertyTexture propertyTexture; + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = 0; + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + PropertyTexturePropertyView view( + model, + testClassProperty, + propertyTextureProperty); + + +}*/ diff --git a/CesiumGltf/test/TestPropertyType.cpp b/CesiumGltf/test/TestPropertyType.cpp index 539d01a3b..acca55dd6 100644 --- a/CesiumGltf/test/TestPropertyType.cpp +++ b/CesiumGltf/test/TestPropertyType.cpp @@ -6,236 +6,273 @@ using namespace CesiumGltf; -TEST_CASE("Test PropertyType utilities function") { - SECTION("Convert string to PropertyType") { - REQUIRE( - convertStringToPropertyType(ClassProperty::Type::SCALAR) == - PropertyType::Scalar); - - REQUIRE( - convertStringToPropertyType(ClassProperty::Type::VEC2) == - PropertyType::Vec2); - - REQUIRE( - convertStringToPropertyType(ClassProperty::Type::VEC3) == - PropertyType::Vec3); - - REQUIRE( - convertStringToPropertyType(ClassProperty::Type::VEC4) == - PropertyType::Vec4); - - REQUIRE( - convertStringToPropertyType(ClassProperty::Type::MAT2) == - PropertyType::Mat2); - - REQUIRE( - convertStringToPropertyType(ClassProperty::Type::MAT3) == - PropertyType::Mat3); - - REQUIRE( - convertStringToPropertyType(ClassProperty::Type::MAT4) == - PropertyType::Mat4); - - REQUIRE( - convertStringToPropertyType(ClassProperty::Type::BOOLEAN) == - PropertyType::Boolean); - - REQUIRE( - convertStringToPropertyType(ClassProperty::Type::STRING) == - PropertyType::String); - - REQUIRE( - convertStringToPropertyType(ClassProperty::Type::ENUM) == - PropertyType::Enum); - - REQUIRE(convertStringToPropertyType("invalid") == PropertyType::Invalid); - } - - SECTION("Convert string to PropertyComponentType") { - REQUIRE( - convertStringToPropertyComponentType( - ClassProperty::ComponentType::UINT8) == - PropertyComponentType::Uint8); - - REQUIRE( - convertStringToPropertyComponentType( - ClassProperty::ComponentType::INT8) == PropertyComponentType::Int8); - - REQUIRE( - convertStringToPropertyComponentType( - ClassProperty::ComponentType::UINT16) == - PropertyComponentType::Uint16); - REQUIRE( - convertStringToPropertyComponentType( - ClassProperty::ComponentType::INT16) == - PropertyComponentType::Int16); - - REQUIRE( - convertStringToPropertyComponentType( - ClassProperty::ComponentType::UINT32) == - PropertyComponentType::Uint32); - - REQUIRE( - convertStringToPropertyComponentType( - ClassProperty::ComponentType::INT32) == - PropertyComponentType::Int32); - REQUIRE( - convertStringToPropertyComponentType( - ClassProperty::ComponentType::UINT64) == - PropertyComponentType::Uint64); - - REQUIRE( - convertStringToPropertyComponentType( - ClassProperty::ComponentType::INT64) == - PropertyComponentType::Int64); - - REQUIRE( - convertStringToPropertyComponentType( - ClassProperty::ComponentType::FLOAT32) == - PropertyComponentType::Float32); - REQUIRE( - convertStringToPropertyComponentType( - ClassProperty::ComponentType::FLOAT64) == - PropertyComponentType::Float64); - - REQUIRE( - convertStringToPropertyComponentType("invalid") == - PropertyComponentType::None); - } - - SECTION("Convert PropertyType to string") { - REQUIRE( - convertPropertyTypeToString(PropertyType::Scalar) == - ClassProperty::Type::SCALAR); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Vec2) == - ClassProperty::Type::VEC2); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Vec3) == - ClassProperty::Type::VEC3); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Vec4) == - ClassProperty::Type::VEC4); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Mat2) == - ClassProperty::Type::MAT2); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Mat3) == - ClassProperty::Type::MAT3); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Mat4) == - ClassProperty::Type::MAT4); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Boolean) == - ClassProperty::Type::BOOLEAN); - - REQUIRE( - convertPropertyTypeToString(PropertyType::String) == - ClassProperty::Type::STRING); - - REQUIRE( - convertPropertyTypeToString(PropertyType::Enum) == - ClassProperty::Type::ENUM); - } - - SECTION("Convert PropertyComponentType to string") { - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Uint8) == - ClassProperty::ComponentType::UINT8); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Int8) == - ClassProperty::ComponentType::INT8); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Uint16) == - ClassProperty::ComponentType::UINT16); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Int16) == - ClassProperty::ComponentType::INT16); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Uint32) == - ClassProperty::ComponentType::UINT32); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Int32) == - ClassProperty::ComponentType::INT32); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Uint64) == - ClassProperty::ComponentType::UINT64); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Int64) == - ClassProperty::ComponentType::INT64); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Float32) == - ClassProperty::ComponentType::FLOAT32); - - REQUIRE( - convertPropertyComponentTypeToString(PropertyComponentType::Float64) == - ClassProperty::ComponentType::FLOAT64); - } - - SECTION("Convert array offset type string to PropertyComponentType") { - REQUIRE( - convertArrayOffsetTypeStringToPropertyComponentType( - PropertyTableProperty::ArrayOffsetType::UINT8) == - PropertyComponentType::Uint8); - - REQUIRE( - convertArrayOffsetTypeStringToPropertyComponentType( - PropertyTableProperty::ArrayOffsetType::UINT16) == - PropertyComponentType::Uint16); - - REQUIRE( - convertArrayOffsetTypeStringToPropertyComponentType( - PropertyTableProperty::ArrayOffsetType::UINT32) == - PropertyComponentType::Uint32); - - REQUIRE( - convertArrayOffsetTypeStringToPropertyComponentType( - PropertyTableProperty::ArrayOffsetType::UINT64) == - PropertyComponentType::Uint64); - - REQUIRE( - convertArrayOffsetTypeStringToPropertyComponentType("invalid") == - PropertyComponentType::None); - } - - SECTION("Convert string offset type string to PropertyComponentType") { - REQUIRE( - convertStringOffsetTypeStringToPropertyComponentType( - PropertyTableProperty::StringOffsetType::UINT8) == - PropertyComponentType::Uint8); - - REQUIRE( - convertStringOffsetTypeStringToPropertyComponentType( - PropertyTableProperty::StringOffsetType::UINT16) == - PropertyComponentType::Uint16); - - REQUIRE( - convertStringOffsetTypeStringToPropertyComponentType( - PropertyTableProperty::StringOffsetType::UINT32) == - PropertyComponentType::Uint32); - - REQUIRE( - convertStringOffsetTypeStringToPropertyComponentType( - PropertyTableProperty::StringOffsetType::UINT64) == - PropertyComponentType::Uint64); - - REQUIRE( - convertStringOffsetTypeStringToPropertyComponentType("invalid") == - PropertyComponentType::None); - } +TEST_CASE("Test convertStringToPropertyType") { + REQUIRE( + convertStringToPropertyType(ClassProperty::Type::SCALAR) == + PropertyType::Scalar); + + REQUIRE( + convertStringToPropertyType(ClassProperty::Type::VEC2) == + PropertyType::Vec2); + + REQUIRE( + convertStringToPropertyType(ClassProperty::Type::VEC3) == + PropertyType::Vec3); + + REQUIRE( + convertStringToPropertyType(ClassProperty::Type::VEC4) == + PropertyType::Vec4); + + REQUIRE( + convertStringToPropertyType(ClassProperty::Type::MAT2) == + PropertyType::Mat2); + + REQUIRE( + convertStringToPropertyType(ClassProperty::Type::MAT3) == + PropertyType::Mat3); + + REQUIRE( + convertStringToPropertyType(ClassProperty::Type::MAT4) == + PropertyType::Mat4); + + REQUIRE( + convertStringToPropertyType(ClassProperty::Type::BOOLEAN) == + PropertyType::Boolean); + + REQUIRE( + convertStringToPropertyType(ClassProperty::Type::STRING) == + PropertyType::String); + + REQUIRE( + convertStringToPropertyType(ClassProperty::Type::ENUM) == + PropertyType::Enum); + + REQUIRE(convertStringToPropertyType("invalid") == PropertyType::Invalid); +} + +TEST_CASE("Test convertStringToPropertyComponentType") { + REQUIRE( + convertStringToPropertyComponentType( + ClassProperty::ComponentType::UINT8) == PropertyComponentType::Uint8); + + REQUIRE( + convertStringToPropertyComponentType( + ClassProperty::ComponentType::INT8) == PropertyComponentType::Int8); + + REQUIRE( + convertStringToPropertyComponentType( + ClassProperty::ComponentType::UINT16) == + PropertyComponentType::Uint16); + REQUIRE( + convertStringToPropertyComponentType( + ClassProperty::ComponentType::INT16) == PropertyComponentType::Int16); + + REQUIRE( + convertStringToPropertyComponentType( + ClassProperty::ComponentType::UINT32) == + PropertyComponentType::Uint32); + + REQUIRE( + convertStringToPropertyComponentType( + ClassProperty::ComponentType::INT32) == PropertyComponentType::Int32); + REQUIRE( + convertStringToPropertyComponentType( + ClassProperty::ComponentType::UINT64) == + PropertyComponentType::Uint64); + + REQUIRE( + convertStringToPropertyComponentType( + ClassProperty::ComponentType::INT64) == PropertyComponentType::Int64); + + REQUIRE( + convertStringToPropertyComponentType( + ClassProperty::ComponentType::FLOAT32) == + PropertyComponentType::Float32); + REQUIRE( + convertStringToPropertyComponentType( + ClassProperty::ComponentType::FLOAT64) == + PropertyComponentType::Float64); + + REQUIRE( + convertStringToPropertyComponentType("invalid") == + PropertyComponentType::None); +} + +TEST_CASE("Test convertPropertyTypeToString") { + REQUIRE( + convertPropertyTypeToString(PropertyType::Scalar) == + ClassProperty::Type::SCALAR); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Vec2) == + ClassProperty::Type::VEC2); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Vec3) == + ClassProperty::Type::VEC3); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Vec4) == + ClassProperty::Type::VEC4); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Mat2) == + ClassProperty::Type::MAT2); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Mat3) == + ClassProperty::Type::MAT3); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Mat4) == + ClassProperty::Type::MAT4); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Boolean) == + ClassProperty::Type::BOOLEAN); + + REQUIRE( + convertPropertyTypeToString(PropertyType::String) == + ClassProperty::Type::STRING); + + REQUIRE( + convertPropertyTypeToString(PropertyType::Enum) == + ClassProperty::Type::ENUM); +} + +TEST_CASE("Test convertPropertyComponentTypeToString") { + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint8) == + ClassProperty::ComponentType::UINT8); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int8) == + ClassProperty::ComponentType::INT8); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint16) == + ClassProperty::ComponentType::UINT16); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int16) == + ClassProperty::ComponentType::INT16); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint32) == + ClassProperty::ComponentType::UINT32); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int32) == + ClassProperty::ComponentType::INT32); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Uint64) == + ClassProperty::ComponentType::UINT64); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Int64) == + ClassProperty::ComponentType::INT64); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Float32) == + ClassProperty::ComponentType::FLOAT32); + + REQUIRE( + convertPropertyComponentTypeToString(PropertyComponentType::Float64) == + ClassProperty::ComponentType::FLOAT64); +} + +TEST_CASE("Test convertArrayOffsetTypeStringToPropertyComponentType") { + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + PropertyTableProperty::ArrayOffsetType::UINT8) == + PropertyComponentType::Uint8); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + PropertyTableProperty::ArrayOffsetType::UINT16) == + PropertyComponentType::Uint16); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + PropertyTableProperty::ArrayOffsetType::UINT32) == + PropertyComponentType::Uint32); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType( + PropertyTableProperty::ArrayOffsetType::UINT64) == + PropertyComponentType::Uint64); + + REQUIRE( + convertArrayOffsetTypeStringToPropertyComponentType("invalid") == + PropertyComponentType::None); +} + +TEST_CASE("Test convertStringOffsetTypeStringToPropertyComponentType") { + REQUIRE( + convertStringOffsetTypeStringToPropertyComponentType( + PropertyTableProperty::StringOffsetType::UINT8) == + PropertyComponentType::Uint8); + + REQUIRE( + convertStringOffsetTypeStringToPropertyComponentType( + PropertyTableProperty::StringOffsetType::UINT16) == + PropertyComponentType::Uint16); + + REQUIRE( + convertStringOffsetTypeStringToPropertyComponentType( + PropertyTableProperty::StringOffsetType::UINT32) == + PropertyComponentType::Uint32); + + REQUIRE( + convertStringOffsetTypeStringToPropertyComponentType( + PropertyTableProperty::StringOffsetType::UINT64) == + PropertyComponentType::Uint64); + + REQUIRE( + convertStringOffsetTypeStringToPropertyComponentType("invalid") == + PropertyComponentType::None); +} + +TEST_CASE("Test getDimensionsFromPropertyType") { + REQUIRE(getDimensionsFromPropertyType(PropertyType::Scalar) == 1); + + REQUIRE(getDimensionsFromPropertyType(PropertyType::Vec2) == 2); + REQUIRE(getDimensionsFromPropertyType(PropertyType::Vec3) == 3); + REQUIRE(getDimensionsFromPropertyType(PropertyType::Vec4) == 4); + + REQUIRE(getDimensionsFromPropertyType(PropertyType::Mat2) == 2); + REQUIRE(getDimensionsFromPropertyType(PropertyType::Mat3) == 3); + REQUIRE(getDimensionsFromPropertyType(PropertyType::Mat4) == 4); + + REQUIRE(getDimensionsFromPropertyType(PropertyType::Boolean) == 0); + REQUIRE(getDimensionsFromPropertyType(PropertyType::String) == 0); + REQUIRE(getDimensionsFromPropertyType(PropertyType::Enum) == 0); + REQUIRE(getDimensionsFromPropertyType(PropertyType::Invalid) == 0); +} + +TEST_CASE("Test getSizeOfComponentType") { + REQUIRE( + getSizeOfComponentType(PropertyComponentType::Int8) == sizeof(int8_t)); + REQUIRE( + getSizeOfComponentType(PropertyComponentType::Uint8) == sizeof(uint8_t)); + REQUIRE( + getSizeOfComponentType(PropertyComponentType::Int16) == sizeof(int16_t)); + REQUIRE( + getSizeOfComponentType(PropertyComponentType::Uint16) == + sizeof(uint16_t)); + REQUIRE( + getSizeOfComponentType(PropertyComponentType::Int32) == sizeof(int32_t)); + REQUIRE( + getSizeOfComponentType(PropertyComponentType::Uint32) == + sizeof(uint32_t)); + REQUIRE( + getSizeOfComponentType(PropertyComponentType::Int64) == sizeof(int64_t)); + REQUIRE( + getSizeOfComponentType(PropertyComponentType::Uint64) == + sizeof(uint64_t)); + REQUIRE( + getSizeOfComponentType(PropertyComponentType::Float32) == sizeof(float)); + REQUIRE( + getSizeOfComponentType(PropertyComponentType::Float64) == sizeof(double)); } From 8155617808483a8cdf9239dc420b009d4e79def4 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 29 Jun 2023 14:49:12 -0400 Subject: [PATCH 065/121] Add tests for templated getPropertyView --- .../CesiumGltf/PropertyTexturePropertyView.h | 11 +- .../include/CesiumGltf/PropertyTextureView.h | 25 +- CesiumGltf/src/PropertyTextureView.cpp | 8 +- CesiumGltf/test/TestPropertyTableView.cpp | 32 +- .../test/TestPropertyTexturePropertyView.cpp | 2 +- CesiumGltf/test/TestPropertyTextureView.cpp | 769 ++++++++++-------- 6 files changed, 481 insertions(+), 366 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index c843781d2..7adb05fa8 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -87,18 +87,13 @@ enum class PropertyTexturePropertyViewStatus { /** * @brief The channels of this property texture property are invalid. - * Channels must be in the range 0-3, with a minimum of one channel. Although + * 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 view only supports a maximum of four channels. + * formats, this implementation only supports four channels max. */ ErrorInvalidChannels, - /** - * @brief This property texture property is trying to sample channels that - * don't exist in the image. - */ - ErrorTooManyChannels, - /** * @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 diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 1ac63f84d..f6a7c0ded 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -129,6 +129,7 @@ class PropertyTextureView { classProperty, propertyTextureProperty); } else if constexpr (IsMetadataVecN::value) { + return createVecNPropertyView(classProperty, propertyTextureProperty); } else if constexpr (IsMetadataArray::value) { return createArrayPropertyView::type>( classProperty, @@ -168,12 +169,12 @@ class PropertyTextureView { std::is_same_v) { return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } else { + return createPropertyViewImpl( + classProperty, + propertyTextureProperty, + sizeof(T)); } - - return createPropertyViewImpl( - classProperty, - propertyTextureProperty, - sizeof(T)); } template @@ -199,15 +200,11 @@ class PropertyTextureView { PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } - // Only uint8 and uint16s are supported. - if (componentType != PropertyComponentType::Uint8 && - componentType != PropertyComponentType::Uint16) { - return PropertyTexturePropertyView( - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - } - // Only up to four bytes of image data are supported. - if (sizeof(T) > 4) { + size_t dimensions = + static_cast(getDimensionsFromPropertyType(type)); + + if (dimensions * getSizeOfComponentType(componentType) > 4) { return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); } @@ -292,7 +289,7 @@ class PropertyTextureView { return PropertyTexturePropertyView(status); } - status = checkImage(samplerIndex); + status = checkImage(imageIndex); if (status != PropertyTexturePropertyViewStatus::Valid) { return PropertyTexturePropertyView(status); } diff --git a/CesiumGltf/src/PropertyTextureView.cpp b/CesiumGltf/src/PropertyTextureView.cpp index 24c9d10ff..d92c00bc2 100644 --- a/CesiumGltf/src/PropertyTextureView.cpp +++ b/CesiumGltf/src/PropertyTextureView.cpp @@ -97,6 +97,10 @@ PropertyTextureView::checkImage(const int32_t imageIndex) const noexcept { PropertyTexturePropertyViewStatus PropertyTextureView::checkChannels( const std::vector& channels, const ImageCesium& image) const noexcept { + if (channels.size() <= 0 || channels.size() > 4) { + return PropertyTexturePropertyViewStatus::ErrorInvalidChannels; + } + int64_t imageChannelCount = static_cast(image.channels); for (size_t i = 0; i < channels.size(); i++) { if (channels[i] < 0 || channels[i] >= imageChannelCount) { @@ -104,10 +108,6 @@ PropertyTexturePropertyViewStatus PropertyTextureView::checkChannels( } } - if (static_cast(imageChannelCount) < channels.size()) { - return PropertyTexturePropertyViewStatus::ErrorTooManyChannels; - } - return PropertyTexturePropertyViewStatus::Valid; } diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index df8fc0a28..4a625a350 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -97,7 +97,7 @@ TEST_CASE("Test property table with nonexistent class") { REQUIRE(!classProperty); } -TEST_CASE("Test scalar property") { +TEST_CASE("Test scalar PropertyTableProperty") { Model model; std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; @@ -247,7 +247,7 @@ TEST_CASE("Test scalar property") { } } -TEST_CASE("Test vecN property") { +TEST_CASE("Test vecN PropertyTableProperty") { Model model; std::vector values = { glm::ivec3(-12, 34, 30), @@ -408,7 +408,7 @@ TEST_CASE("Test vecN property") { } } -TEST_CASE("Test matN property") { +TEST_CASE("Test matN PropertyTableProperty") { Model model; // clang-format off std::vector values = { @@ -583,7 +583,7 @@ TEST_CASE("Test matN property") { } } -TEST_CASE("Test boolean property") { +TEST_CASE("Test boolean PropertyTableProperty") { Model model; int64_t instanceCount = 21; @@ -656,7 +656,7 @@ TEST_CASE("Test boolean property") { } } -TEST_CASE("Test string property") { +TEST_CASE("Test string PropertyTableProperty") { Model model; std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; @@ -2376,7 +2376,7 @@ TEST_CASE("Test callback on invalid property table view") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for invalid property") { +TEST_CASE("Test callback for invalid PropertyTableProperty") { Model model; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2420,7 +2420,7 @@ TEST_CASE("Test callback for invalid property") { REQUIRE(invokedCallbackCount == 2); } -TEST_CASE("Test callback for scalar property") { +TEST_CASE("Test callback for scalar PropertyTableProperty") { Model model; std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; @@ -2485,7 +2485,7 @@ TEST_CASE("Test callback for scalar property") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for vecN property") { +TEST_CASE("Test callback for vecN PropertyTableProperty") { Model model; std::vector values = { glm::ivec3(-12, 34, 30), @@ -2554,7 +2554,7 @@ TEST_CASE("Test callback for vecN property") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for matN property") { +TEST_CASE("Test callback for matN PropertyTableProperty") { Model model; // clang-format off std::vector values = { @@ -2633,7 +2633,7 @@ TEST_CASE("Test callback for matN property") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for boolean property") { +TEST_CASE("Test callback for boolean PropertyTableProperty") { Model model; int64_t instanceCount = 21; @@ -2715,7 +2715,7 @@ TEST_CASE("Test callback for boolean property") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for string property") { +TEST_CASE("Test callback for string PropertyTableProperty") { Model model; std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; @@ -2805,7 +2805,7 @@ TEST_CASE("Test callback for string property") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for scalar array") { +TEST_CASE("Test callback for scalar array PropertyTableProperty") { Model model; std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; @@ -2876,7 +2876,7 @@ TEST_CASE("Test callback for scalar array") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for vecN array") { +TEST_CASE("Test callback for vecN array PropertyTableProperty") { Model model; std::vector values = { glm::ivec3(12, 34, -30), @@ -2953,7 +2953,7 @@ TEST_CASE("Test callback for vecN array") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for matN array") { +TEST_CASE("Test callback for matN array PropertyTableProperty") { Model model; // clang-format off std::vector values = { @@ -3044,7 +3044,7 @@ TEST_CASE("Test callback for matN array") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for boolean array") { +TEST_CASE("Test callback for boolean array PropertyTableProperty") { Model model; std::vector expected = { @@ -3135,7 +3135,7 @@ TEST_CASE("Test callback for boolean array") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for array of strings") { +TEST_CASE("Test callback for string array PropertyTableProperty") { Model model; std::vector expected{ diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index 4b54c49b8..947b3b4c8 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -624,7 +624,7 @@ TEST_CASE("Check array PropertyTexturePropertyView") { view.get(0, 0.5), view.get(0.5, 0.5)}; - for (size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < values.size(); i++) { auto dataStart = data.begin() + i * 4; std::vector expected(dataStart, dataStart + 4); const PropertyArrayView& value = values[i]; diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index f14306282..8db375f17 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -128,6 +128,8 @@ TEST_CASE("Test scalar PropertyTextureProperty") { 2, 1, data); + size_t textureIndex = model.textures.size() - 1; + size_t imageIndex = model.images.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -143,7 +145,7 @@ TEST_CASE("Test scalar PropertyTextureProperty") { PropertyTextureProperty& propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; + propertyTextureProperty.index = static_cast(textureIndex); propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; @@ -175,6 +177,14 @@ TEST_CASE("Test scalar PropertyTextureProperty") { } } + SECTION("Access wrong type") { + PropertyTexturePropertyView u8vec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec2Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorTypeMismatch); + } + SECTION("Access wrong component type") { PropertyTexturePropertyView uint16Invalid = view.getPropertyView("TestClassProperty"); @@ -202,351 +212,369 @@ TEST_CASE("Test scalar PropertyTextureProperty") { arrayInvalid.status() == PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); } + + SECTION("Channel and type mismatch") { + model.images[imageIndex].cesium.channels = 2; + propertyTextureProperty.channels = {0, 1}; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch); + } + + SECTION("Invalid channel values") { + propertyTextureProperty.channels = {5}; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidChannels); + } + + SECTION("Zero channel values") { + propertyTextureProperty.channels.clear(); + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidChannels); + } + + SECTION("Invalid bytes per channel") { + model.images[imageIndex].cesium.bytesPerChannel = 2; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); + } + + SECTION("Empty image") { + model.images[imageIndex].cesium.width = 0; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorEmptyImage); + } + + SECTION("Wrong image index") { + model.textures[textureIndex].source = 1; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidImage); + } + + SECTION("Wrong sampler index") { + model.textures[textureIndex].sampler = 1; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidSampler); + } + + SECTION("Wrong texture index") { + propertyTextureProperty.index = 1; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidTexture); + } } -// TEST_CASE( -// "Test PropertyTexturePropertyView on property with invalid texture -// index") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; -// -// PropertyTexture propertyTexture; -// propertyTexture.classProperty = "TestClass"; -// -// PropertyTextureProperty& propertyTextureProperty = -// propertyTexture.properties["TestClassProperty"]; -// propertyTextureProperty.index = -1; -// propertyTextureProperty.texCoord = 0; -// propertyTextureProperty.channels = {0}; -// -// PropertyTexturePropertyView view( -// model, -// testClassProperty, -// propertyTextureProperty); -// REQUIRE( -// view.status() == -// PropertyTexturePropertyViewStatus::ErrorInvalidTexture); -//} -// -// TEST_CASE( -// "Test PropertyTexturePropertyView on property with invalid sampler index") -// { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; -// -// Image& image = model.images.emplace_back(); -// image.cesium.width = 1; -// image.cesium.height = 1; -// Texture& texture = model.textures.emplace_back(); -// texture.sampler = -1; -// texture.source = 0; -// -// PropertyTexture propertyTexture; -// propertyTexture.classProperty = "TestClass"; -// -// PropertyTextureProperty& propertyTextureProperty = -// propertyTexture.properties["TestClassProperty"]; -// propertyTextureProperty.index = 0; -// propertyTextureProperty.texCoord = 0; -// propertyTextureProperty.channels = {0}; -// -// PropertyTexturePropertyView view( -// model, -// testClassProperty, -// propertyTextureProperty); -// REQUIRE( -// view.status() == -// PropertyTexturePropertyViewStatus::ErrorInvalidTextureSampler); -//} -// -// TEST_CASE( -// "Test PropertyTexturePropertyView on property with invalid image index") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; -// -// model.samplers.emplace_back(); -// -// Texture& texture = model.textures.emplace_back(); -// texture.sampler = 0; -// texture.source = -1; -// -// PropertyTexture propertyTexture; -// propertyTexture.classProperty = "TestClass"; -// -// PropertyTextureProperty& propertyTextureProperty = -// propertyTexture.properties["TestClassProperty"]; -// propertyTextureProperty.index = 0; -// propertyTextureProperty.texCoord = 0; -// propertyTextureProperty.channels = {0}; -// -// PropertyTexturePropertyView view( -// model, -// testClassProperty, -// propertyTextureProperty); -// REQUIRE( -// view.status() == PropertyTexturePropertyViewStatus::ErrorInvalidImage); -//} -// -// TEST_CASE("Test PropertyTexturePropertyView on property with empty image") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; -// -// Image& image = model.images.emplace_back(); -// image.cesium.width = 0; -// image.cesium.height = 0; -// -// model.samplers.emplace_back(); -// -// Texture& texture = model.textures.emplace_back(); -// texture.sampler = 0; -// texture.source = 0; -// -// PropertyTexture propertyTexture; -// propertyTexture.classProperty = "TestClass"; -// -// PropertyTextureProperty& propertyTextureProperty = -// propertyTexture.properties["TestClassProperty"]; -// propertyTextureProperty.index = 0; -// propertyTextureProperty.texCoord = 0; -// propertyTextureProperty.channels = {0}; -// -// PropertyTexturePropertyView view( -// model, -// testClassProperty, -// propertyTextureProperty); -// REQUIRE(view.status() == -// PropertyTexturePropertyViewStatus::ErrorEmptyImage); -//} -// -// TEST_CASE("Test PropertyTextureView on property texture property with zero " -// "channels") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; -// -// Image& image = model.images.emplace_back(); -// image.cesium.width = 1; -// image.cesium.height = 1; -// image.cesium.channels = 1; -// -// model.samplers.emplace_back(); -// -// Texture& texture = model.textures.emplace_back(); -// texture.sampler = 0; -// texture.source = 0; -// -// PropertyTexture propertyTexture; -// propertyTexture.classProperty = "TestClass"; -// -// PropertyTextureProperty& propertyTextureProperty = -// propertyTexture.properties["TestClassProperty"]; -// propertyTextureProperty.index = 0; -// propertyTextureProperty.texCoord = 0; -// propertyTextureProperty.channels = {}; -// -// PropertyTexturePropertyView view( -// model, -// testClassProperty, -// propertyTextureProperty); -// REQUIRE( -// view.status() == -// PropertyTexturePropertyViewStatus::ErrorInvalidChannels); -//} -// -// TEST_CASE("Test PropertyTextureView on property texture property with too -// many " -// "channels") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; -// -// Image& image = model.images.emplace_back(); -// image.cesium.width = 1; -// image.cesium.height = 1; -// image.cesium.channels = 1; -// -// model.samplers.emplace_back(); -// -// Texture& texture = model.textures.emplace_back(); -// texture.sampler = 0; -// texture.source = 0; -// -// PropertyTexture propertyTexture; -// propertyTexture.classProperty = "TestClass"; -// -// PropertyTextureProperty& propertyTextureProperty = -// propertyTexture.properties["TestClassProperty"]; -// propertyTextureProperty.index = 0; -// propertyTextureProperty.texCoord = 0; -// propertyTextureProperty.channels = {0, 1}; -// -// PropertyTexturePropertyView view( -// model, -// testClassProperty, -// propertyTextureProperty); -// REQUIRE( -// view.status() == -// PropertyTexturePropertyViewStatus::ErrorInvalidChannels); -//} -// -// TEST_CASE("Test PropertyTextureView on property texture property with " -// "unsupported class property") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; -// -// Image& image = model.images.emplace_back(); -// image.cesium.width = 1; -// image.cesium.height = 1; -// image.cesium.channels = 1; -// -// model.samplers.emplace_back(); -// -// Texture& texture = model.textures.emplace_back(); -// texture.sampler = 0; -// texture.source = 0; -// -// PropertyTexture propertyTexture; -// propertyTexture.classProperty = "TestClass"; -// -// PropertyTextureProperty& propertyTextureProperty = -// propertyTexture.properties["TestClassProperty"]; -// propertyTextureProperty.index = 0; -// propertyTextureProperty.texCoord = 0; -// propertyTextureProperty.channels = {0, 1}; -// -// PropertyTexturePropertyView view( -// model, -// testClassProperty, -// propertyTextureProperty); -// REQUIRE( -// view.status() == -// PropertyTexturePropertyViewStatus::ErrorInvalidChannels); -//} -/* -TEST_CASE("Test PropertyTexturePropertyView on valid property texture") { +TEST_CASE("Test vecN PropertyTextureProperty") { Model model; + std::vector data = {12, 34, 10, 3, 40, 0, 30, 11}; + + addTextureToModel( + model, + Sampler::WrapS::CLAMP_TO_EDGE, + Sampler::WrapS::CLAMP_TO_EDGE, + 2, + 2, + 2, + data); + size_t textureIndex = model.textures.size() - 1; + size_t imageIndex = model.images.size() - 1; + ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = -testClass.properties["TestClassProperty"]; testClassProperty.type = -ClassProperty::Type::SCALAR; testClassProperty.componentType = -ClassProperty::ComponentType::UINT8; - - Image& image = model.images.emplace_back(); - image.cesium.width = 1; - image.cesium.height = 1; - image.cesium.channels = 1; - - model.samplers.emplace_back(); - - Texture& texture = model.textures.emplace_back(); - texture.sampler = 0; - texture.source = 0; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - PropertyTexture propertyTexture; + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); propertyTexture.classProperty = "TestClass"; PropertyTextureProperty& propertyTextureProperty = propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; + propertyTextureProperty.index = static_cast(textureIndex); propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0}; + propertyTextureProperty.channels = {0, 1}; - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); - REQUIRE(view.status() == PropertyTexturePropertyViewStatus::Valid); + 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::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + PropertyTexturePropertyView u8vec2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec2Property.status() == PropertyTexturePropertyViewStatus::Valid); + + std::vector expected{ + glm::u8vec2(12, 34), + glm::u8vec2(10, 3), + glm::u8vec2(40, 0), + glm::u8vec2(30, 11)}; + std::vector values{ + u8vec2Property.get(0.0, 0.0), + u8vec2Property.get(0.5, 0.0), + u8vec2Property.get(0.0, 0.5), + u8vec2Property.get(0.5, 0.5), + }; + for (size_t i = 0; i < values.size(); ++i) { + REQUIRE(values[i] == expected[i]); + } + } + + SECTION("Access wrong type") { + PropertyTexturePropertyView uint8Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorTypeMismatch); + + PropertyTexturePropertyView u8vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec3Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyTexturePropertyView u16vec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u16vec2Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTexturePropertyView i8vec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i8vec2Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + PropertyTexturePropertyView> arrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Channel and type mismatch") { + model.images[imageIndex].cesium.channels = 4; + propertyTextureProperty.channels = {0, 1, 2, 3}; + PropertyTexturePropertyView u8vec2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec2Property.status() == + PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch); + } + + SECTION("Invalid channel values") { + propertyTextureProperty.channels = {0, 4}; + PropertyTexturePropertyView u8vec2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec2Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidChannels); + } + + SECTION("Invalid bytes per channel") { + model.images[imageIndex].cesium.bytesPerChannel = 2; + PropertyTexturePropertyView u8vec2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec2Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); + } } -TEST_CASE("Test getting value from valid view") { +TEST_CASE("Test array PropertyTextureProperty") { Model model; + // clang-format off + std::vector data = { + 12, 34, 10, + 40, 0, 30, + 80, 4, 2, + 6, 3, 4, + }; + // clang-format on + + addTextureToModel( + model, + Sampler::WrapS::CLAMP_TO_EDGE, + Sampler::WrapS::CLAMP_TO_EDGE, + 2, + 2, + 3, + data); + size_t textureIndex = model.textures.size() - 1; + size_t imageIndex = model.images.size() - 1; + ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = -testClass.properties["TestClassProperty"]; testClassProperty.type = -ClassProperty::Type::SCALAR; testClassProperty.componentType = -ClassProperty::ComponentType::UINT8; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.array = true; + testClassProperty.count = 3; - std::vector values{10, 8, 4, 22}; + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; - Image& image = model.images.emplace_back(); - image.cesium.width = 2; - image.cesium.height = 2; - image.cesium.channels = 1; - image.cesium.bytesPerChannel = 1; - image.cesium.pixelData.resize(values.size()); - std::memcpy(image.cesium.pixelData.data(), values.data(), values.size()); + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(textureIndex); + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0, 1, 2}; - Sampler& sampler = model.samplers.emplace_back(); - sampler.wrapS = Sampler::WrapS::CLAMP_TO_EDGE; - sampler.wrapT = Sampler::WrapT::CLAMP_TO_EDGE; + PropertyTextureView view(model, propertyTexture); + REQUIRE(view.status() == PropertyTextureViewStatus::Valid); - Texture& texture = model.textures.emplace_back(); - texture.sampler = 0; - texture.source = 0; + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); - PropertyTexture propertyTexture; + SECTION("Access correct type") { + PropertyTexturePropertyView> uint8ArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::Valid); + + std::vector> values{ + uint8ArrayProperty.get(0.0, 0.0), + uint8ArrayProperty.get(0.5, 0.0), + uint8ArrayProperty.get(0.0, 0.5), + uint8ArrayProperty.get(0.5, 0.5), + }; + + for (size_t i = 0; i < values.size(); ++i) { + auto dataStart = data.begin() + i * 3; + std::vector expected(dataStart, dataStart + 3); + const PropertyArrayView& value = values[i]; + REQUIRE(static_cast(value.size()) == expected.size()); + for (size_t j = 0; j < expected.size(); j++) { + REQUIRE(value[j] == expected[j]); + } + } + } + + SECTION("Access wrong type") { + PropertyTexturePropertyView> + u8vec3ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + u8vec3ArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyTexturePropertyView> int8ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + int8ArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTexturePropertyView> + uint16ArrayInvalid = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + uint16ArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as non-array") { + PropertyTexturePropertyView uint8Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + + PropertyTexturePropertyView u8vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec3Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Channel and type mismatch") { + model.images[imageIndex].cesium.channels = 4; + propertyTextureProperty.channels = {0, 1, 2, 3}; + PropertyTexturePropertyView> uint8ArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch); + } + + SECTION("Invalid channel values") { + propertyTextureProperty.channels = {0, 4, 1}; + PropertyTexturePropertyView> uint8ArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidChannels); + } + + SECTION("Invalid bytes per channel") { + model.images[imageIndex].cesium.bytesPerChannel = 2; + PropertyTexturePropertyView> uint8ArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); + } +} + +TEST_CASE("Test unsupported PropertyTextureProperty classes") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); propertyTexture.classProperty = "TestClass"; PropertyTextureProperty& propertyTextureProperty = @@ -555,10 +583,105 @@ ClassProperty::ComponentType::UINT8; propertyTextureProperty.texCoord = 0; propertyTextureProperty.channels = {0}; - PropertyTexturePropertyView view( - model, - testClassProperty, - propertyTextureProperty); + PropertyTextureView view(model, propertyTexture); + REQUIRE(view.status() == PropertyTextureViewStatus::Valid); + + SECTION("Unsupported types") { + testClassProperty.type = ClassProperty::Type::BOOLEAN; + PropertyTexturePropertyView boolInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + + testClassProperty.type = ClassProperty::Type::STRING; + PropertyTexturePropertyView stringInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + + testClassProperty.type = ClassProperty::Type::MAT2; + PropertyTexturePropertyView mat2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + mat2Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } + SECTION("Unsupported component types") { + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::FLOAT64; + PropertyTexturePropertyView doubleInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + doubleInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); -}*/ + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT64; + PropertyTexturePropertyView uint64Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint64Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + + testClassProperty.type = ClassProperty::Type::VEC2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + PropertyTexturePropertyView ivec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec2Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::UINT16; + PropertyTexturePropertyView u16vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u16vec3Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } + + SECTION("Unsupported array types") { + testClassProperty.array = true; + + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.count = 5; + PropertyTexturePropertyView> bigArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + bigArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + + testClassProperty.count = std::nullopt; + PropertyTexturePropertyView> + variableArrayInvalid = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + variableArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + + testClassProperty.type = ClassProperty::Type::VEC2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.count = 2; + PropertyTexturePropertyView> + uvec2ArrayInvalid = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + uvec2ArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.count = 1; + PropertyTexturePropertyView> + u8vec3ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + u8vec3ArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } +} From f3ecde1681a19a4c6598073809668377bb006a7c Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 29 Jun 2023 16:51:07 -0400 Subject: [PATCH 066/121] Add callbacks and tests --- CHANGES.md | 12 +- .../include/CesiumGltf/PropertyTextureView.h | 322 ++++++++++++++++- CesiumGltf/test/TestPropertyTextureView.cpp | 338 ++++++++++++++++++ 3 files changed, 652 insertions(+), 20 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 307298603..91672f6d1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index f6a7c0ded..b622cb4c9 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -84,12 +84,11 @@ class PropertyTextureView { * 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 @@ -109,6 +108,104 @@ class PropertyTextureView { return getPropertyViewImpl(propertyName, *pClassProperty); } + /** + * @brief Gets a {@link PropertyTexturePropertyView} through a callback that accepts a + * property name and a {@link PropertyTexturePropertyView} 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} + */ + template + void + getPropertyView(const std::string& propertyName, Callback&& callback) const { + if (this->_status != PropertyTextureViewStatus::Valid) { + callback( + propertyName, + PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorInvalidPropertyTexture)); + return; + } + + const ClassProperty* pClassProperty = getClassProperty(propertyName); + if (!pClassProperty) { + callback( + propertyName, + PropertyTexturePropertyView( + 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)); + } else if (type == PropertyType::Scalar) { + getScalarPropertyViewImpl( + propertyName, + *pClassProperty, + componentType, + std::forward(callback)); + } else if (isPropertyTypeVecN(type)) { + getVecNPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } else { + callback( + propertyName, + PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + return; + } + } + + /** + * @brief Iterates over each property in the {@link PropertyTexture} with a callback + * that accepts a property name and a {@link PropertyTexturePropertyView} 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} + */ + template void forEachProperty(Callback&& callback) const { + for (const auto& property : this->_pClass->properties) { + getPropertyView(property.first, std::forward(callback)); + } + } + private: template PropertyTexturePropertyView getPropertyViewImpl( @@ -140,6 +237,200 @@ class PropertyTextureView { } } + template + 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( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + } + + int64_t count = classProperty.count.value_or(0); + if (count <= 0 || count > 4) { + callback( + propertyName, + PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + } + + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint8: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + default: + callback( + propertyName, + PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + } + } + + template + void getScalarPropertyViewImpl( + const std::string& propertyName, + const ClassProperty& classProperty, + PropertyComponentType componentType, + Callback&& callback) const { + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + return; + case PropertyComponentType::Uint8: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + return; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + return; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Int32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Uint32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + case PropertyComponentType::Float32: + callback( + propertyName, + getPropertyViewImpl(propertyName, classProperty)); + break; + default: + callback( + propertyName, + PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + break; + } + } + + template + void getVecNPropertyViewImpl( + const std::string& propertyName, + const ClassProperty& classProperty, + PropertyComponentType componentType, + Callback&& callback) const { + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint8: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + default: + callback( + propertyName, + PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + break; + } + } + + template + 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( + propertyName, + classProperty, + componentType, + std::forward(callback)); + break; + case 3: + getVecNPropertyViewImpl( + propertyName, + classProperty, + componentType, + std::forward(callback)); + break; + case 4: + getVecNPropertyViewImpl( + propertyName, + classProperty, + componentType, + std::forward(callback)); + break; + default: + callback( + propertyName, + PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorTypeMismatch)); + break; + } + } + template PropertyTexturePropertyView createScalarPropertyView( const ClassProperty& classProperty, @@ -164,17 +455,16 @@ class PropertyTextureView { } // Eight-byte scalar types are unsupported. - if constexpr ( - std::is_same_v || std::is_same_v || - std::is_same_v) { + size_t componentSize = getSizeOfComponentType(componentType); + if (componentSize == 0 || componentSize > 4) { return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - } else { - return createPropertyViewImpl( - classProperty, - propertyTextureProperty, - sizeof(T)); } + + return createPropertyViewImpl( + classProperty, + propertyTextureProperty, + sizeof(T)); } template @@ -251,14 +541,14 @@ class PropertyTextureView { 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>( PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); } - if (componentType == PropertyComponentType::Uint16 && count > 2) { + if (componentSize * count > 4) { return PropertyTexturePropertyView>( PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); } diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index 8db375f17..095b17ddf 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -565,6 +565,344 @@ TEST_CASE("Test array PropertyTextureProperty") { } } +TEST_CASE("Test callback on invalid property texture view") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + 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(); + + 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 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(); + + 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(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 expected{-1, 268, 542, -256}; + std::vector 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, + 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 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(); + + 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(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 expected{ + glm::i8vec2(-1, -1), + glm::i8vec2(12, 1), + glm::i8vec2(30, 2), + glm::i8vec2(0, -1)}; + std::vector 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, + 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 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(); + + 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(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> expected{ + {254, 509}, + {522, 808}, + {30, 512}, + {522, 1279}}; + std::vector 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>, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == + PropertyTexturePropertyViewStatus::Valid); + + for (size_t i = 0; i < expected.size(); ++i) { + std::vector& expectedArray = expected[i]; + glm::vec2& texCoord = texCoords[i]; + PropertyArrayView array = + propertyValue.get(texCoord[0], texCoord[1]); + + REQUIRE(static_cast(array.size()) == expectedArray.size()); + for (int64_t j = 0; j < array.size(); j++) { + REQUIRE(array[j] == expectedArray[static_cast(j)]); + } + } + } else { + FAIL("getPropertyView returned PropertyTexturePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + TEST_CASE("Test unsupported PropertyTextureProperty classes") { Model model; ExtensionModelExtStructuralMetadata& metadata = From bb1dea37392e1572644223ebe131a306fb6f7170 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 3 Jul 2023 16:27:43 -0400 Subject: [PATCH 067/121] Consolidate CI fixes --- .../CesiumGltf/PropertyTablePropertyView.h | 2 +- .../CesiumGltf/PropertyTexturePropertyView.h | 98 +++++++++++-------- .../include/CesiumGltf/PropertyTextureView.h | 4 +- CesiumGltf/include/CesiumGltf/PropertyType.h | 4 +- .../test/TestPropertyTexturePropertyView.cpp | 27 ++--- CesiumGltf/test/TestPropertyTextureView.cpp | 9 +- 6 files changed, 81 insertions(+), 63 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 977ccc995..08a7659e4 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -174,7 +174,7 @@ template class PropertyTablePropertyView { * @brief Constructs an invalid instance for a non-existent property. */ PropertyTablePropertyView() - : _status{PropertyTablePropertyViewStatus::ErrorPropertyDoesNotExist}, + : _status{PropertyTablePropertyViewStatus::ErrorNonexistentProperty}, _values{}, _arrayCount{}, _size{}, diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 7adb05fa8..efeade15b 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -5,7 +5,9 @@ #include "CesiumGltf/PropertyTypeTraits.h" #include "CesiumGltf/Sampler.h" +#include #include +#include #include namespace CesiumGltf { @@ -115,7 +117,7 @@ template class PropertyTexturePropertyView { * @brief Constructs an invalid instance for a non-existent property. */ PropertyTexturePropertyView() noexcept - : _status(PropertyTexturePropertyViewStatus::ErrorUninitialized), + : _status(PropertyTexturePropertyViewStatus::ErrorNonexistentProperty), _pSampler(nullptr), _pImage(nullptr), _texCoordSetIndex(0), @@ -212,11 +214,11 @@ template class PropertyTexturePropertyView { // Clamp to ensure no out-of-bounds data access int64_t x = std::clamp( static_cast(xCoord), - 0LL, + static_cast(0), static_cast(this->_pImage->width) - 1); int64_t y = std::clamp( static_cast(yCoord), - 0LL, + static_cast(0), static_cast(this->_pImage->height) - 1); int64_t pixelIndex = this->_pImage->bytesPerChannel * @@ -284,15 +286,13 @@ template class PropertyTexturePropertyView { if constexpr (IsMetadataScalar::value) { return assembleScalarValue(bytes); - } - - if constexpr (IsMetadataVecN::value) { + } else if constexpr (IsMetadataVecN::value) { return assembleVecNValue(bytes); - } - - if constexpr (IsMetadataArray::value) { + } else if constexpr (IsMetadataArray::value) { return assembleArrayValue::type>( bytes); + } else { + return ElementType(); } } @@ -319,6 +319,7 @@ template class PropertyTexturePropertyView { for (size_t i = 0; i < bytes.size(); i++) { resultAsUint |= static_cast(bytes[i]) << i * 8; } + // Reinterpret the bits as a signed integer. return *reinterpret_cast(&resultAsUint); } else if constexpr (IsMetadataInteger::value) { @@ -332,40 +333,54 @@ template class PropertyTexturePropertyView { ElementType assembleVecNValue(const std::vector& bytes) const noexcept { - ElementType result = ElementType(); + const glm::length_t N = + getDimensionsFromPropertyType(TypeToPropertyType::value); + switch (N) { + case 2: + return assembleVecNValueImpl<2, typename ElementType::value_type>(bytes); + case 3: + return assembleVecNValueImpl<3, typename ElementType::value_type>(bytes); + case 4: + return assembleVecNValueImpl<4, typename ElementType::value_type>(bytes); + default: + return ElementType(); + } + } - PropertyComponentType componentType = - TypeToPropertyType::component; - size_t componentSize = getSizeOfComponentType(componentType); + template + ElementType + assembleVecNValueImpl(const std::vector& bytes) const noexcept { + ElementType result = ElementType(); assert( - componentSize <= 2 && + sizeof(T) <= 2 && "Components cannot be larger than two bytes in size."); - if (componentSize == 2) { - assert( - TypeToPropertyType::value == PropertyType::Vec2 && - "Only vec2s can contain two-byte integer components."); + if constexpr (std::is_same_v) { + assert(N == 2 && "Only vec2s can contain two-byte integer components."); uint16_t x = static_cast(bytes[0]) | (static_cast(bytes[1]) << 8); uint16_t y = static_cast(bytes[2]) | (static_cast(bytes[3]) << 8); - if (componentType == PropertyComponentType::Int16) { - result[0] = *reinterpret_cast(&x); - result[1] = *reinterpret_cast(&y); - } else { - result[0] = x; - result[1] = y; - } + result[0] = *reinterpret_cast(&x); + result[1] = *reinterpret_cast(&y); + } - return result; + if constexpr (std::is_same_v) { + assert(N == 2 && "Only vec2s can contain two-byte integer components."); + result[0] = static_cast(bytes[0]) | + (static_cast(bytes[1]) << 8); + result[1] = static_cast(bytes[2]) | + (static_cast(bytes[3]) << 8); } - if (componentType == PropertyComponentType::Int8) { + if constexpr (std::is_same_v) { for (size_t i = 0; i < bytes.size(); i++) { result[i] = *reinterpret_cast(&bytes[i]); } - } else { + } + + if constexpr (std::is_same_v) { for (size_t i = 0; i < bytes.size(); i++) { result[i] = bytes[i]; } @@ -377,8 +392,9 @@ template class PropertyTexturePropertyView { template PropertyArrayView assembleArrayValue(const std::vector& bytes) const noexcept { - if (sizeof(T) == 2) { - std::vector result(bytes.size() / sizeof(T)); + std::vector result; + if constexpr (sizeof(T) == 2) { + result.resize(bytes.size() / sizeof(T)); for (int i = 0, b = 0; i < result.size(); i++, b += 2) { if constexpr (std::is_signed_v) { using UintType = std::make_unsigned_t; @@ -390,16 +406,14 @@ template class PropertyTexturePropertyView { static_cast(bytes[b]) | (static_cast(bytes[b + 1]) << 8); } } - - return PropertyArrayView(std::move(result)); - } - - std::vector result(bytes.size()); - for (size_t i = 0; i < bytes.size(); i++) { - if constexpr (std::is_signed_v) { - result[i] = *reinterpret_cast(&bytes[i]); - } else { - result[i] = bytes[i]; + } else { + result.resize(bytes.size()); + for (size_t i = 0; i < bytes.size(); i++) { + if constexpr (std::is_signed_v) { + result[i] = *reinterpret_cast(&bytes[i]); + } else { + result[i] = bytes[i]; + } } } return PropertyArrayView(std::move(result)); @@ -420,7 +434,7 @@ template class PropertyTexturePropertyView { return integer % 2 == 1 ? 1.0 - fraction : fraction; } - return glm::clamp(u, 0.0, 1.0); + return std::clamp(u, 0.0, 1.0); } double applySamplerWrapT(const double v, const int32_t wrapT) const noexcept { @@ -438,7 +452,7 @@ template class PropertyTexturePropertyView { return integer % 2 == 1 ? 1.0 - fraction : fraction; } - return glm::clamp(v, 0.0, 1.0); + return std::clamp(v, 0.0, 1.0); } PropertyTexturePropertyViewStatus _status; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index b622cb4c9..0ef93e7f5 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -210,7 +210,7 @@ class PropertyTextureView { template PropertyTexturePropertyView getPropertyViewImpl( const std::string& propertyName, - const ClassProperty& classProperty) const { + [[maybe_unused]] const ClassProperty& classProperty) const { auto propertyTexturePropertyIter = _pPropertyTexture->properties.find(propertyName); if (propertyTexturePropertyIter == _pPropertyTexture->properties.end()) { @@ -218,7 +218,7 @@ class PropertyTextureView { PropertyTexturePropertyViewStatus::ErrorNonexistentProperty); } - const PropertyTextureProperty& propertyTextureProperty = + [[maybe_unused]] const PropertyTextureProperty& propertyTextureProperty = propertyTexturePropertyIter->second; if constexpr (IsMetadataScalar::value) { diff --git a/CesiumGltf/include/CesiumGltf/PropertyType.h b/CesiumGltf/include/CesiumGltf/PropertyType.h index e5c964ec8..8f1c8deff 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyType.h +++ b/CesiumGltf/include/CesiumGltf/PropertyType.h @@ -1,11 +1,11 @@ #pragma once +#include + #include #include #include -#include - namespace CesiumGltf { enum class PropertyType { Invalid, diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index 947b3b4c8..7a329d00f 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -624,13 +624,15 @@ TEST_CASE("Check array PropertyTexturePropertyView") { view.get(0, 0.5), view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { + int64_t size = static_cast(values.size()); + for (int64_t i = 0; i < size; i++) { auto dataStart = data.begin() + i * 4; std::vector expected(dataStart, dataStart + 4); - const PropertyArrayView& value = values[i]; + + const PropertyArrayView& value = values[static_cast(i)]; REQUIRE(static_cast(value.size()) == expected.size()); - for (size_t j = 0; j < expected.size(); j++) { - REQUIRE(value[j] == expected[j]); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE(value[j] == expected[static_cast(j)]); } } } @@ -671,12 +673,13 @@ TEST_CASE("Check array PropertyTexturePropertyView") { view.get(0.5, 0), view.get(0, 0.5), view.get(0.5, 0.5)}; + for (size_t i = 0; i < values.size(); i++) { std::vector& expectedValue = expected[i]; const PropertyArrayView& value = values[i]; REQUIRE(static_cast(value.size()) == expected.size()); - for (size_t j = 0; j < expected.size(); j++) { - REQUIRE(value[j] == expectedValue[j]); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE(value[j] == expectedValue[static_cast(j)]); } } } @@ -723,8 +726,8 @@ TEST_CASE("Check array PropertyTexturePropertyView") { std::vector& expectedValue = expected[i]; const PropertyArrayView& value = values[i]; REQUIRE(static_cast(value.size()) == expectedValue.size()); - for (size_t j = 0; j < expectedValue.size(); j++) { - REQUIRE(value[j] == expectedValue[j]); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE(value[j] == expectedValue[static_cast(j)]); } } } @@ -769,8 +772,8 @@ TEST_CASE("Check array PropertyTexturePropertyView") { std::vector& expectedValue = expected[i]; const PropertyArrayView& value = values[i]; REQUIRE(static_cast(value.size()) == expectedValue.size()); - for (size_t j = 0; j < expectedValue.size(); j++) { - REQUIRE(value[j] == expectedValue[j]); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE(value[j] == expectedValue[static_cast(j)]); } } } @@ -932,8 +935,8 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector& expectedValue = expected[i]; const PropertyArrayView& value = values[i]; REQUIRE(static_cast(value.size()) == expectedValue.size()); - for (size_t j = 0; j < expectedValue.size(); j++) { - REQUIRE(value[j] == expectedValue[j]); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE(value[j] == expectedValue[static_cast(j)]); } } } diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index 095b17ddf..e62dcda17 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -486,13 +486,14 @@ TEST_CASE("Test array PropertyTextureProperty") { uint8ArrayProperty.get(0.5, 0.5), }; - for (size_t i = 0; i < values.size(); ++i) { + int64_t size = static_cast(values.size()); + for (int64_t i = 0; i < size; ++i) { auto dataStart = data.begin() + i * 3; std::vector expected(dataStart, dataStart + 3); - const PropertyArrayView& value = values[i]; + const PropertyArrayView& value = values[static_cast(i)]; REQUIRE(static_cast(value.size()) == expected.size()); - for (size_t j = 0; j < expected.size(); j++) { - REQUIRE(value[j] == expected[j]); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE(value[j] == expected[static_cast(j)]); } } } From b024fe5b8f068dc5585ff0d93bc50b09bf12ca9a Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 3 Jul 2023 17:26:24 -0400 Subject: [PATCH 068/121] Stricter reinforcement of unsupported properties --- .../CesiumGltf/PropertyTexturePropertyView.h | 47 ++--- .../include/CesiumGltf/PropertyTextureView.h | 123 +++++------ CesiumGltf/test/TestPropertyTextureView.cpp | 199 +++++++----------- 3 files changed, 150 insertions(+), 219 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index efeade15b..2b14e1738 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -286,13 +286,15 @@ template class PropertyTexturePropertyView { if constexpr (IsMetadataScalar::value) { return assembleScalarValue(bytes); - } else if constexpr (IsMetadataVecN::value) { + } + + if constexpr (IsMetadataVecN::value) { return assembleVecNValue(bytes); - } else if constexpr (IsMetadataArray::value) { + } + + if constexpr (IsMetadataArray::value) { return assembleArrayValue::type>( bytes); - } else { - return ElementType(); } } @@ -311,23 +313,15 @@ template class PropertyTexturePropertyView { return *reinterpret_cast(&resultAsUint); } - if constexpr ( - IsMetadataInteger::value && - std::is_signed_v) { + if constexpr (IsMetadataInteger::value) { using UintType = std::make_unsigned_t; UintType resultAsUint = 0; for (size_t i = 0; i < bytes.size(); i++) { resultAsUint |= static_cast(bytes[i]) << i * 8; } - // Reinterpret the bits as a signed integer. + // Reinterpret the bits with the correct signedness. return *reinterpret_cast(&resultAsUint); - } else if constexpr (IsMetadataInteger::value) { - ElementType result = 0; - for (size_t i = 0; i < bytes.size(); i++) { - result |= static_cast(bytes[i]) << i * 8; - } - return result; } } @@ -392,30 +386,21 @@ template class PropertyTexturePropertyView { template PropertyArrayView assembleArrayValue(const std::vector& bytes) const noexcept { - std::vector result; + std::vector result(bytes.size() / sizeof(T)); + if constexpr (sizeof(T) == 2) { - result.resize(bytes.size() / sizeof(T)); for (int i = 0, b = 0; i < result.size(); i++, b += 2) { - if constexpr (std::is_signed_v) { - using UintType = std::make_unsigned_t; - UintType resultAsUint = static_cast(bytes[b]) | - (static_cast(bytes[b + 1]) << 8); - result[i] = *reinterpret_cast(&resultAsUint); - } else { - result[i] = - static_cast(bytes[b]) | (static_cast(bytes[b + 1]) << 8); - } + using UintType = std::make_unsigned_t; + UintType resultAsUint = static_cast(bytes[b]) | + (static_cast(bytes[b + 1]) << 8); + result[i] = *reinterpret_cast(&resultAsUint); } } else { - result.resize(bytes.size()); for (size_t i = 0; i < bytes.size(); i++) { - if constexpr (std::is_signed_v) { - result[i] = *reinterpret_cast(&bytes[i]); - } else { - result[i] = bytes[i]; - } + result[i] = *reinterpret_cast(&bytes[i]); } } + return PropertyArrayView(std::move(result)); } diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 0ef93e7f5..eedde43e9 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -210,7 +210,7 @@ class PropertyTextureView { template PropertyTexturePropertyView getPropertyViewImpl( const std::string& propertyName, - [[maybe_unused]] const ClassProperty& classProperty) const { + const ClassProperty& classProperty) const { auto propertyTexturePropertyIter = _pPropertyTexture->properties.find(propertyName); if (propertyTexturePropertyIter == _pPropertyTexture->properties.end()) { @@ -218,22 +218,23 @@ class PropertyTextureView { PropertyTexturePropertyViewStatus::ErrorNonexistentProperty); } - [[maybe_unused]] const PropertyTextureProperty& propertyTextureProperty = + const PropertyTextureProperty& propertyTextureProperty = propertyTexturePropertyIter->second; if constexpr (IsMetadataScalar::value) { return createScalarPropertyView( classProperty, propertyTextureProperty); - } else if constexpr (IsMetadataVecN::value) { + } + + if constexpr (IsMetadataVecN::value) { return createVecNPropertyView(classProperty, propertyTextureProperty); - } else if constexpr (IsMetadataArray::value) { + } + + if constexpr (IsMetadataArray::value) { return createArrayPropertyView::type>( classProperty, propertyTextureProperty); - } else { - return PropertyTexturePropertyView( - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); } } @@ -250,6 +251,7 @@ class PropertyTextureView { propertyName, PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + return; } int64_t count = classProperty.count.value_or(0); @@ -258,6 +260,7 @@ class PropertyTextureView { propertyName, PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + return; } switch (componentType) { @@ -294,6 +297,7 @@ class PropertyTextureView { propertyName, PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + break; } } @@ -370,19 +374,23 @@ class PropertyTextureView { classProperty)); break; case PropertyComponentType::Int16: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; + if constexpr (N == 2) { + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + } case PropertyComponentType::Uint16: - callback( - propertyName, - getPropertyViewImpl>( - propertyName, - classProperty)); - break; + if constexpr (N == 2) { + callback( + propertyName, + getPropertyViewImpl>( + propertyName, + classProperty)); + break; + } default: callback( propertyName, @@ -454,17 +462,13 @@ class PropertyTextureView { PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } - // Eight-byte scalar types are unsupported. - size_t componentSize = getSizeOfComponentType(componentType); - if (componentSize == 0 || componentSize > 4) { - return PropertyTexturePropertyView( - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + // Only up to four bytes of image data are supported. + if constexpr (sizeof(T) <= 4) { + return createPropertyViewImpl( + classProperty, + propertyTextureProperty, + sizeof(T)); } - - return createPropertyViewImpl( - classProperty, - propertyTextureProperty, - sizeof(T)); } template @@ -491,18 +495,12 @@ class PropertyTextureView { } // Only up to four bytes of image data are supported. - size_t dimensions = - static_cast(getDimensionsFromPropertyType(type)); - - if (dimensions * getSizeOfComponentType(componentType) > 4) { - return PropertyTexturePropertyView( - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + if constexpr (sizeof(T) <= 4) { + return createPropertyViewImpl( + classProperty, + propertyTextureProperty, + sizeof(T)); } - - return createPropertyViewImpl( - classProperty, - propertyTextureProperty, - sizeof(T)); } template @@ -520,19 +518,6 @@ class PropertyTextureView { PropertyTexturePropertyViewStatus::ErrorTypeMismatch); } - // Only scalar arrays are supported. - if (type != PropertyType::Scalar) { - return PropertyTexturePropertyView>( - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - } - - // Only up to four elements are supported. - int64_t count = classProperty.count.value_or(0); - if (count <= 0 || count > 4) { - return PropertyTexturePropertyView>( - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - } - const PropertyComponentType componentType = convertStringToPropertyComponentType( classProperty.componentType.value_or("")); @@ -541,22 +526,26 @@ class PropertyTextureView { PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } - // Only up to two-byte components are supported. - size_t componentSize = getSizeOfComponentType(componentType); - if (componentSize == 0 || componentSize > 2) { - return PropertyTexturePropertyView>( - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - } + // Only scalar arrays are supported. The scalar component type must not + // exceed two bytes. + if constexpr (IsMetadataScalar::value && sizeof(T) <= 4) { + // Only up to four elements are supported. + int64_t count = classProperty.count.value_or(0); + if (count <= 0 || count > 4) { + return PropertyTexturePropertyView>( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } - if (componentSize * count > 4) { - return PropertyTexturePropertyView>( - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - } + if (count * sizeof(T) > 4) { + return PropertyTexturePropertyView>( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + } - return createPropertyViewImpl>( - classProperty, - propertyTextureProperty, - count * sizeof(T)); + return createPropertyViewImpl>( + classProperty, + propertyTextureProperty, + count * sizeof(T)); + } } template diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index e62dcda17..d442ee364 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -381,15 +381,6 @@ TEST_CASE("Test vecN PropertyTextureProperty") { PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } - SECTION("Access incorrectly as array") { - PropertyTexturePropertyView> arrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); - } - SECTION("Channel and type mismatch") { model.images[imageIndex].cesium.channels = 4; propertyTextureProperty.channels = {0, 1, 2, 3}; @@ -498,16 +489,6 @@ TEST_CASE("Test array PropertyTextureProperty") { } } - SECTION("Access wrong type") { - PropertyTexturePropertyView> - u8vec3ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - u8vec3ArrayInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorTypeMismatch); - } - SECTION("Access wrong component type") { PropertyTexturePropertyView> int8ArrayInvalid = view.getPropertyView>("TestClassProperty"); @@ -904,123 +885,99 @@ TEST_CASE("Test callback for array PropertyTextureProperty") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test unsupported PropertyTextureProperty classes") { +TEST_CASE("Test callback on unsupported PropertyTextureProperty") { Model model; + // clang-format off + std::vector 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, + 1, + 8, + data); + size_t textureIndex = model.textures.size() - 1; + ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + + ClassProperty& doubleClassProperty = + testClass.properties["DoubleClassProperty"]; + doubleClassProperty.type = ClassProperty::Type::SCALAR; + doubleClassProperty.componentType = ClassProperty::ComponentType::FLOAT64; + + ClassProperty& arrayClassProperty = + testClass.properties["ArrayClassProperty"]; + arrayClassProperty.type = ClassProperty::Type::VEC4; + arrayClassProperty.componentType = ClassProperty::ComponentType::UINT8; + arrayClassProperty.array = true; + arrayClassProperty.count = 2; PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); propertyTexture.classProperty = "TestClass"; - PropertyTextureProperty& propertyTextureProperty = - propertyTexture.properties["TestClassProperty"]; - propertyTextureProperty.index = 0; - propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0}; + PropertyTextureProperty& doubleProperty = + propertyTexture.properties["DoubleClassProperty"]; + doubleProperty.index = static_cast(textureIndex); + doubleProperty.texCoord = 0; + doubleProperty.channels = {0, 1, 2, 3, 4, 5, 6, 7}; + + PropertyTextureProperty& arrayProperty = + propertyTexture.properties["ArrayClassProperty"]; + arrayProperty.index = static_cast(textureIndex); + arrayProperty.texCoord = 0; + arrayProperty.channels = {0, 1, 2, 3, 4, 5, 6, 7}; PropertyTextureView view(model, propertyTexture); REQUIRE(view.status() == PropertyTextureViewStatus::Valid); - SECTION("Unsupported types") { - testClassProperty.type = ClassProperty::Type::BOOLEAN; - PropertyTexturePropertyView boolInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - boolInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - - testClassProperty.type = ClassProperty::Type::STRING; - PropertyTexturePropertyView stringInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - - testClassProperty.type = ClassProperty::Type::MAT2; - PropertyTexturePropertyView mat2Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - mat2Invalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - } - - SECTION("Unsupported component types") { - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::FLOAT64; - PropertyTexturePropertyView doubleInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - doubleInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT64; - PropertyTexturePropertyView uint64Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint64Invalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - - testClassProperty.type = ClassProperty::Type::VEC2; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; - PropertyTexturePropertyView ivec2Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec2Invalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - - testClassProperty.type = ClassProperty::Type::VEC3; - testClassProperty.componentType = ClassProperty::ComponentType::UINT16; - PropertyTexturePropertyView u16vec3Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u16vec3Invalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - } + const ClassProperty* classProperty = + view.getClassProperty("DoubleClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE( + classProperty->componentType == ClassProperty::ComponentType::FLOAT64); + REQUIRE(!classProperty->array); - SECTION("Unsupported array types") { - testClassProperty.array = true; + classProperty = view.getClassProperty("ArrayClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC4); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - testClassProperty.count = 5; - PropertyTexturePropertyView> bigArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - bigArrayInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "DoubleClassProperty", + [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + }); + REQUIRE(invokedCallbackCount == 1); - testClassProperty.count = std::nullopt; - PropertyTexturePropertyView> - variableArrayInvalid = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - variableArrayInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - - testClassProperty.type = ClassProperty::Type::VEC2; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; - testClassProperty.count = 2; - PropertyTexturePropertyView> - uvec2ArrayInvalid = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - uvec2ArrayInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - - testClassProperty.type = ClassProperty::Type::VEC3; - testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - testClassProperty.count = 1; - PropertyTexturePropertyView> - u8vec3ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - u8vec3ArrayInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); - } + view.getPropertyView( + "ArrayClassProperty", + [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); + }); + REQUIRE(invokedCallbackCount == 2); } From 047422b53d0475ba1ad2544fee6511602f0d865d Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 5 Jul 2023 16:35:34 -0400 Subject: [PATCH 069/121] Fix nearest sampling for feature ID textures --- CesiumGltf/src/FeatureIdTextureView.cpp | 23 +++++++++++++++----- CesiumGltf/test/TestFeatureIdTextureView.cpp | 4 ++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/CesiumGltf/src/FeatureIdTextureView.cpp b/CesiumGltf/src/FeatureIdTextureView.cpp index 17a1e981a..22553e8d5 100644 --- a/CesiumGltf/src/FeatureIdTextureView.cpp +++ b/CesiumGltf/src/FeatureIdTextureView.cpp @@ -68,14 +68,25 @@ int64_t FeatureIdTextureView::getFeatureID(double u, double v) const noexcept { return -1; } + // Always use nearest filtering, and use std::floor instead of std::round. + // This is because filtering is supposed to consider the pixel centers. But + // memory access here acts as sampling the beginning of the pixel. Example: + // 0.4 * 2 = 0.8. In a 2x1 pixel image, that should be closer to the left + // pixel's center. But it will round to 1.0 which corresponds to the right + // pixel. So the right pixel has a bigger range than the left one, which is + // incorrect. + double xCoord = std::floor(u * this->_pImage->width); + double yCoord = std::floor(v * this->_pImage->height); + + // Clamp to ensure no out-of-bounds data access int64_t x = std::clamp( - std::llround(u * this->_pImage->width), - 0LL, - (long long)this->_pImage->width - 1); + static_cast(xCoord), + static_cast(0), + static_cast(this->_pImage->width - 1)); int64_t y = std::clamp( - std::llround(v * this->_pImage->height), - 0LL, - (long long)this->_pImage->height - 1); + static_cast(yCoord), + static_cast(0), + static_cast(this->_pImage->height - 1)); int64_t pixelOffset = this->_pImage->bytesPerChannel * this->_pImage->channels * diff --git a/CesiumGltf/test/TestFeatureIdTextureView.cpp b/CesiumGltf/test/TestFeatureIdTextureView.cpp index 5ee2080fc..8569433fe 100644 --- a/CesiumGltf/test/TestFeatureIdTextureView.cpp +++ b/CesiumGltf/test/TestFeatureIdTextureView.cpp @@ -338,9 +338,9 @@ TEST_CASE("Test getFeatureID rounds to nearest pixel") { FeatureIdTextureView view(model, featureIdTexture); REQUIRE(view.status() == FeatureIdTextureViewStatus::Valid); - REQUIRE(view.getFeatureID(0.1, 0.24) == 1); + REQUIRE(view.getFeatureID(0.1, 0.4) == 1); REQUIRE(view.getFeatureID(0.86, 0.2) == 2); - REQUIRE(view.getFeatureID(0.21, 0.555) == 0); + REQUIRE(view.getFeatureID(0.29, 0.555) == 0); REQUIRE(view.getFeatureID(0.99, 0.81) == 7); } From dff210594d591532859d0bdcd47044cf9b64c828 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 5 Jul 2023 17:27:28 -0400 Subject: [PATCH 070/121] Add assert in status constructor for PropertyTexturePropertyView --- CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 2b14e1738..709c25e10 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -137,7 +137,11 @@ template class PropertyTexturePropertyView { _texCoordSetIndex(0), _channels(), _swizzle(""), - _normalized(false) {} + _normalized(false) { + assert( + _status != PropertyTexturePropertyViewStatus::Valid && + "An empty property view should not be constructed with a valid status"); + } /** * @brief Construct a valid view of the data specified by a {@link PropertyTextureProperty}. From 6dcadfe38ebe59649ad3f70c715af14dba241404 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 15 Aug 2023 12:43:10 -0400 Subject: [PATCH 071/121] Create PropertyView --- .../include/CesiumGltf/PropertyArrayView.h | 57 +- .../CesiumGltf/PropertyTablePropertyView.h | 83 +- .../include/CesiumGltf/PropertyTableView.h | 21 +- CesiumGltf/include/CesiumGltf/PropertyView.h | 1593 ++++ CesiumGltf/src/PropertyTableView.cpp | 24 +- .../test/TestPropertyTablePropertyView.cpp | 146 +- CesiumGltf/test/TestPropertyTableView.cpp | 6494 ++++++++--------- CesiumGltf/test/TestPropertyView.cpp | 359 + .../include/CesiumUtility/JsonValue.h | 2 +- 9 files changed, 5422 insertions(+), 3357 deletions(-) create mode 100644 CesiumGltf/include/CesiumGltf/PropertyView.h create mode 100644 CesiumGltf/test/TestPropertyView.cpp diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index b921c13f3..f7978107c 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -37,9 +37,7 @@ template class PropertyArrayView { /** * @brief Constructs an array view from a vector of values. This is mainly - * used by PropertyTextureProperty -- since the values are swizzled from the - * texture, the values cannot be viewed in place, and must passed in through a - * correctly ordered vector. + * used when the values cannot be viewed in place. * * @param values The vector containing the values. */ @@ -85,18 +83,39 @@ template <> class PropertyArrayView { int64_t size) noexcept : _values{buffer}, _bitOffset{bitOffset}, _size{size} {} + /** + * @brief Constructs an array view from a vector of values. This is mainly + * used when the values cannot be viewed in place. + * + * @param values The vector containing the values. + */ + PropertyArrayView(const std::vector&& values) + : _values{std::move(values)}, _bitOffset{0}, _size{0} { + const auto vectorValues = std::get>(_values); + _size = static_cast(vectorValues.size()); + } + bool operator[](int64_t index) const noexcept { + // There's no way to access the bitstream data in std::vector, so this + // implementation is very "either or". + if (std::holds_alternative>(_values)) { + const auto vectorValues = std::get>(_values); + return vectorValues[static_cast(index)]; + } + + const auto values = std::get>(_values); index += _bitOffset; const int64_t byteIndex = index / 8; const int64_t bitIndex = index % 8; - const int bitValue = static_cast(_values[byteIndex] >> bitIndex) & 1; + const int bitValue = static_cast(values[byteIndex] >> bitIndex) & 1; return bitValue == 1; } int64_t size() const noexcept { return _size; } private: - gsl::span _values; + using ArrayType = std::variant, std::vector>; + ArrayType _values; int64_t _bitOffset; int64_t _size; }; @@ -127,7 +146,28 @@ template <> class PropertyArrayView { _stringOffsetType{stringOffsetType}, _size{size} {} + /** + * @brief Constructs an array view from a vector of values. This is mainly + * used when the values cannot be viewed in place. + * + * @param values The vector containing the values. + */ + PropertyArrayView(const std::vector&& values) + : _values{std::move(values)}, + _stringOffsets{}, + _stringOffsetType{PropertyComponentType::None}, + _size{0} { + const auto vectorValues = std::get>(_values); + _size = static_cast(vectorValues.size()); + } + std::string_view operator[](int64_t index) const noexcept { + if (std::holds_alternative>(_values)) { + const auto vectorValues = std::get>(_values); + return vectorValues[static_cast(index)]; + } + + const auto values = std::get>(_values); const size_t currentOffset = getOffsetFromOffsetsBuffer(index, _stringOffsets, _stringOffsetType); const size_t nextOffset = getOffsetFromOffsetsBuffer( @@ -135,15 +175,18 @@ template <> class PropertyArrayView { _stringOffsets, _stringOffsetType); return std::string_view( - reinterpret_cast(_values.data() + currentOffset), + reinterpret_cast(values.data() + currentOffset), (nextOffset - currentOffset)); } int64_t size() const noexcept { return _size; } private: - gsl::span _values; + using ArrayType = + std::variant, std::vector>; + ArrayType _values; gsl::span _stringOffsets; + PropertyComponentType _stringOffsetType; int64_t _size; }; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 08a7659e4..3edc7b0a8 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -2,6 +2,7 @@ #include "CesiumGltf/PropertyArrayView.h" #include "CesiumGltf/PropertyTypeTraits.h" +#include "CesiumGltf/PropertyView.h" #include @@ -168,17 +169,17 @@ enum class PropertyTablePropertyViewStatus { * the scalar types, bool, std::string_view, or PropertyArrayView with T as * one of the aforementioned types. */ -template class PropertyTablePropertyView { +template +class PropertyTablePropertyView : public PropertyView { public: /** * @brief Constructs an invalid instance for a non-existent property. */ PropertyTablePropertyView() - : _status{PropertyTablePropertyViewStatus::ErrorNonexistentProperty}, - _values{}, - _arrayCount{}, - _size{}, - _normalized{} {} + : PropertyView(), + _status{PropertyTablePropertyViewStatus::ErrorNonexistentProperty}, + _values, + _size{} {} /** * @brief Constructs an invalid instance for an erroneous property. @@ -186,7 +187,7 @@ template class PropertyTablePropertyView { * @param status The {@link PropertyTablePropertyViewStatus} indicating the error with the property. */ PropertyTablePropertyView(PropertyTablePropertyViewStatus status) - : _status{status}, _values{}, _arrayCount{}, _size{}, _normalized{} { + : PropertyView(), _status{status}, _values{}, _size{} { assert( _status != PropertyTablePropertyViewStatus::Valid && "An empty property view should not be constructed with a valid status"); @@ -200,10 +201,12 @@ template class PropertyTablePropertyView { * @param normalized Whether this property has a normalized integer type. */ PropertyTablePropertyView( - gsl::span values, + const PropertyTableProperty& property, + const ClassProperty& classProperty, int64_t size, - bool normalized) noexcept - : _status{PropertyTablePropertyViewStatus::Valid}, + gsl::span values) noexcept + : PropertyView(classProperty, property), + _status{PropertyTablePropertyViewStatus::Valid}, _values{values}, _arrayOffsets{}, _arrayOffsetType{PropertyComponentType::None}, @@ -211,9 +214,7 @@ template class PropertyTablePropertyView { _stringOffsets{}, _stringOffsetType{PropertyComponentType::None}, _stringOffsetTypeSize{0}, - _arrayCount{0}, - _size{size}, - _normalized{normalized} {} + _size{size} {} /** * @brief Construct a valid instance pointing to the data specified by @@ -225,18 +226,20 @@ template class PropertyTablePropertyView { * @param offsetType The offset type of stringOffsets specified by {@link PropertyTableProperty::stringOffsetType} * @param arrayCount The number of elements in each array value specified by {@link ClassProperty::count} * @param size The number of elements in the property table specified by {@link PropertyTable::count} - * @param normalized Whether this property has a normalized integer type. + * @param normalized Whether this property has a normalized integer + * type. */ PropertyTablePropertyView( + const PropertyTableProperty& property, + const ClassProperty& classProperty, + int64_t size, gsl::span values, gsl::span arrayOffsets, gsl::span stringOffsets, PropertyComponentType arrayOffsetType, - PropertyComponentType stringOffsetType, - int64_t arrayCount, - int64_t size, - bool normalized) noexcept - : _status{PropertyTablePropertyViewStatus::Valid}, + PropertyComponentType stringOffsetType) noexcept + : PropertyView(classProperty, property), + _status{PropertyTablePropertyViewStatus::Valid}, _values{values}, _arrayOffsets{arrayOffsets}, _arrayOffsetType{arrayOffsetType}, @@ -244,9 +247,7 @@ template class PropertyTablePropertyView { _stringOffsets{stringOffsets}, _stringOffsetType{stringOffsetType}, _stringOffsetTypeSize{getOffsetTypeSize(stringOffsetType)}, - _arrayCount{arrayCount}, - _size{size}, - _normalized{normalized} {} + _size{size} {} /** * @brief Gets the status of this property table property view. @@ -310,21 +311,6 @@ template class PropertyTablePropertyView { return status() == PropertyTablePropertyViewStatus::Valid ? _size : 0; } - /** - * @brief Get the element count of the fixed-length arrays in this property. - * Only applicable when the property is an array type. - * - * @return The count of this property. - */ - int64_t getArrayCount() const noexcept { return _arrayCount; } - - /** - * @brief Whether this property has a normalized integer type. - * - * @return Whether this property has a normalized integer type. - */ - bool isNormalized() const noexcept { return _normalized; } - private: ElementType getNumericValue(int64_t index) const noexcept { return reinterpret_cast(_values.data())[index]; @@ -351,9 +337,10 @@ template class PropertyTablePropertyView { template PropertyArrayView getNumericArrayValues(int64_t index) const noexcept { + size_t count = static_cast(this->arrayCount()); // Handle fixed-length arrays - if (_arrayCount > 0) { - size_t arraySize = _arrayCount * sizeof(T); + if (count > 0) { + size_t arraySize = count * sizeof(T); const gsl::span values( _values.data() + index * arraySize, arraySize); @@ -373,10 +360,11 @@ template class PropertyTablePropertyView { PropertyArrayView getStringArrayValues(int64_t index) const noexcept { + size_t count = static_cast(this->arrayCount()); // Handle fixed-length arrays - if (_arrayCount > 0) { + if (count > 0) { // Copy the corresponding string offsets to pass to the PropertyArrayView. - const size_t arraySize = _arrayCount * _stringOffsetTypeSize; + const size_t arraySize = count * _stringOffsetTypeSize; const gsl::span stringOffsetValues( _stringOffsets.data() + index * arraySize, arraySize + _stringOffsetTypeSize); @@ -384,7 +372,7 @@ template class PropertyTablePropertyView { _values, stringOffsetValues, _stringOffsetType, - _arrayCount); + count); } // Handle variable-length arrays @@ -404,14 +392,15 @@ template class PropertyTablePropertyView { } PropertyArrayView getBooleanArrayValues(int64_t index) const noexcept { + size_t count = static_cast(this->arrayCount()); // Handle fixed-length arrays - if (_arrayCount > 0) { - const size_t offsetBits = _arrayCount * index; - const size_t nextOffsetBits = _arrayCount * (index + 1); + if (count > 0) { + const size_t offsetBits = count * index; + const size_t nextOffsetBits = count * (index + 1); const gsl::span buffer( _values.data() + offsetBits / 8, (nextOffsetBits / 8 - offsetBits / 8 + 1)); - return PropertyArrayView(buffer, offsetBits % 8, _arrayCount); + return PropertyArrayView(buffer, offsetBits % 8, count); } // Handle variable-length arrays @@ -452,8 +441,6 @@ template class PropertyTablePropertyView { PropertyComponentType _stringOffsetType; int64_t _stringOffsetTypeSize; - int64_t _arrayCount; int64_t _size; - bool _normalized; }; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h index 6af76ce7f..c43c26512 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -1025,9 +1025,10 @@ class PropertyTableView { } return PropertyTablePropertyView( - values, + propertyTableProperty, + classProperty, _pPropertyTable->count, - classProperty.normalized); + values); } PropertyTablePropertyView getStringPropertyValues( @@ -1103,14 +1104,14 @@ class PropertyTableView { } return PropertyTablePropertyView>( + propertyTableProperty, + classProperty, + static_cast(_pPropertyTable->count), values, gsl::span(), gsl::span(), PropertyComponentType::None, - PropertyComponentType::None, - static_cast(fixedLengthArrayCount), - static_cast(_pPropertyTable->count), - classProperty.normalized); + PropertyComponentType::None); } // Handle variable-length arrays @@ -1136,14 +1137,14 @@ class PropertyTableView { } return PropertyTablePropertyView>( + propertyTableProperty, + classProperty, + static_cast(_pPropertyTable->count), values, arrayOffsets, gsl::span(), arrayOffsetType, - PropertyComponentType::None, - 0, - static_cast(_pPropertyTable->count), - classProperty.normalized); + PropertyComponentType::None); } PropertyTablePropertyView> diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h new file mode 100644 index 000000000..26bec92ea --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -0,0 +1,1593 @@ +#include "CesiumGltf/ClassProperty.h" +#include "CesiumGltf/PropertyTableProperty.h" +#include "CesiumGltf/PropertyTextureProperty.h" +#include "CesiumGltf/PropertyTypeTraits.h" + +#include +#include + +namespace CesiumGltf { +/** + * @brief Indicates the status of a property view. + * + * The {@link PropertyView} constructor always completes successfully. + * However, it may find fundamental errors within the property definition + * itself. This enumeration provides the reason. + */ +enum class PropertyViewStatus { + /** + * @brief This property view is valid and ready to use. + */ + Valid, + + /** + * @brief This property view is trying to view a property that does not exist. + */ + ErrorNonexistentProperty, + + /** + * @brief This property view's type does not match what is + * specified in {@link ClassProperty::type}. + */ + ErrorTypeMismatch, + + /** + * @brief This property view's component type does not match what + * is specified in {@link ClassProperty::componentType}. + */ + ErrorComponentTypeMismatch, + + /** + * @brief This property view differs from what is specified in + * {@link ClassProperty::array}. + */ + ErrorArrayTypeMismatch, +}; + +/** + * @brief An interface for generic metadata property in EXT_structural_metadata. + * + * Whether they belong to property tables, property textures, or property + * attributes, properties have their own sub-properties affecting the actual + * property values. Although they are typically defined via class property, they + * may be overriden by individual instances of the property. The constructor is + * responsible for resolving those differences. + */ +template class IPropertyView { +public: + /** + * @brief Get the element count of the fixed-length arrays in this property. + * Only applicable when the property is an array type. + * + * @return The count of this property. + */ + virtual int64_t arrayCount() const noexcept = 0; + + /** + * @brief Whether this property has a normalized integer type. + * + * @return Whether this property has a normalized integer type. + */ + virtual bool normalized() const noexcept = 0; + + /** + * @brief Gets the offset to apply to property values. Only applicable to + * SCALAR, VECN, and MATN types when the component type is FLOAT32 or + * FLOAT64, or when the property is normalized. + * + * @returns The property's offset, or std::nullopt if it was not specified. + */ + virtual std::optional offset() const noexcept = 0; + /** + * @brief Gets the scale to apply to property values. Only applicable to + * SCALAR, VECN, and MATN types when the component type is FLOAT32 or + * FLOAT64, or when the property is normalized. + * + * @returns The property's scale, or std::nullopt if it was not specified. + */ + virtual std::optional scale() const noexcept = 0; + + /** + * @brief Gets the maximum allowed value for the property. Only applicable to + * SCALAR, VECN, and MATN types. This is the maximum of all property + * values, after the transforms based on the normalized, offset, and + * scale properties have been applied. + * + * @returns The property's maximum value, or std::nullopt if it was not + * specified. + */ + virtual std::optional max() const noexcept = 0; + + /** + * @brief Gets the minimum allowed value for the property. Only applicable to + * SCALAR, VECN, and MATN types. This is the minimum of all property + * values, after the transforms based on the normalized, offset, and + * scale properties have been applied. + * + * @returns The property's minimum value, or std::nullopt if it was not + * specified. + */ + virtual std::optional min() const noexcept = 0; + + /** + * @brief Whether the property must be present in every entity conforming to + * the class. If not required, instances of the property may include "no data" + * values, or the entire property may be omitted. + */ + virtual bool required() const noexcept = 0; + + /** + * @brief Gets the "no data" value, i.e., the value representing missing data + * in the property wherever it appears. Also known as a sentinel value. This + * is given as the plain property value, without the transforms from the + * normalized, offset, and scale properties. + */ + virtual std::optional noData() const noexcept = 0; + + /** + * @brief Gets the default value to use when encountering a "no data" value or + * an omitted property. The value is given in its final form, taking the + * effect of normalized, offset, and scale properties into account. + */ + virtual std::optional defaultValue() const noexcept = 0; + +protected: + /** + * @brief Gets the status of the property view. Derived classes will often + * have their own status enumerations, so this is only used internally. + */ + virtual PropertyViewStatus propertyViewStatus() const noexcept = 0; +}; + +/** + * @brief Represents a generic metadata property in EXT_structural_metadata. + * Implements the {@link IPropertyView} interface. + * + * Child classes should validate that the class property type matches the + * "ElementType" before constructing a property view. + */ +template +class PropertyView : IPropertyView { +public: + /** + * @brief Constructs an empty property instance. + */ + PropertyView() + : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), + _normalized(false), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + + /** + * @brief Constructs a property instance from a class definition only. + */ + PropertyView(const ClassProperty& classProperty) + : _propertyViewStatus(PropertyViewStatus::Valid), + _normalized(classProperty.normalized), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(classProperty.required), + _noData(std::nullopt), + _defaultValue(std::nullopt) { + if (convertStringToPropertyType(classProperty.type) != + TypeToPropertyType::value) { + _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (!classProperty.componentType && + TypeToPropertyType::component != + PropertyComponentType::None) { + _propertyViewStatus = PropertyViewStatus::ErrorComponentTypeMismatch; + return; + } + + if (classProperty.componentType && + convertStringToPropertyComponentType(*classProperty.componentType) != + TypeToPropertyType::component) { + _propertyViewStatus = PropertyViewStatus::ErrorComponentTypeMismatch; + return; + } + + if (classProperty.array) { + _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + _offset = classProperty.offset + ? getValue(*classProperty.offset) + : std::nullopt; + _scale = classProperty.scale ? getValue(*classProperty.scale) + : std::nullopt; + _max = classProperty.max ? getValue(*classProperty.max) + : std::nullopt; + _min = classProperty.min ? getValue(*classProperty.min) + : std::nullopt; + + if (!_required) { + _noData = classProperty.noData + ? getValue(*classProperty.noData) + : std::nullopt; + _defaultValue = + classProperty.defaultProperty + ? getValue(*classProperty.defaultProperty) + : std::nullopt; + } + } + +protected: + /** + * @brief Constructs a property instance from a property table property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTableProperty& property) + : PropertyView(classProperty) { + if (_propertyViewStatus != PropertyViewStatus::Valid) { + return; + } + + // If the property has its own values, override the class-provided values. + if (property.offset) { + _offset = getValue(*property.offset); + } + + if (property.scale) { + _scale = getValue(*property.scale); + } + + if (property.max) { + _max = getValue(*property.max); + } + + if (property.min) { + _min = getValue(*property.min); + } + } + + /** + * @brief Constructs a property instance from a property texture property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& property) + : PropertyView(classProperty) { + if (_propertyViewStatus != PropertyViewStatus::Valid) { + return; + } + + // If the property has its own values, override the class-provided values. + if (property.offset) { + _offset = getValue(*property.offset); + } + + if (property.scale) { + _scale = getValue(*property.scale); + } + + if (property.max) { + _max = getValue(*property.max); + } + + if (property.min) { + _min = getValue(*property.min); + } + } + +public: + /** + * @copydoc IPropertyView::arrayCount + */ + virtual int64_t arrayCount() const noexcept override { return 0; } + + /** + * @copydoc IPropertyView::normalized + */ + virtual bool normalized() const noexcept override { return _normalized; } + + /** + * @copydoc IPropertyView::offset + */ + virtual std::optional offset() const noexcept override { + return _offset; + } + + /** + * @copydoc IPropertyView::scale + */ + virtual std::optional scale() const noexcept override { + return _scale; + } + + /** + * @copydoc IPropertyView::max + */ + virtual std::optional max() const noexcept override { + return _max; + } + + /** + * @copydoc IPropertyView::min + */ + virtual std::optional min() const noexcept override { + return _min; + } + + /** + * @copydoc IPropertyView::required + */ + virtual bool required() const noexcept override { return _required; } + + /** + * @copydoc IPropertyView::arrayCount + */ + virtual std::optional noData() const noexcept override { + return _noData; + } + + /** + * @copydoc IPropertyView::arrayCount + */ + virtual std::optional defaultValue() const noexcept override { + return _defaultValue; + } + +protected: + /** + * @copydoc IPropertyView::propertyViewStatus + */ + virtual PropertyViewStatus propertyViewStatus() const noexcept override { + return _propertyViewStatus; + } + +private: + PropertyViewStatus _propertyViewStatus; + + bool _normalized; + + std::optional _offset; + std::optional _scale; + std::optional _max; + std::optional _min; + + bool _required; + std::optional _noData; + std::optional _defaultValue; + + /** + * @brief Attempts to parse from the given json value. + * + * If T is a type with multiple components, e.g. a VECN or MATN type, this + * will return std::nullopt if one or more components could not be parsed. + * + * If T is an array view, this will return std::nullopt if one or + * more entries could not be parsed. + * + * @return The value as an instance of T, or std::nullopt if it could not be + * parsed. + */ + template + static std::optional getValue(const CesiumUtility::JsonValue& jsonValue) { + if constexpr (IsMetadataScalar::value) { + return getScalar(jsonValue); + } else + + if constexpr (IsMetadataVecN::value) { + return getVecN(jsonValue); + } else + return std::nullopt; + + // if constexpr (IsMetadataMatN::value) { + //} + } + + /** + * @brief Attempts to parse from the given json value. If it could not be + * parsed as an ElementType, this returns the default value. + * + * If ElementType is a type with multiple components, e.g. a VECN or MATN + * type. + * + * @return The value as an ElementType, or std::nullopt if it could not be + * parsed. + */ + template + static T getValueOrDefault( + const CesiumUtility::JsonValue& jsonValue, + const T& defaultValue) { + if constexpr (IsMetadataScalar::value) { + return jsonValue.getSafeNumberOrDefault(defaultValue); + } + + if constexpr (IsMetadataVecN::value) { + return getVecNOrDefault(jsonValue, defaultValue); + } + + if constexpr (IsMetadataMatN::value) { + } + } + + /** + * @brief Attempts to parse from the given json value. If it could not be + * parsed as an ElementType, this returns the default value. + * + * If ElementType is a type with multiple components, e.g. a VECN or MATN + * type. + * + * @return The value as an ElementType, or std::nullopt if it could not be + * parsed. + */ + template + static std::optional getScalar(const CesiumUtility::JsonValue& jsonValue) { + try { + return jsonValue.getSafeNumber(); + } catch (const CesiumUtility::JsonValueNotRealValue& /*error*/) { + return std::nullopt; + } catch (const gsl::narrowing_error& /*error*/) { + // Continue below. + } + + // If the value is in range, but it loses precision, a narrowing_error will + // be returned. Try to round to a reasonable number anyways, even if it + // loses precision. + if (jsonValue.isInt64()) { + int64_t int64Value = jsonValue.getInt64(); + if (int64Value >= + static_cast(std::numeric_limits::lowest()) && + int64Value <= static_cast(std::numeric_limits::max())) { + return static_cast(int64Value); + } + } else if (jsonValue.isUint64()) { + uint64_t uint64Value = jsonValue.getUint64(); + if (uint64Value <= static_cast(std::numeric_limits::max())) { + return static_cast(uint64Value); + } + } else if (jsonValue.isDouble()) { + double doubleValue = jsonValue.getDouble(); + if (doubleValue >= + static_cast(std::numeric_limits::lowest()) && + doubleValue <= static_cast(std::numeric_limits::max())) { + return static_cast(doubleValue); + } + } + + return std::nullopt; + } + + template + static std::optional + getVecN(const CesiumUtility::JsonValue& jsonValue) { + if (!jsonValue.isArray()) { + return std::nullopt; + } + + return std::nullopt; + // const CesiumUtility::JsonValue::Array& array = value.getArray(); + // glm::length_t N = VecType::length(); + // if (array.size() != N) { + // return std::nullopt; + //} + + // using T = VecType::type; + + // glm::length result; + // for (glm::length_t i = 0; i < N; i++) { + // std::optional value = getValue(array[i]); + // if (!value) { + // return std::nullopt; + // } + + // result[i] = value; + //} + + // return result; + } + + template + static VecType getVecNOrDefault( + const CesiumUtility::JsonValue& value, + const VecType& defaultValue) { + if (!jsonValue.isArray()) { + return defaultValue; + } + + const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + glm::length_t N = VecType::length(); + if (array.size() != N) { + return defaultValue; + } + + using T = VecType::type; + + VecType result; + for (glm::length_t i = 0; i < N; i++) { + std::optional value = getValue(array[i]); + if (!value) { + return std::nullopt; + } + + result[i] = value ? *value : defaultValue; + } + + return result; + } + + // template + // static std::optional + // getMatNFromJsonValue(const CesiumUtility::JsonValue& value) { + // if (!jsonValue.isArray()) { + // return std::nullopt; + // } + + // const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + // if (array.size() != N) { + // return std::nullopt; + // } + + // glm::vec result; + // for (glm::length_t i = 0; i < N; i++) { + // std::optional value = getValue(array[i]); + // if (!value) { + // return std::nullopt; + // } + + // result[i] = value; + // } + + // return result; + //} +}; + +template <> class PropertyView : IPropertyView { +public: + /** + * @brief Constructs an empty property instance. + */ + PropertyView() + : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), + _required(false), + _defaultValue(std::nullopt) {} + + /** + * @brief Constructs a property instance from a class definition only. + */ + PropertyView(const ClassProperty& classProperty) + : _propertyViewStatus(PropertyViewStatus::Valid), + _required(classProperty.required), + _defaultValue(std::nullopt) { + if (classProperty.type != ClassProperty::Type::BOOLEAN) { + _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (classProperty.array) { + _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + if (!_required) { + _defaultValue = classProperty.defaultProperty + ? getBooleanValue(*classProperty.defaultProperty) + : std::nullopt; + } + } + + /** + * @brief Constructs a property instance from a property table property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTableProperty& /*property*/) + : PropertyView(classProperty) {} + + /** + * @brief Constructs a property instance from a property texture property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& /*property*/) + : PropertyView(classProperty) {} + + ~PropertyView() {} + + /** + * @copydoc IPropertyView::arrayCount + */ + virtual int64_t arrayCount() const noexcept override { return 0; } + + /** + * @copydoc IPropertyView::normalized + */ + virtual bool normalized() const noexcept override { return false; } + + /** + * @copydoc IPropertyView::offset + */ + virtual std::optional offset() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::scale + */ + virtual std::optional scale() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::max + */ + virtual std::optional max() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::min + */ + virtual std::optional min() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::required + */ + virtual bool required() const noexcept override { return _required; } + + /** + * @copydoc IPropertyView::noData + */ + virtual std::optional noData() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::defaultValue + */ + virtual std::optional defaultValue() const noexcept override { + return _defaultValue; + } + +protected: + /** + * @copydoc IPropertyView::propertyViewStatus + */ + virtual PropertyViewStatus propertyViewStatus() const noexcept override { + return _propertyViewStatus; + } + +private: + PropertyViewStatus _propertyViewStatus; + bool _required; + std::optional _defaultValue; + + static std::optional + getBooleanValue(const CesiumUtility::JsonValue& value) { + if (!value.isBool()) { + return std::nullopt; + } + + return value.getBool(); + } +}; + +template <> +class PropertyView : IPropertyView { +public: + /** + * @brief Constructs an empty property instance. + */ + PropertyView() + : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + + /** + * @brief Constructs a property instance from a class definition only. + */ + PropertyView(const ClassProperty& classProperty) + : _propertyViewStatus(PropertyViewStatus::Valid), + _required(classProperty.required), + _noData(std::nullopt), + _defaultValue(std::nullopt) { + if (classProperty.type != ClassProperty::Type::STRING) { + _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (classProperty.array) { + _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + if (!_required) { + _noData = classProperty.noData ? getStringValue(*classProperty.noData) + : std::nullopt; + _defaultValue = classProperty.defaultProperty + ? getStringValue(*classProperty.defaultProperty) + : std::nullopt; + } + } + + /** + * @brief Constructs a property instance from a property table property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTableProperty& /*property*/) + : PropertyView(classProperty) {} + + /** + * @brief Constructs a property instance from a property texture property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& /*property*/) + : PropertyView(classProperty) {} + + ~PropertyView() {} + + /** + * @copydoc IPropertyView::arrayCount + */ + virtual int64_t arrayCount() const noexcept override { return 0; } + + /** + * @copydoc IPropertyView::normalized + */ + virtual bool normalized() const noexcept override { return false; } + + /** + * @copydoc IPropertyView::offset + */ + virtual std::optional offset() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::scale + */ + virtual std::optional scale() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::max + */ + virtual std::optional max() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::min + */ + virtual std::optional min() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::required + */ + virtual bool required() const noexcept override { return _required; } + + /** + * @copydoc IPropertyView::noData + */ + virtual std::optional noData() const noexcept override { + if (_noData) + return std::string_view(*_noData); + + return std::nullopt; + } + + /** + * @copydoc IPropertyView::defaultValue + */ + virtual std::optional + defaultValue() const noexcept override { + if (_defaultValue) + return std::string_view(*_defaultValue); + + return std::nullopt; + } + +protected: + /** + * @copydoc IPropertyView::propertyViewStatus + */ + virtual PropertyViewStatus propertyViewStatus() const noexcept override { + return _propertyViewStatus; + } + +private: + PropertyViewStatus _propertyViewStatus; + bool _required; + std::optional _noData; + std::optional _defaultValue; + + static std::optional + getStringValue(const CesiumUtility::JsonValue& value) { + if (!value.isString()) { + return std::nullopt; + } + + return std::string(value.getString().c_str()); + } +}; + +template +class PropertyView> + : IPropertyView> { +public: + /** + * @brief Constructs an empty property instance. + */ + PropertyView() + : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), + _count(0), + _normalized(false), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + + /** + * @brief Constructs a property instance from a class definition only. + */ + PropertyView(const ClassProperty& classProperty) + : _propertyViewStatus(PropertyViewStatus::Valid), + _count(0), + _normalized(classProperty.normalized), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(classProperty.required), + _noData(std::nullopt), + _defaultValue(std::nullopt) { + if (convertStringToPropertyType(classProperty.type) != + TypeToPropertyType::value) { + _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (!classProperty.componentType && + TypeToPropertyType::component != + PropertyComponentType::None) { + _propertyViewStatus = PropertyViewStatus::ErrorComponentTypeMismatch; + return; + } + + if (classProperty.componentType && + convertStringToPropertyComponentType(*classProperty.componentType) != + TypeToPropertyType::component) { + _propertyViewStatus = PropertyViewStatus::ErrorComponentTypeMismatch; + return; + } + + if (!classProperty.array) { + _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + _count = classProperty.count ? *classProperty.count : 0; + + //_offset = classProperty.offset + // ? getValue(*classProperty.offset) + // : std::nullopt; + //_scale = classProperty.scale ? getValue(*classProperty.scale) + // : std::nullopt; + //_max = classProperty.max ? getValue(*classProperty.max) + // : std::nullopt; + //_min = classProperty.min ? getValue(*classProperty.min) + // : std::nullopt; + + //if (!_required) { + // _noData = classProperty.noData + // ? getValue(*classProperty.noData) + // : std::nullopt; + // _defaultValue = + // classProperty.defaultProperty + // ? getValue(*classProperty.defaultProperty) + // : std::nullopt; + //} + } + +protected: + /** + * @brief Constructs a property instance from a property table property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTableProperty& /*property*/) + : PropertyView(classProperty) { + if (_propertyViewStatus != PropertyViewStatus::Valid) { + return; + } + + //// If the property has its own values, override the class-provided values. + //if (property.offset) { + // _offset = getValue(*property.offset); + //} + + //if (property.scale) { + // _scale = getValue(*property.scale); + //} + + //if (property.max) { + // _max = getValue(*property.max); + //} + + //if (property.min) { + // _min = getValue(*property.min); + //} + } + + /** + * @brief Constructs a property instance from a property texture property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& /*property*/) + : PropertyView(classProperty) { + if (_propertyViewStatus != PropertyViewStatus::Valid) { + return; + } + + //// If the property has its own values, override the class-provided values. + //if (property.offset) { + // _offset = getValue(*property.offset); + //} + + //if (property.scale) { + // _scale = getValue(*property.scale); + //} + + //if (property.max) { + // _max = getValue(*property.max); + //} + + //if (property.min) { + // _min = getValue(*property.min); + //} + } + +public: + /** + * @copydoc IPropertyView::arrayCount + */ + virtual int64_t arrayCount() const noexcept override { return _count; } + + /** + * @copydoc IPropertyView::normalized + */ + virtual bool normalized() const noexcept override { return _normalized; } + + /** + * @copydoc IPropertyView::offset + */ + virtual std::optional> + offset() const noexcept override { + return _offset; + } + + /** + * @copydoc IPropertyView::scale + */ + virtual std::optional> + scale() const noexcept override { + return _scale; + } + + /** + * @copydoc IPropertyView::max + */ + virtual std::optional> + max() const noexcept override { + return _max; + } + + /** + * @copydoc IPropertyView::min + */ + virtual std::optional> + min() const noexcept override { + return _min; + } + + /** + * @copydoc IPropertyView::required + */ + virtual bool required() const noexcept override { return _required; } + + /** + * @copydoc IPropertyView::noData + */ + virtual std::optional> + noData() const noexcept override { + return _noData; + } + + /** + * @copydoc IPropertyView::defaultValue + */ + virtual std::optional> + defaultValue() const noexcept override { + return _defaultValue; + } + +protected: + /** + * @copydoc IPropertyView::propertyViewStatus + */ + virtual PropertyViewStatus propertyViewStatus() const noexcept override { + return _propertyViewStatus; + } + +private: + PropertyViewStatus _propertyViewStatus; + + int64_t _count; + bool _normalized; + + std::optional> _offset; + std::optional> _scale; + std::optional> _max; + std::optional> _min; + + bool _required; + std::optional> _noData; + std::optional> _defaultValue; + + /** + * @brief Attempts to parse from the given json value. + * + * If T is a type with multiple components, e.g. a VECN or MATN type, this + * will return std::nullopt if one or more components could not be parsed. + * + * If T is an array view, this will return std::nullopt if one or + * more entries could not be parsed. + * + * @return The value as an instance of T, or std::nullopt if it could not be + * parsed. + */ + template + static std::optional getValue(const CesiumUtility::JsonValue& jsonValue) { + if constexpr (IsMetadataScalar::value) { + return getScalar(jsonValue); + } else + + if constexpr (IsMetadataVecN::value) { + return getVecN(jsonValue); + } else + return std::nullopt; + + // if constexpr (IsMetadataMatN::value) { + //} + } + + /** + * @brief Attempts to parse from the given json value. If it could not be + * parsed as an ElementType, this returns the default value. + * + * If ElementType is a type with multiple components, e.g. a VECN or MATN + * type. + * + * @return The value as an ElementType, or std::nullopt if it could not be + * parsed. + */ + template + static T getValueOrDefault( + const CesiumUtility::JsonValue& jsonValue, + const T& defaultValue) { + if constexpr (IsMetadataScalar::value) { + return jsonValue.getSafeNumberOrDefault(defaultValue); + } + + if constexpr (IsMetadataVecN::value) { + return getVecNOrDefault(jsonValue, defaultValue); + } + + if constexpr (IsMetadataMatN::value) { + } + + if constexpr (IsMetadataArray::value) { + return defaultValue; + // if (!jsonValue.isArray()) { + // return PropertyArrayView(std::vector()); + // } + + // return jsonValue.isArray() + // ? getArrayValueOrDefault(jsonValue.getArray(), + // defaultValue) : defaultValue; + } + } + + /** + * @brief Attempts to parse from the given json value. If it could not be + * parsed as an ElementType, this returns the default value. + * + * If ElementType is a type with multiple components, e.g. a VECN or MATN + * type. + * + * @return The value as an ElementType, or std::nullopt if it could not be + * parsed. + */ + template + static std::optional getScalar(const CesiumUtility::JsonValue& jsonValue) { + try { + return jsonValue.getSafeNumber(); + } catch (const CesiumUtility::JsonValueNotRealValue& /*error*/) { + return std::nullopt; + } catch (const gsl::narrowing_error& /*error*/) { + // Continue below. + } + + // If the value is in range, but it loses precision, a narrowing_error will + // be returned. Try to round to a reasonable number anyways, even if it + // loses precision. + if (jsonValue.isInt64()) { + int64_t int64Value = jsonValue.getInt64(); + if (int64Value >= + static_cast(std::numeric_limits::lowest()) && + int64Value <= static_cast(std::numeric_limits::max())) { + return static_cast(int64Value); + } + } else if (jsonValue.isUint64()) { + uint64_t uint64Value = jsonValue.getUint64(); + if (uint64Value <= static_cast(std::numeric_limits::max())) { + return static_cast(uint64Value); + } + } else if (jsonValue.isDouble()) { + double doubleValue = jsonValue.getDouble(); + if (doubleValue >= + static_cast(std::numeric_limits::lowest()) && + doubleValue <= static_cast(std::numeric_limits::max())) { + return static_cast(doubleValue); + } + } + + return std::nullopt; + } + + template + static std::optional + getVecN(const CesiumUtility::JsonValue& jsonValue) { + if (!jsonValue.isArray()) { + return std::nullopt; + } + + return std::nullopt; + // const CesiumUtility::JsonValue::Array& array = value.getArray(); + // glm::length_t N = VecType::length(); + // if (array.size() != N) { + // return std::nullopt; + //} + + // using T = VecType::type; + + // glm::length result; + // for (glm::length_t i = 0; i < N; i++) { + // std::optional value = getValue(array[i]); + // if (!value) { + // return std::nullopt; + // } + + // result[i] = value; + //} + + // return result; + } + + template + static VecType getVecNOrDefault( + const CesiumUtility::JsonValue& value, + const VecType& defaultValue) { + if (!jsonValue.isArray()) { + return defaultValue; + } + + const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + glm::length_t N = VecType::length(); + if (array.size() != N) { + return defaultValue; + } + + using T = VecType::type; + + VecType result; + for (glm::length_t i = 0; i < N; i++) { + std::optional value = getValue(array[i]); + if (!value) { + return std::nullopt; + } + + result[i] = value ? *value : defaultValue; + } + + return result; + } + + // template + // static std::optional + // getMatNFromJsonValue(const CesiumUtility::JsonValue& value) { + // if (!jsonValue.isArray()) { + // return std::nullopt; + // } + + // const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + // if (array.size() != N) { + // return std::nullopt; + // } + + // glm::vec result; + // for (glm::length_t i = 0; i < N; i++) { + // std::optional value = getValue(array[i]); + // if (!value) { + // return std::nullopt; + // } + + // result[i] = value; + // } + + // return result; + //} + + template + static std::optional> + getArrayValue(const CesiumUtility::JsonValue::Array& /*arrayValue*/) { + return std::nullopt; + // std::vector values(arrayValue.size()); + // for (size_t i = 0; i < arrayValue.size(); i++) { + // const CesiumUtility::JsonValue& value = arrayValue[i]; + // std::optional arrayElement = getValue(value); + // values[i] = arrayElement; + //} + + // return PropertyArrayView(values); + } + + template + static PropertyArrayView getArrayValueOrDefault( + const CesiumUtility::JsonValue::Array& arrayValue, + const ArrayType& defaultElementValue) { + + std::vector values(arrayValue.size()); + for (size_t i = 0; i < arrayValue.size(); i++) { + const CesiumUtility::JsonValue& value = arrayValue[i]; + std::optional arrayElement = getValue(value); + values[i] = arrayElement; + } + + return PropertyArrayView(values); + } +}; + +template <> +class PropertyView> + : IPropertyView> { +public: + /** + * @brief Constructs an empty property instance. + */ + PropertyView() + : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), + _count(0), + _required(false), + _defaultValue(std::nullopt) {} + + /** + * @brief Constructs a property instance from a class definition only. + */ + PropertyView(const ClassProperty& classProperty) + : _propertyViewStatus(PropertyViewStatus::Valid), + _count(0), + _required(classProperty.required), + _defaultValue(std::nullopt) { + if (classProperty.type != ClassProperty::Type::BOOLEAN) { + _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (!classProperty.array) { + _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + _count = classProperty.count ? *classProperty.count : 0; + + if (!_required) { + _defaultValue = + classProperty.defaultProperty + ? getBooleanArrayValues(*classProperty.defaultProperty) + : std::nullopt; + } + } + + /** + * @brief Constructs a property instance from a property table property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTableProperty& /*property*/) + : PropertyView(classProperty) {} + + /** + * @brief Constructs a property instance from a property texture property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& /*property*/) + : PropertyView(classProperty) {} + + ~PropertyView() {} + + /** + * @copydoc IPropertyView::arrayCount + */ + virtual int64_t arrayCount() const noexcept override { return _count; } + + /** + * @copydoc IPropertyView::normalized + */ + virtual bool normalized() const noexcept override { return false; } + + /** + * @copydoc IPropertyView::offset + */ + virtual std::optional> + offset() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::scale + */ + virtual std::optional> + scale() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::max + */ + virtual std::optional> max() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::min + */ + virtual std::optional> min() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::required + */ + virtual bool required() const noexcept override { return _required; } + + /** + * @copydoc IPropertyView::noData + */ + virtual std::optional> + noData() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::defaultValue + */ + virtual std::optional> + defaultValue() const noexcept override { + return _defaultValue; + } + +protected: + /** + * @copydoc IPropertyView::propertyViewStatus + */ + virtual PropertyViewStatus propertyViewStatus() const noexcept override { + return _propertyViewStatus; + } + +private: + PropertyViewStatus _propertyViewStatus; + int64_t _count; + bool _required; + std::optional> _defaultValue; + + static std::optional> + getBooleanArrayValues(const CesiumUtility::JsonValue& value) { + if (!value.isArray()) { + return std::nullopt; + } + + const CesiumUtility::JsonValue::Array& array = value.getArray(); + std::vector values(array.size()); + for (size_t i = 0; i < values.size(); i++) { + if (!array[i].isBool()) { + return std::nullopt; + } + + values[i] = array[i].getBool(); + } + + return values; + } +}; + +template <> +class PropertyView> + : IPropertyView> { +public: + /** + * @brief Constructs an empty property instance. + */ + PropertyView() + : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), + _count(0), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + + /** + * @brief Constructs a property instance from a class definition only. + */ + PropertyView(const ClassProperty& classProperty) + : _propertyViewStatus(PropertyViewStatus::Valid), + _count(0), + _required(classProperty.required), + _noData(std::nullopt), + _defaultValue(std::nullopt) { + if (classProperty.type != ClassProperty::Type::STRING) { + _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (!classProperty.array) { + _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + _count = classProperty.count ? *classProperty.count : 0; + + // if (!_required) { + // _noData = classProperty.noData ? + // getStringArrayData(*classProperty.noData) + // : std::nullopt; + // _defaultValue = classProperty.defaultProperty + // ? getStringArrayData(*classProperty.defaultProperty) + // : std::nullopt; + //} + } + + /** + * @brief Constructs a property instance from a property table property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTableProperty& /*property*/) + : PropertyView(classProperty) {} + + /** + * @brief Constructs a property instance from a property texture property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& /*property*/) + : PropertyView(classProperty) {} + + ~PropertyView() {} + + /** + * @copydoc IPropertyView::arrayCount + */ + virtual int64_t arrayCount() const noexcept override { return _count; } + + /** + * @copydoc IPropertyView::normalized + */ + virtual bool normalized() const noexcept override { return false; } + + /** + * @copydoc IPropertyView::offset + */ + virtual std::optional> + offset() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::scale + */ + virtual std::optional> + scale() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::max + */ + virtual std::optional> + max() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::min + */ + virtual std::optional> + min() const noexcept override { + return std::nullopt; + } + + /** + * @copydoc IPropertyView::required + */ + virtual bool required() const noexcept override { return _required; } + + /** + * @copydoc IPropertyView::noData + */ + virtual std::optional> + noData() const noexcept override { + return _noData; + } + + /** + * @copydoc IPropertyView::defaultValue + */ + virtual std::optional> + defaultValue() const noexcept override { + return _defaultValue; + } + +protected: + /** + * @copydoc IPropertyView::propertyViewStatus + */ + virtual PropertyViewStatus propertyViewStatus() const noexcept override { + return _propertyViewStatus; + } + +private: + PropertyViewStatus _propertyViewStatus; + int64_t _count; + bool _required; + std::optional> _noData; + std::optional> _defaultValue; + + static std::optional> + getStringArrayData(const CesiumUtility::JsonValue& value) { + if (!value.isArray()) { + return std::nullopt; + } + + std::vector strings; + } +}; + +} // namespace CesiumGltf diff --git a/CesiumGltf/src/PropertyTableView.cpp b/CesiumGltf/src/PropertyTableView.cpp index 0e861151e..77d137233 100644 --- a/CesiumGltf/src/PropertyTableView.cpp +++ b/CesiumGltf/src/PropertyTableView.cpp @@ -316,14 +316,14 @@ PropertyTableView::getStringPropertyValues( } return PropertyTablePropertyView( + propertyTableProperty, + classProperty, + _pPropertyTable->count, values, gsl::span(), stringOffsets, PropertyComponentType::None, - offsetType, - 0, - _pPropertyTable->count, - classProperty.normalized); + offsetType); } PropertyTablePropertyView> @@ -389,14 +389,14 @@ PropertyTableView::getStringArrayPropertyValues( } return PropertyTablePropertyView>( + propertyTableProperty, + classProperty, + _pPropertyTable->count, values, gsl::span(), stringOffsets, PropertyComponentType::None, - stringOffsetType, - fixedLengthArrayCount, - _pPropertyTable->count, - classProperty.normalized); + stringOffsetType); } // Get array offset type @@ -472,13 +472,13 @@ PropertyTableView::getStringArrayPropertyValues( } return PropertyTablePropertyView>( + propertyTableProperty, + classProperty, + _pPropertyTable->count, values, arrayOffsets, stringOffsets, arrayOffsetType, - stringOffsetType, - 0, - _pPropertyTable->count, - classProperty.normalized); + stringOffsetType); } } // namespace CesiumGltf diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 8fc0a28c1..8524cde90 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -16,10 +16,22 @@ template static void checkNumeric(const std::vector& expected) { data.resize(expected.size() * sizeof(T)); std::memcpy(data.data(), expected.data(), data.size()); + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + if (componentType != PropertyComponentType::None) { + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + } + PropertyTablePropertyView property( - gsl::span(data.data(), data.size()), + propertyTableProperty, + classProperty, static_cast(expected.size()), - false); + gsl::span(data.data(), data.size())); for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.get(i) == expected[static_cast(i)]); @@ -45,15 +57,30 @@ static void checkVariableLengthArray( offsets.data(), offsets.size() * sizeof(OffsetType)); + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + if (componentType != PropertyComponentType::None) { + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + } + + classProperty.array = true; + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + instanceCount, gsl::span(buffer.data(), buffer.size()), gsl::span(offsetBuffer.data(), offsetBuffer.size()), gsl::span(), offsetType, - PropertyComponentType::None, - 0, - instanceCount, - false); + PropertyComponentType::None); + + REQUIRE(property.arrayCount() == 0); size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { @@ -76,15 +103,31 @@ static void checkFixedLengthArray( buffer.resize(data.size() * sizeof(T)); std::memcpy(buffer.data(), data.data(), data.size() * sizeof(T)); + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + if (componentType != PropertyComponentType::None) { + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + } + + classProperty.array = true; + classProperty.count = fixedLengthArrayCount; + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + instanceCount, gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(), PropertyComponentType::None, - PropertyComponentType::None, - fixedLengthArrayCount, - instanceCount, - false); + PropertyComponentType::None); + + REQUIRE(property.arrayCount() == fixedLengthArrayCount); size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { @@ -221,11 +264,17 @@ TEST_CASE("Check boolean PropertyTablePropertyView") { std::vector data(sizeof(val)); std::memcpy(data.data(), &val, sizeof(val)); + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + size_t instanceCount = sizeof(unsigned long) * CHAR_BIT; PropertyTablePropertyView property( - gsl::span(data.data(), data.size()), + propertyTableProperty, + classProperty, static_cast(instanceCount), - false); + gsl::span(data.data(), data.size())); + for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.get(i) == bits[static_cast(i)]); } @@ -268,15 +317,20 @@ TEST_CASE("Check string PropertyTablePropertyView") { ¤tOffset, sizeof(uint32_t)); + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + PropertyTablePropertyView property( + propertyTableProperty, + classProperty, + static_cast(strings.size()), gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(offsetBuffer.data(), offsetBuffer.size()), PropertyComponentType::None, - PropertyComponentType::Uint32, - 0, - static_cast(strings.size()), - false); + PropertyComponentType::Uint32); + for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.get(i) == strings[static_cast(i)]); } @@ -826,15 +880,23 @@ TEST_CASE("Check fixed-length array of string") { ¤tStringOffset, sizeof(uint32_t)); + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + classProperty.count = 3; + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + static_cast(stringCount / 3), gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(stringOffsets.data(), stringOffsets.size()), PropertyComponentType::None, - PropertyComponentType::Uint32, - 3, - static_cast(stringCount / 3), - false); + PropertyComponentType::Uint32); + + REQUIRE(property.arrayCount() == classProperty.count); size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { @@ -897,17 +959,24 @@ TEST_CASE("Check variable-length string array PropertyTablePropertyView") { ¤tOffset, sizeof(uint32_t)); + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + 3, gsl::span(buffer.data(), buffer.size()), gsl::span( reinterpret_cast(arrayOffsets.data()), arrayOffsets.size() * sizeof(uint32_t)), gsl::span(stringOffsets.data(), stringOffsets.size()), PropertyComponentType::Uint32, - PropertyComponentType::Uint32, - 0, - 3, - false); + PropertyComponentType::Uint32); + + REQUIRE(property.arrayCount() == 0); size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { @@ -928,17 +997,24 @@ TEST_CASE("Check fixed-length boolean array PropertyTablePropertyView") { static_cast(0b11111010), static_cast(0b11100111)}; + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.array = true; + classProperty.count = 12; + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + 2, gsl::span(buffer.data(), buffer.size()), gsl::span(), gsl::span(), PropertyComponentType::Uint32, - PropertyComponentType::None, - 12, - 2, - false); + PropertyComponentType::None); REQUIRE(property.size() == 2); + REQUIRE(property.arrayCount() == classProperty.count); PropertyArrayView val0 = property.get(0); REQUIRE(val0.size() == 12); @@ -979,19 +1055,25 @@ TEST_CASE("Check variable-length boolean array PropertyTablePropertyView") { std::vector offsetBuffer{0, 3, 12, 28}; + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.array = true; + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + 3, gsl::span(buffer.data(), buffer.size()), gsl::span( reinterpret_cast(offsetBuffer.data()), offsetBuffer.size() * sizeof(uint32_t)), gsl::span(), PropertyComponentType::Uint32, - PropertyComponentType::None, - 0, - 3, - false); + PropertyComponentType::None); REQUIRE(property.size() == 3); + REQUIRE(property.arrayCount() == 0); PropertyArrayView val0 = property.get(0); REQUIRE(val0.size() == 3); diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index 4a625a350..434e30124 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -1,3247 +1,3247 @@ -#include "CesiumGltf/PropertyTableView.h" - -#include - -#include - -using namespace CesiumGltf; - -template -void addBufferToModel(Model& model, const std::vector& values) { - Buffer& valueBuffer = model.buffers.emplace_back(); - valueBuffer.cesium.data.resize(values.size() * sizeof(T)); - valueBuffer.byteLength = static_cast(valueBuffer.cesium.data.size()); - std::memcpy( - valueBuffer.cesium.data.data(), - values.data(), - valueBuffer.cesium.data.size()); - - BufferView& valueBufferView = model.bufferViews.emplace_back(); - valueBufferView.buffer = static_cast(model.buffers.size() - 1); - valueBufferView.byteOffset = 0; - valueBufferView.byteLength = valueBuffer.byteLength; -} - -TEST_CASE("Test PropertyTableView on model without EXT_structural_metadata " - "extension") { - Model model; - - // Create an erroneously isolated property table. - PropertyTable propertyTable; - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(10); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(0); - - PropertyTableView view(model, propertyTable); - REQUIRE( - view.status() == PropertyTableViewStatus::ErrorMissingMetadataExtension); - REQUIRE(view.size() == 0); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(!classProperty); -} - -TEST_CASE("Test PropertyTableView on model without metadata schema") { - Model model; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(10); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(0); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::ErrorMissingSchema); - REQUIRE(view.size() == 0); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(!classProperty); -} - -TEST_CASE("Test property table with nonexistent class") { - Model model; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "I Don't Exist"; - propertyTable.count = static_cast(10); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(0); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); - REQUIRE(view.size() == 0); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(!classProperty); -} - -TEST_CASE("Test scalar PropertyTableProperty") { - Model model; - std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; - - addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(values.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); - REQUIRE(classProperty->count == std::nullopt); - REQUIRE(!classProperty->array); - - SECTION("Access correct type") { - PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE(uint32Property.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(uint32Property.size() > 0); - - for (int64_t i = 0; i < uint32Property.size(); ++i) { - REQUIRE(uint32Property.get(i) == values[static_cast(i)]); - } - } - - SECTION("Access wrong type") { - PropertyTablePropertyView uvec3Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uvec3Invalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView u32mat3x3Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat3x3Invalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView boolInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - boolInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView stringInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - } - - SECTION("Access wrong component type") { - PropertyTablePropertyView uint8Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint8Invalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - - PropertyTablePropertyView int32Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - int32Invalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - - PropertyTablePropertyView uint64Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint64Invalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - } - - SECTION("Access incorrectly as array") { - PropertyTablePropertyView> uint32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - uint32ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Wrong buffer index") { - model.bufferViews[valueBufferViewIndex].buffer = 2; - PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); - } - - SECTION("Wrong buffer view index") { - propertyTableProperty.values = -1; - PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); - } - - SECTION("Buffer view points outside of the real buffer length") { - model.buffers[valueBufferIndex].cesium.data.resize(12); - PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); - } - - SECTION("Buffer view length isn't multiple of sizeof(T)") { - model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Buffer view length doesn't match with propertyTableCount") { - model.bufferViews[valueBufferViewIndex].byteLength = 12; - PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Property.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } -} - -TEST_CASE("Test vecN PropertyTableProperty") { - Model model; - std::vector values = { - glm::ivec3(-12, 34, 30), - glm::ivec3(11, 73, 0), - glm::ivec3(-2, 6, 12), - glm::ivec3(-4, 8, -13)}; - - addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::VEC3; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(values.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::VEC3); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); - REQUIRE(classProperty->count == std::nullopt); - REQUIRE(!classProperty->array); - - SECTION("Access correct type") { - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE(ivec3Property.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(ivec3Property.size() > 0); - - for (int64_t i = 0; i < ivec3Property.size(); ++i) { - REQUIRE(ivec3Property.get(i) == values[static_cast(i)]); - } - } - - SECTION("Access wrong type") { - PropertyTablePropertyView int32Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - int32Invalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView ivec2Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec2Invalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView i32mat3x3Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - i32mat3x3Invalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView boolInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - boolInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView stringInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - } - - SECTION("Access wrong component type") { - PropertyTablePropertyView u8vec3Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u8vec3Invalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - - PropertyTablePropertyView i16vec3Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - i16vec3Invalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - - PropertyTablePropertyView vec3Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - vec3Invalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - } - - SECTION("Access incorrectly as array") { - PropertyTablePropertyView> ivec3ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - ivec3ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Wrong buffer index") { - model.bufferViews[valueBufferViewIndex].buffer = 2; - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); - } - - SECTION("Wrong buffer view index") { - propertyTableProperty.values = -1; - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); - } - - SECTION("Buffer view points outside of the real buffer length") { - model.buffers[valueBufferIndex].cesium.data.resize(12); - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Property.status() == - PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); - } - - SECTION("Buffer view length isn't multiple of sizeof(T)") { - model.bufferViews[valueBufferViewIndex].byteLength = 11; - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Property.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Buffer view length doesn't match with propertyTableCount") { - model.bufferViews[valueBufferViewIndex].byteLength = 12; - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Property.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } -} - -TEST_CASE("Test matN PropertyTableProperty") { - Model model; - // clang-format off - std::vector values = { - glm::u32mat2x2( - 12, 34, - 30, 1), - glm::u32mat2x2( - 11, 8, - 73, 102), - glm::u32mat2x2( - 1, 0, - 63, 2), - glm::u32mat2x2( - 4, 8, - 3, 23)}; - // clang-format on - - addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::MAT2; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(values.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::MAT2); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); - REQUIRE(classProperty->count == std::nullopt); - REQUIRE(!classProperty->array); - - SECTION("Access correct type") { - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(u32mat2x2Property.size() > 0); - - for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { - REQUIRE(u32mat2x2Property.get(i) == values[static_cast(i)]); - } - } - - SECTION("Access wrong type") { - PropertyTablePropertyView uint32Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Invalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView uvec2Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uvec2Invalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView u32mat4x4Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat4x4Invalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView boolInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - boolInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView stringInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - } - - SECTION("Access wrong component type") { - PropertyTablePropertyView u8mat2x2Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u8mat2x2Invalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - - PropertyTablePropertyView i32mat2x2Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - i32mat2x2Invalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - - PropertyTablePropertyView mat2Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - mat2Invalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - } - - SECTION("Access incorrectly as array") { - PropertyTablePropertyView> - u32mat2x2ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - u32mat2x2ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Wrong buffer index") { - model.bufferViews[valueBufferViewIndex].buffer = 2; - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); - } - - SECTION("Wrong buffer view index") { - propertyTableProperty.values = -1; - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); - } - - SECTION("Buffer view points outside of the real buffer length") { - model.buffers[valueBufferIndex].cesium.data.resize(sizeof(glm::u32mat2x2)); - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == - PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); - } - - SECTION("Buffer view length isn't multiple of sizeof(T)") { - model.bufferViews[valueBufferViewIndex].byteLength = - sizeof(glm::u32mat2x2) * 4 - 1; - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Buffer view length doesn't match with propertyTableCount") { - model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::u32mat2x2); - - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } -} - -TEST_CASE("Test boolean PropertyTableProperty") { - Model model; - - int64_t instanceCount = 21; - std::vector expected; - std::vector values; - values.resize(3); - for (int64_t i = 0; i < instanceCount; ++i) { - if (i % 2 == 0) { - expected.emplace_back(true); - } else { - expected.emplace_back(false); - } - - uint8_t expectedValue = expected.back(); - int64_t byteIndex = i / 8; - int64_t bitIndex = i % 8; - values[static_cast(byteIndex)] = static_cast( - (expectedValue << bitIndex) | values[static_cast(byteIndex)]); - } - addBufferToModel(model, values); - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::BOOLEAN; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(instanceCount); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); - REQUIRE(classProperty->componentType == std::nullopt); - REQUIRE(classProperty->count == std::nullopt); - REQUIRE(!classProperty->array); - - SECTION("Access correct type") { - PropertyTablePropertyView boolProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE(boolProperty.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(boolProperty.size() == instanceCount); - for (int64_t i = 0; i < boolProperty.size(); ++i) { - bool expectedValue = expected[static_cast(i)]; - REQUIRE(boolProperty.get(i) == expectedValue); - } - } - - SECTION("Buffer size doesn't match with propertyTableCount") { - propertyTable.count = 66; - PropertyTablePropertyView boolProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - boolProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } -} - -TEST_CASE("Test string PropertyTableProperty") { - Model model; - - std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; - size_t totalBytes = 0; - for (const std::string& expectedValue : expected) { - totalBytes += expectedValue.size(); - } - - std::vector stringOffsets( - (expected.size() + 1) * sizeof(uint32_t)); - std::vector values(totalBytes); - uint32_t* offsetValue = reinterpret_cast(stringOffsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - const std::string& expectedValue = expected[i]; - std::memcpy( - values.data() + offsetValue[i], - expectedValue.c_str(), - expectedValue.size()); - offsetValue[i + 1] = - offsetValue[i] + static_cast(expectedValue.size()); - } - - addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - addBufferToModel(model, stringOffsets); - size_t offsetBufferIndex = model.buffers.size() - 1; - size_t offsetBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::STRING; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(expected.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT32; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - propertyTableProperty.stringOffsets = - static_cast(offsetBufferViewIndex); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::STRING); - REQUIRE(classProperty->componentType == std::nullopt); - REQUIRE(classProperty->count == std::nullopt); - REQUIRE(!classProperty->array); - - SECTION("Access correct type") { - PropertyTablePropertyView stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - REQUIRE(stringProperty.get(static_cast(i)) == expected[i]); - } - } - - SECTION("Wrong array type") { - PropertyTablePropertyView> - stringArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - stringArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Wrong offset type") { - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT8; - PropertyTablePropertyView stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT64; - stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.stringOffsetType = "NONSENSE"; - stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); - - propertyTableProperty.stringOffsetType = ""; - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::StringOffsetType::UINT32; - stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); - } - - SECTION("Offset values are not sorted ascending") { - uint32_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[2] = - static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); - } - - SECTION("Offset value points outside of value buffer") { - uint32_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = - static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); - } -} - -TEST_CASE("Test fixed-length scalar array") { - Model model; - std::vector values = - {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; - testClassProperty.array = true; - testClassProperty.count = 3; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - values.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 3); - - SECTION("Access the right type") { - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); - - for (int64_t i = 0; i < arrayProperty.size(); ++i) { - PropertyArrayView member = arrayProperty.get(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 3 + j)]); - } - } - } - - SECTION("Wrong type") { - PropertyTablePropertyView> boolArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView> uvec2ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - uvec2ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - } - - SECTION("Wrong component type") { - PropertyTablePropertyView> int32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - int32ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - } - - SECTION("Not an array type") { - PropertyTablePropertyView uint32Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint32Invalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Buffer size is not a multiple of type size") { - model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Negative component count") { - testClassProperty.count = -1; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == PropertyTablePropertyViewStatus:: - ErrorArrayCountAndOffsetBufferDontExist); - } - - SECTION("Value buffer doesn't fit into property table count") { - testClassProperty.count = 55; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } -} - -TEST_CASE("Test variable-length scalar array") { - Model model; - - std::vector> expected{ - {12, 33, 11, 344, 112, 444, 1}, - {}, - {}, - {122, 23, 333, 12}, - {}, - {333, 311, 22, 34}, - {}, - {33, 1888, 233, 33019}}; - size_t numOfElements = 0; - for (const auto& expectedMember : expected) { - numOfElements += expectedMember.size(); - } - - std::vector values(numOfElements * sizeof(uint16_t)); - std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); - uint64_t* offsetValue = reinterpret_cast(offsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - std::memcpy( - values.data() + offsetValue[i], - expected[i].data(), - expected[i].size() * sizeof(uint16_t)); - offsetValue[i + 1] = offsetValue[i] + expected[i].size() * sizeof(uint16_t); - } - - addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - addBufferToModel(model, offsets); - size_t offsetBufferIndex = model.buffers.size() - 1; - size_t offsetBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - 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; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(expected.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - propertyTableProperty.arrayOffsets = - static_cast(offsetBufferViewIndex); - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - 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); - - SECTION("Access the correct type") { - PropertyTablePropertyView> property = - view.getPropertyView>("TestClassProperty"); - REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - PropertyArrayView valueMember = - property.get(static_cast(i)); - REQUIRE(valueMember.size() == static_cast(expected[i].size())); - for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(expected[i][j] == valueMember[static_cast(j)]); - } - } - } - SECTION("Wrong offset type") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - - propertyTableProperty.arrayOffsetType = ""; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT64; - arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - } - - SECTION("Offset values are not sorted ascending") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); - } - - SECTION("Offset value points outside of value buffer") { - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = - static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); - } - - SECTION("Count and offset buffer are both present") { - testClassProperty.count = 3; - PropertyTablePropertyView> property = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - property.status() == - PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); - } -} - -TEST_CASE("Test fixed-length vecN array") { - Model model; - std::vector values = { - glm::ivec3(12, 34, -30), - glm::ivec3(-2, 0, 1), - glm::ivec3(1, 2, 8), - glm::ivec3(-100, 84, 6), - glm::ivec3(2, -2, -2), - glm::ivec3(40, 61, 3), - }; - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::VEC3; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; - testClassProperty.array = true; - testClassProperty.count = 2; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - values.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::VEC3); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 2); - - SECTION("Access the right type") { - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); - - for (int64_t i = 0; i < arrayProperty.size(); ++i) { - PropertyArrayView member = arrayProperty.get(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 2 + j)]); - } - } - } - - SECTION("Wrong type") { - PropertyTablePropertyView> int32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - int32ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView> ivec2ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - ivec2ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - } - - SECTION("Wrong component type") { - PropertyTablePropertyView> uvec3ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - uvec3ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - } - - SECTION("Not an array type") { - PropertyTablePropertyView ivec3Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Invalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Buffer size is not a multiple of type size") { - model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Negative component count") { - testClassProperty.count = -1; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == PropertyTablePropertyViewStatus:: - ErrorArrayCountAndOffsetBufferDontExist); - } - - SECTION("Value buffer doesn't fit into property table count") { - testClassProperty.count = 55; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } -} - -TEST_CASE("Test variable-length vecN array") { - Model model; - // clang-format off - std::vector> expected{ - { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1) }, - { glm::ivec3(1, 2, 8), }, - {}, - { glm::ivec3(-100, 84, 6), glm::ivec3(2, -2, -2), glm::ivec3(40, 61, 3) }, - { glm::ivec3(-1, 4, -7) }, - }; - // clang-format on - - size_t numOfElements = 0; - for (const auto& expectedMember : expected) { - numOfElements += expectedMember.size(); - } - - std::vector values(numOfElements * sizeof(glm::ivec3)); - std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); - uint64_t* offsetValue = reinterpret_cast(offsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - std::memcpy( - values.data() + offsetValue[i], - expected[i].data(), - expected[i].size() * sizeof(glm::ivec3)); - offsetValue[i + 1] = - offsetValue[i] + expected[i].size() * sizeof(glm::ivec3); - } - - addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - addBufferToModel(model, offsets); - size_t offsetBufferIndex = model.buffers.size() - 1; - size_t offsetBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::VEC3; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; - testClassProperty.array = true; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(expected.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - propertyTableProperty.arrayOffsets = - static_cast(offsetBufferViewIndex); - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::VEC3); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); - REQUIRE(classProperty->array); - REQUIRE(!classProperty->count); - - SECTION("Access the correct type") { - PropertyTablePropertyView> property = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - PropertyArrayView valueMember = - property.get(static_cast(i)); - REQUIRE(valueMember.size() == static_cast(expected[i].size())); - for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(expected[i][j] == valueMember[static_cast(j)]); - } - } - } - - SECTION("Wrong offset type") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - - propertyTableProperty.arrayOffsetType = ""; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT64; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - } - - SECTION("Offset values are not sorted ascending") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); - } - - SECTION("Offset value points outside of value buffer") { - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = - static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); - } - - SECTION("Count and offset buffer are both present") { - testClassProperty.count = 3; - PropertyTablePropertyView> property = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - property.status() == - PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); - } -} - -TEST_CASE("Test fixed-length matN array") { - Model model; - // clang-format off - std::vector values = { - glm::i32mat2x2( - 12, 34, - -30, 20), - glm::i32mat2x2( - -2, -2, - 0, 1), - glm::i32mat2x2( - 1, 2, - 8, 5), - glm::i32mat2x2( - -100, 3, - 84, 6), - glm::i32mat2x2( - 2, 12, - -2, -2), - glm::i32mat2x2( - 40, 61, - 7, -3), - }; - // clang-format on - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::MAT2; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; - testClassProperty.array = true; - testClassProperty.count = 2; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - values.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::MAT2); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 2); - - SECTION("Access the right type") { - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); - - for (int64_t i = 0; i < arrayProperty.size(); ++i) { - PropertyArrayView member = arrayProperty.get(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 2 + j)]); - } - } - } - - SECTION("Wrong type") { - PropertyTablePropertyView> int32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - int32ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView> ivec2ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - ivec2ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - } - - SECTION("Wrong component type") { - PropertyTablePropertyView> - u32mat2x2ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - u32mat2x2ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - } - - SECTION("Not an array type") { - PropertyTablePropertyView ivec3Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Invalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Buffer size is not a multiple of type size") { - model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Negative component count") { - testClassProperty.count = -1; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == PropertyTablePropertyViewStatus:: - ErrorArrayCountAndOffsetBufferDontExist); - } - - SECTION("Value buffer doesn't fit into property table count") { - testClassProperty.count = 55; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } -} - -TEST_CASE("Test variable-length matN array") { - Model model; - // clang-format off - std::vector data0{ - glm::i32mat2x2( - 3, -2, - 1, 0), - glm::i32mat2x2( - 40, 3, - 8, -9) - }; - std::vector data1{ - glm::i32mat2x2( - 1, 10, - 7, 8), - }; - std::vector data2{ - glm::i32mat2x2( - 18, 0, - 1, 17), - glm::i32mat2x2( - -4, -2, - -9, 1), - glm::i32mat2x2( - 1, 8, - -99, 3), - }; - // clang-format on - - std::vector> - expected{data0, {}, data1, data2, {}}; - - size_t numOfElements = 0; - for (const auto& expectedMember : expected) { - numOfElements += expectedMember.size(); - } - - std::vector values(numOfElements * sizeof(glm::i32mat2x2)); - std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); - uint64_t* offsetValue = reinterpret_cast(offsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - std::memcpy( - values.data() + offsetValue[i], - expected[i].data(), - expected[i].size() * sizeof(glm::i32mat2x2)); - offsetValue[i + 1] = - offsetValue[i] + expected[i].size() * sizeof(glm::i32mat2x2); - } - - addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - addBufferToModel(model, offsets); - size_t offsetBufferIndex = model.buffers.size() - 1; - size_t offsetBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::MAT2; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; - testClassProperty.array = true; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(expected.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - propertyTableProperty.arrayOffsets = - static_cast(offsetBufferViewIndex); - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::MAT2); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); - REQUIRE(classProperty->array); - REQUIRE(!classProperty->count); - - SECTION("Access the correct type") { - PropertyTablePropertyView> property = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - PropertyArrayView valueMember = - property.get(static_cast(i)); - REQUIRE(valueMember.size() == static_cast(expected[i].size())); - for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(expected[i][j] == valueMember[static_cast(j)]); - } - } - } - - SECTION("Wrong offset type") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - - propertyTableProperty.arrayOffsetType = ""; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT64; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - } - - SECTION("Offset values are not sorted ascending") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); - } - - SECTION("Offset value points outside of value buffer") { - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = - static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); - } - - SECTION("Count and offset buffer are both present") { - testClassProperty.count = 3; - PropertyTablePropertyView> property = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - property.status() == - PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); - } -} - -TEST_CASE("Test fixed-length boolean array") { - Model model; - - std::vector expected = { - true, - false, - false, - true, - false, - false, - true, - true, - true, - false, - false, - true}; - std::vector values; - size_t requiredBytesSize = static_cast( - glm::ceil(static_cast(expected.size()) / 8.0)); - values.resize(requiredBytesSize); - for (size_t i = 0; i < expected.size(); ++i) { - uint8_t expectedValue = expected[i]; - size_t byteIndex = i / 8; - size_t bitIndex = i % 8; - values[byteIndex] = - static_cast((expectedValue << bitIndex) | values[byteIndex]); - } - - addBufferToModel(model, values); - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::BOOLEAN; - testClassProperty.array = true; - testClassProperty.count = 3; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - expected.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 3); - - SECTION("Access correct type") { - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(boolArrayProperty.size() == propertyTable.count); - REQUIRE(boolArrayProperty.size() > 0); - for (int64_t i = 0; i < boolArrayProperty.size(); ++i) { - PropertyArrayView valueMember = boolArrayProperty.get(i); - for (int64_t j = 0; j < valueMember.size(); ++j) { - REQUIRE(valueMember[j] == expected[static_cast(i * 3 + j)]); - } - } - } - - SECTION("Wrong type") { - PropertyTablePropertyView> uint8ArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - uint8ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - } - - SECTION("View is not array type") { - PropertyTablePropertyView boolInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - boolInvalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Value buffer doesn't have enough required bytes") { - testClassProperty.count = 11; - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } - - SECTION("Count is negative") { - testClassProperty.count = -1; - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorArrayCountAndOffsetBufferDontExist); - } -} - -TEST_CASE("Test variable-length boolean array") { - Model model; - - std::vector> expected{ - {true, false, true, true, false, true, true}, - {}, - {}, - {}, - {false, false, false, false}, - {true, false, true}, - {false}, - {true, true, true, true, true, false, false}}; - size_t numOfElements = 0; - for (const auto& expectedMember : expected) { - numOfElements += expectedMember.size(); - } - - size_t requiredBytesSize = - static_cast(glm::ceil(static_cast(numOfElements) / 8.0)); - std::vector values(requiredBytesSize); - std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); - uint64_t* offsetValue = reinterpret_cast(offsets.data()); - size_t indexSoFar = 0; - for (size_t i = 0; i < expected.size(); ++i) { - for (size_t j = 0; j < expected[i].size(); ++j) { - uint8_t expectedValue = expected[i][j]; - size_t byteIndex = indexSoFar / 8; - size_t bitIndex = indexSoFar % 8; - values[byteIndex] = static_cast( - (expectedValue << bitIndex) | static_cast(values[byteIndex])); - ++indexSoFar; - } - offsetValue[i + 1] = offsetValue[i] + expected[i].size(); - } - - addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - addBufferToModel(model, offsets); - size_t offsetBufferIndex = model.buffers.size() - 1; - size_t offsetBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::BOOLEAN; - testClassProperty.array = true; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(expected.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - propertyTableProperty.arrayOffsets = - static_cast(offsetBufferViewIndex); - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); - REQUIRE(classProperty->array); - REQUIRE(!classProperty->count); - - SECTION("Access correct type") { - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - PropertyArrayView arrayMember = - boolArrayProperty.get(static_cast(i)); - REQUIRE(arrayMember.size() == static_cast(expected[i].size())); - for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(expected[i][j] == arrayMember[static_cast(j)]); - } - } - } - - SECTION("Wrong offset type") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - - propertyTableProperty.arrayOffsetType = ""; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT64; - arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - } - - SECTION("Offset values are not sorted ascending") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); - } - - SECTION("Offset value points outside of value buffer") { - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = static_cast( - model.buffers[valueBufferIndex].byteLength * 8 + 20); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); - } - - SECTION("Count and offset buffer both present") { - testClassProperty.count = 3; - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); - } -} - -TEST_CASE("Test fixed-length arrays of strings") { - Model model; - - std::vector expected{ - "What's up", - "Breaking news!!! Aliens no longer attacks the US first", - "But they still abduct my cows! Those milk thiefs! 👽 🐮", - "I'm not crazy. My mother had me tested 🤪", - "I love you, meat bags! ❤️", - "Book in the freezer"}; - - size_t totalBytes = 0; - for (const std::string& expectedValue : expected) { - totalBytes += expectedValue.size(); - } - - std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); - std::vector values(totalBytes); - uint32_t* offsetValue = reinterpret_cast(offsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - const std::string& expectedValue = expected[i]; - std::memcpy( - values.data() + offsetValue[i], - expectedValue.c_str(), - expectedValue.size()); - offsetValue[i + 1] = - offsetValue[i] + static_cast(expectedValue.size()); - } - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - addBufferToModel(model, offsets); - size_t offsetBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::STRING; - testClassProperty.array = true; - testClassProperty.count = 2; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - expected.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT32; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - propertyTableProperty.stringOffsets = - static_cast(offsetBufferViewIndex); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::STRING); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 2); - - SECTION("Access correct type") { - PropertyTablePropertyView> - stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(stringProperty.size() == 3); - - PropertyArrayView v0 = stringProperty.get(0); - REQUIRE(v0.size() == 2); - REQUIRE(v0[0] == "What's up"); - REQUIRE(v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); - - PropertyArrayView v1 = stringProperty.get(1); - REQUIRE(v1.size() == 2); - REQUIRE(v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); - REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); - - PropertyArrayView v2 = stringProperty.get(2); - REQUIRE(v2.size() == 2); - REQUIRE(v2[0] == "I love you, meat bags! ❤️"); - REQUIRE(v2[1] == "Book in the freezer"); - } - - SECTION("Array type mismatch") { - PropertyTablePropertyView stringProperty = - view.getPropertyView("TestClassProperty"); - REQUIRE( - stringProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Count is negative") { - testClassProperty.count = -1; - PropertyTablePropertyView> - stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - stringProperty.status() == PropertyTablePropertyViewStatus:: - ErrorArrayCountAndOffsetBufferDontExist); - } - - SECTION("Offset type is unknown") { - propertyTableProperty.stringOffsetType = "NONSENSE"; - PropertyTablePropertyView> - stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - stringProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); - - propertyTableProperty.stringOffsetType = ""; - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT32; - stringProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - stringProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); - } - - SECTION("String offsets don't exist") { - propertyTableProperty.stringOffsets = -1; - PropertyTablePropertyView> - stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - stringProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetBufferView); - } -} - -TEST_CASE("Test variable-length arrays of strings") { - Model model; - - std::vector> expected{ - {"What's up"}, - {"Breaking news!!! Aliens no longer attacks the US first", - "But they still abduct my cows! Those milk thiefs! 👽 🐮"}, - {"I'm not crazy. My mother had me tested 🤪", - "I love you, meat bags! ❤️", - "Book in the freezer"}}; - - size_t totalBytes = 0; - size_t numOfElements = 0; - for (const auto& expectedValues : expected) { - for (const auto& value : expectedValues) { - totalBytes += value.size(); - } - - numOfElements += expectedValues.size(); - } - - std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); - std::vector stringOffsets((numOfElements + 1) * sizeof(uint32_t)); - std::vector values(totalBytes); - uint32_t* offsetValue = reinterpret_cast(offsets.data()); - uint32_t* stringOffsetValue = - reinterpret_cast(stringOffsets.data()); - size_t strOffsetIdx = 0; - for (size_t i = 0; i < expected.size(); ++i) { - for (size_t j = 0; j < expected[i].size(); ++j) { - const std::string& expectedValue = expected[i][j]; - std::memcpy( - values.data() + stringOffsetValue[strOffsetIdx], - expectedValue.c_str(), - expectedValue.size()); - - stringOffsetValue[strOffsetIdx + 1] = - stringOffsetValue[strOffsetIdx] + - static_cast(expectedValue.size()); - ++strOffsetIdx; - } - - offsetValue[i + 1] = - offsetValue[i] + - static_cast(expected[i].size() * sizeof(uint32_t)); - } - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - addBufferToModel(model, offsets); - size_t arrayOffsetBuffer = model.buffers.size() - 1; - size_t arrayOffsetBufferView = model.bufferViews.size() - 1; - - addBufferToModel(model, stringOffsets); - size_t stringOffsetBuffer = model.buffers.size() - 1; - size_t stringOffsetBufferView = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::STRING; - testClassProperty.array = true; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(expected.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT32; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT32; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - propertyTableProperty.arrayOffsets = - static_cast(arrayOffsetBufferView); - propertyTableProperty.stringOffsets = - static_cast(stringOffsetBufferView); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::STRING); - REQUIRE(classProperty->array); - REQUIRE(!classProperty->componentType); - REQUIRE(!classProperty->count); - - SECTION("Access correct type") { - PropertyTablePropertyView> - stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - PropertyArrayView stringArray = - stringProperty.get(static_cast(i)); - for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(stringArray[static_cast(j)] == expected[i][j]); - } - } - } - - SECTION("Wrong array offset type") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView> - arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT32; - } - - SECTION("Wrong string offset type") { - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT8; - PropertyTablePropertyView> - arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT16; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.stringOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT32; - } - - SECTION("Array offset values are not sorted ascending") { - uint32_t* offset = reinterpret_cast( - model.buffers[arrayOffsetBuffer].cesium.data.data()); - offset[0] = static_cast(1000); - PropertyTablePropertyView> - arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); - offset[0] = 0; - } - - SECTION("String offset values are not sorted ascending") { - uint32_t* offset = reinterpret_cast( - model.buffers[stringOffsetBuffer].cesium.data.data()); - offset[0] = static_cast(1000); - PropertyTablePropertyView> - arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); - offset[0] = 0; - } - - SECTION("Array offset value points outside of value buffer") { - uint32_t* offset = reinterpret_cast( - model.buffers[arrayOffsetBuffer].cesium.data.data()); - uint32_t previousValue = offset[propertyTable.count]; - offset[propertyTable.count] = static_cast(100000); - PropertyTablePropertyView> - arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); - offset[propertyTable.count] = previousValue; - } - - SECTION("String offset value points outside of value buffer") { - uint32_t* offset = reinterpret_cast( - model.buffers[stringOffsetBuffer].cesium.data.data()); - uint32_t previousValue = offset[6]; - offset[6] = static_cast(100000); - PropertyTablePropertyView> - arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); - offset[6] = previousValue; - } - - SECTION("Count and offset buffer both present") { - testClassProperty.count = 3; - PropertyTablePropertyView> - boolArrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); - } -} - -TEST_CASE("Test callback on invalid property table view") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - metadata.schema.emplace(); - - // Property table has a nonexistent class. - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(5); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(-1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); - REQUIRE(view.size() == 0); - - 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() == - PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); - REQUIRE(propertyValue.size() == 0); - }); - - REQUIRE(invokedCallbackCount == 1); -} - -TEST_CASE("Test callback for invalid PropertyTableProperty") { - Model model; - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["InvalidProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(5); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["InvalidProperty"]; - propertyTableProperty.values = static_cast(-1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - 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() != PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() == 0); - }; - - view.getPropertyView("InvalidProperty", testCallback); - view.getPropertyView("NonexistentProperty", testCallback); - - REQUIRE(invokedCallbackCount == 2); -} - -TEST_CASE("Test callback for scalar PropertyTableProperty") { - Model model; - std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(values.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); - REQUIRE(!classProperty->array); - REQUIRE(classProperty->count == std::nullopt); - - uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&values, &invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) mutable { - invokedCallbackCount++; - if constexpr (std::is_same_v< - PropertyTablePropertyView, - decltype(propertyValue)>) { - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - - for (int64_t i = 0; i < propertyValue.size(); ++i) { - REQUIRE( - static_cast(propertyValue.get(i)) == - values[static_cast(i)]); - } - } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); - } - }); - - REQUIRE(invokedCallbackCount == 1); -} - -TEST_CASE("Test callback for vecN PropertyTableProperty") { - Model model; - std::vector values = { - glm::ivec3(-12, 34, 30), - glm::ivec3(11, 73, 0), - glm::ivec3(-2, 6, 12), - glm::ivec3(-4, 8, -13)}; - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::VEC3; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(values.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::VEC3); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); - REQUIRE(classProperty->count == std::nullopt); - REQUIRE(!classProperty->array); - - uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&values, &invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) mutable { - invokedCallbackCount++; - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - - if constexpr (std::is_same_v< - PropertyTablePropertyView, - decltype(propertyValue)>) { - for (int64_t i = 0; i < propertyValue.size(); ++i) { - REQUIRE( - static_cast(propertyValue.get(i)) == - values[static_cast(i)]); - } - } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); - } - }); - - REQUIRE(invokedCallbackCount == 1); -} - -TEST_CASE("Test callback for matN PropertyTableProperty") { - Model model; - // clang-format off - std::vector values = { - glm::u32mat2x2( - 12, 34, - 30, 1), - glm::u32mat2x2( - 11, 8, - 73, 102), - glm::u32mat2x2( - 1, 0, - 63, 2), - glm::u32mat2x2( - 4, 8, - 3, 23)}; - // clang-format on - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::MAT2; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(values.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::MAT2); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); - REQUIRE(classProperty->count == std::nullopt); - REQUIRE(!classProperty->array); - - uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&values, &invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) mutable { - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - - if constexpr (std::is_same_v< - PropertyTablePropertyView, - decltype(propertyValue)>) { - for (int64_t i = 0; i < propertyValue.size(); ++i) { - REQUIRE( - static_cast(propertyValue.get(i)) == - values[static_cast(i)]); - } - } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); - } - invokedCallbackCount++; - }); - - REQUIRE(invokedCallbackCount == 1); -} - -TEST_CASE("Test callback for boolean PropertyTableProperty") { - Model model; - - int64_t instanceCount = 21; - std::vector expected; - std::vector values; - values.resize(3); - for (int64_t i = 0; i < instanceCount; ++i) { - if (i % 2 == 0) { - expected.emplace_back(true); - } else { - expected.emplace_back(false); - } - - uint8_t expectedValue = expected.back(); - int64_t byteIndex = i / 8; - int64_t bitIndex = i % 8; - values[static_cast(byteIndex)] = static_cast( - (expectedValue << bitIndex) | values[static_cast(byteIndex)]); - } - - addBufferToModel(model, values); - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::BOOLEAN; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(instanceCount); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); - REQUIRE(classProperty->componentType == std::nullopt); - REQUIRE(classProperty->count == std::nullopt); - REQUIRE(!classProperty->array); - - uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&expected, &invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) mutable { - invokedCallbackCount++; - - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - - if constexpr (std::is_same_v< - PropertyTablePropertyView, - decltype(propertyValue)>) { - for (int64_t i = 0; i < propertyValue.size(); ++i) { - REQUIRE( - static_cast(propertyValue.get(i)) == - expected[static_cast(i)]); - } - } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); - } - }); - - REQUIRE(invokedCallbackCount == 1); -} - -TEST_CASE("Test callback for string PropertyTableProperty") { - Model model; - - std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; - size_t totalBytes = 0; - for (const std::string& expectedValue : expected) { - totalBytes += expectedValue.size(); - } - - std::vector stringOffsets( - (expected.size() + 1) * sizeof(uint32_t)); - std::vector values(totalBytes); - uint32_t* offsetValue = reinterpret_cast(stringOffsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - const std::string& expectedValue = expected[i]; - std::memcpy( - values.data() + offsetValue[i], - expectedValue.c_str(), - expectedValue.size()); - offsetValue[i + 1] = - offsetValue[i] + static_cast(expectedValue.size()); - } - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - addBufferToModel(model, stringOffsets); - size_t offsetBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::STRING; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(expected.size()); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT32; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - propertyTableProperty.stringOffsets = - static_cast(offsetBufferViewIndex); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::STRING); - REQUIRE(classProperty->componentType == std::nullopt); - REQUIRE(classProperty->count == std::nullopt); - REQUIRE(!classProperty->array); - - uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&expected, &invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) mutable { - invokedCallbackCount++; - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - - if constexpr (std::is_same_v< - PropertyTablePropertyView, - decltype(propertyValue)>) { - for (int64_t i = 0; i < propertyValue.size(); ++i) { - REQUIRE( - static_cast(propertyValue.get(i)) == - expected[static_cast(i)]); - } - } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); - } - }); - - REQUIRE(invokedCallbackCount == 1); -} - -TEST_CASE("Test callback for scalar array PropertyTableProperty") { - Model model; - std::vector values = - {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; - - addBufferToModel(model, values); - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; - testClassProperty.array = true; - testClassProperty.count = 3; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - values.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 3); - - uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&values, &invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) { - invokedCallbackCount++; - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - - if constexpr (std::is_same_v< - PropertyTablePropertyView< - PropertyArrayView>, - decltype(propertyValue)>) { - for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.get(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 3 + j)]); - } - } - } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); - } - }); - - REQUIRE(invokedCallbackCount == 1); -} - -TEST_CASE("Test callback for vecN array PropertyTableProperty") { - Model model; - std::vector values = { - glm::ivec3(12, 34, -30), - glm::ivec3(-2, 0, 1), - glm::ivec3(1, 2, 8), - glm::ivec3(-100, 84, 6), - glm::ivec3(2, -2, -2), - glm::ivec3(40, 61, 3), - }; - - addBufferToModel(model, values); - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::VEC3; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; - testClassProperty.array = true; - testClassProperty.count = 2; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - values.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::VEC3); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 2); - - uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&values, &invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) { - invokedCallbackCount++; - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - - if constexpr (std::is_same_v< - PropertyTablePropertyView< - PropertyArrayView>, - decltype(propertyValue)>) { - for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.get(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 2 + j)]); - } - } - } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); - } - }); - - REQUIRE(invokedCallbackCount == 1); -} - -TEST_CASE("Test callback for matN array PropertyTableProperty") { - Model model; - // clang-format off - std::vector values = { - glm::i32mat2x2( - 12, 34, - -30, 20), - glm::i32mat2x2( - -2, -2, - 0, 1), - glm::i32mat2x2( - 1, 2, - 8, 5), - glm::i32mat2x2( - -100, 3, - 84, 6), - glm::i32mat2x2( - 2, 12, - -2, -2), - glm::i32mat2x2( - 40, 61, - 7, -3), - }; - // clang-format on - - addBufferToModel(model, values); - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::MAT2; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; - testClassProperty.array = true; - testClassProperty.count = 2; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - values.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::MAT2); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 2); - - uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&values, &invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) { - invokedCallbackCount++; - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - - if constexpr (std::is_same_v< - PropertyTablePropertyView< - PropertyArrayView>, - decltype(propertyValue)>) { - for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.get(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 2 + j)]); - } - } - } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); - } - }); - - REQUIRE(invokedCallbackCount == 1); -} - -TEST_CASE("Test callback for boolean array PropertyTableProperty") { - Model model; - - std::vector expected = { - true, - false, - false, - true, - false, - false, - true, - true, - true, - false, - false, - true}; - std::vector values; - size_t requiredBytesSize = static_cast( - glm::ceil(static_cast(expected.size()) / 8.0)); - values.resize(requiredBytesSize); - for (size_t i = 0; i < expected.size(); ++i) { - uint8_t expectedValue = expected[i]; - size_t byteIndex = i / 8; - size_t bitIndex = i % 8; - values[byteIndex] = - static_cast((expectedValue << bitIndex) | values[byteIndex]); - } - - addBufferToModel(model, values); - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::BOOLEAN; - testClassProperty.array = true; - testClassProperty.count = 3; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - expected.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 3); - - uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&expected, &invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) { - invokedCallbackCount++; - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - - if constexpr (std::is_same_v< - PropertyTablePropertyView>, - decltype(propertyValue)>) { - for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.get(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == expected[static_cast(i * 3 + j)]); - } - } - } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); - } - }); - - REQUIRE(invokedCallbackCount == 1); -} - -TEST_CASE("Test callback for string array PropertyTableProperty") { - Model model; - - std::vector expected{ - "What's up", - "Breaking news!!! Aliens no longer attacks the US first", - "But they still abduct my cows! Those milk thiefs! 👽 🐮", - "I'm not crazy. My mother had me tested 🤪", - "I love you, meat bags! ❤️", - "Book in the freezer"}; - - size_t totalBytes = 0; - for (const std::string& expectedValue : expected) { - totalBytes += expectedValue.size(); - } - - std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); - std::vector values(totalBytes); - uint32_t* offsetValue = reinterpret_cast(offsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - const std::string& expectedValue = expected[i]; - std::memcpy( - values.data() + offsetValue[i], - expectedValue.c_str(), - expectedValue.size()); - offsetValue[i + 1] = - offsetValue[i] + static_cast(expectedValue.size()); - } - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - addBufferToModel(model, offsets); - size_t offsetBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::STRING; - testClassProperty.array = true; - testClassProperty.count = 2; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - expected.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT32; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - propertyTableProperty.stringOffsets = - static_cast(offsetBufferViewIndex); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::STRING); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 2); - - uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) { - invokedCallbackCount++; - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() == 3); - - if constexpr (std::is_same_v< - PropertyTablePropertyView< - PropertyArrayView>, - decltype(propertyValue)>) { - PropertyArrayView v0 = propertyValue.get(0); - REQUIRE(v0.size() == 2); - REQUIRE(v0[0] == "What's up"); - REQUIRE( - v0[1] == - "Breaking news!!! Aliens no longer attacks the US first"); - - PropertyArrayView v1 = propertyValue.get(1); - REQUIRE(v1.size() == 2); - REQUIRE( - v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); - REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); - - PropertyArrayView v2 = propertyValue.get(2); - REQUIRE(v2.size() == 2); - REQUIRE(v2[0] == "I love you, meat bags! ❤️"); - REQUIRE(v2[1] == "Book in the freezer"); - } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); - } - }); - - REQUIRE(invokedCallbackCount == 1); -} +//#include "CesiumGltf/PropertyTableView.h" +// +//#include +// +//#include +// +//using namespace CesiumGltf; +// +//template +//void addBufferToModel(Model& model, const std::vector& values) { +// Buffer& valueBuffer = model.buffers.emplace_back(); +// valueBuffer.cesium.data.resize(values.size() * sizeof(T)); +// valueBuffer.byteLength = static_cast(valueBuffer.cesium.data.size()); +// std::memcpy( +// valueBuffer.cesium.data.data(), +// values.data(), +// valueBuffer.cesium.data.size()); +// +// BufferView& valueBufferView = model.bufferViews.emplace_back(); +// valueBufferView.buffer = static_cast(model.buffers.size() - 1); +// valueBufferView.byteOffset = 0; +// valueBufferView.byteLength = valueBuffer.byteLength; +//} +// +//TEST_CASE("Test PropertyTableView on model without EXT_structural_metadata " +// "extension") { +// Model model; +// +// // Create an erroneously isolated property table. +// PropertyTable propertyTable; +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(10); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(0); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE( +// view.status() == PropertyTableViewStatus::ErrorMissingMetadataExtension); +// REQUIRE(view.size() == 0); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(!classProperty); +//} +// +//TEST_CASE("Test PropertyTableView on model without metadata schema") { +// Model model; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(10); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(0); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::ErrorMissingSchema); +// REQUIRE(view.size() == 0); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(!classProperty); +//} +// +//TEST_CASE("Test property table with nonexistent class") { +// Model model; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::SCALAR; +// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "I Don't Exist"; +// propertyTable.count = static_cast(10); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(0); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); +// REQUIRE(view.size() == 0); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(!classProperty); +//} +// +//TEST_CASE("Test scalar PropertyTableProperty") { +// Model model; +// std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; +// +// addBufferToModel(model, values); +// size_t valueBufferIndex = model.buffers.size() - 1; +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::SCALAR; +// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(values.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); +// REQUIRE(classProperty->count == std::nullopt); +// REQUIRE(!classProperty->array); +// +// SECTION("Access correct type") { +// PropertyTablePropertyView uint32Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(uint32Property.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(uint32Property.size() > 0); +// +// for (int64_t i = 0; i < uint32Property.size(); ++i) { +// REQUIRE(uint32Property.get(i) == values[static_cast(i)]); +// } +// } +// +// SECTION("Access wrong type") { +// PropertyTablePropertyView uvec3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uvec3Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView u32mat3x3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u32mat3x3Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView boolInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// boolInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView stringInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// stringInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// } +// +// SECTION("Access wrong component type") { +// PropertyTablePropertyView uint8Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint8Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyTablePropertyView int32Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// int32Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyTablePropertyView uint64Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint64Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Access incorrectly as array") { +// PropertyTablePropertyView> uint32ArrayInvalid = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// uint32ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Wrong buffer index") { +// model.bufferViews[valueBufferViewIndex].buffer = 2; +// PropertyTablePropertyView uint32Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint32Property.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); +// } +// +// SECTION("Wrong buffer view index") { +// propertyTableProperty.values = -1; +// PropertyTablePropertyView uint32Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint32Property.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); +// } +// +// SECTION("Buffer view points outside of the real buffer length") { +// model.buffers[valueBufferIndex].cesium.data.resize(12); +// PropertyTablePropertyView uint32Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint32Property.status() == +// PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); +// } +// +// SECTION("Buffer view length isn't multiple of sizeof(T)") { +// model.bufferViews[valueBufferViewIndex].byteLength = 13; +// PropertyTablePropertyView uint32Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint32Property.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeNotDivisibleByTypeSize); +// } +// +// SECTION("Buffer view length doesn't match with propertyTableCount") { +// model.bufferViews[valueBufferViewIndex].byteLength = 12; +// PropertyTablePropertyView uint32Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint32Property.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// } +//} +// +//TEST_CASE("Test vecN PropertyTableProperty") { +// Model model; +// std::vector values = { +// glm::ivec3(-12, 34, 30), +// glm::ivec3(11, 73, 0), +// glm::ivec3(-2, 6, 12), +// glm::ivec3(-4, 8, -13)}; +// +// addBufferToModel(model, values); +// size_t valueBufferIndex = model.buffers.size() - 1; +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::VEC3; +// testClassProperty.componentType = ClassProperty::ComponentType::INT32; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(values.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::VEC3); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); +// REQUIRE(classProperty->count == std::nullopt); +// REQUIRE(!classProperty->array); +// +// SECTION("Access correct type") { +// PropertyTablePropertyView ivec3Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(ivec3Property.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(ivec3Property.size() > 0); +// +// for (int64_t i = 0; i < ivec3Property.size(); ++i) { +// REQUIRE(ivec3Property.get(i) == values[static_cast(i)]); +// } +// } +// +// SECTION("Access wrong type") { +// PropertyTablePropertyView int32Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// int32Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView ivec2Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// ivec2Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView i32mat3x3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// i32mat3x3Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView boolInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// boolInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView stringInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// stringInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// } +// +// SECTION("Access wrong component type") { +// PropertyTablePropertyView u8vec3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec3Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyTablePropertyView i16vec3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// i16vec3Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyTablePropertyView vec3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// vec3Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Access incorrectly as array") { +// PropertyTablePropertyView> ivec3ArrayInvalid = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// ivec3ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Wrong buffer index") { +// model.bufferViews[valueBufferViewIndex].buffer = 2; +// PropertyTablePropertyView ivec3Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// ivec3Property.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); +// } +// +// SECTION("Wrong buffer view index") { +// propertyTableProperty.values = -1; +// PropertyTablePropertyView ivec3Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// ivec3Property.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); +// } +// +// SECTION("Buffer view points outside of the real buffer length") { +// model.buffers[valueBufferIndex].cesium.data.resize(12); +// PropertyTablePropertyView ivec3Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// ivec3Property.status() == +// PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); +// } +// +// SECTION("Buffer view length isn't multiple of sizeof(T)") { +// model.bufferViews[valueBufferViewIndex].byteLength = 11; +// PropertyTablePropertyView ivec3Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// ivec3Property.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeNotDivisibleByTypeSize); +// } +// +// SECTION("Buffer view length doesn't match with propertyTableCount") { +// model.bufferViews[valueBufferViewIndex].byteLength = 12; +// PropertyTablePropertyView ivec3Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// ivec3Property.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// } +//} +// +//TEST_CASE("Test matN PropertyTableProperty") { +// Model model; +// // clang-format off +// std::vector values = { +// glm::u32mat2x2( +// 12, 34, +// 30, 1), +// glm::u32mat2x2( +// 11, 8, +// 73, 102), +// glm::u32mat2x2( +// 1, 0, +// 63, 2), +// glm::u32mat2x2( +// 4, 8, +// 3, 23)}; +// // clang-format on +// +// addBufferToModel(model, values); +// size_t valueBufferIndex = model.buffers.size() - 1; +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::MAT2; +// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(values.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::MAT2); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); +// REQUIRE(classProperty->count == std::nullopt); +// REQUIRE(!classProperty->array); +// +// SECTION("Access correct type") { +// PropertyTablePropertyView u32mat2x2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u32mat2x2Property.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(u32mat2x2Property.size() > 0); +// +// for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { +// REQUIRE(u32mat2x2Property.get(i) == values[static_cast(i)]); +// } +// } +// +// SECTION("Access wrong type") { +// PropertyTablePropertyView uint32Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint32Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView uvec2Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uvec2Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView u32mat4x4Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u32mat4x4Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView boolInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// boolInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView stringInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// stringInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// } +// +// SECTION("Access wrong component type") { +// PropertyTablePropertyView u8mat2x2Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8mat2x2Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyTablePropertyView i32mat2x2Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// i32mat2x2Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyTablePropertyView mat2Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// mat2Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Access incorrectly as array") { +// PropertyTablePropertyView> +// u32mat2x2ArrayInvalid = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// u32mat2x2ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Wrong buffer index") { +// model.bufferViews[valueBufferViewIndex].buffer = 2; +// PropertyTablePropertyView u32mat2x2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u32mat2x2Property.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); +// } +// +// SECTION("Wrong buffer view index") { +// propertyTableProperty.values = -1; +// PropertyTablePropertyView u32mat2x2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u32mat2x2Property.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); +// } +// +// SECTION("Buffer view points outside of the real buffer length") { +// model.buffers[valueBufferIndex].cesium.data.resize(sizeof(glm::u32mat2x2)); +// PropertyTablePropertyView u32mat2x2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u32mat2x2Property.status() == +// PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); +// } +// +// SECTION("Buffer view length isn't multiple of sizeof(T)") { +// model.bufferViews[valueBufferViewIndex].byteLength = +// sizeof(glm::u32mat2x2) * 4 - 1; +// PropertyTablePropertyView u32mat2x2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u32mat2x2Property.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeNotDivisibleByTypeSize); +// } +// +// SECTION("Buffer view length doesn't match with propertyTableCount") { +// model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::u32mat2x2); +// +// PropertyTablePropertyView u32mat2x2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u32mat2x2Property.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// } +//} +// +//TEST_CASE("Test boolean PropertyTableProperty") { +// Model model; +// +// int64_t instanceCount = 21; +// std::vector expected; +// std::vector values; +// values.resize(3); +// for (int64_t i = 0; i < instanceCount; ++i) { +// if (i % 2 == 0) { +// expected.emplace_back(true); +// } else { +// expected.emplace_back(false); +// } +// +// uint8_t expectedValue = expected.back(); +// int64_t byteIndex = i / 8; +// int64_t bitIndex = i % 8; +// values[static_cast(byteIndex)] = static_cast( +// (expectedValue << bitIndex) | values[static_cast(byteIndex)]); +// } +// addBufferToModel(model, values); +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::BOOLEAN; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(instanceCount); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = +// static_cast(model.bufferViews.size() - 1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); +// REQUIRE(classProperty->componentType == std::nullopt); +// REQUIRE(classProperty->count == std::nullopt); +// REQUIRE(!classProperty->array); +// +// SECTION("Access correct type") { +// PropertyTablePropertyView boolProperty = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(boolProperty.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(boolProperty.size() == instanceCount); +// for (int64_t i = 0; i < boolProperty.size(); ++i) { +// bool expectedValue = expected[static_cast(i)]; +// REQUIRE(boolProperty.get(i) == expectedValue); +// } +// } +// +// SECTION("Buffer size doesn't match with propertyTableCount") { +// propertyTable.count = 66; +// PropertyTablePropertyView boolProperty = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// boolProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// } +//} +// +//TEST_CASE("Test string PropertyTableProperty") { +// Model model; +// +// std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; +// size_t totalBytes = 0; +// for (const std::string& expectedValue : expected) { +// totalBytes += expectedValue.size(); +// } +// +// std::vector stringOffsets( +// (expected.size() + 1) * sizeof(uint32_t)); +// std::vector values(totalBytes); +// uint32_t* offsetValue = reinterpret_cast(stringOffsets.data()); +// for (size_t i = 0; i < expected.size(); ++i) { +// const std::string& expectedValue = expected[i]; +// std::memcpy( +// values.data() + offsetValue[i], +// expectedValue.c_str(), +// expectedValue.size()); +// offsetValue[i + 1] = +// offsetValue[i] + static_cast(expectedValue.size()); +// } +// +// addBufferToModel(model, values); +// size_t valueBufferIndex = model.buffers.size() - 1; +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// addBufferToModel(model, stringOffsets); +// size_t offsetBufferIndex = model.buffers.size() - 1; +// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::STRING; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(expected.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT32; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// propertyTableProperty.stringOffsets = +// static_cast(offsetBufferViewIndex); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::STRING); +// REQUIRE(classProperty->componentType == std::nullopt); +// REQUIRE(classProperty->count == std::nullopt); +// REQUIRE(!classProperty->array); +// +// SECTION("Access correct type") { +// PropertyTablePropertyView stringProperty = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); +// for (size_t i = 0; i < expected.size(); ++i) { +// REQUIRE(stringProperty.get(static_cast(i)) == expected[i]); +// } +// } +// +// SECTION("Wrong array type") { +// PropertyTablePropertyView> +// stringArrayInvalid = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// stringArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Wrong offset type") { +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT8; +// PropertyTablePropertyView stringProperty = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// stringProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT64; +// stringProperty = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// stringProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.stringOffsetType = "NONSENSE"; +// stringProperty = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// stringProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); +// +// propertyTableProperty.stringOffsetType = ""; +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::StringOffsetType::UINT32; +// stringProperty = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// stringProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); +// } +// +// SECTION("Offset values are not sorted ascending") { +// uint32_t* offset = reinterpret_cast( +// model.buffers[offsetBufferIndex].cesium.data.data()); +// offset[2] = +// static_cast(model.buffers[valueBufferIndex].byteLength + 4); +// PropertyTablePropertyView stringProperty = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// stringProperty.status() == +// PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); +// } +// +// SECTION("Offset value points outside of value buffer") { +// uint32_t* offset = reinterpret_cast( +// model.buffers[offsetBufferIndex].cesium.data.data()); +// offset[propertyTable.count] = +// static_cast(model.buffers[valueBufferIndex].byteLength + 4); +// PropertyTablePropertyView stringProperty = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// stringProperty.status() == +// PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); +// } +//} +// +//TEST_CASE("Test fixed-length scalar array") { +// Model model; +// std::vector values = +// {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; +// +// addBufferToModel(model, values); +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::SCALAR; +// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; +// testClassProperty.array = true; +// testClassProperty.count = 3; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast( +// values.size() / static_cast(testClassProperty.count.value())); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = +// static_cast(model.bufferViews.size() - 1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); +// REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 3); +// +// SECTION("Access the right type") { +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); +// +// for (int64_t i = 0; i < arrayProperty.size(); ++i) { +// PropertyArrayView member = arrayProperty.get(i); +// for (int64_t j = 0; j < member.size(); ++j) { +// REQUIRE(member[j] == values[static_cast(i * 3 + j)]); +// } +// } +// } +// +// SECTION("Wrong type") { +// PropertyTablePropertyView> boolArrayInvalid = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// boolArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView> uvec2ArrayInvalid = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// uvec2ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// } +// +// SECTION("Wrong component type") { +// PropertyTablePropertyView> int32ArrayInvalid = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// int32ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Not an array type") { +// PropertyTablePropertyView uint32Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint32Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Buffer size is not a multiple of type size") { +// model.bufferViews[valueBufferViewIndex].byteLength = 13; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeNotDivisibleByTypeSize); +// } +// +// SECTION("Negative component count") { +// testClassProperty.count = -1; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == PropertyTablePropertyViewStatus:: +// ErrorArrayCountAndOffsetBufferDontExist); +// } +// +// SECTION("Value buffer doesn't fit into property table count") { +// testClassProperty.count = 55; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// } +//} +// +//TEST_CASE("Test variable-length scalar array") { +// Model model; +// +// std::vector> expected{ +// {12, 33, 11, 344, 112, 444, 1}, +// {}, +// {}, +// {122, 23, 333, 12}, +// {}, +// {333, 311, 22, 34}, +// {}, +// {33, 1888, 233, 33019}}; +// size_t numOfElements = 0; +// for (const auto& expectedMember : expected) { +// numOfElements += expectedMember.size(); +// } +// +// std::vector values(numOfElements * sizeof(uint16_t)); +// std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); +// uint64_t* offsetValue = reinterpret_cast(offsets.data()); +// for (size_t i = 0; i < expected.size(); ++i) { +// std::memcpy( +// values.data() + offsetValue[i], +// expected[i].data(), +// expected[i].size() * sizeof(uint16_t)); +// offsetValue[i + 1] = offsetValue[i] + expected[i].size() * sizeof(uint16_t); +// } +// +// addBufferToModel(model, values); +// size_t valueBufferIndex = model.buffers.size() - 1; +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// addBufferToModel(model, offsets); +// size_t offsetBufferIndex = model.buffers.size() - 1; +// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// 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; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(expected.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// propertyTableProperty.arrayOffsets = +// static_cast(offsetBufferViewIndex); +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT64; +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// 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); +// +// SECTION("Access the correct type") { +// PropertyTablePropertyView> property = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); +// for (size_t i = 0; i < expected.size(); ++i) { +// PropertyArrayView valueMember = +// property.get(static_cast(i)); +// REQUIRE(valueMember.size() == static_cast(expected[i].size())); +// for (size_t j = 0; j < expected[i].size(); ++j) { +// REQUIRE(expected[i][j] == valueMember[static_cast(j)]); +// } +// } +// } +// SECTION("Wrong offset type") { +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT8; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT16; +// arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.arrayOffsetType = "NONSENSE"; +// arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); +// +// propertyTableProperty.arrayOffsetType = ""; +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT64; +// arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); +// } +// +// SECTION("Offset values are not sorted ascending") { +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT64; +// uint64_t* offset = reinterpret_cast( +// model.buffers[offsetBufferIndex].cesium.data.data()); +// offset[propertyTable.count] = 0; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); +// } +// +// SECTION("Offset value points outside of value buffer") { +// uint64_t* offset = reinterpret_cast( +// model.buffers[offsetBufferIndex].cesium.data.data()); +// offset[propertyTable.count] = +// static_cast(model.buffers[valueBufferIndex].byteLength + 4); +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); +// } +// +// SECTION("Count and offset buffer are both present") { +// testClassProperty.count = 3; +// PropertyTablePropertyView> property = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// property.status() == +// PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); +// } +//} +// +//TEST_CASE("Test fixed-length vecN array") { +// Model model; +// std::vector values = { +// glm::ivec3(12, 34, -30), +// glm::ivec3(-2, 0, 1), +// glm::ivec3(1, 2, 8), +// glm::ivec3(-100, 84, 6), +// glm::ivec3(2, -2, -2), +// glm::ivec3(40, 61, 3), +// }; +// +// addBufferToModel(model, values); +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::VEC3; +// testClassProperty.componentType = ClassProperty::ComponentType::INT32; +// testClassProperty.array = true; +// testClassProperty.count = 2; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast( +// values.size() / static_cast(testClassProperty.count.value())); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = +// static_cast(model.bufferViews.size() - 1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::VEC3); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); +// REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 2); +// +// SECTION("Access the right type") { +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); +// +// for (int64_t i = 0; i < arrayProperty.size(); ++i) { +// PropertyArrayView member = arrayProperty.get(i); +// for (int64_t j = 0; j < member.size(); ++j) { +// REQUIRE(member[j] == values[static_cast(i * 2 + j)]); +// } +// } +// } +// +// SECTION("Wrong type") { +// PropertyTablePropertyView> int32ArrayInvalid = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// int32ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView> ivec2ArrayInvalid = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// ivec2ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// } +// +// SECTION("Wrong component type") { +// PropertyTablePropertyView> uvec3ArrayInvalid = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// uvec3ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Not an array type") { +// PropertyTablePropertyView ivec3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// ivec3Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Buffer size is not a multiple of type size") { +// model.bufferViews[valueBufferViewIndex].byteLength = 13; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeNotDivisibleByTypeSize); +// } +// +// SECTION("Negative component count") { +// testClassProperty.count = -1; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == PropertyTablePropertyViewStatus:: +// ErrorArrayCountAndOffsetBufferDontExist); +// } +// +// SECTION("Value buffer doesn't fit into property table count") { +// testClassProperty.count = 55; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// } +//} +// +//TEST_CASE("Test variable-length vecN array") { +// Model model; +// // clang-format off +// std::vector> expected{ +// { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1) }, +// { glm::ivec3(1, 2, 8), }, +// {}, +// { glm::ivec3(-100, 84, 6), glm::ivec3(2, -2, -2), glm::ivec3(40, 61, 3) }, +// { glm::ivec3(-1, 4, -7) }, +// }; +// // clang-format on +// +// size_t numOfElements = 0; +// for (const auto& expectedMember : expected) { +// numOfElements += expectedMember.size(); +// } +// +// std::vector values(numOfElements * sizeof(glm::ivec3)); +// std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); +// uint64_t* offsetValue = reinterpret_cast(offsets.data()); +// for (size_t i = 0; i < expected.size(); ++i) { +// std::memcpy( +// values.data() + offsetValue[i], +// expected[i].data(), +// expected[i].size() * sizeof(glm::ivec3)); +// offsetValue[i + 1] = +// offsetValue[i] + expected[i].size() * sizeof(glm::ivec3); +// } +// +// addBufferToModel(model, values); +// size_t valueBufferIndex = model.buffers.size() - 1; +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// addBufferToModel(model, offsets); +// size_t offsetBufferIndex = model.buffers.size() - 1; +// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::VEC3; +// testClassProperty.componentType = ClassProperty::ComponentType::INT32; +// testClassProperty.array = true; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(expected.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// propertyTableProperty.arrayOffsets = +// static_cast(offsetBufferViewIndex); +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT64; +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::VEC3); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); +// REQUIRE(classProperty->array); +// REQUIRE(!classProperty->count); +// +// SECTION("Access the correct type") { +// PropertyTablePropertyView> property = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); +// for (size_t i = 0; i < expected.size(); ++i) { +// PropertyArrayView valueMember = +// property.get(static_cast(i)); +// REQUIRE(valueMember.size() == static_cast(expected[i].size())); +// for (size_t j = 0; j < expected[i].size(); ++j) { +// REQUIRE(expected[i][j] == valueMember[static_cast(j)]); +// } +// } +// } +// +// SECTION("Wrong offset type") { +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT8; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT16; +// arrayProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.arrayOffsetType = "NONSENSE"; +// arrayProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); +// +// propertyTableProperty.arrayOffsetType = ""; +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT64; +// arrayProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); +// } +// +// SECTION("Offset values are not sorted ascending") { +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT64; +// uint64_t* offset = reinterpret_cast( +// model.buffers[offsetBufferIndex].cesium.data.data()); +// offset[propertyTable.count] = 0; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); +// } +// +// SECTION("Offset value points outside of value buffer") { +// uint64_t* offset = reinterpret_cast( +// model.buffers[offsetBufferIndex].cesium.data.data()); +// offset[propertyTable.count] = +// static_cast(model.buffers[valueBufferIndex].byteLength + 4); +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); +// } +// +// SECTION("Count and offset buffer are both present") { +// testClassProperty.count = 3; +// PropertyTablePropertyView> property = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// property.status() == +// PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); +// } +//} +// +//TEST_CASE("Test fixed-length matN array") { +// Model model; +// // clang-format off +// std::vector values = { +// glm::i32mat2x2( +// 12, 34, +// -30, 20), +// glm::i32mat2x2( +// -2, -2, +// 0, 1), +// glm::i32mat2x2( +// 1, 2, +// 8, 5), +// glm::i32mat2x2( +// -100, 3, +// 84, 6), +// glm::i32mat2x2( +// 2, 12, +// -2, -2), +// glm::i32mat2x2( +// 40, 61, +// 7, -3), +// }; +// // clang-format on +// +// addBufferToModel(model, values); +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::MAT2; +// testClassProperty.componentType = ClassProperty::ComponentType::INT32; +// testClassProperty.array = true; +// testClassProperty.count = 2; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast( +// values.size() / static_cast(testClassProperty.count.value())); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = +// static_cast(model.bufferViews.size() - 1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::MAT2); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); +// REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 2); +// +// SECTION("Access the right type") { +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); +// +// for (int64_t i = 0; i < arrayProperty.size(); ++i) { +// PropertyArrayView member = arrayProperty.get(i); +// for (int64_t j = 0; j < member.size(); ++j) { +// REQUIRE(member[j] == values[static_cast(i * 2 + j)]); +// } +// } +// } +// +// SECTION("Wrong type") { +// PropertyTablePropertyView> int32ArrayInvalid = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// int32ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyTablePropertyView> ivec2ArrayInvalid = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// ivec2ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// } +// +// SECTION("Wrong component type") { +// PropertyTablePropertyView> +// u32mat2x2ArrayInvalid = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// u32mat2x2ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Not an array type") { +// PropertyTablePropertyView ivec3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// ivec3Invalid.status() == +// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Buffer size is not a multiple of type size") { +// model.bufferViews[valueBufferViewIndex].byteLength = 13; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeNotDivisibleByTypeSize); +// } +// +// SECTION("Negative component count") { +// testClassProperty.count = -1; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == PropertyTablePropertyViewStatus:: +// ErrorArrayCountAndOffsetBufferDontExist); +// } +// +// SECTION("Value buffer doesn't fit into property table count") { +// testClassProperty.count = 55; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// } +//} +// +//TEST_CASE("Test variable-length matN array") { +// Model model; +// // clang-format off +// std::vector data0{ +// glm::i32mat2x2( +// 3, -2, +// 1, 0), +// glm::i32mat2x2( +// 40, 3, +// 8, -9) +// }; +// std::vector data1{ +// glm::i32mat2x2( +// 1, 10, +// 7, 8), +// }; +// std::vector data2{ +// glm::i32mat2x2( +// 18, 0, +// 1, 17), +// glm::i32mat2x2( +// -4, -2, +// -9, 1), +// glm::i32mat2x2( +// 1, 8, +// -99, 3), +// }; +// // clang-format on +// +// std::vector> +// expected{data0, {}, data1, data2, {}}; +// +// size_t numOfElements = 0; +// for (const auto& expectedMember : expected) { +// numOfElements += expectedMember.size(); +// } +// +// std::vector values(numOfElements * sizeof(glm::i32mat2x2)); +// std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); +// uint64_t* offsetValue = reinterpret_cast(offsets.data()); +// for (size_t i = 0; i < expected.size(); ++i) { +// std::memcpy( +// values.data() + offsetValue[i], +// expected[i].data(), +// expected[i].size() * sizeof(glm::i32mat2x2)); +// offsetValue[i + 1] = +// offsetValue[i] + expected[i].size() * sizeof(glm::i32mat2x2); +// } +// +// addBufferToModel(model, values); +// size_t valueBufferIndex = model.buffers.size() - 1; +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// addBufferToModel(model, offsets); +// size_t offsetBufferIndex = model.buffers.size() - 1; +// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::MAT2; +// testClassProperty.componentType = ClassProperty::ComponentType::INT32; +// testClassProperty.array = true; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(expected.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// propertyTableProperty.arrayOffsets = +// static_cast(offsetBufferViewIndex); +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT64; +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::MAT2); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); +// REQUIRE(classProperty->array); +// REQUIRE(!classProperty->count); +// +// SECTION("Access the correct type") { +// PropertyTablePropertyView> property = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); +// for (size_t i = 0; i < expected.size(); ++i) { +// PropertyArrayView valueMember = +// property.get(static_cast(i)); +// REQUIRE(valueMember.size() == static_cast(expected[i].size())); +// for (size_t j = 0; j < expected[i].size(); ++j) { +// REQUIRE(expected[i][j] == valueMember[static_cast(j)]); +// } +// } +// } +// +// SECTION("Wrong offset type") { +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT8; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT16; +// arrayProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.arrayOffsetType = "NONSENSE"; +// arrayProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); +// +// propertyTableProperty.arrayOffsetType = ""; +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT64; +// arrayProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); +// } +// +// SECTION("Offset values are not sorted ascending") { +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT64; +// uint64_t* offset = reinterpret_cast( +// model.buffers[offsetBufferIndex].cesium.data.data()); +// offset[propertyTable.count] = 0; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); +// } +// +// SECTION("Offset value points outside of value buffer") { +// uint64_t* offset = reinterpret_cast( +// model.buffers[offsetBufferIndex].cesium.data.data()); +// offset[propertyTable.count] = +// static_cast(model.buffers[valueBufferIndex].byteLength + 4); +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); +// } +// +// SECTION("Count and offset buffer are both present") { +// testClassProperty.count = 3; +// PropertyTablePropertyView> property = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// property.status() == +// PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); +// } +//} +// +//TEST_CASE("Test fixed-length boolean array") { +// Model model; +// +// std::vector expected = { +// true, +// false, +// false, +// true, +// false, +// false, +// true, +// true, +// true, +// false, +// false, +// true}; +// std::vector values; +// size_t requiredBytesSize = static_cast( +// glm::ceil(static_cast(expected.size()) / 8.0)); +// values.resize(requiredBytesSize); +// for (size_t i = 0; i < expected.size(); ++i) { +// uint8_t expectedValue = expected[i]; +// size_t byteIndex = i / 8; +// size_t bitIndex = i % 8; +// values[byteIndex] = +// static_cast((expectedValue << bitIndex) | values[byteIndex]); +// } +// +// addBufferToModel(model, values); +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::BOOLEAN; +// testClassProperty.array = true; +// testClassProperty.count = 3; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast( +// expected.size() / static_cast(testClassProperty.count.value())); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = +// static_cast(model.bufferViews.size() - 1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); +// REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 3); +// +// SECTION("Access correct type") { +// PropertyTablePropertyView> boolArrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(boolArrayProperty.size() == propertyTable.count); +// REQUIRE(boolArrayProperty.size() > 0); +// for (int64_t i = 0; i < boolArrayProperty.size(); ++i) { +// PropertyArrayView valueMember = boolArrayProperty.get(i); +// for (int64_t j = 0; j < valueMember.size(); ++j) { +// REQUIRE(valueMember[j] == expected[static_cast(i * 3 + j)]); +// } +// } +// } +// +// SECTION("Wrong type") { +// PropertyTablePropertyView> uint8ArrayInvalid = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// uint8ArrayInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorTypeMismatch); +// } +// +// SECTION("View is not array type") { +// PropertyTablePropertyView boolInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// boolInvalid.status() == +// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Value buffer doesn't have enough required bytes") { +// testClassProperty.count = 11; +// PropertyTablePropertyView> boolArrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// boolArrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// } +// +// SECTION("Count is negative") { +// testClassProperty.count = -1; +// PropertyTablePropertyView> boolArrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// boolArrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorArrayCountAndOffsetBufferDontExist); +// } +//} +// +//TEST_CASE("Test variable-length boolean array") { +// Model model; +// +// std::vector> expected{ +// {true, false, true, true, false, true, true}, +// {}, +// {}, +// {}, +// {false, false, false, false}, +// {true, false, true}, +// {false}, +// {true, true, true, true, true, false, false}}; +// size_t numOfElements = 0; +// for (const auto& expectedMember : expected) { +// numOfElements += expectedMember.size(); +// } +// +// size_t requiredBytesSize = +// static_cast(glm::ceil(static_cast(numOfElements) / 8.0)); +// std::vector values(requiredBytesSize); +// std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); +// uint64_t* offsetValue = reinterpret_cast(offsets.data()); +// size_t indexSoFar = 0; +// for (size_t i = 0; i < expected.size(); ++i) { +// for (size_t j = 0; j < expected[i].size(); ++j) { +// uint8_t expectedValue = expected[i][j]; +// size_t byteIndex = indexSoFar / 8; +// size_t bitIndex = indexSoFar % 8; +// values[byteIndex] = static_cast( +// (expectedValue << bitIndex) | static_cast(values[byteIndex])); +// ++indexSoFar; +// } +// offsetValue[i + 1] = offsetValue[i] + expected[i].size(); +// } +// +// addBufferToModel(model, values); +// size_t valueBufferIndex = model.buffers.size() - 1; +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// addBufferToModel(model, offsets); +// size_t offsetBufferIndex = model.buffers.size() - 1; +// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::BOOLEAN; +// testClassProperty.array = true; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(expected.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// propertyTableProperty.arrayOffsets = +// static_cast(offsetBufferViewIndex); +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT64; +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); +// REQUIRE(classProperty->array); +// REQUIRE(!classProperty->count); +// +// SECTION("Access correct type") { +// PropertyTablePropertyView> boolArrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); +// for (size_t i = 0; i < expected.size(); ++i) { +// PropertyArrayView arrayMember = +// boolArrayProperty.get(static_cast(i)); +// REQUIRE(arrayMember.size() == static_cast(expected[i].size())); +// for (size_t j = 0; j < expected[i].size(); ++j) { +// REQUIRE(expected[i][j] == arrayMember[static_cast(j)]); +// } +// } +// } +// +// SECTION("Wrong offset type") { +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT8; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT16; +// arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.arrayOffsetType = "NONSENSE"; +// arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); +// +// propertyTableProperty.arrayOffsetType = ""; +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT64; +// arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); +// } +// +// SECTION("Offset values are not sorted ascending") { +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT64; +// uint64_t* offset = reinterpret_cast( +// model.buffers[offsetBufferIndex].cesium.data.data()); +// offset[propertyTable.count] = 0; +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); +// } +// +// SECTION("Offset value points outside of value buffer") { +// uint64_t* offset = reinterpret_cast( +// model.buffers[offsetBufferIndex].cesium.data.data()); +// offset[propertyTable.count] = static_cast( +// model.buffers[valueBufferIndex].byteLength * 8 + 20); +// PropertyTablePropertyView> arrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); +// } +// +// SECTION("Count and offset buffer both present") { +// testClassProperty.count = 3; +// PropertyTablePropertyView> boolArrayProperty = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// boolArrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); +// } +//} +// +//TEST_CASE("Test fixed-length arrays of strings") { +// Model model; +// +// std::vector expected{ +// "What's up", +// "Breaking news!!! Aliens no longer attacks the US first", +// "But they still abduct my cows! Those milk thiefs! 👽 🐮", +// "I'm not crazy. My mother had me tested 🤪", +// "I love you, meat bags! ❤️", +// "Book in the freezer"}; +// +// size_t totalBytes = 0; +// for (const std::string& expectedValue : expected) { +// totalBytes += expectedValue.size(); +// } +// +// std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); +// std::vector values(totalBytes); +// uint32_t* offsetValue = reinterpret_cast(offsets.data()); +// for (size_t i = 0; i < expected.size(); ++i) { +// const std::string& expectedValue = expected[i]; +// std::memcpy( +// values.data() + offsetValue[i], +// expectedValue.c_str(), +// expectedValue.size()); +// offsetValue[i + 1] = +// offsetValue[i] + static_cast(expectedValue.size()); +// } +// +// addBufferToModel(model, values); +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// addBufferToModel(model, offsets); +// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::STRING; +// testClassProperty.array = true; +// testClassProperty.count = 2; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast( +// expected.size() / static_cast(testClassProperty.count.value())); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT32; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// propertyTableProperty.stringOffsets = +// static_cast(offsetBufferViewIndex); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::STRING); +// REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 2); +// +// SECTION("Access correct type") { +// PropertyTablePropertyView> +// stringProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(stringProperty.size() == 3); +// +// PropertyArrayView v0 = stringProperty.get(0); +// REQUIRE(v0.size() == 2); +// REQUIRE(v0[0] == "What's up"); +// REQUIRE(v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); +// +// PropertyArrayView v1 = stringProperty.get(1); +// REQUIRE(v1.size() == 2); +// REQUIRE(v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); +// REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); +// +// PropertyArrayView v2 = stringProperty.get(2); +// REQUIRE(v2.size() == 2); +// REQUIRE(v2[0] == "I love you, meat bags! ❤️"); +// REQUIRE(v2[1] == "Book in the freezer"); +// } +// +// SECTION("Array type mismatch") { +// PropertyTablePropertyView stringProperty = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// stringProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Count is negative") { +// testClassProperty.count = -1; +// PropertyTablePropertyView> +// stringProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// stringProperty.status() == PropertyTablePropertyViewStatus:: +// ErrorArrayCountAndOffsetBufferDontExist); +// } +// +// SECTION("Offset type is unknown") { +// propertyTableProperty.stringOffsetType = "NONSENSE"; +// PropertyTablePropertyView> +// stringProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// stringProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); +// +// propertyTableProperty.stringOffsetType = ""; +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT32; +// stringProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// stringProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); +// } +// +// SECTION("String offsets don't exist") { +// propertyTableProperty.stringOffsets = -1; +// PropertyTablePropertyView> +// stringProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// stringProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetBufferView); +// } +//} +// +//TEST_CASE("Test variable-length arrays of strings") { +// Model model; +// +// std::vector> expected{ +// {"What's up"}, +// {"Breaking news!!! Aliens no longer attacks the US first", +// "But they still abduct my cows! Those milk thiefs! 👽 🐮"}, +// {"I'm not crazy. My mother had me tested 🤪", +// "I love you, meat bags! ❤️", +// "Book in the freezer"}}; +// +// size_t totalBytes = 0; +// size_t numOfElements = 0; +// for (const auto& expectedValues : expected) { +// for (const auto& value : expectedValues) { +// totalBytes += value.size(); +// } +// +// numOfElements += expectedValues.size(); +// } +// +// std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); +// std::vector stringOffsets((numOfElements + 1) * sizeof(uint32_t)); +// std::vector values(totalBytes); +// uint32_t* offsetValue = reinterpret_cast(offsets.data()); +// uint32_t* stringOffsetValue = +// reinterpret_cast(stringOffsets.data()); +// size_t strOffsetIdx = 0; +// for (size_t i = 0; i < expected.size(); ++i) { +// for (size_t j = 0; j < expected[i].size(); ++j) { +// const std::string& expectedValue = expected[i][j]; +// std::memcpy( +// values.data() + stringOffsetValue[strOffsetIdx], +// expectedValue.c_str(), +// expectedValue.size()); +// +// stringOffsetValue[strOffsetIdx + 1] = +// stringOffsetValue[strOffsetIdx] + +// static_cast(expectedValue.size()); +// ++strOffsetIdx; +// } +// +// offsetValue[i + 1] = +// offsetValue[i] + +// static_cast(expected[i].size() * sizeof(uint32_t)); +// } +// +// addBufferToModel(model, values); +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// addBufferToModel(model, offsets); +// size_t arrayOffsetBuffer = model.buffers.size() - 1; +// size_t arrayOffsetBufferView = model.bufferViews.size() - 1; +// +// addBufferToModel(model, stringOffsets); +// size_t stringOffsetBuffer = model.buffers.size() - 1; +// size_t stringOffsetBufferView = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::STRING; +// testClassProperty.array = true; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(expected.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT32; +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT32; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// propertyTableProperty.arrayOffsets = +// static_cast(arrayOffsetBufferView); +// propertyTableProperty.stringOffsets = +// static_cast(stringOffsetBufferView); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::STRING); +// REQUIRE(classProperty->array); +// REQUIRE(!classProperty->componentType); +// REQUIRE(!classProperty->count); +// +// SECTION("Access correct type") { +// PropertyTablePropertyView> +// stringProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); +// for (size_t i = 0; i < expected.size(); ++i) { +// PropertyArrayView stringArray = +// stringProperty.get(static_cast(i)); +// for (size_t j = 0; j < expected[i].size(); ++j) { +// REQUIRE(stringArray[static_cast(j)] == expected[i][j]); +// } +// } +// } +// +// SECTION("Wrong array offset type") { +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT8; +// PropertyTablePropertyView> +// arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT16; +// arrayProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.arrayOffsetType = "NONSENSE"; +// arrayProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); +// propertyTableProperty.arrayOffsetType = +// PropertyTableProperty::ArrayOffsetType::UINT32; +// } +// +// SECTION("Wrong string offset type") { +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT8; +// PropertyTablePropertyView> +// arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT16; +// arrayProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus:: +// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); +// +// propertyTableProperty.stringOffsetType = "NONSENSE"; +// arrayProperty = view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT32; +// } +// +// SECTION("Array offset values are not sorted ascending") { +// uint32_t* offset = reinterpret_cast( +// model.buffers[arrayOffsetBuffer].cesium.data.data()); +// offset[0] = static_cast(1000); +// PropertyTablePropertyView> +// arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); +// offset[0] = 0; +// } +// +// SECTION("String offset values are not sorted ascending") { +// uint32_t* offset = reinterpret_cast( +// model.buffers[stringOffsetBuffer].cesium.data.data()); +// offset[0] = static_cast(1000); +// PropertyTablePropertyView> +// arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); +// offset[0] = 0; +// } +// +// SECTION("Array offset value points outside of value buffer") { +// uint32_t* offset = reinterpret_cast( +// model.buffers[arrayOffsetBuffer].cesium.data.data()); +// uint32_t previousValue = offset[propertyTable.count]; +// offset[propertyTable.count] = static_cast(100000); +// PropertyTablePropertyView> +// arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); +// offset[propertyTable.count] = previousValue; +// } +// +// SECTION("String offset value points outside of value buffer") { +// uint32_t* offset = reinterpret_cast( +// model.buffers[stringOffsetBuffer].cesium.data.data()); +// uint32_t previousValue = offset[6]; +// offset[6] = static_cast(100000); +// PropertyTablePropertyView> +// arrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); +// offset[6] = previousValue; +// } +// +// SECTION("Count and offset buffer both present") { +// testClassProperty.count = 3; +// PropertyTablePropertyView> +// boolArrayProperty = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// boolArrayProperty.status() == +// PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); +// } +//} +// +//TEST_CASE("Test callback on invalid property table view") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// metadata.schema.emplace(); +// +// // Property table has a nonexistent class. +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(5); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(-1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); +// REQUIRE(view.size() == 0); +// +// 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() == +// PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); +// REQUIRE(propertyValue.size() == 0); +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +//TEST_CASE("Test callback for invalid PropertyTableProperty") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["InvalidProperty"]; +// testClassProperty.type = ClassProperty::Type::SCALAR; +// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(5); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["InvalidProperty"]; +// propertyTableProperty.values = static_cast(-1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// 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() != PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() == 0); +// }; +// +// view.getPropertyView("InvalidProperty", testCallback); +// view.getPropertyView("NonexistentProperty", testCallback); +// +// REQUIRE(invokedCallbackCount == 2); +//} +// +//TEST_CASE("Test callback for scalar PropertyTableProperty") { +// Model model; +// std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; +// +// addBufferToModel(model, values); +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::SCALAR; +// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(values.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); +// REQUIRE(!classProperty->array); +// REQUIRE(classProperty->count == std::nullopt); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&values, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) mutable { +// invokedCallbackCount++; +// if constexpr (std::is_same_v< +// PropertyTablePropertyView, +// decltype(propertyValue)>) { +// REQUIRE( +// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() > 0); +// +// for (int64_t i = 0; i < propertyValue.size(); ++i) { +// REQUIRE( +// static_cast(propertyValue.get(i)) == +// values[static_cast(i)]); +// } +// } else { +// FAIL( +// "getPropertyView returned PropertyTablePropertyView of incorrect " +// "type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +//TEST_CASE("Test callback for vecN PropertyTableProperty") { +// Model model; +// std::vector values = { +// glm::ivec3(-12, 34, 30), +// glm::ivec3(11, 73, 0), +// glm::ivec3(-2, 6, 12), +// glm::ivec3(-4, 8, -13)}; +// +// addBufferToModel(model, values); +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::VEC3; +// testClassProperty.componentType = ClassProperty::ComponentType::INT32; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(values.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::VEC3); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); +// REQUIRE(classProperty->count == std::nullopt); +// REQUIRE(!classProperty->array); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&values, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) mutable { +// invokedCallbackCount++; +// REQUIRE( +// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() > 0); +// +// if constexpr (std::is_same_v< +// PropertyTablePropertyView, +// decltype(propertyValue)>) { +// for (int64_t i = 0; i < propertyValue.size(); ++i) { +// REQUIRE( +// static_cast(propertyValue.get(i)) == +// values[static_cast(i)]); +// } +// } else { +// FAIL( +// "getPropertyView returned PropertyTablePropertyView of incorrect " +// "type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +//TEST_CASE("Test callback for matN PropertyTableProperty") { +// Model model; +// // clang-format off +// std::vector values = { +// glm::u32mat2x2( +// 12, 34, +// 30, 1), +// glm::u32mat2x2( +// 11, 8, +// 73, 102), +// glm::u32mat2x2( +// 1, 0, +// 63, 2), +// glm::u32mat2x2( +// 4, 8, +// 3, 23)}; +// // clang-format on +// +// addBufferToModel(model, values); +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::MAT2; +// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(values.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::MAT2); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); +// REQUIRE(classProperty->count == std::nullopt); +// REQUIRE(!classProperty->array); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&values, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) mutable { +// REQUIRE( +// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() > 0); +// +// if constexpr (std::is_same_v< +// PropertyTablePropertyView, +// decltype(propertyValue)>) { +// for (int64_t i = 0; i < propertyValue.size(); ++i) { +// REQUIRE( +// static_cast(propertyValue.get(i)) == +// values[static_cast(i)]); +// } +// } else { +// FAIL( +// "getPropertyView returned PropertyTablePropertyView of incorrect " +// "type for TestClassProperty."); +// } +// invokedCallbackCount++; +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +//TEST_CASE("Test callback for boolean PropertyTableProperty") { +// Model model; +// +// int64_t instanceCount = 21; +// std::vector expected; +// std::vector values; +// values.resize(3); +// for (int64_t i = 0; i < instanceCount; ++i) { +// if (i % 2 == 0) { +// expected.emplace_back(true); +// } else { +// expected.emplace_back(false); +// } +// +// uint8_t expectedValue = expected.back(); +// int64_t byteIndex = i / 8; +// int64_t bitIndex = i % 8; +// values[static_cast(byteIndex)] = static_cast( +// (expectedValue << bitIndex) | values[static_cast(byteIndex)]); +// } +// +// addBufferToModel(model, values); +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::BOOLEAN; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(instanceCount); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = +// static_cast(model.bufferViews.size() - 1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); +// REQUIRE(classProperty->componentType == std::nullopt); +// REQUIRE(classProperty->count == std::nullopt); +// REQUIRE(!classProperty->array); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&expected, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) mutable { +// invokedCallbackCount++; +// +// REQUIRE( +// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() > 0); +// +// if constexpr (std::is_same_v< +// PropertyTablePropertyView, +// decltype(propertyValue)>) { +// for (int64_t i = 0; i < propertyValue.size(); ++i) { +// REQUIRE( +// static_cast(propertyValue.get(i)) == +// expected[static_cast(i)]); +// } +// } else { +// FAIL( +// "getPropertyView returned PropertyTablePropertyView of incorrect " +// "type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +//TEST_CASE("Test callback for string PropertyTableProperty") { +// Model model; +// +// std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; +// size_t totalBytes = 0; +// for (const std::string& expectedValue : expected) { +// totalBytes += expectedValue.size(); +// } +// +// std::vector stringOffsets( +// (expected.size() + 1) * sizeof(uint32_t)); +// std::vector values(totalBytes); +// uint32_t* offsetValue = reinterpret_cast(stringOffsets.data()); +// for (size_t i = 0; i < expected.size(); ++i) { +// const std::string& expectedValue = expected[i]; +// std::memcpy( +// values.data() + offsetValue[i], +// expectedValue.c_str(), +// expectedValue.size()); +// offsetValue[i + 1] = +// offsetValue[i] + static_cast(expectedValue.size()); +// } +// +// addBufferToModel(model, values); +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// addBufferToModel(model, stringOffsets); +// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::STRING; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast(expected.size()); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT32; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// propertyTableProperty.stringOffsets = +// static_cast(offsetBufferViewIndex); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::STRING); +// REQUIRE(classProperty->componentType == std::nullopt); +// REQUIRE(classProperty->count == std::nullopt); +// REQUIRE(!classProperty->array); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&expected, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) mutable { +// invokedCallbackCount++; +// REQUIRE( +// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() > 0); +// +// if constexpr (std::is_same_v< +// PropertyTablePropertyView, +// decltype(propertyValue)>) { +// for (int64_t i = 0; i < propertyValue.size(); ++i) { +// REQUIRE( +// static_cast(propertyValue.get(i)) == +// expected[static_cast(i)]); +// } +// } else { +// FAIL( +// "getPropertyView returned PropertyTablePropertyView of incorrect " +// "type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +//TEST_CASE("Test callback for scalar array PropertyTableProperty") { +// Model model; +// std::vector values = +// {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; +// +// addBufferToModel(model, values); +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::SCALAR; +// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; +// testClassProperty.array = true; +// testClassProperty.count = 3; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast( +// values.size() / static_cast(testClassProperty.count.value())); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = +// static_cast(model.bufferViews.size() - 1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); +// REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 3); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&values, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) { +// invokedCallbackCount++; +// REQUIRE( +// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() > 0); +// +// if constexpr (std::is_same_v< +// PropertyTablePropertyView< +// PropertyArrayView>, +// decltype(propertyValue)>) { +// for (int64_t i = 0; i < propertyValue.size(); ++i) { +// PropertyArrayView member = propertyValue.get(i); +// for (int64_t j = 0; j < member.size(); ++j) { +// REQUIRE(member[j] == values[static_cast(i * 3 + j)]); +// } +// } +// } else { +// FAIL( +// "getPropertyView returned PropertyTablePropertyView of incorrect " +// "type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +//TEST_CASE("Test callback for vecN array PropertyTableProperty") { +// Model model; +// std::vector values = { +// glm::ivec3(12, 34, -30), +// glm::ivec3(-2, 0, 1), +// glm::ivec3(1, 2, 8), +// glm::ivec3(-100, 84, 6), +// glm::ivec3(2, -2, -2), +// glm::ivec3(40, 61, 3), +// }; +// +// addBufferToModel(model, values); +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::VEC3; +// testClassProperty.componentType = ClassProperty::ComponentType::INT32; +// testClassProperty.array = true; +// testClassProperty.count = 2; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast( +// values.size() / static_cast(testClassProperty.count.value())); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = +// static_cast(model.bufferViews.size() - 1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::VEC3); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); +// REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 2); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&values, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) { +// invokedCallbackCount++; +// REQUIRE( +// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() > 0); +// +// if constexpr (std::is_same_v< +// PropertyTablePropertyView< +// PropertyArrayView>, +// decltype(propertyValue)>) { +// for (int64_t i = 0; i < propertyValue.size(); ++i) { +// PropertyArrayView member = propertyValue.get(i); +// for (int64_t j = 0; j < member.size(); ++j) { +// REQUIRE(member[j] == values[static_cast(i * 2 + j)]); +// } +// } +// } else { +// FAIL( +// "getPropertyView returned PropertyTablePropertyView of incorrect " +// "type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +//TEST_CASE("Test callback for matN array PropertyTableProperty") { +// Model model; +// // clang-format off +// std::vector values = { +// glm::i32mat2x2( +// 12, 34, +// -30, 20), +// glm::i32mat2x2( +// -2, -2, +// 0, 1), +// glm::i32mat2x2( +// 1, 2, +// 8, 5), +// glm::i32mat2x2( +// -100, 3, +// 84, 6), +// glm::i32mat2x2( +// 2, 12, +// -2, -2), +// glm::i32mat2x2( +// 40, 61, +// 7, -3), +// }; +// // clang-format on +// +// addBufferToModel(model, values); +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::MAT2; +// testClassProperty.componentType = ClassProperty::ComponentType::INT32; +// testClassProperty.array = true; +// testClassProperty.count = 2; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast( +// values.size() / static_cast(testClassProperty.count.value())); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = +// static_cast(model.bufferViews.size() - 1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::MAT2); +// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); +// REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 2); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&values, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) { +// invokedCallbackCount++; +// REQUIRE( +// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() > 0); +// +// if constexpr (std::is_same_v< +// PropertyTablePropertyView< +// PropertyArrayView>, +// decltype(propertyValue)>) { +// for (int64_t i = 0; i < propertyValue.size(); ++i) { +// PropertyArrayView member = propertyValue.get(i); +// for (int64_t j = 0; j < member.size(); ++j) { +// REQUIRE(member[j] == values[static_cast(i * 2 + j)]); +// } +// } +// } else { +// FAIL( +// "getPropertyView returned PropertyTablePropertyView of incorrect " +// "type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +//TEST_CASE("Test callback for boolean array PropertyTableProperty") { +// Model model; +// +// std::vector expected = { +// true, +// false, +// false, +// true, +// false, +// false, +// true, +// true, +// true, +// false, +// false, +// true}; +// std::vector values; +// size_t requiredBytesSize = static_cast( +// glm::ceil(static_cast(expected.size()) / 8.0)); +// values.resize(requiredBytesSize); +// for (size_t i = 0; i < expected.size(); ++i) { +// uint8_t expectedValue = expected[i]; +// size_t byteIndex = i / 8; +// size_t bitIndex = i % 8; +// values[byteIndex] = +// static_cast((expectedValue << bitIndex) | values[byteIndex]); +// } +// +// addBufferToModel(model, values); +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::BOOLEAN; +// testClassProperty.array = true; +// testClassProperty.count = 3; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast( +// expected.size() / static_cast(testClassProperty.count.value())); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.values = +// static_cast(model.bufferViews.size() - 1); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); +// REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 3); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&expected, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) { +// invokedCallbackCount++; +// REQUIRE( +// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() > 0); +// +// if constexpr (std::is_same_v< +// PropertyTablePropertyView>, +// decltype(propertyValue)>) { +// for (int64_t i = 0; i < propertyValue.size(); ++i) { +// PropertyArrayView member = propertyValue.get(i); +// for (int64_t j = 0; j < member.size(); ++j) { +// REQUIRE(member[j] == expected[static_cast(i * 3 + j)]); +// } +// } +// } else { +// FAIL( +// "getPropertyView returned PropertyTablePropertyView of incorrect " +// "type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +//TEST_CASE("Test callback for string array PropertyTableProperty") { +// Model model; +// +// std::vector expected{ +// "What's up", +// "Breaking news!!! Aliens no longer attacks the US first", +// "But they still abduct my cows! Those milk thiefs! 👽 🐮", +// "I'm not crazy. My mother had me tested 🤪", +// "I love you, meat bags! ❤️", +// "Book in the freezer"}; +// +// size_t totalBytes = 0; +// for (const std::string& expectedValue : expected) { +// totalBytes += expectedValue.size(); +// } +// +// std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); +// std::vector values(totalBytes); +// uint32_t* offsetValue = reinterpret_cast(offsets.data()); +// for (size_t i = 0; i < expected.size(); ++i) { +// const std::string& expectedValue = expected[i]; +// std::memcpy( +// values.data() + offsetValue[i], +// expectedValue.c_str(), +// expectedValue.size()); +// offsetValue[i + 1] = +// offsetValue[i] + static_cast(expectedValue.size()); +// } +// +// addBufferToModel(model, values); +// size_t valueBufferViewIndex = model.bufferViews.size() - 1; +// +// addBufferToModel(model, offsets); +// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; +// testClassProperty.type = ClassProperty::Type::STRING; +// testClassProperty.array = true; +// testClassProperty.count = 2; +// +// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); +// propertyTable.classProperty = "TestClass"; +// propertyTable.count = static_cast( +// expected.size() / static_cast(testClassProperty.count.value())); +// +// PropertyTableProperty& propertyTableProperty = +// propertyTable.properties["TestClassProperty"]; +// propertyTableProperty.stringOffsetType = +// PropertyTableProperty::StringOffsetType::UINT32; +// propertyTableProperty.values = static_cast(valueBufferViewIndex); +// propertyTableProperty.stringOffsets = +// static_cast(offsetBufferViewIndex); +// +// PropertyTableView view(model, propertyTable); +// REQUIRE(view.status() == PropertyTableViewStatus::Valid); +// REQUIRE(view.size() == propertyTable.count); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::STRING); +// REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 2); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) { +// invokedCallbackCount++; +// REQUIRE( +// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); +// REQUIRE(propertyValue.size() == 3); +// +// if constexpr (std::is_same_v< +// PropertyTablePropertyView< +// PropertyArrayView>, +// decltype(propertyValue)>) { +// PropertyArrayView v0 = propertyValue.get(0); +// REQUIRE(v0.size() == 2); +// REQUIRE(v0[0] == "What's up"); +// REQUIRE( +// v0[1] == +// "Breaking news!!! Aliens no longer attacks the US first"); +// +// PropertyArrayView v1 = propertyValue.get(1); +// REQUIRE(v1.size() == 2); +// REQUIRE( +// v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); +// REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); +// +// PropertyArrayView v2 = propertyValue.get(2); +// REQUIRE(v2.size() == 2); +// REQUIRE(v2[0] == "I love you, meat bags! ❤️"); +// REQUIRE(v2[1] == "Book in the freezer"); +// } else { +// FAIL( +// "getPropertyView returned PropertyTablePropertyView of incorrect " +// "type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp new file mode 100644 index 000000000..ee3bf466b --- /dev/null +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -0,0 +1,359 @@ +#include "CesiumGltf/PropertyView.h" + +#include + +using namespace CesiumGltf; +using namespace CesiumUtility; + +TEST_CASE("Constructs empty PropertyView") { + PropertyView view; + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); +} + +TEST_CASE("Boolean PropertyView") { + SECTION("Ignores non-applicable properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.normalized = true; + classProperty.offset = JsonValue(true); + classProperty.scale = JsonValue(true); + classProperty.max = JsonValue(true); + classProperty.min = JsonValue(true); + classProperty.noData = JsonValue(true); + + PropertyView view(classProperty); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.noData()); + } + + SECTION("Ignores count (array is false)") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.count = 5; + + PropertyView view(classProperty); + REQUIRE(view.arrayCount() == 0); + } + + SECTION("Constructs with defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.required = false; + classProperty.defaultProperty = JsonValue(false); + + PropertyView view(classProperty); + REQUIRE(!view.required()); + REQUIRE(view.defaultValue()); + REQUIRE(!*view.defaultValue()); + } + + SECTION("Ignores defaultProperty when required is true") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.required = true; + classProperty.defaultProperty = JsonValue(false); + + PropertyView view(classProperty); + REQUIRE(view.required()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Returns nullopt for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.defaultProperty = JsonValue(1); + + PropertyView view(classProperty); + REQUIRE(!view.required()); + REQUIRE(!view.defaultValue()); + } +} + +TEST_CASE("Scalar PropertyView") { + SECTION("Constructs with non-optional properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.normalized = true; + classProperty.required = true; + + PropertyView view(classProperty); + REQUIRE(view.normalized()); + REQUIRE(view.required()); + + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Ignores count (array is false)") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.count = 5; + + PropertyView view(classProperty); + REQUIRE(view.arrayCount() == 0); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.offset = JsonValue(5); + classProperty.scale = JsonValue(2); + classProperty.max = JsonValue(10); + classProperty.min = JsonValue(-10); + + PropertyView view(classProperty); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); + + REQUIRE(*view.offset() == 5); + REQUIRE(*view.scale() == 2); + REQUIRE(*view.max() == 10); + REQUIRE(*view.min() == -10); + } + + SECTION("Returns nullopt for out-of-bounds offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.offset = JsonValue(129); + classProperty.scale = JsonValue(255); + classProperty.max = JsonValue(1000); + classProperty.min = JsonValue(-1000); + + PropertyView view(classProperty); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + } + + SECTION("Rounds numbers where possible") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.offset = JsonValue(-5.5); + classProperty.scale = JsonValue(2.4); + classProperty.max = JsonValue(150); + classProperty.min = JsonValue(-150); + + PropertyView view(classProperty); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + + REQUIRE(*view.offset() == -5); + REQUIRE(*view.scale() == 2); + } + + SECTION("Returns nullopt for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.offset = JsonValue("10"); + classProperty.scale = JsonValue(false); + classProperty.max = JsonValue(JsonValue::Array()); + classProperty.min = JsonValue(JsonValue::Array{10}); + + PropertyView view(classProperty); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.required = false; + classProperty.noData = JsonValue(0); + classProperty.defaultProperty = JsonValue(1); + + PropertyView view(classProperty); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + REQUIRE(*view.noData() == 0); + REQUIRE(*view.defaultValue() == 1); + } + + SECTION("Ignores noData and defaultProperty when required is true") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.required = true; + classProperty.noData = JsonValue(0); + classProperty.defaultProperty = JsonValue(1); + + PropertyView view(classProperty); + REQUIRE(view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } +} + +TEST_CASE("String PropertyView") { + SECTION("Ignores non-applicable properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.normalized = true; + classProperty.offset = JsonValue("test"); + classProperty.scale = JsonValue("test"); + classProperty.max = JsonValue("test"); + classProperty.min = JsonValue("test"); + + PropertyView view(classProperty); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + } + + SECTION("Ignores count (array is false)") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.count = 5; + + PropertyView view(classProperty); + REQUIRE(view.arrayCount() == 0); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.required = false; + classProperty.noData = JsonValue("null"); + classProperty.defaultProperty = JsonValue("default"); + + PropertyView view(classProperty); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + REQUIRE(*view.noData() == "null"); + REQUIRE(*view.defaultValue() == "default"); + } + + SECTION("Ignores noData and defaultProperty when required is true") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.required = true; + classProperty.noData = JsonValue("null"); + classProperty.defaultProperty = JsonValue("default"); + + PropertyView view(classProperty); + REQUIRE(view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Returns nullopt for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.noData = JsonValue::Array{JsonValue("null")}; + classProperty.defaultProperty = JsonValue(true); + + PropertyView view(classProperty); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } +} + +TEST_CASE("Boolean Array PropertyView") { + SECTION("Ignores non-applicable properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.normalized = true; + classProperty.offset = JsonValue::Array{JsonValue(true)}; + classProperty.scale = JsonValue::Array{JsonValue(true)}; + classProperty.max = JsonValue::Array{JsonValue(true)}; + classProperty.min = JsonValue::Array{JsonValue(true)}; + classProperty.noData = JsonValue::Array{JsonValue(true)}; + + PropertyView> view(classProperty); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.noData()); + } + + SECTION("Constructs with count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.array = true; + classProperty.count = 5; + + PropertyView> view(classProperty); + REQUIRE(view.arrayCount() == 5); + } + + SECTION("Constructs with defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.array = true; + classProperty.required = false; + classProperty.defaultProperty = + JsonValue::Array{JsonValue(false), JsonValue(true)}; + + PropertyView> view(classProperty); + REQUIRE(!view.required()); + REQUIRE(view.defaultValue()); + + const auto defaultValue = *view.defaultValue(); + REQUIRE(defaultValue.size() == 2); + REQUIRE(!defaultValue[0]); + REQUIRE(defaultValue[1]); + } + + SECTION("Ignores defaultProperty when required is true") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.array = true; + classProperty.required = true; + classProperty.defaultProperty = + JsonValue::Array{JsonValue(false), JsonValue(true)}; + + PropertyView view(classProperty); + REQUIRE(view.required()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Returns nullopt for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.array = true; + classProperty.defaultProperty = JsonValue(true); + + PropertyView view(classProperty); + REQUIRE(!view.required()); + REQUIRE(!view.defaultValue()); + } +} diff --git a/CesiumUtility/include/CesiumUtility/JsonValue.h b/CesiumUtility/include/CesiumUtility/JsonValue.h index 47773ed14..8a4b2afc0 100644 --- a/CesiumUtility/include/CesiumUtility/JsonValue.h +++ b/CesiumUtility/include/CesiumUtility/JsonValue.h @@ -413,7 +413,7 @@ class CESIUMUTILITY_API JsonValue final { /** * @brief Gets the array from the value. - * @return The arrayj. + * @return The array. * @throws std::bad_variant_access if the underlying type is not a * JsonValue::Array */ From bfbb6945e58a65aa3e4fd34796d93b9716b389ab Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 16 Aug 2023 13:56:37 -0400 Subject: [PATCH 072/121] Add support for vecN --- .../include/CesiumGltf/PropertyArrayView.h | 104 +- CesiumGltf/include/CesiumGltf/PropertyView.h | 797 +- CesiumGltf/test/TestPropertyTableView.cpp | 6494 ++++++++--------- CesiumGltf/test/TestPropertyView.cpp | 322 +- 4 files changed, 3746 insertions(+), 3971 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index f7978107c..119187f24 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -67,7 +67,7 @@ template <> class PropertyArrayView { /** * @brief Constructs an empty array view. */ - PropertyArrayView() : _values{}, _bitOffset{0}, _size{0} {} + PropertyArrayView() : _values{}, _size{0} {} /** * @brief Constructs an array view from a buffer. @@ -81,7 +81,7 @@ template <> class PropertyArrayView { const gsl::span& buffer, int64_t bitOffset, int64_t size) noexcept - : _values{buffer}, _bitOffset{bitOffset}, _size{size} {} + : _values{BooleanArrayView{buffer, bitOffset}}, _size{size} {} /** * @brief Constructs an array view from a vector of values. This is mainly @@ -90,33 +90,35 @@ template <> class PropertyArrayView { * @param values The vector containing the values. */ PropertyArrayView(const std::vector&& values) - : _values{std::move(values)}, _bitOffset{0}, _size{0} { - const auto vectorValues = std::get>(_values); - _size = static_cast(vectorValues.size()); + : _values{std::move(values)}, _size{0} { + size_t size = std::get>(_values).size(); + _size = static_cast(size); } bool operator[](int64_t index) const noexcept { - // There's no way to access the bitstream data in std::vector, so this - // implementation is very "either or". - if (std::holds_alternative>(_values)) { - const auto vectorValues = std::get>(_values); - return vectorValues[static_cast(index)]; - } - - const auto values = std::get>(_values); - index += _bitOffset; - const int64_t byteIndex = index / 8; - const int64_t bitIndex = index % 8; - const int bitValue = static_cast(values[byteIndex] >> bitIndex) & 1; - return bitValue == 1; + return std::visit( + [index](auto const& values) -> auto const { return values[index]; }, + _values); } int64_t size() const noexcept { return _size; } private: - using ArrayType = std::variant, std::vector>; + struct BooleanArrayView { + gsl::span values; + int64_t bitOffset = 0; + + bool operator[](int64_t index) const noexcept { + index += bitOffset; + const int64_t byteIndex = index / 8; + const int64_t bitIndex = index % 8; + const int bitValue = static_cast(values[byteIndex] >> bitIndex) & 1; + return bitValue == 1; + } + }; + + using ArrayType = std::variant>; ArrayType _values; - int64_t _bitOffset; int64_t _size; }; @@ -125,8 +127,7 @@ template <> class PropertyArrayView { /** * @brief Constructs an empty array view. */ - PropertyArrayView() - : _values{}, _stringOffsets{}, _stringOffsetType{}, _size{0} {} + PropertyArrayView() : _values{}, _size{0} {} /** * @brief Constructs an array view from buffers and their information. @@ -141,9 +142,7 @@ template <> class PropertyArrayView { const gsl::span& stringOffsets, PropertyComponentType stringOffsetType, int64_t size) noexcept - : _values{values}, - _stringOffsets{stringOffsets}, - _stringOffsetType{stringOffsetType}, + : _values{StringArrayView{values, stringOffsets, stringOffsetType}}, _size{size} {} /** @@ -152,42 +151,43 @@ template <> class PropertyArrayView { * * @param values The vector containing the values. */ - PropertyArrayView(const std::vector&& values) - : _values{std::move(values)}, - _stringOffsets{}, - _stringOffsetType{PropertyComponentType::None}, - _size{0} { - const auto vectorValues = std::get>(_values); - _size = static_cast(vectorValues.size()); + PropertyArrayView(const std::vector&& values) noexcept + : _values{std::move(values)}, _size{0} { + size_t size = std::get>(_values).size(); + _size = static_cast(size); } std::string_view operator[](int64_t index) const noexcept { - if (std::holds_alternative>(_values)) { - const auto vectorValues = std::get>(_values); - return vectorValues[static_cast(index)]; - } - - const auto values = std::get>(_values); - const size_t currentOffset = - getOffsetFromOffsetsBuffer(index, _stringOffsets, _stringOffsetType); - const size_t nextOffset = getOffsetFromOffsetsBuffer( - index + 1, - _stringOffsets, - _stringOffsetType); - return std::string_view( - reinterpret_cast(values.data() + currentOffset), - (nextOffset - currentOffset)); + return std::visit( + [index](auto const& values) -> auto const { + return std::string_view(values[index]); + }, + _values); } int64_t size() const noexcept { return _size; } private: - using ArrayType = - std::variant, std::vector>; - ArrayType _values; - gsl::span _stringOffsets; + struct StringArrayView { + gsl::span values; + gsl::span stringOffsets; + PropertyComponentType stringOffsetType = PropertyComponentType::None; + + std::string_view operator[](int64_t index) const noexcept { + const size_t currentOffset = + getOffsetFromOffsetsBuffer(index, stringOffsets, stringOffsetType); + const size_t nextOffset = getOffsetFromOffsetsBuffer( + index + 1, + stringOffsets, + stringOffsetType); + return std::string_view( + reinterpret_cast(values.data() + currentOffset), + (nextOffset - currentOffset)); + } + }; - PropertyComponentType _stringOffsetType; + using ArrayType = std::variant>; + ArrayType _values; int64_t _size; }; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 26bec92ea..39e9f7949 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -7,43 +7,6 @@ #include namespace CesiumGltf { -/** - * @brief Indicates the status of a property view. - * - * The {@link PropertyView} constructor always completes successfully. - * However, it may find fundamental errors within the property definition - * itself. This enumeration provides the reason. - */ -enum class PropertyViewStatus { - /** - * @brief This property view is valid and ready to use. - */ - Valid, - - /** - * @brief This property view is trying to view a property that does not exist. - */ - ErrorNonexistentProperty, - - /** - * @brief This property view's type does not match what is - * specified in {@link ClassProperty::type}. - */ - ErrorTypeMismatch, - - /** - * @brief This property view's component type does not match what - * is specified in {@link ClassProperty::componentType}. - */ - ErrorComponentTypeMismatch, - - /** - * @brief This property view differs from what is specified in - * {@link ClassProperty::array}. - */ - ErrorArrayTypeMismatch, -}; - /** * @brief An interface for generic metadata property in EXT_structural_metadata. * @@ -52,6 +15,15 @@ enum class PropertyViewStatus { * property values. Although they are typically defined via class property, they * may be overriden by individual instances of the property. The constructor is * responsible for resolving those differences. + * + * However, there are fundamental differences between property tables, property + * textures, and property attributes. Notably, the ways in which values are + * stored -- as well as what types of values are even supported -- vary between + * the three. Therefore, this interface has no "status" and does not validate + * ElementType against the input class property. Derived classes must do their + * own validation to ensure that ElementType matches the given class definition. + * + * @tparam ElementType The C++ type of the values in this property */ template class IPropertyView { public: @@ -130,13 +102,6 @@ template class IPropertyView { * effect of normalized, offset, and scale properties into account. */ virtual std::optional defaultValue() const noexcept = 0; - -protected: - /** - * @brief Gets the status of the property view. Derived classes will often - * have their own status enumerations, so this is only used internally. - */ - virtual PropertyViewStatus propertyViewStatus() const noexcept = 0; }; /** @@ -153,8 +118,7 @@ class PropertyView : IPropertyView { * @brief Constructs an empty property instance. */ PropertyView() - : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), - _normalized(false), + : _normalized(false), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -167,8 +131,7 @@ class PropertyView : IPropertyView { * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _propertyViewStatus(PropertyViewStatus::Valid), - _normalized(classProperty.normalized), + : _normalized(classProperty.normalized), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -176,49 +139,21 @@ class PropertyView : IPropertyView { _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { - if (convertStringToPropertyType(classProperty.type) != - TypeToPropertyType::value) { - _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; - return; + if constexpr (IsMetadataNumeric::value) { + _offset = + classProperty.offset ? getValue(*classProperty.offset) : std::nullopt; + _scale = + classProperty.scale ? getValue(*classProperty.scale) : std::nullopt; + _max = classProperty.max ? getValue(*classProperty.max) : std::nullopt; + _min = classProperty.min ? getValue(*classProperty.min) : std::nullopt; } - if (!classProperty.componentType && - TypeToPropertyType::component != - PropertyComponentType::None) { - _propertyViewStatus = PropertyViewStatus::ErrorComponentTypeMismatch; - return; - } - - if (classProperty.componentType && - convertStringToPropertyComponentType(*classProperty.componentType) != - TypeToPropertyType::component) { - _propertyViewStatus = PropertyViewStatus::ErrorComponentTypeMismatch; - return; - } - - if (classProperty.array) { - _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; - return; - } - - _offset = classProperty.offset - ? getValue(*classProperty.offset) - : std::nullopt; - _scale = classProperty.scale ? getValue(*classProperty.scale) - : std::nullopt; - _max = classProperty.max ? getValue(*classProperty.max) - : std::nullopt; - _min = classProperty.min ? getValue(*classProperty.min) - : std::nullopt; - if (!_required) { - _noData = classProperty.noData - ? getValue(*classProperty.noData) - : std::nullopt; - _defaultValue = - classProperty.defaultProperty - ? getValue(*classProperty.defaultProperty) - : std::nullopt; + _noData = + classProperty.noData ? getValue(*classProperty.noData) : std::nullopt; + _defaultValue = classProperty.defaultProperty + ? getValue(*classProperty.defaultProperty) + : std::nullopt; } } @@ -231,25 +166,23 @@ class PropertyView : IPropertyView { const ClassProperty& classProperty, const PropertyTableProperty& property) : PropertyView(classProperty) { - if (_propertyViewStatus != PropertyViewStatus::Valid) { - return; - } - // If the property has its own values, override the class-provided values. - if (property.offset) { - _offset = getValue(*property.offset); - } + if constexpr (IsMetadataNumeric::value) { + if (property.offset) { + _offset = getValue(*property.offset); + } - if (property.scale) { - _scale = getValue(*property.scale); - } + if (property.scale) { + _scale = getValue(*property.scale); + } - if (property.max) { - _max = getValue(*property.max); - } + if (property.max) { + _max = getValue(*property.max); + } - if (property.min) { - _min = getValue(*property.min); + if (property.min) { + _min = getValue(*property.min); + } } } @@ -261,25 +194,23 @@ class PropertyView : IPropertyView { const ClassProperty& classProperty, const PropertyTextureProperty& property) : PropertyView(classProperty) { - if (_propertyViewStatus != PropertyViewStatus::Valid) { - return; - } - // If the property has its own values, override the class-provided values. - if (property.offset) { - _offset = getValue(*property.offset); - } + if constexpr (IsMetadataNumeric::value) { + if (property.offset) { + _offset = getValue(*property.offset); + } - if (property.scale) { - _scale = getValue(*property.scale); - } + if (property.scale) { + _scale = getValue(*property.scale); + } - if (property.max) { - _max = getValue(*property.max); - } + if (property.max) { + _max = getValue(*property.max); + } - if (property.min) { - _min = getValue(*property.min); + if (property.min) { + _min = getValue(*property.min); + } } } @@ -328,30 +259,20 @@ class PropertyView : IPropertyView { virtual bool required() const noexcept override { return _required; } /** - * @copydoc IPropertyView::arrayCount + * @copydoc IPropertyView::noData */ virtual std::optional noData() const noexcept override { return _noData; } /** - * @copydoc IPropertyView::arrayCount + * @copydoc IPropertyView::defaultValue */ virtual std::optional defaultValue() const noexcept override { return _defaultValue; } -protected: - /** - * @copydoc IPropertyView::propertyViewStatus - */ - virtual PropertyViewStatus propertyViewStatus() const noexcept override { - return _propertyViewStatus; - } - private: - PropertyViewStatus _propertyViewStatus; - bool _normalized; std::optional _offset; @@ -369,98 +290,39 @@ class PropertyView : IPropertyView { * If T is a type with multiple components, e.g. a VECN or MATN type, this * will return std::nullopt if one or more components could not be parsed. * - * If T is an array view, this will return std::nullopt if one or - * more entries could not be parsed. - * * @return The value as an instance of T, or std::nullopt if it could not be * parsed. */ - template - static std::optional getValue(const CesiumUtility::JsonValue& jsonValue) { - if constexpr (IsMetadataScalar::value) { - return getScalar(jsonValue); - } else - - if constexpr (IsMetadataVecN::value) { - return getVecN(jsonValue); + static std::optional + getValue(const CesiumUtility::JsonValue& jsonValue) { + if constexpr (IsMetadataScalar::value) { + return getScalar(jsonValue); + } else if constexpr (IsMetadataVecN::value) { + return getVecN(jsonValue); } else return std::nullopt; - // if constexpr (IsMetadataMatN::value) { //} } /** - * @brief Attempts to parse from the given json value. If it could not be - * parsed as an ElementType, this returns the default value. - * - * If ElementType is a type with multiple components, e.g. a VECN or MATN - * type. - * - * @return The value as an ElementType, or std::nullopt if it could not be - * parsed. - */ - template - static T getValueOrDefault( - const CesiumUtility::JsonValue& jsonValue, - const T& defaultValue) { - if constexpr (IsMetadataScalar::value) { - return jsonValue.getSafeNumberOrDefault(defaultValue); - } - - if constexpr (IsMetadataVecN::value) { - return getVecNOrDefault(jsonValue, defaultValue); - } - - if constexpr (IsMetadataMatN::value) { - } - } - - /** - * @brief Attempts to parse from the given json value. If it could not be - * parsed as an ElementType, this returns the default value. + * @brief Attempts to parse a scalar from the given JSON value. If the JSON + * value is a number of the wrong type, this will round it to the closest + * representation in the desired type, if possible. Otherwise, this returns + * std::nullopt. * - * If ElementType is a type with multiple components, e.g. a VECN or MATN - * type. - * - * @return The value as an ElementType, or std::nullopt if it could not be + * @return The value as a type T, or std::nullopt if it could not be * parsed. */ template static std::optional getScalar(const CesiumUtility::JsonValue& jsonValue) { try { - return jsonValue.getSafeNumber(); + return jsonValue.getSafeNumber(); } catch (const CesiumUtility::JsonValueNotRealValue& /*error*/) { return std::nullopt; } catch (const gsl::narrowing_error& /*error*/) { - // Continue below. - } - - // If the value is in range, but it loses precision, a narrowing_error will - // be returned. Try to round to a reasonable number anyways, even if it - // loses precision. - if (jsonValue.isInt64()) { - int64_t int64Value = jsonValue.getInt64(); - if (int64Value >= - static_cast(std::numeric_limits::lowest()) && - int64Value <= static_cast(std::numeric_limits::max())) { - return static_cast(int64Value); - } - } else if (jsonValue.isUint64()) { - uint64_t uint64Value = jsonValue.getUint64(); - if (uint64Value <= static_cast(std::numeric_limits::max())) { - return static_cast(uint64Value); - } - } else if (jsonValue.isDouble()) { - double doubleValue = jsonValue.getDouble(); - if (doubleValue >= - static_cast(std::numeric_limits::lowest()) && - doubleValue <= static_cast(std::numeric_limits::max())) { - return static_cast(doubleValue); - } + return std::nullopt; } - - return std::nullopt; } template @@ -470,81 +332,55 @@ class PropertyView : IPropertyView { return std::nullopt; } - return std::nullopt; - // const CesiumUtility::JsonValue::Array& array = value.getArray(); - // glm::length_t N = VecType::length(); - // if (array.size() != N) { - // return std::nullopt; - //} + const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + glm::length_t N = VecType::length(); + if (array.size() != N) { + return std::nullopt; + } - // using T = VecType::type; + using T = VecType::value_type; - // glm::length result; - // for (glm::length_t i = 0; i < N; i++) { - // std::optional value = getValue(array[i]); - // if (!value) { - // return std::nullopt; - // } + VecType result; + for (glm::length_t i = 0; i < N; i++) { + std::optional value = getScalar(array[i]); + if (!value) { + return std::nullopt; + } - // result[i] = value; - //} + result[i] = *value; + } - // return result; + return result; } - template - static VecType getVecNOrDefault( - const CesiumUtility::JsonValue& value, - const VecType& defaultValue) { + template + static std::optional + getMatNFromJsonValue(const CesiumUtility::JsonValue& value) { if (!jsonValue.isArray()) { - return defaultValue; + return std::nullopt; } const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); glm::length_t N = VecType::length(); - if (array.size() != N) { - return defaultValue; + glm::length_t numValues = N * N; + if (array.size() != numValues) { + return std::nullopt; } - using T = VecType::type; + using T = MatType::value_type; - VecType result; - for (glm::length_t i = 0; i < N; i++) { - std::optional value = getValue(array[i]); + MatType result; + for (glm::length_t i = 0; i < numValues; i++) { + std::optional value = getScalar(array[i]); if (!value) { return std::nullopt; } - result[i] = value ? *value : defaultValue; + result[i] = value; } return result; } - - // template - // static std::optional - // getMatNFromJsonValue(const CesiumUtility::JsonValue& value) { - // if (!jsonValue.isArray()) { - // return std::nullopt; - // } - - // const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); - // if (array.size() != N) { - // return std::nullopt; - // } - - // glm::vec result; - // for (glm::length_t i = 0; i < N; i++) { - // std::optional value = getValue(array[i]); - // if (!value) { - // return std::nullopt; - // } - - // result[i] = value; - // } - - // return result; - //} }; template <> class PropertyView : IPropertyView { @@ -552,28 +388,13 @@ template <> class PropertyView : IPropertyView { /** * @brief Constructs an empty property instance. */ - PropertyView() - : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), - _required(false), - _defaultValue(std::nullopt) {} + PropertyView() : _required(false), _defaultValue(std::nullopt) {} /** * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _propertyViewStatus(PropertyViewStatus::Valid), - _required(classProperty.required), - _defaultValue(std::nullopt) { - if (classProperty.type != ClassProperty::Type::BOOLEAN) { - _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; - return; - } - - if (classProperty.array) { - _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; - return; - } - + : _required(classProperty.required), _defaultValue(std::nullopt) { if (!_required) { _defaultValue = classProperty.defaultProperty ? getBooleanValue(*classProperty.defaultProperty) @@ -581,6 +402,7 @@ template <> class PropertyView : IPropertyView { } } +protected: /** * @brief Constructs a property instance from a property table property and * its class definition. @@ -599,8 +421,7 @@ template <> class PropertyView : IPropertyView { const PropertyTextureProperty& /*property*/) : PropertyView(classProperty) {} - ~PropertyView() {} - +public: /** * @copydoc IPropertyView::arrayCount */ @@ -658,16 +479,7 @@ template <> class PropertyView : IPropertyView { return _defaultValue; } -protected: - /** - * @copydoc IPropertyView::propertyViewStatus - */ - virtual PropertyViewStatus propertyViewStatus() const noexcept override { - return _propertyViewStatus; - } - private: - PropertyViewStatus _propertyViewStatus; bool _required; std::optional _defaultValue; @@ -688,29 +500,15 @@ class PropertyView : IPropertyView { * @brief Constructs an empty property instance. */ PropertyView() - : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), - _required(false), - _noData(std::nullopt), - _defaultValue(std::nullopt) {} + : _required(false), _noData(std::nullopt), _defaultValue(std::nullopt) {} /** * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _propertyViewStatus(PropertyViewStatus::Valid), - _required(classProperty.required), + : _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { - if (classProperty.type != ClassProperty::Type::STRING) { - _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; - return; - } - - if (classProperty.array) { - _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; - return; - } - if (!_required) { _noData = classProperty.noData ? getStringValue(*classProperty.noData) : std::nullopt; @@ -720,6 +518,7 @@ class PropertyView : IPropertyView { } } +protected: /** * @brief Constructs a property instance from a property table property and * its class definition. @@ -738,8 +537,7 @@ class PropertyView : IPropertyView { const PropertyTextureProperty& /*property*/) : PropertyView(classProperty) {} - ~PropertyView() {} - +public: /** * @copydoc IPropertyView::arrayCount */ @@ -804,16 +602,7 @@ class PropertyView : IPropertyView { return std::nullopt; } -protected: - /** - * @copydoc IPropertyView::propertyViewStatus - */ - virtual PropertyViewStatus propertyViewStatus() const noexcept override { - return _propertyViewStatus; - } - private: - PropertyViewStatus _propertyViewStatus; bool _required; std::optional _noData; std::optional _defaultValue; @@ -836,8 +625,7 @@ class PropertyView> * @brief Constructs an empty property instance. */ PropertyView() - : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), - _count(0), + : _count(0), _normalized(false), _offset(std::nullopt), _scale(std::nullopt), @@ -851,8 +639,7 @@ class PropertyView> * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _propertyViewStatus(PropertyViewStatus::Valid), - _count(0), + : _count(_count = classProperty.count ? *classProperty.count : 0), _normalized(classProperty.normalized), _offset(std::nullopt), _scale(std::nullopt), @@ -861,33 +648,6 @@ class PropertyView> _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { - if (convertStringToPropertyType(classProperty.type) != - TypeToPropertyType::value) { - _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; - return; - } - - if (!classProperty.componentType && - TypeToPropertyType::component != - PropertyComponentType::None) { - _propertyViewStatus = PropertyViewStatus::ErrorComponentTypeMismatch; - return; - } - - if (classProperty.componentType && - convertStringToPropertyComponentType(*classProperty.componentType) != - TypeToPropertyType::component) { - _propertyViewStatus = PropertyViewStatus::ErrorComponentTypeMismatch; - return; - } - - if (!classProperty.array) { - _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; - return; - } - - _count = classProperty.count ? *classProperty.count : 0; - //_offset = classProperty.offset // ? getValue(*classProperty.offset) // : std::nullopt; @@ -898,7 +658,7 @@ class PropertyView> //_min = classProperty.min ? getValue(*classProperty.min) // : std::nullopt; - //if (!_required) { + // if (!_required) { // _noData = classProperty.noData // ? getValue(*classProperty.noData) // : std::nullopt; @@ -918,24 +678,20 @@ class PropertyView> const ClassProperty& classProperty, const PropertyTableProperty& /*property*/) : PropertyView(classProperty) { - if (_propertyViewStatus != PropertyViewStatus::Valid) { - return; - } - //// If the property has its own values, override the class-provided values. - //if (property.offset) { + // if (property.offset) { // _offset = getValue(*property.offset); //} - //if (property.scale) { + // if (property.scale) { // _scale = getValue(*property.scale); //} - //if (property.max) { + // if (property.max) { // _max = getValue(*property.max); //} - //if (property.min) { + // if (property.min) { // _min = getValue(*property.min); //} } @@ -948,24 +704,20 @@ class PropertyView> const ClassProperty& classProperty, const PropertyTextureProperty& /*property*/) : PropertyView(classProperty) { - if (_propertyViewStatus != PropertyViewStatus::Valid) { - return; - } - //// If the property has its own values, override the class-provided values. - //if (property.offset) { + // if (property.offset) { // _offset = getValue(*property.offset); //} - //if (property.scale) { + // if (property.scale) { // _scale = getValue(*property.scale); //} - //if (property.max) { + // if (property.max) { // _max = getValue(*property.max); //} - //if (property.min) { + // if (property.min) { // _min = getValue(*property.min); //} } @@ -1034,17 +786,7 @@ class PropertyView> return _defaultValue; } -protected: - /** - * @copydoc IPropertyView::propertyViewStatus - */ - virtual PropertyViewStatus propertyViewStatus() const noexcept override { - return _propertyViewStatus; - } - private: - PropertyViewStatus _propertyViewStatus; - int64_t _count; bool _normalized; @@ -1060,23 +802,19 @@ class PropertyView> /** * @brief Attempts to parse from the given json value. * - * If T is a type with multiple components, e.g. a VECN or MATN type, this - * will return std::nullopt if one or more components could not be parsed. - * - * If T is an array view, this will return std::nullopt if one or - * more entries could not be parsed. - * - * @return The value as an instance of T, or std::nullopt if it could not be + * If ElementType is a type with multiple components, e.g. a VECN or MATN + * type, this will return std::nullopt if one or more components could not be * parsed. - */ - template - static std::optional getValue(const CesiumUtility::JsonValue& jsonValue) { - if constexpr (IsMetadataScalar::value) { - return getScalar(jsonValue); - } else - - if constexpr (IsMetadataVecN::value) { - return getVecN(jsonValue); + * + * @return The value as an instance of ElementType, or std::nullopt if it + * could not be parsed. + */ + static std::optional + getValue(const CesiumUtility::JsonValue& jsonValue) { + if constexpr (IsMetadataScalar::value) { + return getScalar(jsonValue); + } else if constexpr (IsMetadataVecN::value) { + return getVecN(jsonValue); } else return std::nullopt; @@ -1084,43 +822,6 @@ class PropertyView> //} } - /** - * @brief Attempts to parse from the given json value. If it could not be - * parsed as an ElementType, this returns the default value. - * - * If ElementType is a type with multiple components, e.g. a VECN or MATN - * type. - * - * @return The value as an ElementType, or std::nullopt if it could not be - * parsed. - */ - template - static T getValueOrDefault( - const CesiumUtility::JsonValue& jsonValue, - const T& defaultValue) { - if constexpr (IsMetadataScalar::value) { - return jsonValue.getSafeNumberOrDefault(defaultValue); - } - - if constexpr (IsMetadataVecN::value) { - return getVecNOrDefault(jsonValue, defaultValue); - } - - if constexpr (IsMetadataMatN::value) { - } - - if constexpr (IsMetadataArray::value) { - return defaultValue; - // if (!jsonValue.isArray()) { - // return PropertyArrayView(std::vector()); - // } - - // return jsonValue.isArray() - // ? getArrayValueOrDefault(jsonValue.getArray(), - // defaultValue) : defaultValue; - } - } - /** * @brief Attempts to parse from the given json value. If it could not be * parsed as an ElementType, this returns the default value. @@ -1138,89 +839,30 @@ class PropertyView> } catch (const CesiumUtility::JsonValueNotRealValue& /*error*/) { return std::nullopt; } catch (const gsl::narrowing_error& /*error*/) { - // Continue below. - } - - // If the value is in range, but it loses precision, a narrowing_error will - // be returned. Try to round to a reasonable number anyways, even if it - // loses precision. - if (jsonValue.isInt64()) { - int64_t int64Value = jsonValue.getInt64(); - if (int64Value >= - static_cast(std::numeric_limits::lowest()) && - int64Value <= static_cast(std::numeric_limits::max())) { - return static_cast(int64Value); - } - } else if (jsonValue.isUint64()) { - uint64_t uint64Value = jsonValue.getUint64(); - if (uint64Value <= static_cast(std::numeric_limits::max())) { - return static_cast(uint64Value); - } - } else if (jsonValue.isDouble()) { - double doubleValue = jsonValue.getDouble(); - if (doubleValue >= - static_cast(std::numeric_limits::lowest()) && - doubleValue <= static_cast(std::numeric_limits::max())) { - return static_cast(doubleValue); - } + return std::nullopt; } - - return std::nullopt; } - template - static std::optional + template + static std::optional> getVecN(const CesiumUtility::JsonValue& jsonValue) { if (!jsonValue.isArray()) { return std::nullopt; } - return std::nullopt; - // const CesiumUtility::JsonValue::Array& array = value.getArray(); - // glm::length_t N = VecType::length(); - // if (array.size() != N) { - // return std::nullopt; - //} - - // using T = VecType::type; - - // glm::length result; - // for (glm::length_t i = 0; i < N; i++) { - // std::optional value = getValue(array[i]); - // if (!value) { - // return std::nullopt; - // } - - // result[i] = value; - //} - - // return result; - } - - template - static VecType getVecNOrDefault( - const CesiumUtility::JsonValue& value, - const VecType& defaultValue) { - if (!jsonValue.isArray()) { - return defaultValue; - } - - const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); - glm::length_t N = VecType::length(); + const CesiumUtility::JsonValue::Array& array = value.getArray(); if (array.size() != N) { - return defaultValue; + return std::nullopt; } - using T = VecType::type; - - VecType result; + glm::vec result; for (glm::length_t i = 0; i < N; i++) { - std::optional value = getValue(array[i]); + std::optional value = getValue(array[i]); if (!value) { return std::nullopt; } - result[i] = value ? *value : defaultValue; + result[i] = value; } return result; @@ -1250,35 +892,6 @@ class PropertyView> // return result; //} - - template - static std::optional> - getArrayValue(const CesiumUtility::JsonValue::Array& /*arrayValue*/) { - return std::nullopt; - // std::vector values(arrayValue.size()); - // for (size_t i = 0; i < arrayValue.size(); i++) { - // const CesiumUtility::JsonValue& value = arrayValue[i]; - // std::optional arrayElement = getValue(value); - // values[i] = arrayElement; - //} - - // return PropertyArrayView(values); - } - - template - static PropertyArrayView getArrayValueOrDefault( - const CesiumUtility::JsonValue::Array& arrayValue, - const ArrayType& defaultElementValue) { - - std::vector values(arrayValue.size()); - for (size_t i = 0; i < arrayValue.size(); i++) { - const CesiumUtility::JsonValue& value = arrayValue[i]; - std::optional arrayElement = getValue(value); - values[i] = arrayElement; - } - - return PropertyArrayView(values); - } }; template <> @@ -1288,40 +901,23 @@ class PropertyView> /** * @brief Constructs an empty property instance. */ - PropertyView() - : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), - _count(0), - _required(false), - _defaultValue(std::nullopt) {} + PropertyView() : _count(0), _required(false), _defaultValue(std::nullopt) {} /** * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _propertyViewStatus(PropertyViewStatus::Valid), - _count(0), + : _count(classProperty.count ? *classProperty.count : 0), _required(classProperty.required), _defaultValue(std::nullopt) { - if (classProperty.type != ClassProperty::Type::BOOLEAN) { - _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; - return; - } - - if (!classProperty.array) { - _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; - return; - } - - _count = classProperty.count ? *classProperty.count : 0; - if (!_required) { - _defaultValue = - classProperty.defaultProperty - ? getBooleanArrayValues(*classProperty.defaultProperty) - : std::nullopt; + _defaultValue = classProperty.defaultProperty + ? getBooleanArrayValue(*classProperty.defaultProperty) + : std::nullopt; } } +protected: /** * @brief Constructs a property instance from a property table property and * its class definition. @@ -1340,8 +936,7 @@ class PropertyView> const PropertyTextureProperty& /*property*/) : PropertyView(classProperty) {} - ~PropertyView() {} - +public: /** * @copydoc IPropertyView::arrayCount */ @@ -1400,25 +995,22 @@ class PropertyView> */ virtual std::optional> defaultValue() const noexcept override { - return _defaultValue; - } - -protected: - /** - * @copydoc IPropertyView::propertyViewStatus - */ - virtual PropertyViewStatus propertyViewStatus() const noexcept override { - return _propertyViewStatus; + if (!_defaultValue) { + return std::nullopt; + } + // Not as easy to construct a gsl::span for the boolean data (the .data() of + // a boolean vector is inaccessible). Just make a copy. + std::vector defaultValueCopy(*_defaultValue); + return PropertyArrayView(std::move(defaultValueCopy)); } private: - PropertyViewStatus _propertyViewStatus; int64_t _count; bool _required; - std::optional> _defaultValue; + std::optional> _defaultValue; - static std::optional> - getBooleanArrayValues(const CesiumUtility::JsonValue& value) { + static std::optional> + getBooleanArrayValue(const CesiumUtility::JsonValue& value) { if (!value.isArray()) { return std::nullopt; } @@ -1444,44 +1036,27 @@ class PropertyView> /** * @brief Constructs an empty property instance. */ - PropertyView() - : _propertyViewStatus(PropertyViewStatus::ErrorNonexistentProperty), - _count(0), - _required(false), - _noData(std::nullopt), - _defaultValue(std::nullopt) {} + PropertyView() : _count(0), _required(false), _noData(), _defaultValue() {} /** * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _propertyViewStatus(PropertyViewStatus::Valid), - _count(0), + : _count(classProperty.count ? *classProperty.count : 0), _required(classProperty.required), - _noData(std::nullopt), - _defaultValue(std::nullopt) { - if (classProperty.type != ClassProperty::Type::STRING) { - _propertyViewStatus = PropertyViewStatus::ErrorTypeMismatch; - return; - } - - if (!classProperty.array) { - _propertyViewStatus = PropertyViewStatus::ErrorArrayTypeMismatch; - return; + _noData(), + _defaultValue() { + if (!_required) { + _noData = classProperty.noData + ? getStringArrayValue(*classProperty.noData) + : std::nullopt; + _defaultValue = classProperty.defaultProperty + ? getStringArrayValue(*classProperty.defaultProperty) + : std::nullopt; } - - _count = classProperty.count ? *classProperty.count : 0; - - // if (!_required) { - // _noData = classProperty.noData ? - // getStringArrayData(*classProperty.noData) - // : std::nullopt; - // _defaultValue = classProperty.defaultProperty - // ? getStringArrayData(*classProperty.defaultProperty) - // : std::nullopt; - //} } +protected: /** * @brief Constructs a property instance from a property table property and * its class definition. @@ -1500,8 +1075,7 @@ class PropertyView> const PropertyTextureProperty& /*property*/) : PropertyView(classProperty) {} - ~PropertyView() {} - +public: /** * @copydoc IPropertyView::arrayCount */ @@ -1554,7 +1128,14 @@ class PropertyView> */ virtual std::optional> noData() const noexcept override { - return _noData; + if (!_noData) { + return std::nullopt; + } + + // Just copy the strings. Easier than iterating through all of the strings + // to generate an offsets buffer with a best-fitting offset type. + std::vector noDataCopy(*_noData); + return PropertyArrayView(std::move(noDataCopy)); } /** @@ -1562,31 +1143,43 @@ class PropertyView> */ virtual std::optional> defaultValue() const noexcept override { - return _defaultValue; - } + if (!_defaultValue) { + return std::nullopt; + } -protected: - /** - * @copydoc IPropertyView::propertyViewStatus - */ - virtual PropertyViewStatus propertyViewStatus() const noexcept override { - return _propertyViewStatus; + // Just copy the strings. Easier than iterating through all of the strings + // to generate an offsets buffer with a best-fitting offset type. + std::vector defaultValueCopy(*_defaultValue); + return PropertyArrayView(std::move(defaultValueCopy)); } private: - PropertyViewStatus _propertyViewStatus; int64_t _count; bool _required; - std::optional> _noData; - std::optional> _defaultValue; - static std::optional> - getStringArrayData(const CesiumUtility::JsonValue& value) { - if (!value.isArray()) { + std::optional> _noData; + std::optional> _defaultValue; + + static std::optional> + getStringArrayValue(const CesiumUtility::JsonValue& jsonValue) { + if (!jsonValue.isArray()) { return std::nullopt; } - std::vector strings; + std::vector result; + const auto array = jsonValue.getArray(); + result.reserve(array.size()); + + for (size_t i = 0; i < array.size(); i++) { + if (!array[i].isString()) { + // The entire array is invalidated; return. + return std::nullopt; + } + + result.push_back(array[i].getString()); + } + + return result; } }; diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index 434e30124..4a625a350 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -1,3247 +1,3247 @@ -//#include "CesiumGltf/PropertyTableView.h" -// -//#include -// -//#include -// -//using namespace CesiumGltf; -// -//template -//void addBufferToModel(Model& model, const std::vector& values) { -// Buffer& valueBuffer = model.buffers.emplace_back(); -// valueBuffer.cesium.data.resize(values.size() * sizeof(T)); -// valueBuffer.byteLength = static_cast(valueBuffer.cesium.data.size()); -// std::memcpy( -// valueBuffer.cesium.data.data(), -// values.data(), -// valueBuffer.cesium.data.size()); -// -// BufferView& valueBufferView = model.bufferViews.emplace_back(); -// valueBufferView.buffer = static_cast(model.buffers.size() - 1); -// valueBufferView.byteOffset = 0; -// valueBufferView.byteLength = valueBuffer.byteLength; -//} -// -//TEST_CASE("Test PropertyTableView on model without EXT_structural_metadata " -// "extension") { -// Model model; -// -// // Create an erroneously isolated property table. -// PropertyTable propertyTable; -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(10); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(0); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE( -// view.status() == PropertyTableViewStatus::ErrorMissingMetadataExtension); -// REQUIRE(view.size() == 0); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(!classProperty); -//} -// -//TEST_CASE("Test PropertyTableView on model without metadata schema") { -// Model model; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(10); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(0); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::ErrorMissingSchema); -// REQUIRE(view.size() == 0); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(!classProperty); -//} -// -//TEST_CASE("Test property table with nonexistent class") { -// Model model; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::SCALAR; -// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "I Don't Exist"; -// propertyTable.count = static_cast(10); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(0); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); -// REQUIRE(view.size() == 0); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(!classProperty); -//} -// -//TEST_CASE("Test scalar PropertyTableProperty") { -// Model model; -// std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; -// -// addBufferToModel(model, values); -// size_t valueBufferIndex = model.buffers.size() - 1; -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::SCALAR; -// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(values.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); -// REQUIRE(classProperty->count == std::nullopt); -// REQUIRE(!classProperty->array); -// -// SECTION("Access correct type") { -// PropertyTablePropertyView uint32Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(uint32Property.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(uint32Property.size() > 0); -// -// for (int64_t i = 0; i < uint32Property.size(); ++i) { -// REQUIRE(uint32Property.get(i) == values[static_cast(i)]); -// } -// } -// -// SECTION("Access wrong type") { -// PropertyTablePropertyView uvec3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uvec3Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView u32mat3x3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u32mat3x3Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView boolInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// boolInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView stringInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// stringInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// } -// -// SECTION("Access wrong component type") { -// PropertyTablePropertyView uint8Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint8Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyTablePropertyView int32Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// int32Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyTablePropertyView uint64Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint64Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Access incorrectly as array") { -// PropertyTablePropertyView> uint32ArrayInvalid = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// uint32ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Wrong buffer index") { -// model.bufferViews[valueBufferViewIndex].buffer = 2; -// PropertyTablePropertyView uint32Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint32Property.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); -// } -// -// SECTION("Wrong buffer view index") { -// propertyTableProperty.values = -1; -// PropertyTablePropertyView uint32Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint32Property.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); -// } -// -// SECTION("Buffer view points outside of the real buffer length") { -// model.buffers[valueBufferIndex].cesium.data.resize(12); -// PropertyTablePropertyView uint32Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint32Property.status() == -// PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); -// } -// -// SECTION("Buffer view length isn't multiple of sizeof(T)") { -// model.bufferViews[valueBufferViewIndex].byteLength = 13; -// PropertyTablePropertyView uint32Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint32Property.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeNotDivisibleByTypeSize); -// } -// -// SECTION("Buffer view length doesn't match with propertyTableCount") { -// model.bufferViews[valueBufferViewIndex].byteLength = 12; -// PropertyTablePropertyView uint32Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint32Property.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// } -//} -// -//TEST_CASE("Test vecN PropertyTableProperty") { -// Model model; -// std::vector values = { -// glm::ivec3(-12, 34, 30), -// glm::ivec3(11, 73, 0), -// glm::ivec3(-2, 6, 12), -// glm::ivec3(-4, 8, -13)}; -// -// addBufferToModel(model, values); -// size_t valueBufferIndex = model.buffers.size() - 1; -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::VEC3; -// testClassProperty.componentType = ClassProperty::ComponentType::INT32; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(values.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::VEC3); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); -// REQUIRE(classProperty->count == std::nullopt); -// REQUIRE(!classProperty->array); -// -// SECTION("Access correct type") { -// PropertyTablePropertyView ivec3Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(ivec3Property.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(ivec3Property.size() > 0); -// -// for (int64_t i = 0; i < ivec3Property.size(); ++i) { -// REQUIRE(ivec3Property.get(i) == values[static_cast(i)]); -// } -// } -// -// SECTION("Access wrong type") { -// PropertyTablePropertyView int32Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// int32Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView ivec2Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// ivec2Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView i32mat3x3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// i32mat3x3Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView boolInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// boolInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView stringInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// stringInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// } -// -// SECTION("Access wrong component type") { -// PropertyTablePropertyView u8vec3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec3Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyTablePropertyView i16vec3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// i16vec3Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyTablePropertyView vec3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// vec3Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Access incorrectly as array") { -// PropertyTablePropertyView> ivec3ArrayInvalid = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// ivec3ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Wrong buffer index") { -// model.bufferViews[valueBufferViewIndex].buffer = 2; -// PropertyTablePropertyView ivec3Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// ivec3Property.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); -// } -// -// SECTION("Wrong buffer view index") { -// propertyTableProperty.values = -1; -// PropertyTablePropertyView ivec3Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// ivec3Property.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); -// } -// -// SECTION("Buffer view points outside of the real buffer length") { -// model.buffers[valueBufferIndex].cesium.data.resize(12); -// PropertyTablePropertyView ivec3Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// ivec3Property.status() == -// PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); -// } -// -// SECTION("Buffer view length isn't multiple of sizeof(T)") { -// model.bufferViews[valueBufferViewIndex].byteLength = 11; -// PropertyTablePropertyView ivec3Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// ivec3Property.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeNotDivisibleByTypeSize); -// } -// -// SECTION("Buffer view length doesn't match with propertyTableCount") { -// model.bufferViews[valueBufferViewIndex].byteLength = 12; -// PropertyTablePropertyView ivec3Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// ivec3Property.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// } -//} -// -//TEST_CASE("Test matN PropertyTableProperty") { -// Model model; -// // clang-format off -// std::vector values = { -// glm::u32mat2x2( -// 12, 34, -// 30, 1), -// glm::u32mat2x2( -// 11, 8, -// 73, 102), -// glm::u32mat2x2( -// 1, 0, -// 63, 2), -// glm::u32mat2x2( -// 4, 8, -// 3, 23)}; -// // clang-format on -// -// addBufferToModel(model, values); -// size_t valueBufferIndex = model.buffers.size() - 1; -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::MAT2; -// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(values.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::MAT2); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); -// REQUIRE(classProperty->count == std::nullopt); -// REQUIRE(!classProperty->array); -// -// SECTION("Access correct type") { -// PropertyTablePropertyView u32mat2x2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u32mat2x2Property.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(u32mat2x2Property.size() > 0); -// -// for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { -// REQUIRE(u32mat2x2Property.get(i) == values[static_cast(i)]); -// } -// } -// -// SECTION("Access wrong type") { -// PropertyTablePropertyView uint32Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint32Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView uvec2Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uvec2Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView u32mat4x4Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u32mat4x4Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView boolInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// boolInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView stringInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// stringInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// } -// -// SECTION("Access wrong component type") { -// PropertyTablePropertyView u8mat2x2Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8mat2x2Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyTablePropertyView i32mat2x2Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// i32mat2x2Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyTablePropertyView mat2Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// mat2Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Access incorrectly as array") { -// PropertyTablePropertyView> -// u32mat2x2ArrayInvalid = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// u32mat2x2ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Wrong buffer index") { -// model.bufferViews[valueBufferViewIndex].buffer = 2; -// PropertyTablePropertyView u32mat2x2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u32mat2x2Property.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); -// } -// -// SECTION("Wrong buffer view index") { -// propertyTableProperty.values = -1; -// PropertyTablePropertyView u32mat2x2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u32mat2x2Property.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); -// } -// -// SECTION("Buffer view points outside of the real buffer length") { -// model.buffers[valueBufferIndex].cesium.data.resize(sizeof(glm::u32mat2x2)); -// PropertyTablePropertyView u32mat2x2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u32mat2x2Property.status() == -// PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); -// } -// -// SECTION("Buffer view length isn't multiple of sizeof(T)") { -// model.bufferViews[valueBufferViewIndex].byteLength = -// sizeof(glm::u32mat2x2) * 4 - 1; -// PropertyTablePropertyView u32mat2x2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u32mat2x2Property.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeNotDivisibleByTypeSize); -// } -// -// SECTION("Buffer view length doesn't match with propertyTableCount") { -// model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::u32mat2x2); -// -// PropertyTablePropertyView u32mat2x2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u32mat2x2Property.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// } -//} -// -//TEST_CASE("Test boolean PropertyTableProperty") { -// Model model; -// -// int64_t instanceCount = 21; -// std::vector expected; -// std::vector values; -// values.resize(3); -// for (int64_t i = 0; i < instanceCount; ++i) { -// if (i % 2 == 0) { -// expected.emplace_back(true); -// } else { -// expected.emplace_back(false); -// } -// -// uint8_t expectedValue = expected.back(); -// int64_t byteIndex = i / 8; -// int64_t bitIndex = i % 8; -// values[static_cast(byteIndex)] = static_cast( -// (expectedValue << bitIndex) | values[static_cast(byteIndex)]); -// } -// addBufferToModel(model, values); -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::BOOLEAN; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(instanceCount); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = -// static_cast(model.bufferViews.size() - 1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); -// REQUIRE(classProperty->componentType == std::nullopt); -// REQUIRE(classProperty->count == std::nullopt); -// REQUIRE(!classProperty->array); -// -// SECTION("Access correct type") { -// PropertyTablePropertyView boolProperty = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(boolProperty.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(boolProperty.size() == instanceCount); -// for (int64_t i = 0; i < boolProperty.size(); ++i) { -// bool expectedValue = expected[static_cast(i)]; -// REQUIRE(boolProperty.get(i) == expectedValue); -// } -// } -// -// SECTION("Buffer size doesn't match with propertyTableCount") { -// propertyTable.count = 66; -// PropertyTablePropertyView boolProperty = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// boolProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// } -//} -// -//TEST_CASE("Test string PropertyTableProperty") { -// Model model; -// -// std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; -// size_t totalBytes = 0; -// for (const std::string& expectedValue : expected) { -// totalBytes += expectedValue.size(); -// } -// -// std::vector stringOffsets( -// (expected.size() + 1) * sizeof(uint32_t)); -// std::vector values(totalBytes); -// uint32_t* offsetValue = reinterpret_cast(stringOffsets.data()); -// for (size_t i = 0; i < expected.size(); ++i) { -// const std::string& expectedValue = expected[i]; -// std::memcpy( -// values.data() + offsetValue[i], -// expectedValue.c_str(), -// expectedValue.size()); -// offsetValue[i + 1] = -// offsetValue[i] + static_cast(expectedValue.size()); -// } -// -// addBufferToModel(model, values); -// size_t valueBufferIndex = model.buffers.size() - 1; -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// addBufferToModel(model, stringOffsets); -// size_t offsetBufferIndex = model.buffers.size() - 1; -// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::STRING; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(expected.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT32; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// propertyTableProperty.stringOffsets = -// static_cast(offsetBufferViewIndex); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::STRING); -// REQUIRE(classProperty->componentType == std::nullopt); -// REQUIRE(classProperty->count == std::nullopt); -// REQUIRE(!classProperty->array); -// -// SECTION("Access correct type") { -// PropertyTablePropertyView stringProperty = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); -// for (size_t i = 0; i < expected.size(); ++i) { -// REQUIRE(stringProperty.get(static_cast(i)) == expected[i]); -// } -// } -// -// SECTION("Wrong array type") { -// PropertyTablePropertyView> -// stringArrayInvalid = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// stringArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Wrong offset type") { -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT8; -// PropertyTablePropertyView stringProperty = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// stringProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT64; -// stringProperty = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// stringProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.stringOffsetType = "NONSENSE"; -// stringProperty = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// stringProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); -// -// propertyTableProperty.stringOffsetType = ""; -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::StringOffsetType::UINT32; -// stringProperty = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// stringProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); -// } -// -// SECTION("Offset values are not sorted ascending") { -// uint32_t* offset = reinterpret_cast( -// model.buffers[offsetBufferIndex].cesium.data.data()); -// offset[2] = -// static_cast(model.buffers[valueBufferIndex].byteLength + 4); -// PropertyTablePropertyView stringProperty = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// stringProperty.status() == -// PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); -// } -// -// SECTION("Offset value points outside of value buffer") { -// uint32_t* offset = reinterpret_cast( -// model.buffers[offsetBufferIndex].cesium.data.data()); -// offset[propertyTable.count] = -// static_cast(model.buffers[valueBufferIndex].byteLength + 4); -// PropertyTablePropertyView stringProperty = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// stringProperty.status() == -// PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); -// } -//} -// -//TEST_CASE("Test fixed-length scalar array") { -// Model model; -// std::vector values = -// {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; -// -// addBufferToModel(model, values); -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::SCALAR; -// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; -// testClassProperty.array = true; -// testClassProperty.count = 3; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast( -// values.size() / static_cast(testClassProperty.count.value())); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = -// static_cast(model.bufferViews.size() - 1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); -// REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 3); -// -// SECTION("Access the right type") { -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); -// -// for (int64_t i = 0; i < arrayProperty.size(); ++i) { -// PropertyArrayView member = arrayProperty.get(i); -// for (int64_t j = 0; j < member.size(); ++j) { -// REQUIRE(member[j] == values[static_cast(i * 3 + j)]); -// } -// } -// } -// -// SECTION("Wrong type") { -// PropertyTablePropertyView> boolArrayInvalid = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// boolArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView> uvec2ArrayInvalid = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// uvec2ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// } -// -// SECTION("Wrong component type") { -// PropertyTablePropertyView> int32ArrayInvalid = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// int32ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Not an array type") { -// PropertyTablePropertyView uint32Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint32Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Buffer size is not a multiple of type size") { -// model.bufferViews[valueBufferViewIndex].byteLength = 13; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeNotDivisibleByTypeSize); -// } -// -// SECTION("Negative component count") { -// testClassProperty.count = -1; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == PropertyTablePropertyViewStatus:: -// ErrorArrayCountAndOffsetBufferDontExist); -// } -// -// SECTION("Value buffer doesn't fit into property table count") { -// testClassProperty.count = 55; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// } -//} -// -//TEST_CASE("Test variable-length scalar array") { -// Model model; -// -// std::vector> expected{ -// {12, 33, 11, 344, 112, 444, 1}, -// {}, -// {}, -// {122, 23, 333, 12}, -// {}, -// {333, 311, 22, 34}, -// {}, -// {33, 1888, 233, 33019}}; -// size_t numOfElements = 0; -// for (const auto& expectedMember : expected) { -// numOfElements += expectedMember.size(); -// } -// -// std::vector values(numOfElements * sizeof(uint16_t)); -// std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); -// uint64_t* offsetValue = reinterpret_cast(offsets.data()); -// for (size_t i = 0; i < expected.size(); ++i) { -// std::memcpy( -// values.data() + offsetValue[i], -// expected[i].data(), -// expected[i].size() * sizeof(uint16_t)); -// offsetValue[i + 1] = offsetValue[i] + expected[i].size() * sizeof(uint16_t); -// } -// -// addBufferToModel(model, values); -// size_t valueBufferIndex = model.buffers.size() - 1; -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// addBufferToModel(model, offsets); -// size_t offsetBufferIndex = model.buffers.size() - 1; -// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// 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; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(expected.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// propertyTableProperty.arrayOffsets = -// static_cast(offsetBufferViewIndex); -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT64; -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// 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); -// -// SECTION("Access the correct type") { -// PropertyTablePropertyView> property = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); -// for (size_t i = 0; i < expected.size(); ++i) { -// PropertyArrayView valueMember = -// property.get(static_cast(i)); -// REQUIRE(valueMember.size() == static_cast(expected[i].size())); -// for (size_t j = 0; j < expected[i].size(); ++j) { -// REQUIRE(expected[i][j] == valueMember[static_cast(j)]); -// } -// } -// } -// SECTION("Wrong offset type") { -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT8; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT16; -// arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.arrayOffsetType = "NONSENSE"; -// arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); -// -// propertyTableProperty.arrayOffsetType = ""; -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT64; -// arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); -// } -// -// SECTION("Offset values are not sorted ascending") { -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT64; -// uint64_t* offset = reinterpret_cast( -// model.buffers[offsetBufferIndex].cesium.data.data()); -// offset[propertyTable.count] = 0; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); -// } -// -// SECTION("Offset value points outside of value buffer") { -// uint64_t* offset = reinterpret_cast( -// model.buffers[offsetBufferIndex].cesium.data.data()); -// offset[propertyTable.count] = -// static_cast(model.buffers[valueBufferIndex].byteLength + 4); -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); -// } -// -// SECTION("Count and offset buffer are both present") { -// testClassProperty.count = 3; -// PropertyTablePropertyView> property = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// property.status() == -// PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); -// } -//} -// -//TEST_CASE("Test fixed-length vecN array") { -// Model model; -// std::vector values = { -// glm::ivec3(12, 34, -30), -// glm::ivec3(-2, 0, 1), -// glm::ivec3(1, 2, 8), -// glm::ivec3(-100, 84, 6), -// glm::ivec3(2, -2, -2), -// glm::ivec3(40, 61, 3), -// }; -// -// addBufferToModel(model, values); -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::VEC3; -// testClassProperty.componentType = ClassProperty::ComponentType::INT32; -// testClassProperty.array = true; -// testClassProperty.count = 2; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast( -// values.size() / static_cast(testClassProperty.count.value())); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = -// static_cast(model.bufferViews.size() - 1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::VEC3); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); -// REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 2); -// -// SECTION("Access the right type") { -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); -// -// for (int64_t i = 0; i < arrayProperty.size(); ++i) { -// PropertyArrayView member = arrayProperty.get(i); -// for (int64_t j = 0; j < member.size(); ++j) { -// REQUIRE(member[j] == values[static_cast(i * 2 + j)]); -// } -// } -// } -// -// SECTION("Wrong type") { -// PropertyTablePropertyView> int32ArrayInvalid = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// int32ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView> ivec2ArrayInvalid = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// ivec2ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// } -// -// SECTION("Wrong component type") { -// PropertyTablePropertyView> uvec3ArrayInvalid = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// uvec3ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Not an array type") { -// PropertyTablePropertyView ivec3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// ivec3Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Buffer size is not a multiple of type size") { -// model.bufferViews[valueBufferViewIndex].byteLength = 13; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeNotDivisibleByTypeSize); -// } -// -// SECTION("Negative component count") { -// testClassProperty.count = -1; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == PropertyTablePropertyViewStatus:: -// ErrorArrayCountAndOffsetBufferDontExist); -// } -// -// SECTION("Value buffer doesn't fit into property table count") { -// testClassProperty.count = 55; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// } -//} -// -//TEST_CASE("Test variable-length vecN array") { -// Model model; -// // clang-format off -// std::vector> expected{ -// { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1) }, -// { glm::ivec3(1, 2, 8), }, -// {}, -// { glm::ivec3(-100, 84, 6), glm::ivec3(2, -2, -2), glm::ivec3(40, 61, 3) }, -// { glm::ivec3(-1, 4, -7) }, -// }; -// // clang-format on -// -// size_t numOfElements = 0; -// for (const auto& expectedMember : expected) { -// numOfElements += expectedMember.size(); -// } -// -// std::vector values(numOfElements * sizeof(glm::ivec3)); -// std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); -// uint64_t* offsetValue = reinterpret_cast(offsets.data()); -// for (size_t i = 0; i < expected.size(); ++i) { -// std::memcpy( -// values.data() + offsetValue[i], -// expected[i].data(), -// expected[i].size() * sizeof(glm::ivec3)); -// offsetValue[i + 1] = -// offsetValue[i] + expected[i].size() * sizeof(glm::ivec3); -// } -// -// addBufferToModel(model, values); -// size_t valueBufferIndex = model.buffers.size() - 1; -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// addBufferToModel(model, offsets); -// size_t offsetBufferIndex = model.buffers.size() - 1; -// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::VEC3; -// testClassProperty.componentType = ClassProperty::ComponentType::INT32; -// testClassProperty.array = true; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(expected.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// propertyTableProperty.arrayOffsets = -// static_cast(offsetBufferViewIndex); -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT64; -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::VEC3); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); -// REQUIRE(classProperty->array); -// REQUIRE(!classProperty->count); -// -// SECTION("Access the correct type") { -// PropertyTablePropertyView> property = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); -// for (size_t i = 0; i < expected.size(); ++i) { -// PropertyArrayView valueMember = -// property.get(static_cast(i)); -// REQUIRE(valueMember.size() == static_cast(expected[i].size())); -// for (size_t j = 0; j < expected[i].size(); ++j) { -// REQUIRE(expected[i][j] == valueMember[static_cast(j)]); -// } -// } -// } -// -// SECTION("Wrong offset type") { -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT8; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT16; -// arrayProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.arrayOffsetType = "NONSENSE"; -// arrayProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); -// -// propertyTableProperty.arrayOffsetType = ""; -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT64; -// arrayProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); -// } -// -// SECTION("Offset values are not sorted ascending") { -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT64; -// uint64_t* offset = reinterpret_cast( -// model.buffers[offsetBufferIndex].cesium.data.data()); -// offset[propertyTable.count] = 0; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); -// } -// -// SECTION("Offset value points outside of value buffer") { -// uint64_t* offset = reinterpret_cast( -// model.buffers[offsetBufferIndex].cesium.data.data()); -// offset[propertyTable.count] = -// static_cast(model.buffers[valueBufferIndex].byteLength + 4); -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); -// } -// -// SECTION("Count and offset buffer are both present") { -// testClassProperty.count = 3; -// PropertyTablePropertyView> property = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// property.status() == -// PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); -// } -//} -// -//TEST_CASE("Test fixed-length matN array") { -// Model model; -// // clang-format off -// std::vector values = { -// glm::i32mat2x2( -// 12, 34, -// -30, 20), -// glm::i32mat2x2( -// -2, -2, -// 0, 1), -// glm::i32mat2x2( -// 1, 2, -// 8, 5), -// glm::i32mat2x2( -// -100, 3, -// 84, 6), -// glm::i32mat2x2( -// 2, 12, -// -2, -2), -// glm::i32mat2x2( -// 40, 61, -// 7, -3), -// }; -// // clang-format on -// -// addBufferToModel(model, values); -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::MAT2; -// testClassProperty.componentType = ClassProperty::ComponentType::INT32; -// testClassProperty.array = true; -// testClassProperty.count = 2; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast( -// values.size() / static_cast(testClassProperty.count.value())); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = -// static_cast(model.bufferViews.size() - 1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::MAT2); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); -// REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 2); -// -// SECTION("Access the right type") { -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); -// -// for (int64_t i = 0; i < arrayProperty.size(); ++i) { -// PropertyArrayView member = arrayProperty.get(i); -// for (int64_t j = 0; j < member.size(); ++j) { -// REQUIRE(member[j] == values[static_cast(i * 2 + j)]); -// } -// } -// } -// -// SECTION("Wrong type") { -// PropertyTablePropertyView> int32ArrayInvalid = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// int32ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyTablePropertyView> ivec2ArrayInvalid = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// ivec2ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// } -// -// SECTION("Wrong component type") { -// PropertyTablePropertyView> -// u32mat2x2ArrayInvalid = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// u32mat2x2ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Not an array type") { -// PropertyTablePropertyView ivec3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// ivec3Invalid.status() == -// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Buffer size is not a multiple of type size") { -// model.bufferViews[valueBufferViewIndex].byteLength = 13; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeNotDivisibleByTypeSize); -// } -// -// SECTION("Negative component count") { -// testClassProperty.count = -1; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == PropertyTablePropertyViewStatus:: -// ErrorArrayCountAndOffsetBufferDontExist); -// } -// -// SECTION("Value buffer doesn't fit into property table count") { -// testClassProperty.count = 55; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// } -//} -// -//TEST_CASE("Test variable-length matN array") { -// Model model; -// // clang-format off -// std::vector data0{ -// glm::i32mat2x2( -// 3, -2, -// 1, 0), -// glm::i32mat2x2( -// 40, 3, -// 8, -9) -// }; -// std::vector data1{ -// glm::i32mat2x2( -// 1, 10, -// 7, 8), -// }; -// std::vector data2{ -// glm::i32mat2x2( -// 18, 0, -// 1, 17), -// glm::i32mat2x2( -// -4, -2, -// -9, 1), -// glm::i32mat2x2( -// 1, 8, -// -99, 3), -// }; -// // clang-format on -// -// std::vector> -// expected{data0, {}, data1, data2, {}}; -// -// size_t numOfElements = 0; -// for (const auto& expectedMember : expected) { -// numOfElements += expectedMember.size(); -// } -// -// std::vector values(numOfElements * sizeof(glm::i32mat2x2)); -// std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); -// uint64_t* offsetValue = reinterpret_cast(offsets.data()); -// for (size_t i = 0; i < expected.size(); ++i) { -// std::memcpy( -// values.data() + offsetValue[i], -// expected[i].data(), -// expected[i].size() * sizeof(glm::i32mat2x2)); -// offsetValue[i + 1] = -// offsetValue[i] + expected[i].size() * sizeof(glm::i32mat2x2); -// } -// -// addBufferToModel(model, values); -// size_t valueBufferIndex = model.buffers.size() - 1; -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// addBufferToModel(model, offsets); -// size_t offsetBufferIndex = model.buffers.size() - 1; -// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::MAT2; -// testClassProperty.componentType = ClassProperty::ComponentType::INT32; -// testClassProperty.array = true; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(expected.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// propertyTableProperty.arrayOffsets = -// static_cast(offsetBufferViewIndex); -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT64; -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::MAT2); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); -// REQUIRE(classProperty->array); -// REQUIRE(!classProperty->count); -// -// SECTION("Access the correct type") { -// PropertyTablePropertyView> property = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); -// for (size_t i = 0; i < expected.size(); ++i) { -// PropertyArrayView valueMember = -// property.get(static_cast(i)); -// REQUIRE(valueMember.size() == static_cast(expected[i].size())); -// for (size_t j = 0; j < expected[i].size(); ++j) { -// REQUIRE(expected[i][j] == valueMember[static_cast(j)]); -// } -// } -// } -// -// SECTION("Wrong offset type") { -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT8; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT16; -// arrayProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.arrayOffsetType = "NONSENSE"; -// arrayProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); -// -// propertyTableProperty.arrayOffsetType = ""; -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT64; -// arrayProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); -// } -// -// SECTION("Offset values are not sorted ascending") { -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT64; -// uint64_t* offset = reinterpret_cast( -// model.buffers[offsetBufferIndex].cesium.data.data()); -// offset[propertyTable.count] = 0; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); -// } -// -// SECTION("Offset value points outside of value buffer") { -// uint64_t* offset = reinterpret_cast( -// model.buffers[offsetBufferIndex].cesium.data.data()); -// offset[propertyTable.count] = -// static_cast(model.buffers[valueBufferIndex].byteLength + 4); -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); -// } -// -// SECTION("Count and offset buffer are both present") { -// testClassProperty.count = 3; -// PropertyTablePropertyView> property = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// property.status() == -// PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); -// } -//} -// -//TEST_CASE("Test fixed-length boolean array") { -// Model model; -// -// std::vector expected = { -// true, -// false, -// false, -// true, -// false, -// false, -// true, -// true, -// true, -// false, -// false, -// true}; -// std::vector values; -// size_t requiredBytesSize = static_cast( -// glm::ceil(static_cast(expected.size()) / 8.0)); -// values.resize(requiredBytesSize); -// for (size_t i = 0; i < expected.size(); ++i) { -// uint8_t expectedValue = expected[i]; -// size_t byteIndex = i / 8; -// size_t bitIndex = i % 8; -// values[byteIndex] = -// static_cast((expectedValue << bitIndex) | values[byteIndex]); -// } -// -// addBufferToModel(model, values); -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::BOOLEAN; -// testClassProperty.array = true; -// testClassProperty.count = 3; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast( -// expected.size() / static_cast(testClassProperty.count.value())); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = -// static_cast(model.bufferViews.size() - 1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); -// REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 3); -// -// SECTION("Access correct type") { -// PropertyTablePropertyView> boolArrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(boolArrayProperty.size() == propertyTable.count); -// REQUIRE(boolArrayProperty.size() > 0); -// for (int64_t i = 0; i < boolArrayProperty.size(); ++i) { -// PropertyArrayView valueMember = boolArrayProperty.get(i); -// for (int64_t j = 0; j < valueMember.size(); ++j) { -// REQUIRE(valueMember[j] == expected[static_cast(i * 3 + j)]); -// } -// } -// } -// -// SECTION("Wrong type") { -// PropertyTablePropertyView> uint8ArrayInvalid = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// uint8ArrayInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorTypeMismatch); -// } -// -// SECTION("View is not array type") { -// PropertyTablePropertyView boolInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// boolInvalid.status() == -// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Value buffer doesn't have enough required bytes") { -// testClassProperty.count = 11; -// PropertyTablePropertyView> boolArrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// boolArrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// } -// -// SECTION("Count is negative") { -// testClassProperty.count = -1; -// PropertyTablePropertyView> boolArrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// boolArrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorArrayCountAndOffsetBufferDontExist); -// } -//} -// -//TEST_CASE("Test variable-length boolean array") { -// Model model; -// -// std::vector> expected{ -// {true, false, true, true, false, true, true}, -// {}, -// {}, -// {}, -// {false, false, false, false}, -// {true, false, true}, -// {false}, -// {true, true, true, true, true, false, false}}; -// size_t numOfElements = 0; -// for (const auto& expectedMember : expected) { -// numOfElements += expectedMember.size(); -// } -// -// size_t requiredBytesSize = -// static_cast(glm::ceil(static_cast(numOfElements) / 8.0)); -// std::vector values(requiredBytesSize); -// std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); -// uint64_t* offsetValue = reinterpret_cast(offsets.data()); -// size_t indexSoFar = 0; -// for (size_t i = 0; i < expected.size(); ++i) { -// for (size_t j = 0; j < expected[i].size(); ++j) { -// uint8_t expectedValue = expected[i][j]; -// size_t byteIndex = indexSoFar / 8; -// size_t bitIndex = indexSoFar % 8; -// values[byteIndex] = static_cast( -// (expectedValue << bitIndex) | static_cast(values[byteIndex])); -// ++indexSoFar; -// } -// offsetValue[i + 1] = offsetValue[i] + expected[i].size(); -// } -// -// addBufferToModel(model, values); -// size_t valueBufferIndex = model.buffers.size() - 1; -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// addBufferToModel(model, offsets); -// size_t offsetBufferIndex = model.buffers.size() - 1; -// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::BOOLEAN; -// testClassProperty.array = true; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(expected.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// propertyTableProperty.arrayOffsets = -// static_cast(offsetBufferViewIndex); -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT64; -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); -// REQUIRE(classProperty->array); -// REQUIRE(!classProperty->count); -// -// SECTION("Access correct type") { -// PropertyTablePropertyView> boolArrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); -// for (size_t i = 0; i < expected.size(); ++i) { -// PropertyArrayView arrayMember = -// boolArrayProperty.get(static_cast(i)); -// REQUIRE(arrayMember.size() == static_cast(expected[i].size())); -// for (size_t j = 0; j < expected[i].size(); ++j) { -// REQUIRE(expected[i][j] == arrayMember[static_cast(j)]); -// } -// } -// } -// -// SECTION("Wrong offset type") { -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT8; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT16; -// arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.arrayOffsetType = "NONSENSE"; -// arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); -// -// propertyTableProperty.arrayOffsetType = ""; -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT64; -// arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); -// } -// -// SECTION("Offset values are not sorted ascending") { -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT64; -// uint64_t* offset = reinterpret_cast( -// model.buffers[offsetBufferIndex].cesium.data.data()); -// offset[propertyTable.count] = 0; -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); -// } -// -// SECTION("Offset value points outside of value buffer") { -// uint64_t* offset = reinterpret_cast( -// model.buffers[offsetBufferIndex].cesium.data.data()); -// offset[propertyTable.count] = static_cast( -// model.buffers[valueBufferIndex].byteLength * 8 + 20); -// PropertyTablePropertyView> arrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); -// } -// -// SECTION("Count and offset buffer both present") { -// testClassProperty.count = 3; -// PropertyTablePropertyView> boolArrayProperty = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// boolArrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); -// } -//} -// -//TEST_CASE("Test fixed-length arrays of strings") { -// Model model; -// -// std::vector expected{ -// "What's up", -// "Breaking news!!! Aliens no longer attacks the US first", -// "But they still abduct my cows! Those milk thiefs! 👽 🐮", -// "I'm not crazy. My mother had me tested 🤪", -// "I love you, meat bags! ❤️", -// "Book in the freezer"}; -// -// size_t totalBytes = 0; -// for (const std::string& expectedValue : expected) { -// totalBytes += expectedValue.size(); -// } -// -// std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); -// std::vector values(totalBytes); -// uint32_t* offsetValue = reinterpret_cast(offsets.data()); -// for (size_t i = 0; i < expected.size(); ++i) { -// const std::string& expectedValue = expected[i]; -// std::memcpy( -// values.data() + offsetValue[i], -// expectedValue.c_str(), -// expectedValue.size()); -// offsetValue[i + 1] = -// offsetValue[i] + static_cast(expectedValue.size()); -// } -// -// addBufferToModel(model, values); -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// addBufferToModel(model, offsets); -// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::STRING; -// testClassProperty.array = true; -// testClassProperty.count = 2; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast( -// expected.size() / static_cast(testClassProperty.count.value())); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT32; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// propertyTableProperty.stringOffsets = -// static_cast(offsetBufferViewIndex); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::STRING); -// REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 2); -// -// SECTION("Access correct type") { -// PropertyTablePropertyView> -// stringProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(stringProperty.size() == 3); -// -// PropertyArrayView v0 = stringProperty.get(0); -// REQUIRE(v0.size() == 2); -// REQUIRE(v0[0] == "What's up"); -// REQUIRE(v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); -// -// PropertyArrayView v1 = stringProperty.get(1); -// REQUIRE(v1.size() == 2); -// REQUIRE(v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); -// REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); -// -// PropertyArrayView v2 = stringProperty.get(2); -// REQUIRE(v2.size() == 2); -// REQUIRE(v2[0] == "I love you, meat bags! ❤️"); -// REQUIRE(v2[1] == "Book in the freezer"); -// } -// -// SECTION("Array type mismatch") { -// PropertyTablePropertyView stringProperty = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// stringProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Count is negative") { -// testClassProperty.count = -1; -// PropertyTablePropertyView> -// stringProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// stringProperty.status() == PropertyTablePropertyViewStatus:: -// ErrorArrayCountAndOffsetBufferDontExist); -// } -// -// SECTION("Offset type is unknown") { -// propertyTableProperty.stringOffsetType = "NONSENSE"; -// PropertyTablePropertyView> -// stringProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// stringProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); -// -// propertyTableProperty.stringOffsetType = ""; -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT32; -// stringProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// stringProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); -// } -// -// SECTION("String offsets don't exist") { -// propertyTableProperty.stringOffsets = -1; -// PropertyTablePropertyView> -// stringProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// stringProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetBufferView); -// } -//} -// -//TEST_CASE("Test variable-length arrays of strings") { -// Model model; -// -// std::vector> expected{ -// {"What's up"}, -// {"Breaking news!!! Aliens no longer attacks the US first", -// "But they still abduct my cows! Those milk thiefs! 👽 🐮"}, -// {"I'm not crazy. My mother had me tested 🤪", -// "I love you, meat bags! ❤️", -// "Book in the freezer"}}; -// -// size_t totalBytes = 0; -// size_t numOfElements = 0; -// for (const auto& expectedValues : expected) { -// for (const auto& value : expectedValues) { -// totalBytes += value.size(); -// } -// -// numOfElements += expectedValues.size(); -// } -// -// std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); -// std::vector stringOffsets((numOfElements + 1) * sizeof(uint32_t)); -// std::vector values(totalBytes); -// uint32_t* offsetValue = reinterpret_cast(offsets.data()); -// uint32_t* stringOffsetValue = -// reinterpret_cast(stringOffsets.data()); -// size_t strOffsetIdx = 0; -// for (size_t i = 0; i < expected.size(); ++i) { -// for (size_t j = 0; j < expected[i].size(); ++j) { -// const std::string& expectedValue = expected[i][j]; -// std::memcpy( -// values.data() + stringOffsetValue[strOffsetIdx], -// expectedValue.c_str(), -// expectedValue.size()); -// -// stringOffsetValue[strOffsetIdx + 1] = -// stringOffsetValue[strOffsetIdx] + -// static_cast(expectedValue.size()); -// ++strOffsetIdx; -// } -// -// offsetValue[i + 1] = -// offsetValue[i] + -// static_cast(expected[i].size() * sizeof(uint32_t)); -// } -// -// addBufferToModel(model, values); -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// addBufferToModel(model, offsets); -// size_t arrayOffsetBuffer = model.buffers.size() - 1; -// size_t arrayOffsetBufferView = model.bufferViews.size() - 1; -// -// addBufferToModel(model, stringOffsets); -// size_t stringOffsetBuffer = model.buffers.size() - 1; -// size_t stringOffsetBufferView = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::STRING; -// testClassProperty.array = true; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(expected.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT32; -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT32; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// propertyTableProperty.arrayOffsets = -// static_cast(arrayOffsetBufferView); -// propertyTableProperty.stringOffsets = -// static_cast(stringOffsetBufferView); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::STRING); -// REQUIRE(classProperty->array); -// REQUIRE(!classProperty->componentType); -// REQUIRE(!classProperty->count); -// -// SECTION("Access correct type") { -// PropertyTablePropertyView> -// stringProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); -// for (size_t i = 0; i < expected.size(); ++i) { -// PropertyArrayView stringArray = -// stringProperty.get(static_cast(i)); -// for (size_t j = 0; j < expected[i].size(); ++j) { -// REQUIRE(stringArray[static_cast(j)] == expected[i][j]); -// } -// } -// } -// -// SECTION("Wrong array offset type") { -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT8; -// PropertyTablePropertyView> -// arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT16; -// arrayProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.arrayOffsetType = "NONSENSE"; -// arrayProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); -// propertyTableProperty.arrayOffsetType = -// PropertyTableProperty::ArrayOffsetType::UINT32; -// } -// -// SECTION("Wrong string offset type") { -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT8; -// PropertyTablePropertyView> -// arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT16; -// arrayProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus:: -// ErrorBufferViewSizeDoesNotMatchPropertyTableCount); -// -// propertyTableProperty.stringOffsetType = "NONSENSE"; -// arrayProperty = view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT32; -// } -// -// SECTION("Array offset values are not sorted ascending") { -// uint32_t* offset = reinterpret_cast( -// model.buffers[arrayOffsetBuffer].cesium.data.data()); -// offset[0] = static_cast(1000); -// PropertyTablePropertyView> -// arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); -// offset[0] = 0; -// } -// -// SECTION("String offset values are not sorted ascending") { -// uint32_t* offset = reinterpret_cast( -// model.buffers[stringOffsetBuffer].cesium.data.data()); -// offset[0] = static_cast(1000); -// PropertyTablePropertyView> -// arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); -// offset[0] = 0; -// } -// -// SECTION("Array offset value points outside of value buffer") { -// uint32_t* offset = reinterpret_cast( -// model.buffers[arrayOffsetBuffer].cesium.data.data()); -// uint32_t previousValue = offset[propertyTable.count]; -// offset[propertyTable.count] = static_cast(100000); -// PropertyTablePropertyView> -// arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); -// offset[propertyTable.count] = previousValue; -// } -// -// SECTION("String offset value points outside of value buffer") { -// uint32_t* offset = reinterpret_cast( -// model.buffers[stringOffsetBuffer].cesium.data.data()); -// uint32_t previousValue = offset[6]; -// offset[6] = static_cast(100000); -// PropertyTablePropertyView> -// arrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); -// offset[6] = previousValue; -// } -// -// SECTION("Count and offset buffer both present") { -// testClassProperty.count = 3; -// PropertyTablePropertyView> -// boolArrayProperty = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// boolArrayProperty.status() == -// PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); -// } -//} -// -//TEST_CASE("Test callback on invalid property table view") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// metadata.schema.emplace(); -// -// // Property table has a nonexistent class. -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(5); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(-1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); -// REQUIRE(view.size() == 0); -// -// 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() == -// PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); -// REQUIRE(propertyValue.size() == 0); -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -//TEST_CASE("Test callback for invalid PropertyTableProperty") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["InvalidProperty"]; -// testClassProperty.type = ClassProperty::Type::SCALAR; -// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(5); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["InvalidProperty"]; -// propertyTableProperty.values = static_cast(-1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// 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() != PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() == 0); -// }; -// -// view.getPropertyView("InvalidProperty", testCallback); -// view.getPropertyView("NonexistentProperty", testCallback); -// -// REQUIRE(invokedCallbackCount == 2); -//} -// -//TEST_CASE("Test callback for scalar PropertyTableProperty") { -// Model model; -// std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; -// -// addBufferToModel(model, values); -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::SCALAR; -// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(values.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); -// REQUIRE(!classProperty->array); -// REQUIRE(classProperty->count == std::nullopt); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&values, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) mutable { -// invokedCallbackCount++; -// if constexpr (std::is_same_v< -// PropertyTablePropertyView, -// decltype(propertyValue)>) { -// REQUIRE( -// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() > 0); -// -// for (int64_t i = 0; i < propertyValue.size(); ++i) { -// REQUIRE( -// static_cast(propertyValue.get(i)) == -// values[static_cast(i)]); -// } -// } else { -// FAIL( -// "getPropertyView returned PropertyTablePropertyView of incorrect " -// "type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -//TEST_CASE("Test callback for vecN PropertyTableProperty") { -// Model model; -// std::vector values = { -// glm::ivec3(-12, 34, 30), -// glm::ivec3(11, 73, 0), -// glm::ivec3(-2, 6, 12), -// glm::ivec3(-4, 8, -13)}; -// -// addBufferToModel(model, values); -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::VEC3; -// testClassProperty.componentType = ClassProperty::ComponentType::INT32; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(values.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::VEC3); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); -// REQUIRE(classProperty->count == std::nullopt); -// REQUIRE(!classProperty->array); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&values, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) mutable { -// invokedCallbackCount++; -// REQUIRE( -// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() > 0); -// -// if constexpr (std::is_same_v< -// PropertyTablePropertyView, -// decltype(propertyValue)>) { -// for (int64_t i = 0; i < propertyValue.size(); ++i) { -// REQUIRE( -// static_cast(propertyValue.get(i)) == -// values[static_cast(i)]); -// } -// } else { -// FAIL( -// "getPropertyView returned PropertyTablePropertyView of incorrect " -// "type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -//TEST_CASE("Test callback for matN PropertyTableProperty") { -// Model model; -// // clang-format off -// std::vector values = { -// glm::u32mat2x2( -// 12, 34, -// 30, 1), -// glm::u32mat2x2( -// 11, 8, -// 73, 102), -// glm::u32mat2x2( -// 1, 0, -// 63, 2), -// glm::u32mat2x2( -// 4, 8, -// 3, 23)}; -// // clang-format on -// -// addBufferToModel(model, values); -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::MAT2; -// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(values.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::MAT2); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); -// REQUIRE(classProperty->count == std::nullopt); -// REQUIRE(!classProperty->array); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&values, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) mutable { -// REQUIRE( -// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() > 0); -// -// if constexpr (std::is_same_v< -// PropertyTablePropertyView, -// decltype(propertyValue)>) { -// for (int64_t i = 0; i < propertyValue.size(); ++i) { -// REQUIRE( -// static_cast(propertyValue.get(i)) == -// values[static_cast(i)]); -// } -// } else { -// FAIL( -// "getPropertyView returned PropertyTablePropertyView of incorrect " -// "type for TestClassProperty."); -// } -// invokedCallbackCount++; -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -//TEST_CASE("Test callback for boolean PropertyTableProperty") { -// Model model; -// -// int64_t instanceCount = 21; -// std::vector expected; -// std::vector values; -// values.resize(3); -// for (int64_t i = 0; i < instanceCount; ++i) { -// if (i % 2 == 0) { -// expected.emplace_back(true); -// } else { -// expected.emplace_back(false); -// } -// -// uint8_t expectedValue = expected.back(); -// int64_t byteIndex = i / 8; -// int64_t bitIndex = i % 8; -// values[static_cast(byteIndex)] = static_cast( -// (expectedValue << bitIndex) | values[static_cast(byteIndex)]); -// } -// -// addBufferToModel(model, values); -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::BOOLEAN; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(instanceCount); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = -// static_cast(model.bufferViews.size() - 1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); -// REQUIRE(classProperty->componentType == std::nullopt); -// REQUIRE(classProperty->count == std::nullopt); -// REQUIRE(!classProperty->array); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&expected, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) mutable { -// invokedCallbackCount++; -// -// REQUIRE( -// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() > 0); -// -// if constexpr (std::is_same_v< -// PropertyTablePropertyView, -// decltype(propertyValue)>) { -// for (int64_t i = 0; i < propertyValue.size(); ++i) { -// REQUIRE( -// static_cast(propertyValue.get(i)) == -// expected[static_cast(i)]); -// } -// } else { -// FAIL( -// "getPropertyView returned PropertyTablePropertyView of incorrect " -// "type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -//TEST_CASE("Test callback for string PropertyTableProperty") { -// Model model; -// -// std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; -// size_t totalBytes = 0; -// for (const std::string& expectedValue : expected) { -// totalBytes += expectedValue.size(); -// } -// -// std::vector stringOffsets( -// (expected.size() + 1) * sizeof(uint32_t)); -// std::vector values(totalBytes); -// uint32_t* offsetValue = reinterpret_cast(stringOffsets.data()); -// for (size_t i = 0; i < expected.size(); ++i) { -// const std::string& expectedValue = expected[i]; -// std::memcpy( -// values.data() + offsetValue[i], -// expectedValue.c_str(), -// expectedValue.size()); -// offsetValue[i + 1] = -// offsetValue[i] + static_cast(expectedValue.size()); -// } -// -// addBufferToModel(model, values); -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// addBufferToModel(model, stringOffsets); -// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::STRING; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast(expected.size()); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT32; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// propertyTableProperty.stringOffsets = -// static_cast(offsetBufferViewIndex); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::STRING); -// REQUIRE(classProperty->componentType == std::nullopt); -// REQUIRE(classProperty->count == std::nullopt); -// REQUIRE(!classProperty->array); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&expected, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) mutable { -// invokedCallbackCount++; -// REQUIRE( -// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() > 0); -// -// if constexpr (std::is_same_v< -// PropertyTablePropertyView, -// decltype(propertyValue)>) { -// for (int64_t i = 0; i < propertyValue.size(); ++i) { -// REQUIRE( -// static_cast(propertyValue.get(i)) == -// expected[static_cast(i)]); -// } -// } else { -// FAIL( -// "getPropertyView returned PropertyTablePropertyView of incorrect " -// "type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -//TEST_CASE("Test callback for scalar array PropertyTableProperty") { -// Model model; -// std::vector values = -// {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; -// -// addBufferToModel(model, values); -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::SCALAR; -// testClassProperty.componentType = ClassProperty::ComponentType::UINT32; -// testClassProperty.array = true; -// testClassProperty.count = 3; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast( -// values.size() / static_cast(testClassProperty.count.value())); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = -// static_cast(model.bufferViews.size() - 1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); -// REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 3); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&values, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) { -// invokedCallbackCount++; -// REQUIRE( -// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() > 0); -// -// if constexpr (std::is_same_v< -// PropertyTablePropertyView< -// PropertyArrayView>, -// decltype(propertyValue)>) { -// for (int64_t i = 0; i < propertyValue.size(); ++i) { -// PropertyArrayView member = propertyValue.get(i); -// for (int64_t j = 0; j < member.size(); ++j) { -// REQUIRE(member[j] == values[static_cast(i * 3 + j)]); -// } -// } -// } else { -// FAIL( -// "getPropertyView returned PropertyTablePropertyView of incorrect " -// "type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -//TEST_CASE("Test callback for vecN array PropertyTableProperty") { -// Model model; -// std::vector values = { -// glm::ivec3(12, 34, -30), -// glm::ivec3(-2, 0, 1), -// glm::ivec3(1, 2, 8), -// glm::ivec3(-100, 84, 6), -// glm::ivec3(2, -2, -2), -// glm::ivec3(40, 61, 3), -// }; -// -// addBufferToModel(model, values); -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::VEC3; -// testClassProperty.componentType = ClassProperty::ComponentType::INT32; -// testClassProperty.array = true; -// testClassProperty.count = 2; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast( -// values.size() / static_cast(testClassProperty.count.value())); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = -// static_cast(model.bufferViews.size() - 1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::VEC3); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); -// REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 2); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&values, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) { -// invokedCallbackCount++; -// REQUIRE( -// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() > 0); -// -// if constexpr (std::is_same_v< -// PropertyTablePropertyView< -// PropertyArrayView>, -// decltype(propertyValue)>) { -// for (int64_t i = 0; i < propertyValue.size(); ++i) { -// PropertyArrayView member = propertyValue.get(i); -// for (int64_t j = 0; j < member.size(); ++j) { -// REQUIRE(member[j] == values[static_cast(i * 2 + j)]); -// } -// } -// } else { -// FAIL( -// "getPropertyView returned PropertyTablePropertyView of incorrect " -// "type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -//TEST_CASE("Test callback for matN array PropertyTableProperty") { -// Model model; -// // clang-format off -// std::vector values = { -// glm::i32mat2x2( -// 12, 34, -// -30, 20), -// glm::i32mat2x2( -// -2, -2, -// 0, 1), -// glm::i32mat2x2( -// 1, 2, -// 8, 5), -// glm::i32mat2x2( -// -100, 3, -// 84, 6), -// glm::i32mat2x2( -// 2, 12, -// -2, -2), -// glm::i32mat2x2( -// 40, 61, -// 7, -3), -// }; -// // clang-format on -// -// addBufferToModel(model, values); -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::MAT2; -// testClassProperty.componentType = ClassProperty::ComponentType::INT32; -// testClassProperty.array = true; -// testClassProperty.count = 2; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast( -// values.size() / static_cast(testClassProperty.count.value())); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = -// static_cast(model.bufferViews.size() - 1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::MAT2); -// REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); -// REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 2); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&values, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) { -// invokedCallbackCount++; -// REQUIRE( -// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() > 0); -// -// if constexpr (std::is_same_v< -// PropertyTablePropertyView< -// PropertyArrayView>, -// decltype(propertyValue)>) { -// for (int64_t i = 0; i < propertyValue.size(); ++i) { -// PropertyArrayView member = propertyValue.get(i); -// for (int64_t j = 0; j < member.size(); ++j) { -// REQUIRE(member[j] == values[static_cast(i * 2 + j)]); -// } -// } -// } else { -// FAIL( -// "getPropertyView returned PropertyTablePropertyView of incorrect " -// "type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -//TEST_CASE("Test callback for boolean array PropertyTableProperty") { -// Model model; -// -// std::vector expected = { -// true, -// false, -// false, -// true, -// false, -// false, -// true, -// true, -// true, -// false, -// false, -// true}; -// std::vector values; -// size_t requiredBytesSize = static_cast( -// glm::ceil(static_cast(expected.size()) / 8.0)); -// values.resize(requiredBytesSize); -// for (size_t i = 0; i < expected.size(); ++i) { -// uint8_t expectedValue = expected[i]; -// size_t byteIndex = i / 8; -// size_t bitIndex = i % 8; -// values[byteIndex] = -// static_cast((expectedValue << bitIndex) | values[byteIndex]); -// } -// -// addBufferToModel(model, values); -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::BOOLEAN; -// testClassProperty.array = true; -// testClassProperty.count = 3; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast( -// expected.size() / static_cast(testClassProperty.count.value())); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.values = -// static_cast(model.bufferViews.size() - 1); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); -// REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 3); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&expected, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) { -// invokedCallbackCount++; -// REQUIRE( -// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() > 0); -// -// if constexpr (std::is_same_v< -// PropertyTablePropertyView>, -// decltype(propertyValue)>) { -// for (int64_t i = 0; i < propertyValue.size(); ++i) { -// PropertyArrayView member = propertyValue.get(i); -// for (int64_t j = 0; j < member.size(); ++j) { -// REQUIRE(member[j] == expected[static_cast(i * 3 + j)]); -// } -// } -// } else { -// FAIL( -// "getPropertyView returned PropertyTablePropertyView of incorrect " -// "type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -//TEST_CASE("Test callback for string array PropertyTableProperty") { -// Model model; -// -// std::vector expected{ -// "What's up", -// "Breaking news!!! Aliens no longer attacks the US first", -// "But they still abduct my cows! Those milk thiefs! 👽 🐮", -// "I'm not crazy. My mother had me tested 🤪", -// "I love you, meat bags! ❤️", -// "Book in the freezer"}; -// -// size_t totalBytes = 0; -// for (const std::string& expectedValue : expected) { -// totalBytes += expectedValue.size(); -// } -// -// std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); -// std::vector values(totalBytes); -// uint32_t* offsetValue = reinterpret_cast(offsets.data()); -// for (size_t i = 0; i < expected.size(); ++i) { -// const std::string& expectedValue = expected[i]; -// std::memcpy( -// values.data() + offsetValue[i], -// expectedValue.c_str(), -// expectedValue.size()); -// offsetValue[i + 1] = -// offsetValue[i] + static_cast(expectedValue.size()); -// } -// -// addBufferToModel(model, values); -// size_t valueBufferViewIndex = model.bufferViews.size() - 1; -// -// addBufferToModel(model, offsets); -// size_t offsetBufferViewIndex = model.bufferViews.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; -// testClassProperty.type = ClassProperty::Type::STRING; -// testClassProperty.array = true; -// testClassProperty.count = 2; -// -// PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); -// propertyTable.classProperty = "TestClass"; -// propertyTable.count = static_cast( -// expected.size() / static_cast(testClassProperty.count.value())); -// -// PropertyTableProperty& propertyTableProperty = -// propertyTable.properties["TestClassProperty"]; -// propertyTableProperty.stringOffsetType = -// PropertyTableProperty::StringOffsetType::UINT32; -// propertyTableProperty.values = static_cast(valueBufferViewIndex); -// propertyTableProperty.stringOffsets = -// static_cast(offsetBufferViewIndex); -// -// PropertyTableView view(model, propertyTable); -// REQUIRE(view.status() == PropertyTableViewStatus::Valid); -// REQUIRE(view.size() == propertyTable.count); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::STRING); -// REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 2); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) { -// invokedCallbackCount++; -// REQUIRE( -// propertyValue.status() == PropertyTablePropertyViewStatus::Valid); -// REQUIRE(propertyValue.size() == 3); -// -// if constexpr (std::is_same_v< -// PropertyTablePropertyView< -// PropertyArrayView>, -// decltype(propertyValue)>) { -// PropertyArrayView v0 = propertyValue.get(0); -// REQUIRE(v0.size() == 2); -// REQUIRE(v0[0] == "What's up"); -// REQUIRE( -// v0[1] == -// "Breaking news!!! Aliens no longer attacks the US first"); -// -// PropertyArrayView v1 = propertyValue.get(1); -// REQUIRE(v1.size() == 2); -// REQUIRE( -// v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); -// REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); -// -// PropertyArrayView v2 = propertyValue.get(2); -// REQUIRE(v2.size() == 2); -// REQUIRE(v2[0] == "I love you, meat bags! ❤️"); -// REQUIRE(v2[1] == "Book in the freezer"); -// } else { -// FAIL( -// "getPropertyView returned PropertyTablePropertyView of incorrect " -// "type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} +#include "CesiumGltf/PropertyTableView.h" + +#include + +#include + +using namespace CesiumGltf; + +template +void addBufferToModel(Model& model, const std::vector& values) { + Buffer& valueBuffer = model.buffers.emplace_back(); + valueBuffer.cesium.data.resize(values.size() * sizeof(T)); + valueBuffer.byteLength = static_cast(valueBuffer.cesium.data.size()); + std::memcpy( + valueBuffer.cesium.data.data(), + values.data(), + valueBuffer.cesium.data.size()); + + BufferView& valueBufferView = model.bufferViews.emplace_back(); + valueBufferView.buffer = static_cast(model.buffers.size() - 1); + valueBufferView.byteOffset = 0; + valueBufferView.byteLength = valueBuffer.byteLength; +} + +TEST_CASE("Test PropertyTableView on model without EXT_structural_metadata " + "extension") { + Model model; + + // Create an erroneously isolated property table. + PropertyTable propertyTable; + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(10); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(0); + + PropertyTableView view(model, propertyTable); + REQUIRE( + view.status() == PropertyTableViewStatus::ErrorMissingMetadataExtension); + REQUIRE(view.size() == 0); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test PropertyTableView on model without metadata schema") { + Model model; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(10); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(0); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::ErrorMissingSchema); + REQUIRE(view.size() == 0); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test property table with nonexistent class") { + Model model; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "I Don't Exist"; + propertyTable.count = static_cast(10); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(0); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); + REQUIRE(view.size() == 0); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test scalar PropertyTableProperty") { + Model model; + std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + PropertyTablePropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(uint32Property.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(uint32Property.size() > 0); + + for (int64_t i = 0; i < uint32Property.size(); ++i) { + REQUIRE(uint32Property.get(i) == values[static_cast(i)]); + } + } + + SECTION("Access wrong type") { + PropertyTablePropertyView uvec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uvec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView u32mat3x3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat3x3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView boolInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView stringInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyTablePropertyView uint8Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTablePropertyView int32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + int32Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTablePropertyView uint64Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint64Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + PropertyTablePropertyView> uint32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint32ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Wrong buffer index") { + model.bufferViews[valueBufferViewIndex].buffer = 2; + PropertyTablePropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); + } + + SECTION("Wrong buffer view index") { + propertyTableProperty.values = -1; + PropertyTablePropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[valueBufferIndex].cesium.data.resize(12); + PropertyTablePropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Property.status() == + PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Buffer view length isn't multiple of sizeof(T)") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + PropertyTablePropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Property.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Buffer view length doesn't match with propertyTableCount") { + model.bufferViews[valueBufferViewIndex].byteLength = 12; + PropertyTablePropertyView uint32Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Property.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test vecN PropertyTableProperty") { + Model model; + std::vector values = { + glm::ivec3(-12, 34, 30), + glm::ivec3(11, 73, 0), + glm::ivec3(-2, 6, 12), + glm::ivec3(-4, 8, -13)}; + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(ivec3Property.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(ivec3Property.size() > 0); + + for (int64_t i = 0; i < ivec3Property.size(); ++i) { + REQUIRE(ivec3Property.get(i) == values[static_cast(i)]); + } + } + + SECTION("Access wrong type") { + PropertyTablePropertyView int32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + int32Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView ivec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView i32mat3x3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i32mat3x3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView boolInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView stringInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyTablePropertyView u8vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTablePropertyView i16vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i16vec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTablePropertyView vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + vec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + PropertyTablePropertyView> ivec3ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + ivec3ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Wrong buffer index") { + model.bufferViews[valueBufferViewIndex].buffer = 2; + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); + } + + SECTION("Wrong buffer view index") { + propertyTableProperty.values = -1; + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[valueBufferIndex].cesium.data.resize(12); + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Buffer view length isn't multiple of sizeof(T)") { + model.bufferViews[valueBufferViewIndex].byteLength = 11; + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Buffer view length doesn't match with propertyTableCount") { + model.bufferViews[valueBufferViewIndex].byteLength = 12; + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test matN PropertyTableProperty") { + Model model; + // clang-format off + std::vector values = { + glm::u32mat2x2( + 12, 34, + 30, 1), + glm::u32mat2x2( + 11, 8, + 73, 102), + glm::u32mat2x2( + 1, 0, + 63, 2), + glm::u32mat2x2( + 4, 8, + 3, 23)}; + // clang-format on + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(u32mat2x2Property.size() > 0); + + for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { + REQUIRE(u32mat2x2Property.get(i) == values[static_cast(i)]); + } + } + + SECTION("Access wrong type") { + PropertyTablePropertyView uint32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView uvec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uvec2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView u32mat4x4Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat4x4Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView boolInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView stringInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyTablePropertyView u8mat2x2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8mat2x2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTablePropertyView i32mat2x2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i32mat2x2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTablePropertyView mat2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + mat2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + PropertyTablePropertyView> + u32mat2x2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + u32mat2x2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Wrong buffer index") { + model.bufferViews[valueBufferViewIndex].buffer = 2; + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); + } + + SECTION("Wrong buffer view index") { + propertyTableProperty.values = -1; + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[valueBufferIndex].cesium.data.resize(sizeof(glm::u32mat2x2)); + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Buffer view length isn't multiple of sizeof(T)") { + model.bufferViews[valueBufferViewIndex].byteLength = + sizeof(glm::u32mat2x2) * 4 - 1; + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Buffer view length doesn't match with propertyTableCount") { + model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::u32mat2x2); + + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test boolean PropertyTableProperty") { + Model model; + + int64_t instanceCount = 21; + std::vector expected; + std::vector values; + values.resize(3); + for (int64_t i = 0; i < instanceCount; ++i) { + if (i % 2 == 0) { + expected.emplace_back(true); + } else { + expected.emplace_back(false); + } + + uint8_t expectedValue = expected.back(); + int64_t byteIndex = i / 8; + int64_t bitIndex = i % 8; + values[static_cast(byteIndex)] = static_cast( + (expectedValue << bitIndex) | values[static_cast(byteIndex)]); + } + addBufferToModel(model, values); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(instanceCount); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->componentType == std::nullopt); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + PropertyTablePropertyView boolProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE(boolProperty.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(boolProperty.size() == instanceCount); + for (int64_t i = 0; i < boolProperty.size(); ++i) { + bool expectedValue = expected[static_cast(i)]; + REQUIRE(boolProperty.get(i) == expectedValue); + } + } + + SECTION("Buffer size doesn't match with propertyTableCount") { + propertyTable.count = 66; + PropertyTablePropertyView boolProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test string PropertyTableProperty") { + Model model; + + std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; + size_t totalBytes = 0; + for (const std::string& expectedValue : expected) { + totalBytes += expectedValue.size(); + } + + std::vector stringOffsets( + (expected.size() + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(stringOffsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + const std::string& expectedValue = expected[i]; + std::memcpy( + values.data() + offsetValue[i], + expectedValue.c_str(), + expectedValue.size()); + offsetValue[i + 1] = + offsetValue[i] + static_cast(expectedValue.size()); + } + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, stringOffsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.stringOffsets = + static_cast(offsetBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); + REQUIRE(classProperty->componentType == std::nullopt); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + PropertyTablePropertyView stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + REQUIRE(stringProperty.get(static_cast(i)) == expected[i]); + } + } + + SECTION("Wrong array type") { + PropertyTablePropertyView> + stringArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + stringArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Wrong offset type") { + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT8; + PropertyTablePropertyView stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT64; + stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.stringOffsetType = "NONSENSE"; + stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); + + propertyTableProperty.stringOffsetType = ""; + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::StringOffsetType::UINT32; + stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + uint32_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[2] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + PropertyTablePropertyView stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint32_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + PropertyTablePropertyView stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); + } +} + +TEST_CASE("Test fixed-length scalar array") { + Model model; + std::vector values = + {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.array = true; + testClassProperty.count = 3; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + + SECTION("Access the right type") { + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + + for (int64_t i = 0; i < arrayProperty.size(); ++i) { + PropertyArrayView member = arrayProperty.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 3 + j)]); + } + } + } + + SECTION("Wrong type") { + PropertyTablePropertyView> boolArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView> uvec2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + uvec2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Wrong component type") { + PropertyTablePropertyView> int32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + int32ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Not an array type") { + PropertyTablePropertyView uint32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Invalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Buffer size is not a multiple of type size") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Negative component count") { + testClassProperty.count = -1; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Value buffer doesn't fit into property table count") { + testClassProperty.count = 55; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test variable-length scalar array") { + Model model; + + std::vector> expected{ + {12, 33, 11, 344, 112, 444, 1}, + {}, + {}, + {122, 23, 333, 12}, + {}, + {333, 311, 22, 34}, + {}, + {33, 1888, 233, 33019}}; + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + std::vector values(numOfElements * sizeof(uint16_t)); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + std::memcpy( + values.data() + offsetValue[i], + expected[i].data(), + expected[i].size() * sizeof(uint16_t)); + offsetValue[i + 1] = offsetValue[i] + expected[i].size() * sizeof(uint16_t); + } + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + 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; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + 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); + + SECTION("Access the correct type") { + PropertyTablePropertyView> property = + view.getPropertyView>("TestClassProperty"); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + PropertyArrayView valueMember = + property.get(static_cast(i)); + REQUIRE(valueMember.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + REQUIRE(expected[i][j] == valueMember[static_cast(j)]); + } + } + } + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT8; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT16; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT64; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer are both present") { + testClassProperty.count = 3; + PropertyTablePropertyView> property = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test fixed-length vecN array") { + Model model; + std::vector values = { + glm::ivec3(12, 34, -30), + glm::ivec3(-2, 0, 1), + glm::ivec3(1, 2, 8), + glm::ivec3(-100, 84, 6), + glm::ivec3(2, -2, -2), + glm::ivec3(40, 61, 3), + }; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + SECTION("Access the right type") { + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + + for (int64_t i = 0; i < arrayProperty.size(); ++i) { + PropertyArrayView member = arrayProperty.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + } + } + } + + SECTION("Wrong type") { + PropertyTablePropertyView> int32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + int32ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView> ivec2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + ivec2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Wrong component type") { + PropertyTablePropertyView> uvec3ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + uvec3ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Not an array type") { + PropertyTablePropertyView ivec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Buffer size is not a multiple of type size") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Negative component count") { + testClassProperty.count = -1; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Value buffer doesn't fit into property table count") { + testClassProperty.count = 55; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test variable-length vecN array") { + Model model; + // clang-format off + std::vector> expected{ + { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1) }, + { glm::ivec3(1, 2, 8), }, + {}, + { glm::ivec3(-100, 84, 6), glm::ivec3(2, -2, -2), glm::ivec3(40, 61, 3) }, + { glm::ivec3(-1, 4, -7) }, + }; + // clang-format on + + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + std::vector values(numOfElements * sizeof(glm::ivec3)); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + std::memcpy( + values.data() + offsetValue[i], + expected[i].data(), + expected[i].size() * sizeof(glm::ivec3)); + offsetValue[i + 1] = + offsetValue[i] + expected[i].size() * sizeof(glm::ivec3); + } + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + + SECTION("Access the correct type") { + PropertyTablePropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + PropertyArrayView valueMember = + property.get(static_cast(i)); + REQUIRE(valueMember.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + REQUIRE(expected[i][j] == valueMember[static_cast(j)]); + } + } + } + + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT8; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT16; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT64; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer are both present") { + testClassProperty.count = 3; + PropertyTablePropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test fixed-length matN array") { + Model model; + // clang-format off + std::vector values = { + glm::i32mat2x2( + 12, 34, + -30, 20), + glm::i32mat2x2( + -2, -2, + 0, 1), + glm::i32mat2x2( + 1, 2, + 8, 5), + glm::i32mat2x2( + -100, 3, + 84, 6), + glm::i32mat2x2( + 2, 12, + -2, -2), + glm::i32mat2x2( + 40, 61, + 7, -3), + }; + // clang-format on + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + SECTION("Access the right type") { + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + + for (int64_t i = 0; i < arrayProperty.size(); ++i) { + PropertyArrayView member = arrayProperty.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + } + } + } + + SECTION("Wrong type") { + PropertyTablePropertyView> int32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + int32ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView> ivec2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + ivec2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Wrong component type") { + PropertyTablePropertyView> + u32mat2x2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + u32mat2x2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Not an array type") { + PropertyTablePropertyView ivec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Buffer size is not a multiple of type size") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Negative component count") { + testClassProperty.count = -1; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Value buffer doesn't fit into property table count") { + testClassProperty.count = 55; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test variable-length matN array") { + Model model; + // clang-format off + std::vector data0{ + glm::i32mat2x2( + 3, -2, + 1, 0), + glm::i32mat2x2( + 40, 3, + 8, -9) + }; + std::vector data1{ + glm::i32mat2x2( + 1, 10, + 7, 8), + }; + std::vector data2{ + glm::i32mat2x2( + 18, 0, + 1, 17), + glm::i32mat2x2( + -4, -2, + -9, 1), + glm::i32mat2x2( + 1, 8, + -99, 3), + }; + // clang-format on + + std::vector> + expected{data0, {}, data1, data2, {}}; + + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + std::vector values(numOfElements * sizeof(glm::i32mat2x2)); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + std::memcpy( + values.data() + offsetValue[i], + expected[i].data(), + expected[i].size() * sizeof(glm::i32mat2x2)); + offsetValue[i + 1] = + offsetValue[i] + expected[i].size() * sizeof(glm::i32mat2x2); + } + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + + SECTION("Access the correct type") { + PropertyTablePropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + PropertyArrayView valueMember = + property.get(static_cast(i)); + REQUIRE(valueMember.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + REQUIRE(expected[i][j] == valueMember[static_cast(j)]); + } + } + } + + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT8; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT16; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT64; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer are both present") { + testClassProperty.count = 3; + PropertyTablePropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test fixed-length boolean array") { + Model model; + + std::vector expected = { + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true}; + std::vector values; + size_t requiredBytesSize = static_cast( + glm::ceil(static_cast(expected.size()) / 8.0)); + values.resize(requiredBytesSize); + for (size_t i = 0; i < expected.size(); ++i) { + uint8_t expectedValue = expected[i]; + size_t byteIndex = i / 8; + size_t bitIndex = i % 8; + values[byteIndex] = + static_cast((expectedValue << bitIndex) | values[byteIndex]); + } + + addBufferToModel(model, values); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; + testClassProperty.array = true; + testClassProperty.count = 3; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + expected.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + + SECTION("Access correct type") { + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(boolArrayProperty.size() == propertyTable.count); + REQUIRE(boolArrayProperty.size() > 0); + for (int64_t i = 0; i < boolArrayProperty.size(); ++i) { + PropertyArrayView valueMember = boolArrayProperty.get(i); + for (int64_t j = 0; j < valueMember.size(); ++j) { + REQUIRE(valueMember[j] == expected[static_cast(i * 3 + j)]); + } + } + } + + SECTION("Wrong type") { + PropertyTablePropertyView> uint8ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("View is not array type") { + PropertyTablePropertyView boolInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolInvalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Value buffer doesn't have enough required bytes") { + testClassProperty.count = 11; + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } + + SECTION("Count is negative") { + testClassProperty.count = -1; + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } +} + +TEST_CASE("Test variable-length boolean array") { + Model model; + + std::vector> expected{ + {true, false, true, true, false, true, true}, + {}, + {}, + {}, + {false, false, false, false}, + {true, false, true}, + {false}, + {true, true, true, true, true, false, false}}; + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + size_t requiredBytesSize = + static_cast(glm::ceil(static_cast(numOfElements) / 8.0)); + std::vector values(requiredBytesSize); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + size_t indexSoFar = 0; + for (size_t i = 0; i < expected.size(); ++i) { + for (size_t j = 0; j < expected[i].size(); ++j) { + uint8_t expectedValue = expected[i][j]; + size_t byteIndex = indexSoFar / 8; + size_t bitIndex = indexSoFar % 8; + values[byteIndex] = static_cast( + (expectedValue << bitIndex) | static_cast(values[byteIndex])); + ++indexSoFar; + } + offsetValue[i + 1] = offsetValue[i] + expected[i].size(); + } + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; + testClassProperty.array = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + + SECTION("Access correct type") { + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + PropertyArrayView arrayMember = + boolArrayProperty.get(static_cast(i)); + REQUIRE(arrayMember.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + REQUIRE(expected[i][j] == arrayMember[static_cast(j)]); + } + } + } + + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT8; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT16; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT64; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = static_cast( + model.buffers[valueBufferIndex].byteLength * 8 + 20); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer both present") { + testClassProperty.count = 3; + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test fixed-length arrays of strings") { + Model model; + + std::vector expected{ + "What's up", + "Breaking news!!! Aliens no longer attacks the US first", + "But they still abduct my cows! Those milk thiefs! 👽 🐮", + "I'm not crazy. My mother had me tested 🤪", + "I love you, meat bags! ❤️", + "Book in the freezer"}; + + size_t totalBytes = 0; + for (const std::string& expectedValue : expected) { + totalBytes += expectedValue.size(); + } + + std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + const std::string& expectedValue = expected[i]; + std::memcpy( + values.data() + offsetValue[i], + expectedValue.c_str(), + expectedValue.size()); + offsetValue[i + 1] = + offsetValue[i] + static_cast(expectedValue.size()); + } + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; + testClassProperty.array = true; + testClassProperty.count = 2; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + expected.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.stringOffsets = + static_cast(offsetBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + SECTION("Access correct type") { + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(stringProperty.size() == 3); + + PropertyArrayView v0 = stringProperty.get(0); + REQUIRE(v0.size() == 2); + REQUIRE(v0[0] == "What's up"); + REQUIRE(v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); + + PropertyArrayView v1 = stringProperty.get(1); + REQUIRE(v1.size() == 2); + REQUIRE(v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); + REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); + + PropertyArrayView v2 = stringProperty.get(2); + REQUIRE(v2.size() == 2); + REQUIRE(v2[0] == "I love you, meat bags! ❤️"); + REQUIRE(v2[1] == "Book in the freezer"); + } + + SECTION("Array type mismatch") { + PropertyTablePropertyView stringProperty = + view.getPropertyView("TestClassProperty"); + REQUIRE( + stringProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Count is negative") { + testClassProperty.count = -1; + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + stringProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Offset type is unknown") { + propertyTableProperty.stringOffsetType = "NONSENSE"; + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + stringProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); + + propertyTableProperty.stringOffsetType = ""; + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT32; + stringProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + stringProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); + } + + SECTION("String offsets don't exist") { + propertyTableProperty.stringOffsets = -1; + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + stringProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetBufferView); + } +} + +TEST_CASE("Test variable-length arrays of strings") { + Model model; + + std::vector> expected{ + {"What's up"}, + {"Breaking news!!! Aliens no longer attacks the US first", + "But they still abduct my cows! Those milk thiefs! 👽 🐮"}, + {"I'm not crazy. My mother had me tested 🤪", + "I love you, meat bags! ❤️", + "Book in the freezer"}}; + + size_t totalBytes = 0; + size_t numOfElements = 0; + for (const auto& expectedValues : expected) { + for (const auto& value : expectedValues) { + totalBytes += value.size(); + } + + numOfElements += expectedValues.size(); + } + + std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); + std::vector stringOffsets((numOfElements + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(offsets.data()); + uint32_t* stringOffsetValue = + reinterpret_cast(stringOffsets.data()); + size_t strOffsetIdx = 0; + for (size_t i = 0; i < expected.size(); ++i) { + for (size_t j = 0; j < expected[i].size(); ++j) { + const std::string& expectedValue = expected[i][j]; + std::memcpy( + values.data() + stringOffsetValue[strOffsetIdx], + expectedValue.c_str(), + expectedValue.size()); + + stringOffsetValue[strOffsetIdx + 1] = + stringOffsetValue[strOffsetIdx] + + static_cast(expectedValue.size()); + ++strOffsetIdx; + } + + offsetValue[i + 1] = + offsetValue[i] + + static_cast(expected[i].size() * sizeof(uint32_t)); + } + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t arrayOffsetBuffer = model.buffers.size() - 1; + size_t arrayOffsetBufferView = model.bufferViews.size() - 1; + + addBufferToModel(model, stringOffsets); + size_t stringOffsetBuffer = model.buffers.size() - 1; + size_t stringOffsetBufferView = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; + testClassProperty.array = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT32; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(arrayOffsetBufferView); + propertyTableProperty.stringOffsets = + static_cast(stringOffsetBufferView); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->componentType); + REQUIRE(!classProperty->count); + + SECTION("Access correct type") { + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + PropertyArrayView stringArray = + stringProperty.get(static_cast(i)); + for (size_t j = 0; j < expected[i].size(); ++j) { + REQUIRE(stringArray[static_cast(j)] == expected[i][j]); + } + } + } + + SECTION("Wrong array offset type") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT8; + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT16; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT32; + } + + SECTION("Wrong string offset type") { + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT8; + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT16; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.stringOffsetType = "NONSENSE"; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT32; + } + + SECTION("Array offset values are not sorted ascending") { + uint32_t* offset = reinterpret_cast( + model.buffers[arrayOffsetBuffer].cesium.data.data()); + offset[0] = static_cast(1000); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); + offset[0] = 0; + } + + SECTION("String offset values are not sorted ascending") { + uint32_t* offset = reinterpret_cast( + model.buffers[stringOffsetBuffer].cesium.data.data()); + offset[0] = static_cast(1000); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); + offset[0] = 0; + } + + SECTION("Array offset value points outside of value buffer") { + uint32_t* offset = reinterpret_cast( + model.buffers[arrayOffsetBuffer].cesium.data.data()); + uint32_t previousValue = offset[propertyTable.count]; + offset[propertyTable.count] = static_cast(100000); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); + offset[propertyTable.count] = previousValue; + } + + SECTION("String offset value points outside of value buffer") { + uint32_t* offset = reinterpret_cast( + model.buffers[stringOffsetBuffer].cesium.data.data()); + uint32_t previousValue = offset[6]; + offset[6] = static_cast(100000); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); + offset[6] = previousValue; + } + + SECTION("Count and offset buffer both present") { + testClassProperty.count = 3; + PropertyTablePropertyView> + boolArrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test callback on invalid property table view") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + metadata.schema.emplace(); + + // Property table has a nonexistent class. + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(5); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(-1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::ErrorClassNotFound); + REQUIRE(view.size() == 0); + + 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() == + PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); + REQUIRE(propertyValue.size() == 0); + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for invalid PropertyTableProperty") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["InvalidProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(5); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["InvalidProperty"]; + propertyTableProperty.values = static_cast(-1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + 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() != PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() == 0); + }; + + view.getPropertyView("InvalidProperty", testCallback); + view.getPropertyView("NonexistentProperty", testCallback); + + REQUIRE(invokedCallbackCount == 2); +} + +TEST_CASE("Test callback for scalar PropertyTableProperty") { + Model model; + std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->count == std::nullopt); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + if constexpr (std::is_same_v< + PropertyTablePropertyView, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + for (int64_t i = 0; i < propertyValue.size(); ++i) { + REQUIRE( + static_cast(propertyValue.get(i)) == + values[static_cast(i)]); + } + } else { + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for vecN PropertyTableProperty") { + Model model; + std::vector values = { + glm::ivec3(-12, 34, 30), + glm::ivec3(11, 73, 0), + glm::ivec3(-2, 6, 12), + glm::ivec3(-4, 8, -13)}; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + PropertyTablePropertyView, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + REQUIRE( + static_cast(propertyValue.get(i)) == + values[static_cast(i)]); + } + } else { + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for matN PropertyTableProperty") { + Model model; + // clang-format off + std::vector values = { + glm::u32mat2x2( + 12, 34, + 30, 1), + glm::u32mat2x2( + 11, 8, + 73, 102), + glm::u32mat2x2( + 1, 0, + 63, 2), + glm::u32mat2x2( + 4, 8, + 3, 23)}; + // clang-format on + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + PropertyTablePropertyView, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + REQUIRE( + static_cast(propertyValue.get(i)) == + values[static_cast(i)]); + } + } else { + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); + } + invokedCallbackCount++; + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for boolean PropertyTableProperty") { + Model model; + + int64_t instanceCount = 21; + std::vector expected; + std::vector values; + values.resize(3); + for (int64_t i = 0; i < instanceCount; ++i) { + if (i % 2 == 0) { + expected.emplace_back(true); + } else { + expected.emplace_back(false); + } + + uint8_t expectedValue = expected.back(); + int64_t byteIndex = i / 8; + int64_t bitIndex = i % 8; + values[static_cast(byteIndex)] = static_cast( + (expectedValue << bitIndex) | values[static_cast(byteIndex)]); + } + + addBufferToModel(model, values); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(instanceCount); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->componentType == std::nullopt); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&expected, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + PropertyTablePropertyView, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + REQUIRE( + static_cast(propertyValue.get(i)) == + expected[static_cast(i)]); + } + } else { + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for string PropertyTableProperty") { + Model model; + + std::vector expected{"What's up", "Test_0", "Test_1", "", "Hi"}; + size_t totalBytes = 0; + for (const std::string& expectedValue : expected) { + totalBytes += expectedValue.size(); + } + + std::vector stringOffsets( + (expected.size() + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(stringOffsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + const std::string& expectedValue = expected[i]; + std::memcpy( + values.data() + offsetValue[i], + expectedValue.c_str(), + expectedValue.size()); + offsetValue[i + 1] = + offsetValue[i] + static_cast(expectedValue.size()); + } + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, stringOffsets); + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.stringOffsets = + static_cast(offsetBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); + REQUIRE(classProperty->componentType == std::nullopt); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&expected, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + PropertyTablePropertyView, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + REQUIRE( + static_cast(propertyValue.get(i)) == + expected[static_cast(i)]); + } + } else { + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for scalar array PropertyTableProperty") { + Model model; + std::vector values = + {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; + + addBufferToModel(model, values); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.array = true; + testClassProperty.count = 3; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + PropertyTablePropertyView< + PropertyArrayView>, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + PropertyArrayView member = propertyValue.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 3 + j)]); + } + } + } else { + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for vecN array PropertyTableProperty") { + Model model; + std::vector values = { + glm::ivec3(12, 34, -30), + glm::ivec3(-2, 0, 1), + glm::ivec3(1, 2, 8), + glm::ivec3(-100, 84, 6), + glm::ivec3(2, -2, -2), + glm::ivec3(40, 61, 3), + }; + + addBufferToModel(model, values); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + PropertyTablePropertyView< + PropertyArrayView>, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + PropertyArrayView member = propertyValue.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + } + } + } else { + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for matN array PropertyTableProperty") { + Model model; + // clang-format off + std::vector values = { + glm::i32mat2x2( + 12, 34, + -30, 20), + glm::i32mat2x2( + -2, -2, + 0, 1), + glm::i32mat2x2( + 1, 2, + 8, 5), + glm::i32mat2x2( + -100, 3, + 84, 6), + glm::i32mat2x2( + 2, 12, + -2, -2), + glm::i32mat2x2( + 40, 61, + 7, -3), + }; + // clang-format on + + addBufferToModel(model, values); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + PropertyTablePropertyView< + PropertyArrayView>, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + PropertyArrayView member = propertyValue.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + } + } + } else { + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for boolean array PropertyTableProperty") { + Model model; + + std::vector expected = { + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true}; + std::vector values; + size_t requiredBytesSize = static_cast( + glm::ceil(static_cast(expected.size()) / 8.0)); + values.resize(requiredBytesSize); + for (size_t i = 0; i < expected.size(); ++i) { + uint8_t expectedValue = expected[i]; + size_t byteIndex = i / 8; + size_t bitIndex = i % 8; + values[byteIndex] = + static_cast((expectedValue << bitIndex) | values[byteIndex]); + } + + addBufferToModel(model, values); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; + testClassProperty.array = true; + testClassProperty.count = 3; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + expected.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&expected, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + PropertyTablePropertyView>, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + PropertyArrayView member = propertyValue.get(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == expected[static_cast(i * 3 + j)]); + } + } + } else { + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for string array PropertyTableProperty") { + Model model; + + std::vector expected{ + "What's up", + "Breaking news!!! Aliens no longer attacks the US first", + "But they still abduct my cows! Those milk thiefs! 👽 🐮", + "I'm not crazy. My mother had me tested 🤪", + "I love you, meat bags! ❤️", + "Book in the freezer"}; + + size_t totalBytes = 0; + for (const std::string& expectedValue : expected) { + totalBytes += expectedValue.size(); + } + + std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + const std::string& expectedValue = expected[i]; + std::memcpy( + values.data() + offsetValue[i], + expectedValue.c_str(), + expectedValue.size()); + offsetValue[i + 1] = + offsetValue[i] + static_cast(expectedValue.size()); + } + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; + testClassProperty.array = true; + testClassProperty.count = 2; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + expected.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.stringOffsets = + static_cast(offsetBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() == 3); + + if constexpr (std::is_same_v< + PropertyTablePropertyView< + PropertyArrayView>, + decltype(propertyValue)>) { + PropertyArrayView v0 = propertyValue.get(0); + REQUIRE(v0.size() == 2); + REQUIRE(v0[0] == "What's up"); + REQUIRE( + v0[1] == + "Breaking news!!! Aliens no longer attacks the US first"); + + PropertyArrayView v1 = propertyValue.get(1); + REQUIRE(v1.size() == 2); + REQUIRE( + v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); + REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); + + PropertyArrayView v2 = propertyValue.get(2); + REQUIRE(v2.size() == 2); + REQUIRE(v2[0] == "I love you, meat bags! ❤️"); + REQUIRE(v2[1] == "Book in the freezer"); + } else { + FAIL( + "getPropertyView returned PropertyTablePropertyView of incorrect " + "type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp index ee3bf466b..27106da09 100644 --- a/CesiumGltf/test/TestPropertyView.cpp +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -23,11 +23,11 @@ TEST_CASE("Boolean PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.normalized = true; - classProperty.offset = JsonValue(true); - classProperty.scale = JsonValue(true); - classProperty.max = JsonValue(true); - classProperty.min = JsonValue(true); - classProperty.noData = JsonValue(true); + classProperty.offset = true; + classProperty.scale = true; + classProperty.max = true; + classProperty.min = true; + classProperty.noData = true; PropertyView view(classProperty); REQUIRE(!view.normalized()); @@ -38,7 +38,7 @@ TEST_CASE("Boolean PropertyView") { REQUIRE(!view.noData()); } - SECTION("Ignores count (array is false)") { + SECTION("Ignores count") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.count = 5; @@ -51,7 +51,7 @@ TEST_CASE("Boolean PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.required = false; - classProperty.defaultProperty = JsonValue(false); + classProperty.defaultProperty = false; PropertyView view(classProperty); REQUIRE(!view.required()); @@ -63,7 +63,7 @@ TEST_CASE("Boolean PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.required = true; - classProperty.defaultProperty = JsonValue(false); + classProperty.defaultProperty = false; PropertyView view(classProperty); REQUIRE(view.required()); @@ -73,7 +73,7 @@ TEST_CASE("Boolean PropertyView") { SECTION("Returns nullopt for invalid types") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; - classProperty.defaultProperty = JsonValue(1); + classProperty.defaultProperty = 1; PropertyView view(classProperty); REQUIRE(!view.required()); @@ -102,7 +102,7 @@ TEST_CASE("Scalar PropertyView") { REQUIRE(!view.defaultValue()); } - SECTION("Ignores count (array is false)") { + SECTION("Ignores count") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; @@ -116,10 +116,10 @@ TEST_CASE("Scalar PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::INT16; - classProperty.offset = JsonValue(5); - classProperty.scale = JsonValue(2); - classProperty.max = JsonValue(10); - classProperty.min = JsonValue(-10); + classProperty.offset = 5; + classProperty.scale = 2; + classProperty.max = 10; + classProperty.min = -10; PropertyView view(classProperty); REQUIRE(view.offset()); @@ -133,49 +133,34 @@ TEST_CASE("Scalar PropertyView") { REQUIRE(*view.min() == -10); } - SECTION("Returns nullopt for out-of-bounds offset, scale, max, and min") { + SECTION("Returns nullopt for out-of-bounds values") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.offset = JsonValue(129); - classProperty.scale = JsonValue(255); - classProperty.max = JsonValue(1000); - classProperty.min = JsonValue(-1000); + classProperty.offset = 20; + classProperty.scale = 255; + classProperty.max = 127; + classProperty.min = -1000; PropertyView view(classProperty); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - } + REQUIRE(view.offset()); + REQUIRE(view.max()); - SECTION("Rounds numbers where possible") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.offset = JsonValue(-5.5); - classProperty.scale = JsonValue(2.4); - classProperty.max = JsonValue(150); - classProperty.min = JsonValue(-150); + REQUIRE(*view.offset() == 20); + REQUIRE(*view.max() == 127); - PropertyView view(classProperty); - REQUIRE(view.offset()); - REQUIRE(view.scale()); - REQUIRE(!view.max()); + REQUIRE(!view.scale()); REQUIRE(!view.min()); - - REQUIRE(*view.offset() == -5); - REQUIRE(*view.scale() == 2); } SECTION("Returns nullopt for invalid types") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.offset = JsonValue("10"); - classProperty.scale = JsonValue(false); - classProperty.max = JsonValue(JsonValue::Array()); - classProperty.min = JsonValue(JsonValue::Array{10}); + classProperty.offset = "10"; + classProperty.scale = false; + classProperty.max = 5.5; + classProperty.min = JsonValue::Array{1}; PropertyView view(classProperty); REQUIRE(!view.offset()); @@ -189,8 +174,8 @@ TEST_CASE("Scalar PropertyView") { classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.required = false; - classProperty.noData = JsonValue(0); - classProperty.defaultProperty = JsonValue(1); + classProperty.noData = 0; + classProperty.defaultProperty = 1; PropertyView view(classProperty); REQUIRE(!view.required()); @@ -206,8 +191,8 @@ TEST_CASE("Scalar PropertyView") { classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.required = true; - classProperty.noData = JsonValue(0); - classProperty.defaultProperty = JsonValue(1); + classProperty.noData = 0; + classProperty.defaultProperty = 1; PropertyView view(classProperty); REQUIRE(view.required()); @@ -216,15 +201,135 @@ TEST_CASE("Scalar PropertyView") { } } +TEST_CASE("VecN PropertyView") { + SECTION("Constructs with non-optional properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.normalized = true; + classProperty.required = true; + + PropertyView view(classProperty); + REQUIRE(view.normalized()); + REQUIRE(view.required()); + + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Ignores count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.count = 5; + + PropertyView view(classProperty); + REQUIRE(view.arrayCount() == 0); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.offset = JsonValue::Array{-1, 1, 2}; + classProperty.scale = JsonValue::Array{2, 1, 3}; + classProperty.max = JsonValue::Array{10, 5, 6}; + classProperty.min = JsonValue::Array{-11, -12, -13}; + + PropertyView view(classProperty); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); + + REQUIRE(*view.offset() == glm::i16vec3(-1, 1, 2)); + REQUIRE(*view.scale() == glm::i16vec3(2, 1, 3)); + REQUIRE(*view.max() == glm::i16vec3(10, 5, 6)); + REQUIRE(*view.min() == glm::i16vec3(-11, -12, -13)); + } + + SECTION("Returns nullopt for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.offset = JsonValue::Array{-1, 2}; + classProperty.scale = JsonValue::Array{1, 128}; + classProperty.max = JsonValue::Array{10, 5}; + classProperty.min = JsonValue::Array{-200, 0}; + + PropertyView view(classProperty); + REQUIRE(view.offset()); + REQUIRE(view.max()); + + REQUIRE(*view.offset() == glm::i8vec2(-1, 2)); + REQUIRE(*view.max() == glm::i8vec2(10, 5)); + + REQUIRE(!view.scale()); + REQUIRE(!view.min()); + } + + SECTION("Returns nullopt for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.offset = "(1, 2, 3)"; + classProperty.scale = 1; + classProperty.max = JsonValue::Array{10, 20, 30, 40}; + classProperty.min = JsonValue::Array{-10, -1}; + + PropertyView view(classProperty); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC4; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.required = false; + classProperty.noData = JsonValue::Array{0.0f, 0.0f, 0.0f, 0.0f}; + classProperty.defaultProperty = JsonValue::Array{1.0f, 2.0f, 3.0f, 4.0f}; + + PropertyView view(classProperty); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + REQUIRE(*view.noData() == glm::vec4(0.0f)); + REQUIRE(*view.defaultValue() == glm::vec4(1.0f, 2.0f, 3.0f, 4.0f)); + } + + SECTION("Ignores noData and defaultProperty when required is true") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC4; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.required = true; + classProperty.noData = JsonValue::Array{0.0f, 0.0f, 0.0f, 0.0f}; + classProperty.defaultProperty = JsonValue::Array{1.0f, 2.0f, 3.0f, 4.0f}; + + PropertyView view(classProperty); + REQUIRE(view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } +} + TEST_CASE("String PropertyView") { SECTION("Ignores non-applicable properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; classProperty.normalized = true; - classProperty.offset = JsonValue("test"); - classProperty.scale = JsonValue("test"); - classProperty.max = JsonValue("test"); - classProperty.min = JsonValue("test"); + classProperty.offset = "offset"; + classProperty.scale = "scale"; + classProperty.max = "max"; + classProperty.min = "min"; PropertyView view(classProperty); REQUIRE(!view.normalized()); @@ -234,7 +339,7 @@ TEST_CASE("String PropertyView") { REQUIRE(!view.min()); } - SECTION("Ignores count (array is false)") { + SECTION("Ignores count") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; classProperty.count = 5; @@ -247,8 +352,8 @@ TEST_CASE("String PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; classProperty.required = false; - classProperty.noData = JsonValue("null"); - classProperty.defaultProperty = JsonValue("default"); + classProperty.noData = "null"; + classProperty.defaultProperty = "default"; PropertyView view(classProperty); REQUIRE(!view.required()); @@ -263,8 +368,8 @@ TEST_CASE("String PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; classProperty.required = true; - classProperty.noData = JsonValue("null"); - classProperty.defaultProperty = JsonValue("default"); + classProperty.noData = "null"; + classProperty.defaultProperty = "default"; PropertyView view(classProperty); REQUIRE(view.required()); @@ -275,8 +380,8 @@ TEST_CASE("String PropertyView") { SECTION("Returns nullopt for invalid types") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; - classProperty.noData = JsonValue::Array{JsonValue("null")}; - classProperty.defaultProperty = JsonValue(true); + classProperty.noData = JsonValue::Array{"null"}; + classProperty.defaultProperty = true; PropertyView view(classProperty); REQUIRE(!view.required()); @@ -290,11 +395,11 @@ TEST_CASE("Boolean Array PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.normalized = true; - classProperty.offset = JsonValue::Array{JsonValue(true)}; - classProperty.scale = JsonValue::Array{JsonValue(true)}; - classProperty.max = JsonValue::Array{JsonValue(true)}; - classProperty.min = JsonValue::Array{JsonValue(true)}; - classProperty.noData = JsonValue::Array{JsonValue(true)}; + classProperty.offset = JsonValue::Array{true}; + classProperty.scale = JsonValue::Array{true}; + classProperty.max = JsonValue::Array{true}; + classProperty.min = JsonValue::Array{true}; + classProperty.noData = JsonValue::Array{true}; PropertyView> view(classProperty); REQUIRE(!view.normalized()); @@ -320,8 +425,7 @@ TEST_CASE("Boolean Array PropertyView") { classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.array = true; classProperty.required = false; - classProperty.defaultProperty = - JsonValue::Array{JsonValue(false), JsonValue(true)}; + classProperty.defaultProperty = JsonValue::Array{false, true}; PropertyView> view(classProperty); REQUIRE(!view.required()); @@ -338,10 +442,9 @@ TEST_CASE("Boolean Array PropertyView") { classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.array = true; classProperty.required = true; - classProperty.defaultProperty = - JsonValue::Array{JsonValue(false), JsonValue(true)}; + classProperty.defaultProperty = JsonValue::Array{false, true}; - PropertyView view(classProperty); + PropertyView> view(classProperty); REQUIRE(view.required()); REQUIRE(!view.defaultValue()); } @@ -350,10 +453,89 @@ TEST_CASE("Boolean Array PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.array = true; - classProperty.defaultProperty = JsonValue(true); + classProperty.defaultProperty = true; - PropertyView view(classProperty); + PropertyView> view(classProperty); REQUIRE(!view.required()); REQUIRE(!view.defaultValue()); } } + +TEST_CASE("String Array PropertyView") { + SECTION("Ignores non-applicable properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + classProperty.normalized = true; + classProperty.offset = {"offset"}; + classProperty.scale = {"scale"}; + classProperty.max = {"max"}; + classProperty.min = {"min"}; + + PropertyView> view(classProperty); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + } + + SECTION("Constructs with count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + classProperty.count = 5; + + PropertyView> view(classProperty); + REQUIRE(view.arrayCount() == classProperty.count); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + classProperty.required = false; + classProperty.noData = JsonValue::Array{"null", "0"}; + classProperty.defaultProperty = JsonValue::Array{"default1", "default2"}; + + PropertyView> view(classProperty); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + const auto noData = *view.noData(); + REQUIRE(noData.size() == 2); + REQUIRE(noData[0] == "null"); + REQUIRE(noData[1] == "0"); + + const auto defaultValue = *view.defaultValue(); + REQUIRE(defaultValue.size() == 2); + REQUIRE(defaultValue[0] == "default1"); + REQUIRE(defaultValue[1] == "default2"); + } + + SECTION("Ignores noData and defaultProperty when required is true") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.required = true; + classProperty.noData = JsonValue::Array{"null", "0"}; + classProperty.defaultProperty = JsonValue::Array{"default1", "default2"}; + + PropertyView> view(classProperty); + REQUIRE(view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Returns nullopt for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.noData = JsonValue::Array{"null"}; + classProperty.defaultProperty = true; + + PropertyView view(classProperty); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } +} From ba779b7c415d181ac9f211112229adc35051a219 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 16 Aug 2023 14:56:02 -0400 Subject: [PATCH 073/121] Add support for matN values --- .../include/CesiumGltf/PropertyArrayView.h | 62 +++--- CesiumGltf/include/CesiumGltf/PropertyView.h | 37 ++-- CesiumGltf/test/TestPropertyView.cpp | 194 ++++++++++++++++++ 3 files changed, 249 insertions(+), 44 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index 119187f24..a6db9667f 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -67,7 +67,7 @@ template <> class PropertyArrayView { /** * @brief Constructs an empty array view. */ - PropertyArrayView() : _values{}, _size{0} {} + PropertyArrayView() : _values{} {} /** * @brief Constructs an array view from a buffer. @@ -81,7 +81,7 @@ template <> class PropertyArrayView { const gsl::span& buffer, int64_t bitOffset, int64_t size) noexcept - : _values{BooleanArrayView{buffer, bitOffset}}, _size{size} {} + : _values{BooleanArrayView{buffer, bitOffset, size}} {} /** * @brief Constructs an array view from a vector of values. This is mainly @@ -90,10 +90,7 @@ template <> class PropertyArrayView { * @param values The vector containing the values. */ PropertyArrayView(const std::vector&& values) - : _values{std::move(values)}, _size{0} { - size_t size = std::get>(_values).size(); - _size = static_cast(size); - } + : _values{std::move(values)} {} bool operator[](int64_t index) const noexcept { return std::visit( @@ -101,25 +98,31 @@ template <> class PropertyArrayView { _values); } - int64_t size() const noexcept { return _size; } + int64_t size() const noexcept { + return std::visit( + [](auto const& values) { return static_cast(values.size()); }, + _values); + } private: struct BooleanArrayView { - gsl::span values; - int64_t bitOffset = 0; + gsl::span _values; + int64_t _bitOffset = 0; + int64_t _size = 0; bool operator[](int64_t index) const noexcept { - index += bitOffset; + index += _bitOffset; const int64_t byteIndex = index / 8; const int64_t bitIndex = index % 8; - const int bitValue = static_cast(values[byteIndex] >> bitIndex) & 1; + const int bitValue = static_cast(_values[byteIndex] >> bitIndex) & 1; return bitValue == 1; } + + int64_t size() const noexcept { return _size; } }; using ArrayType = std::variant>; ArrayType _values; - int64_t _size; }; template <> class PropertyArrayView { @@ -127,7 +130,7 @@ template <> class PropertyArrayView { /** * @brief Constructs an empty array view. */ - PropertyArrayView() : _values{}, _size{0} {} + PropertyArrayView() : _values{} {} /** * @brief Constructs an array view from buffers and their information. @@ -142,8 +145,8 @@ template <> class PropertyArrayView { const gsl::span& stringOffsets, PropertyComponentType stringOffsetType, int64_t size) noexcept - : _values{StringArrayView{values, stringOffsets, stringOffsetType}}, - _size{size} {} + : _values{ + StringArrayView{values, stringOffsets, stringOffsetType, size}} {} /** * @brief Constructs an array view from a vector of values. This is mainly @@ -152,10 +155,7 @@ template <> class PropertyArrayView { * @param values The vector containing the values. */ PropertyArrayView(const std::vector&& values) noexcept - : _values{std::move(values)}, _size{0} { - size_t size = std::get>(_values).size(); - _size = static_cast(size); - } + : _values{std::move(values)} {} std::string_view operator[](int64_t index) const noexcept { return std::visit( @@ -165,29 +165,35 @@ template <> class PropertyArrayView { _values); } - int64_t size() const noexcept { return _size; } + int64_t size() const noexcept { + return std::visit( + [](auto const& values) { return static_cast(values.size()); }, + _values); + } private: struct StringArrayView { - gsl::span values; - gsl::span stringOffsets; - PropertyComponentType stringOffsetType = PropertyComponentType::None; + gsl::span _values; + gsl::span _stringOffsets; + PropertyComponentType _stringOffsetType = PropertyComponentType::None; + int64_t _size = 0; std::string_view operator[](int64_t index) const noexcept { const size_t currentOffset = - getOffsetFromOffsetsBuffer(index, stringOffsets, stringOffsetType); + getOffsetFromOffsetsBuffer(index, _stringOffsets, _stringOffsetType); const size_t nextOffset = getOffsetFromOffsetsBuffer( index + 1, - stringOffsets, - stringOffsetType); + _stringOffsets, + _stringOffsetType); return std::string_view( - reinterpret_cast(values.data() + currentOffset), + reinterpret_cast(_values.data() + currentOffset), (nextOffset - currentOffset)); } + + int64_t size() const noexcept { return _size; } }; using ArrayType = std::variant>; ArrayType _values; - int64_t _size; }; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 39e9f7949..d56c15e88 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -297,12 +297,15 @@ class PropertyView : IPropertyView { getValue(const CesiumUtility::JsonValue& jsonValue) { if constexpr (IsMetadataScalar::value) { return getScalar(jsonValue); - } else if constexpr (IsMetadataVecN::value) { + } + + if constexpr (IsMetadataVecN::value) { return getVecN(jsonValue); - } else - return std::nullopt; - // if constexpr (IsMetadataMatN::value) { - //} + } + + if constexpr (IsMetadataMatN::value) { + return getMatN(jsonValue); + } } /** @@ -333,7 +336,7 @@ class PropertyView : IPropertyView { } const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); - glm::length_t N = VecType::length(); + constexpr glm::length_t N = VecType::length(); if (array.size() != N) { return std::nullopt; } @@ -355,28 +358,30 @@ class PropertyView : IPropertyView { template static std::optional - getMatNFromJsonValue(const CesiumUtility::JsonValue& value) { + getMatN(const CesiumUtility::JsonValue& jsonValue) { if (!jsonValue.isArray()) { return std::nullopt; } const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); - glm::length_t N = VecType::length(); - glm::length_t numValues = N * N; - if (array.size() != numValues) { + constexpr glm::length_t N = MatType::length(); + if (array.size() != N * N) { return std::nullopt; } using T = MatType::value_type; MatType result; - for (glm::length_t i = 0; i < numValues; i++) { - std::optional value = getScalar(array[i]); - if (!value) { - return std::nullopt; + for (glm::length_t i = 0; i < N; i++) { + // Try to parse each value in the column. + for (glm::length_t j = 0; j < N; j++) { + std::optional value = getScalar(array[i * N + j]); + if (!value) { + return std::nullopt; + } + + result[i][j] = *value; } - - result[i] = value; } return result; diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp index 27106da09..52b49d9d3 100644 --- a/CesiumGltf/test/TestPropertyView.cpp +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -321,6 +321,200 @@ TEST_CASE("VecN PropertyView") { } } +TEST_CASE("MatN PropertyView") { + SECTION("Constructs with non-optional properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.normalized = true; + classProperty.required = true; + + PropertyView view(classProperty); + REQUIRE(view.normalized()); + REQUIRE(view.required()); + + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Ignores count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.count = 5; + + PropertyView view(classProperty); + REQUIRE(view.arrayCount() == 0); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + // clang-format off + classProperty.offset = JsonValue::Array{ + -1, 1, 2, + 3, -1, 4, + -5, -5, 0}; + classProperty.scale = JsonValue::Array{ + 1, 1, 1, + 2, 2, 3, + 3, 4, 5}; + classProperty.max = JsonValue::Array{ + 20, 5, 20, + 30, 22, 43, + 37, 1, 8}; + classProperty.min = JsonValue::Array{ + -10, -2, -3, + 0, 20, 4, + 9, 4, 5}; + // clang-format on + + PropertyView view(classProperty); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); + + // clang-format off + glm::imat3x3 expectedOffset( + -1, 1, 2, + 3, -1, 4, + -5, -5, 0); + REQUIRE(*view.offset() == expectedOffset); + + glm::imat3x3 expectedScale( + 1, 1, 1, + 2, 2, 3, + 3, 4, 5); + REQUIRE(*view.scale() == expectedScale); + + glm::imat3x3 expectedMax( + 20, 5, 20, + 30, 22, 43, + 37, 1, 8); + REQUIRE(*view.max() == expectedMax); + + glm::imat3x3 expectedMin( + -10, -2, -3, + 0, 20, 4, + 9, 4, 5); + REQUIRE(*view.min() == expectedMin); + // clang-format on + } + + SECTION("Returns nullopt for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + // clang-format off + classProperty.offset = JsonValue::Array{ + -1, 2, + 129, -2}; + classProperty.scale = JsonValue::Array{ + 1, 7, + 4, 6}; + classProperty.max = JsonValue::Array{ + 10, 240, + 1, 8}; + classProperty.min = JsonValue::Array{ + -29, -40, + -55, -43}; + // clang-format on + + PropertyView view(classProperty); + REQUIRE(view.scale()); + REQUIRE(view.min()); + + // clang-format off + glm::i8mat2x2 expectedScale( + 1, 7, + 4, 6); + REQUIRE(*view.scale() == expectedScale); + + glm::i8mat2x2 expectedMin( + -29, -40, + -55, -43); + REQUIRE(*view.min() == expectedMin); + // clang-format on + + REQUIRE(!view.offset()); + REQUIRE(!view.max()); + } + + SECTION("Returns nullopt for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.offset = "(1, 2, 3, 4)"; + classProperty.scale = 1; + classProperty.max = JsonValue::Array{10, 20, 30, 40, 50}; + classProperty.min = JsonValue::Array{0, 0}; + + PropertyView view(classProperty); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.required = false; + // clang-format off + classProperty.noData = JsonValue::Array{ + 0.0f, 0.0f, + 0.0f, 0.0f}; + classProperty.defaultProperty = JsonValue::Array{ + 1.0f, 2.0f, + 3.0f, 4.0f}; + // clang-format on + + PropertyView view(classProperty); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + // clang-format off + glm::mat2 expectedNoData( + 0.0f, 0.0f, + 0.0f, 0.0f); + REQUIRE(*view.noData() == expectedNoData); + + glm::mat2 expectedDefaultValue( + 1.0f, 2.0f, + 3.0f, 4.0f); + REQUIRE(*view.defaultValue() == expectedDefaultValue); + } + + SECTION("Ignores noData and defaultProperty when required is true") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.required = true; + // clang-format off + classProperty.noData = JsonValue::Array{ + 0.0f, 0.0f, + 0.0f, 0.0f}; + classProperty.defaultProperty = JsonValue::Array{ + 1.0f, 2.0f, + 3.0f, 4.0f}; + // clang-format on + + PropertyView view(classProperty); + REQUIRE(view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } +} + TEST_CASE("String PropertyView") { SECTION("Ignores non-applicable properties") { ClassProperty classProperty; From e7743ea61c0aba4d0649050298e09df4c5bb13f4 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 17 Aug 2023 13:55:54 -0400 Subject: [PATCH 074/121] Change status enum to static consts --- .../include/CesiumGltf/PropertyArrayView.h | 114 +- .../CesiumGltf/PropertyTablePropertyView.h | 119 +- .../include/CesiumGltf/PropertyTableView.h | 6 +- .../CesiumGltf/PropertyTexturePropertyView.h | 1 + CesiumGltf/include/CesiumGltf/PropertyView.h | 1069 +++++++++++++---- CesiumGltf/src/PropertyTableView.cpp | 18 +- CesiumGltf/test/TestPropertyView.cpp | 861 ++++++++++--- 7 files changed, 1640 insertions(+), 548 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index a6db9667f..987908925 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -81,48 +81,22 @@ template <> class PropertyArrayView { const gsl::span& buffer, int64_t bitOffset, int64_t size) noexcept - : _values{BooleanArrayView{buffer, bitOffset, size}} {} - - /** - * @brief Constructs an array view from a vector of values. This is mainly - * used when the values cannot be viewed in place. - * - * @param values The vector containing the values. - */ - PropertyArrayView(const std::vector&& values) - : _values{std::move(values)} {} + : _values{buffer}, _bitOffset{bitOffset}, _size{size} {} bool operator[](int64_t index) const noexcept { - return std::visit( - [index](auto const& values) -> auto const { return values[index]; }, - _values); + index += _bitOffset; + const int64_t byteIndex = index / 8; + const int64_t bitIndex = index % 8; + const int bitValue = static_cast(_values[byteIndex] >> bitIndex) & 1; + return bitValue == 1; } - int64_t size() const noexcept { - return std::visit( - [](auto const& values) { return static_cast(values.size()); }, - _values); - } + int64_t size() const noexcept { return _size; } private: - struct BooleanArrayView { - gsl::span _values; - int64_t _bitOffset = 0; - int64_t _size = 0; - - bool operator[](int64_t index) const noexcept { - index += _bitOffset; - const int64_t byteIndex = index / 8; - const int64_t bitIndex = index % 8; - const int bitValue = static_cast(_values[byteIndex] >> bitIndex) & 1; - return bitValue == 1; - } - - int64_t size() const noexcept { return _size; } - }; - - using ArrayType = std::variant>; - ArrayType _values; + gsl::span _values; + int64_t _bitOffset = 0; + int64_t _size = 0; }; template <> class PropertyArrayView { @@ -130,7 +104,11 @@ template <> class PropertyArrayView { /** * @brief Constructs an empty array view. */ - PropertyArrayView() : _values{} {} + PropertyArrayView() + : _values{}, + _stringOffsets{}, + _stringOffsetType{PropertyComponentType::None}, + _size{0} {} /** * @brief Constructs an array view from buffers and their information. @@ -145,55 +123,29 @@ template <> class PropertyArrayView { const gsl::span& stringOffsets, PropertyComponentType stringOffsetType, int64_t size) noexcept - : _values{ - StringArrayView{values, stringOffsets, stringOffsetType, size}} {} - - /** - * @brief Constructs an array view from a vector of values. This is mainly - * used when the values cannot be viewed in place. - * - * @param values The vector containing the values. - */ - PropertyArrayView(const std::vector&& values) noexcept - : _values{std::move(values)} {} + : _values{values}, + _stringOffsets{stringOffsets}, + _stringOffsetType{stringOffsetType}, + _size(size) {} std::string_view operator[](int64_t index) const noexcept { - return std::visit( - [index](auto const& values) -> auto const { - return std::string_view(values[index]); - }, - _values); + const size_t currentOffset = + getOffsetFromOffsetsBuffer(index, _stringOffsets, _stringOffsetType); + const size_t nextOffset = getOffsetFromOffsetsBuffer( + index + 1, + _stringOffsets, + _stringOffsetType); + return std::string_view( + reinterpret_cast(_values.data() + currentOffset), + (nextOffset - currentOffset)); } - int64_t size() const noexcept { - return std::visit( - [](auto const& values) { return static_cast(values.size()); }, - _values); - } + int64_t size() const noexcept { return _size; } private: - struct StringArrayView { - gsl::span _values; - gsl::span _stringOffsets; - PropertyComponentType _stringOffsetType = PropertyComponentType::None; - int64_t _size = 0; - - std::string_view operator[](int64_t index) const noexcept { - const size_t currentOffset = - getOffsetFromOffsetsBuffer(index, _stringOffsets, _stringOffsetType); - const size_t nextOffset = getOffsetFromOffsetsBuffer( - index + 1, - _stringOffsets, - _stringOffsetType); - return std::string_view( - reinterpret_cast(_values.data() + currentOffset), - (nextOffset - currentOffset)); - } - - int64_t size() const noexcept { return _size; } - }; - - using ArrayType = std::variant>; - ArrayType _values; + gsl::span _values; + gsl::span _stringOffsets; + PropertyComponentType _stringOffsetType; + int64_t _size; }; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 3edc7b0a8..6c0d269b1 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -21,138 +21,113 @@ namespace CesiumGltf { * but instead indicate that its {@link PropertyTablePropertyView::size} is 0. * This enumeration provides the reason. */ -enum class PropertyTablePropertyViewStatus { - /** - * @brief This property view is valid and ready to use. - */ - Valid, - - /** - * @brief This property view was initialized from an invalid - * {@link PropertyTable}. - */ - ErrorInvalidPropertyTable, - - /** - * @brief This property view is trying to view a property that does not exist - * in the {@link PropertyTable}. - */ - ErrorNonexistentProperty, - - /** - * @brief This property view's type does not match what is - * specified in {@link ClassProperty::type}. - */ - ErrorTypeMismatch, - - /** - * @brief This property view's component type does not match what - * is specified in {@link ClassProperty::componentType}. - */ - ErrorComponentTypeMismatch, - +class PropertyTablePropertyViewStatus : public PropertyViewStatus { +public: /** - * @brief This property view differs from what is specified in - * {@link ClassProperty::array}. + * @brief This property view was initialized from an invalid {@link PropertyTable}. */ - ErrorArrayTypeMismatch, + static const PropertyViewStatusType ErrorInvalidPropertyTable = 12; /** * @brief This property view does not have a valid value buffer view index. */ - ErrorInvalidValueBufferView, + static const PropertyViewStatusType ErrorInvalidValueBufferView = 13; /** * @brief This array property view does not have a valid array offset buffer * view index. */ - ErrorInvalidArrayOffsetBufferView, + static const PropertyViewStatusType ErrorInvalidArrayOffsetBufferView = 14; /** * @brief This string property view does not have a valid string offset buffer * view index. */ - ErrorInvalidStringOffsetBufferView, + static const PropertyViewStatusType ErrorInvalidStringOffsetBufferView = 15; /** * @brief This property view has a valid value buffer view, but the buffer * view specifies an invalid buffer index. */ - ErrorInvalidValueBuffer, + static const PropertyViewStatusType ErrorInvalidValueBuffer = 16; /** * @brief This property view has a valid array string buffer view, but the * buffer view specifies an invalid buffer index. */ - ErrorInvalidArrayOffsetBuffer, + static const PropertyViewStatusType ErrorInvalidArrayOffsetBuffer = 17; /** * @brief This property view has a valid string offset buffer view, but the * buffer view specifies an invalid buffer index. */ - ErrorInvalidStringOffsetBuffer, + static const PropertyViewStatusType ErrorInvalidStringOffsetBuffer = 18; /** * @brief This property view has a buffer view that points outside the bounds * of its target buffer. */ - ErrorBufferViewOutOfBounds, + static const PropertyViewStatusType ErrorBufferViewOutOfBounds = 19; /** * @brief This property view has an invalid buffer view; its length is not * a multiple of the size of its type / offset type. */ - ErrorBufferViewSizeNotDivisibleByTypeSize, + static const PropertyViewStatusType + ErrorBufferViewSizeNotDivisibleByTypeSize = 20; /** * @brief This property view has an invalid buffer view; its length does not * match the size of the property table. */ - ErrorBufferViewSizeDoesNotMatchPropertyTableCount, + static const PropertyViewStatusType + ErrorBufferViewSizeDoesNotMatchPropertyTableCount = 21; /** * @brief This array property view has both a fixed length and an offset * buffer view defined. */ - ErrorArrayCountAndOffsetBufferCoexist, + static const PropertyViewStatusType ErrorArrayCountAndOffsetBufferCoexist = + 22; /** * @brief This array property view has neither a fixed length nor an offset * buffer view defined. */ - ErrorArrayCountAndOffsetBufferDontExist, + static const PropertyViewStatusType ErrorArrayCountAndOffsetBufferDontExist = + 23; /** * @brief This property view has an unknown array offset type. */ - ErrorInvalidArrayOffsetType, + static const PropertyViewStatusType ErrorInvalidArrayOffsetType = 24; /** * @brief This property view has an unknown string offset type. */ - ErrorInvalidStringOffsetType, + static const PropertyViewStatusType ErrorInvalidStringOffsetType = 25; /** * @brief This property view's array offset values are not sorted in ascending * order. */ - ErrorArrayOffsetsNotSorted, + static const PropertyViewStatusType ErrorArrayOffsetsNotSorted = 26; /** * @brief This property view's string offset values are not sorted in * ascending order. */ - ErrorStringOffsetsNotSorted, + static const PropertyViewStatusType ErrorStringOffsetsNotSorted = 27; /** * @brief This property view has an array offset that is out of bounds. */ - ErrorArrayOffsetOutOfBounds, + static const PropertyViewStatusType ErrorArrayOffsetOutOfBounds = 28; /** * @brief This property view has a string offset that is out of bounds. */ - ErrorStringOffsetOutOfBounds + static const PropertyViewStatusType ErrorStringOffsetOutOfBounds = 29; }; /** @@ -179,15 +154,32 @@ class PropertyTablePropertyView : public PropertyView { : PropertyView(), _status{PropertyTablePropertyViewStatus::ErrorNonexistentProperty}, _values, - _size{} {} + _size{0}, + _arrayOffsets{}, + _arrayOffsetType{PropertyComponentType::None}, + _arrayOffsetTypeSize{0}, + _stringOffsets{}, + _stringOffsetType{PropertyComponentType::None}, + _stringOffsetTypeSize{0}, + {} /** * @brief Constructs an invalid instance for an erroneous property. * - * @param status The {@link PropertyTablePropertyViewStatus} indicating the error with the property. + * @param status The value of {@link PropertyTablePropertyViewStatus} indicating the error with the property. */ - PropertyTablePropertyView(PropertyTablePropertyViewStatus status) - : PropertyView(), _status{status}, _values{}, _size{} { + PropertyTablePropertyView(PropertyViewStatusType status) + : PropertyView(), + _status{status}, + _values{}, + _size{0}, + _arrayOffsets{}, + _arrayOffsetType{PropertyComponentType::None}, + _arrayOffsetTypeSize{0}, + _stringOffsets{}, + _stringOffsetType{PropertyComponentType::None}, + _stringOffsetTypeSize{0} + { assert( _status != PropertyTablePropertyViewStatus::Valid && "An empty property view should not be constructed with a valid status"); @@ -208,13 +200,14 @@ class PropertyTablePropertyView : public PropertyView { : PropertyView(classProperty, property), _status{PropertyTablePropertyViewStatus::Valid}, _values{values}, + _size{size}, _arrayOffsets{}, _arrayOffsetType{PropertyComponentType::None}, _arrayOffsetTypeSize{0}, _stringOffsets{}, _stringOffsetType{PropertyComponentType::None}, - _stringOffsetTypeSize{0}, - _size{size} {} + _stringOffsetTypeSize{0} + {} /** * @brief Construct a valid instance pointing to the data specified by @@ -250,14 +243,9 @@ class PropertyTablePropertyView : public PropertyView { _size{size} {} /** - * @brief Gets the status of this property table property view. - * - * Indicates whether the view accurately reflects the property's data, or - * whether an error occurred. - * - * @return The status of this property view. + * @copydoc IPropertyView::status */ - PropertyTablePropertyViewStatus status() const noexcept { return _status; } + virtual int32_t status() const noexcept override { return _status; } /** * @brief Get the value of an element of the {@link PropertyTable}. @@ -430,8 +418,9 @@ class PropertyTablePropertyView : public PropertyView { } } - PropertyTablePropertyViewStatus _status; + PropertyViewStatusType _status; gsl::span _values; + int64_t _size; gsl::span _arrayOffsets; PropertyComponentType _arrayOffsetType; @@ -440,7 +429,5 @@ class PropertyTablePropertyView : public PropertyView { gsl::span _stringOffsets; PropertyComponentType _stringOffsetType; int64_t _stringOffsetTypeSize; - - int64_t _size; }; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h index c43c26512..1f5fb9a31 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -1152,11 +1152,11 @@ class PropertyTableView { const ClassProperty& classProperty, const PropertyTableProperty& propertyTableProperty) const; - PropertyTablePropertyViewStatus getBufferSafe( + PropertyViewStatusType getBufferSafe( int32_t bufferView, gsl::span& buffer) const noexcept; - PropertyTablePropertyViewStatus getArrayOffsetsBufferSafe( + PropertyViewStatusType getArrayOffsetsBufferSafe( int32_t arrayOffsetsBufferView, PropertyComponentType arrayOffsetType, size_t valuesBufferSize, @@ -1164,7 +1164,7 @@ class PropertyTableView { bool checkBitsSize, gsl::span& arrayOffsetsBuffer) const noexcept; - PropertyTablePropertyViewStatus getStringOffsetsBufferSafe( + PropertyViewStatusType getStringOffsetsBufferSafe( int32_t stringOffsetsBufferView, PropertyComponentType stringOffsetType, size_t valuesBufferSize, diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 709c25e10..95417462a 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -4,6 +4,7 @@ #include "CesiumGltf/PropertyTextureProperty.h" #include "CesiumGltf/PropertyTypeTraits.h" #include "CesiumGltf/Sampler.h" +#include "CesiumGltf/PropertyView.h" #include #include diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index d56c15e88..e897be9b3 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -7,26 +7,98 @@ #include namespace CesiumGltf { + +typedef int32_t PropertyViewStatusType; + +class PropertyViewStatus { +public: + /** + * @brief This property view is valid and ready to use. + */ + static const PropertyViewStatusType Valid = 0; + + /** + * @brief This property view is trying to view a property that does not + * exist. + */ + static const PropertyViewStatusType ErrorNonexistentProperty = 1; + + /** + * @brief This property view's type does not match what is + * specified in {@link ClassProperty::type}. + */ + static const PropertyViewStatusType ErrorTypeMismatch = 2; + + /** + * @brief This property view's component type does not match what + * is specified in {@link ClassProperty::componentType}. + */ + static const PropertyViewStatusType ErrorComponentTypeMismatch = 3; + + /** + * @brief This property view differs from what is specified in + * {@link ClassProperty::array}. + */ + static const PropertyViewStatusType ErrorArrayTypeMismatch = 4; + + /** + * @brief This property says it is normalized, but is not of an integer + * component type. + */ + static const PropertyViewStatusType ErrorInvalidNormalization = 5; + + /** + * @brief The property provided an invalid offset value. + */ + static const PropertyViewStatusType ErrorInvalidOffset = 6; + + /** + * @brief The property provided an invalid scale value. + */ + static const PropertyViewStatusType ErrorInvalidScale = 7; + + /** + * @brief The property provided an invalid maximum value. + */ + static const PropertyViewStatusType ErrorInvalidMax = 8; + + /** + * @brief The property provided an invalid minimum value. + */ + static const PropertyViewStatusType ErrorInvalidMin = 9; + + /** + * @brief The property provided an invalid "no data" value. + */ + static const PropertyViewStatusType ErrorInvalidNoDataValue = 10; + + /** + * @brief The property provided an invalid default value. + */ + static const PropertyViewStatusType ErrorInvalidDefaultValue = 11; +}; + /** * @brief An interface for generic metadata property in EXT_structural_metadata. * * Whether they belong to property tables, property textures, or property * attributes, properties have their own sub-properties affecting the actual * property values. Although they are typically defined via class property, they - * may be overriden by individual instances of the property. The constructor is + * may be overridden by individual instances of the property. The constructor is * responsible for resolving those differences. * - * However, there are fundamental differences between property tables, property - * textures, and property attributes. Notably, the ways in which values are - * stored -- as well as what types of values are even supported -- vary between - * the three. Therefore, this interface has no "status" and does not validate - * ElementType against the input class property. Derived classes must do their - * own validation to ensure that ElementType matches the given class definition. - * * @tparam ElementType The C++ type of the values in this property */ template class IPropertyView { public: + /** + * @brief Gets the status of this property view, indicating whether an error + * occurred. + * + * @return The status of this property view. + */ + virtual PropertyViewStatusType status() const noexcept = 0; + /** * @brief Get the element count of the fixed-length arrays in this property. * Only applicable when the property is an array type. @@ -118,7 +190,8 @@ class PropertyView : IPropertyView { * @brief Constructs an empty property instance. */ PropertyView() - : _normalized(false), + : _status(PropertyViewStatus::ErrorNonexistentProperty), + _normalized(false), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -131,7 +204,8 @@ class PropertyView : IPropertyView { * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _normalized(classProperty.normalized), + : _status(PropertyViewStatus::Valid), + _normalized(classProperty.normalized), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -139,21 +213,107 @@ class PropertyView : IPropertyView { _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { + if (convertPropertyTypeToString(TypeToPropertyType::value) != + classProperty.type) { + _status = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (!classProperty.componentType && + TypeToPropertyType::component != + PropertyComponentType::None) { + _status = PropertyViewStatus::ErrorComponentTypeMismatch; + return; + } + + if (classProperty.componentType && + convertPropertyComponentTypeToString( + TypeToPropertyType::component) != + *classProperty.componentType) { + _status = PropertyViewStatus::ErrorComponentTypeMismatch; + return; + } + + if (classProperty.array) { + _status = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + if (classProperty.normalized) { + PropertyComponentType componentType = + TypeToPropertyType::component; + switch (componentType) { + case PropertyComponentType::Uint8: + case PropertyComponentType::Int8: + case PropertyComponentType::Uint16: + case PropertyComponentType::Int16: + case PropertyComponentType::Uint32: + case PropertyComponentType::Int32: + case PropertyComponentType::Uint64: + case PropertyComponentType::Int64: + break; + default: + _status = PropertyViewStatus::ErrorInvalidNormalization; + return; + } + } + if constexpr (IsMetadataNumeric::value) { - _offset = - classProperty.offset ? getValue(*classProperty.offset) : std::nullopt; - _scale = - classProperty.scale ? getValue(*classProperty.scale) : std::nullopt; - _max = classProperty.max ? getValue(*classProperty.max) : std::nullopt; - _min = classProperty.min ? getValue(*classProperty.min) : std::nullopt; + if (classProperty.offset) { + _offset = getValue(*classProperty.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (classProperty.scale) { + _scale = getValue(*classProperty.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (classProperty.max) { + _max = getValue(*classProperty.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (classProperty.min) { + _min = getValue(*classProperty.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } } if (!_required) { - _noData = - classProperty.noData ? getValue(*classProperty.noData) : std::nullopt; - _defaultValue = classProperty.defaultProperty - ? getValue(*classProperty.defaultProperty) - : std::nullopt; + if (classProperty.noData) { + _noData = getValue(*classProperty.noData); + if (!_noData) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; + } + } + + if (classProperty.defaultProperty) { + _defaultValue = getValue(*classProperty.defaultProperty); + if (!_defaultValue) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; + } + } } } @@ -166,22 +326,46 @@ class PropertyView : IPropertyView { const ClassProperty& classProperty, const PropertyTableProperty& property) : PropertyView(classProperty) { + if (_status != PropertyViewStatus::Valid) { + return; + } + // If the property has its own values, override the class-provided values. if constexpr (IsMetadataNumeric::value) { if (property.offset) { _offset = getValue(*property.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } } if (property.scale) { _scale = getValue(*property.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } } if (property.max) { _max = getValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } } if (property.min) { _min = getValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } } } } @@ -194,27 +378,58 @@ class PropertyView : IPropertyView { const ClassProperty& classProperty, const PropertyTextureProperty& property) : PropertyView(classProperty) { + if (_status != PropertyViewStatus::Valid) { + return; + } + // If the property has its own values, override the class-provided values. if constexpr (IsMetadataNumeric::value) { if (property.offset) { _offset = getValue(*property.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } } if (property.scale) { _scale = getValue(*property.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } } if (property.max) { _max = getValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } } if (property.min) { _min = getValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } } } } public: + /** + * @copydoc IPropertyView::status + */ + virtual PropertyViewStatusType status() const noexcept override { + return _status; + } + /** * @copydoc IPropertyView::arrayCount */ @@ -273,6 +488,7 @@ class PropertyView : IPropertyView { } private: + PropertyViewStatusType _status; bool _normalized; std::optional _offset; @@ -308,15 +524,6 @@ class PropertyView : IPropertyView { } } - /** - * @brief Attempts to parse a scalar from the given JSON value. If the JSON - * value is a number of the wrong type, this will round it to the closest - * representation in the desired type, if possible. Otherwise, this returns - * std::nullopt. - * - * @return The value as a type T, or std::nullopt if it could not be - * parsed. - */ template static std::optional getScalar(const CesiumUtility::JsonValue& jsonValue) { try { @@ -341,7 +548,7 @@ class PropertyView : IPropertyView { return std::nullopt; } - using T = VecType::value_type; + using T = typename VecType::value_type; VecType result; for (glm::length_t i = 0; i < N; i++) { @@ -369,7 +576,7 @@ class PropertyView : IPropertyView { return std::nullopt; } - using T = MatType::value_type; + using T = typename MatType::value_type; MatType result; for (glm::length_t i = 0; i < N; i++) { @@ -393,17 +600,35 @@ template <> class PropertyView : IPropertyView { /** * @brief Constructs an empty property instance. */ - PropertyView() : _required(false), _defaultValue(std::nullopt) {} + PropertyView() + : _status(PropertyViewStatus::ErrorNonexistentProperty), + _required(false), + _defaultValue(std::nullopt) {} /** * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _required(classProperty.required), _defaultValue(std::nullopt) { - if (!_required) { - _defaultValue = classProperty.defaultProperty - ? getBooleanValue(*classProperty.defaultProperty) - : std::nullopt; + : _status(PropertyViewStatus::Valid), + _required(classProperty.required), + _defaultValue(std::nullopt) { + if (classProperty.type != ClassProperty::Type::BOOLEAN) { + _status = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (classProperty.array) { + _status = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + if (!_required && classProperty.defaultProperty) { + _defaultValue = getBooleanValue(*classProperty.defaultProperty); + if (!_defaultValue) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; + } } } @@ -427,6 +652,13 @@ template <> class PropertyView : IPropertyView { : PropertyView(classProperty) {} public: + /** + * @copydoc IPropertyView::status + */ + virtual PropertyViewStatusType status() const noexcept override { + return _status; + } + /** * @copydoc IPropertyView::arrayCount */ @@ -485,6 +717,7 @@ template <> class PropertyView : IPropertyView { } private: + PropertyViewStatusType _status; bool _required; std::optional _defaultValue; @@ -505,21 +738,46 @@ class PropertyView : IPropertyView { * @brief Constructs an empty property instance. */ PropertyView() - : _required(false), _noData(std::nullopt), _defaultValue(std::nullopt) {} + : _status(PropertyViewStatus::ErrorNonexistentProperty), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} /** * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _required(classProperty.required), + : _status(PropertyViewStatus::Valid), + _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { + if (classProperty.type != ClassProperty::Type::STRING) { + _status = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (classProperty.array) { + _status = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + if (!_required) { - _noData = classProperty.noData ? getStringValue(*classProperty.noData) - : std::nullopt; - _defaultValue = classProperty.defaultProperty - ? getStringValue(*classProperty.defaultProperty) - : std::nullopt; + if (classProperty.noData) { + _noData = getStringValue(*classProperty.noData); + if (!_noData) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; + } + } + if (classProperty.defaultProperty) { + _defaultValue = getStringValue(*classProperty.defaultProperty); + if (!_defaultValue) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; + } + } } } @@ -543,6 +801,13 @@ class PropertyView : IPropertyView { : PropertyView(classProperty) {} public: + /** + * @copydoc IPropertyView::status + */ + virtual PropertyViewStatusType status() const noexcept override { + return _status; + } + /** * @copydoc IPropertyView::arrayCount */ @@ -608,6 +873,7 @@ class PropertyView : IPropertyView { } private: + PropertyViewStatusType _status; bool _required; std::optional _noData; std::optional _defaultValue; @@ -630,7 +896,8 @@ class PropertyView> * @brief Constructs an empty property instance. */ PropertyView() - : _count(0), + : _status(PropertyViewStatus::ErrorNonexistentProperty), + _count(0), _normalized(false), _offset(std::nullopt), _scale(std::nullopt), @@ -644,7 +911,8 @@ class PropertyView> * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _count(_count = classProperty.count ? *classProperty.count : 0), + : _status(PropertyViewStatus::Valid), + _count(_count = classProperty.count ? *classProperty.count : 0), _normalized(classProperty.normalized), _offset(std::nullopt), _scale(std::nullopt), @@ -653,25 +921,99 @@ class PropertyView> _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { - //_offset = classProperty.offset - // ? getValue(*classProperty.offset) - // : std::nullopt; - //_scale = classProperty.scale ? getValue(*classProperty.scale) - // : std::nullopt; - //_max = classProperty.max ? getValue(*classProperty.max) - // : std::nullopt; - //_min = classProperty.min ? getValue(*classProperty.min) - // : std::nullopt; - - // if (!_required) { - // _noData = classProperty.noData - // ? getValue(*classProperty.noData) - // : std::nullopt; - // _defaultValue = - // classProperty.defaultProperty - // ? getValue(*classProperty.defaultProperty) - // : std::nullopt; - //} + if (convertPropertyTypeToString(TypeToPropertyType::value) != + classProperty.type) { + _status = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (!classProperty.componentType && + TypeToPropertyType::component != + PropertyComponentType::None) { + _status = PropertyViewStatus::ErrorComponentTypeMismatch; + return; + } + + if (classProperty.componentType && + convertPropertyComponentTypeToString( + TypeToPropertyType::component) != + *classProperty.componentType) { + _status = PropertyViewStatus::ErrorComponentTypeMismatch; + return; + } + + if (!classProperty.array) { + _status = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + if (classProperty.normalized && !IsMetadataInteger::value) { + _status = PropertyViewStatus::ErrorInvalidNormalization; + return; + } + + // If the property has its own values, override the class-provided values. + if constexpr (IsMetadataNumeric::value) { + if (classProperty.offset) { + _offset = getArrayValue(*classProperty.offset); + if (!_offset || + (_count > 0 && _offset->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (classProperty.scale) { + _scale = getArrayValue(*classProperty.scale); + if (!_scale || + (_count > 0 && _scale->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (classProperty.max) { + _max = getArrayValue(*classProperty.max); + if (!_max || + (_count > 0 && _max->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (classProperty.min) { + _min = getArrayValue(*classProperty.min); + if (!_min || + (_count > 0 && _min->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + } + + if (!_required) { + if (classProperty.noData) { + _noData = getArrayValue(*classProperty.noData); + if (!_noData) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; + } + } + + if (classProperty.defaultProperty) { + _defaultValue = getArrayValue(*classProperty.defaultProperty); + if (!_defaultValue) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; + } + } + } } protected: @@ -681,24 +1023,50 @@ class PropertyView> */ PropertyView( const ClassProperty& classProperty, - const PropertyTableProperty& /*property*/) + const PropertyTableProperty& property) : PropertyView(classProperty) { - //// If the property has its own values, override the class-provided values. - // if (property.offset) { - // _offset = getValue(*property.offset); - //} + if (_status != PropertyViewStatus::Valid) { + return; + } + + // If the property has its own values, override the class-provided values. + if constexpr (IsMetadataNumeric::value) { + if (property.offset) { + _offset = getArrayValue(*property.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } - // if (property.scale) { - // _scale = getValue(*property.scale); - //} + if (property.scale) { + _scale = getArrayValue(*property.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } - // if (property.max) { - // _max = getValue(*property.max); - //} + if (property.max) { + _max = getArrayValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } - // if (property.min) { - // _min = getValue(*property.min); - //} + if (property.min) { + _min = getArrayValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + } } /** @@ -707,27 +1075,60 @@ class PropertyView> */ PropertyView( const ClassProperty& classProperty, - const PropertyTextureProperty& /*property*/) + const PropertyTextureProperty& property) : PropertyView(classProperty) { - //// If the property has its own values, override the class-provided values. - // if (property.offset) { - // _offset = getValue(*property.offset); - //} + if (_status != PropertyViewStatus::Valid) { + return; + } - // if (property.scale) { - // _scale = getValue(*property.scale); - //} + // If the property has its own values, override the class-provided values. + if constexpr (IsMetadataNumeric::value) { + if (property.offset) { + _offset = getArrayValue(*property.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } - // if (property.max) { - // _max = getValue(*property.max); - //} + if (property.scale) { + _scale = getArrayValue(*property.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (property.max) { + _max = getArrayValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } - // if (property.min) { - // _min = getValue(*property.min); - //} + if (property.min) { + _min = getArrayValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + } } public: + /** + * @copydoc IPropertyView::status + */ + virtual PropertyViewStatusType status() const noexcept override { + return _status; + } + /** * @copydoc IPropertyView::arrayCount */ @@ -743,7 +1144,12 @@ class PropertyView> */ virtual std::optional> offset() const noexcept override { - return _offset; + if (!_offset) { + return std::nullopt; + } + + return PropertyArrayView( + gsl::span(_offset->data(), _offset->size())); } /** @@ -751,7 +1157,12 @@ class PropertyView> */ virtual std::optional> scale() const noexcept override { - return _scale; + if (!_scale) { + return std::nullopt; + } + + return PropertyArrayView( + gsl::span(_scale->data(), _scale->size())); } /** @@ -759,7 +1170,12 @@ class PropertyView> */ virtual std::optional> max() const noexcept override { - return _max; + if (!_max) { + return std::nullopt; + } + + return PropertyArrayView( + gsl::span(_max->data(), _max->size())); } /** @@ -767,7 +1183,12 @@ class PropertyView> */ virtual std::optional> min() const noexcept override { - return _min; + if (!_min) { + return std::nullopt; + } + + return PropertyArrayView( + gsl::span(_min->data(), _min->size())); } /** @@ -780,7 +1201,12 @@ class PropertyView> */ virtual std::optional> noData() const noexcept override { - return _noData; + if (!_noData) { + return std::nullopt; + } + + return PropertyArrayView( + gsl::span(_noData->data(), _noData->size())); } /** @@ -788,59 +1214,81 @@ class PropertyView> */ virtual std::optional> defaultValue() const noexcept override { - return _defaultValue; + if (!_defaultValue) { + return std::nullopt; + } + + return PropertyArrayView(gsl::span( + _defaultValue->data(), + _defaultValue->size())); } private: + PropertyViewStatusType _status; int64_t _count; bool _normalized; - std::optional> _offset; - std::optional> _scale; - std::optional> _max; - std::optional> _min; + std::optional> _offset; + std::optional> _scale; + std::optional> _max; + std::optional> _min; bool _required; - std::optional> _noData; - std::optional> _defaultValue; + std::optional> _noData; + std::optional> _defaultValue; - /** - * @brief Attempts to parse from the given json value. - * - * If ElementType is a type with multiple components, e.g. a VECN or MATN - * type, this will return std::nullopt if one or more components could not be - * parsed. - * - * @return The value as an instance of ElementType, or std::nullopt if it - * could not be parsed. - */ - static std::optional - getValue(const CesiumUtility::JsonValue& jsonValue) { - if constexpr (IsMetadataScalar::value) { - return getScalar(jsonValue); - } else if constexpr (IsMetadataVecN::value) { - return getVecN(jsonValue); - } else + static std::optional> + getArrayValue(const CesiumUtility::JsonValue& jsonValue) { + if (!jsonValue.isArray()) { return std::nullopt; + } + + const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + std::vector values; + values.reserve(array.size()); + + if constexpr (IsMetadataScalar::value) { + for (size_t i = 0; i < array.size(); i++) { + std::optional element = getScalar(array[i]); + if (!element) { + return std::nullopt; + } + + values.push_back(*element); + } + } + if constexpr (IsMetadataVecN::value) { + for (size_t i = 0; i < array.size(); i++) { + std::optional element = getVecN(array[i]); + if (!element) { + return std::nullopt; + } + + values.push_back(*element); + } + } + + if constexpr (IsMetadataMatN::value) { + for (size_t i = 0; i < array.size(); i++) { + std::optional element = getMatN(array[i]); + if (!element) { + return std::nullopt; + } + + values.push_back(*element); + } + } - // if constexpr (IsMetadataMatN::value) { - //} + std::vector result(values.size() * sizeof(ElementType)); + std::memcpy(result.data(), values.data(), result.size()); + + return result; } - /** - * @brief Attempts to parse from the given json value. If it could not be - * parsed as an ElementType, this returns the default value. - * - * If ElementType is a type with multiple components, e.g. a VECN or MATN - * type. - * - * @return The value as an ElementType, or std::nullopt if it could not be - * parsed. - */ template static std::optional getScalar(const CesiumUtility::JsonValue& jsonValue) { try { - return jsonValue.getSafeNumber(); + return jsonValue.getSafeNumber(); } catch (const CesiumUtility::JsonValueNotRealValue& /*error*/) { return std::nullopt; } catch (const gsl::narrowing_error& /*error*/) { @@ -848,55 +1296,64 @@ class PropertyView> } } - template - static std::optional> + template + static std::optional getVecN(const CesiumUtility::JsonValue& jsonValue) { if (!jsonValue.isArray()) { return std::nullopt; } - const CesiumUtility::JsonValue::Array& array = value.getArray(); + const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + constexpr glm::length_t N = VecType::length(); if (array.size() != N) { return std::nullopt; } - glm::vec result; + using T = typename VecType::value_type; + + VecType result; for (glm::length_t i = 0; i < N; i++) { - std::optional value = getValue(array[i]); + std::optional value = getScalar(array[i]); if (!value) { return std::nullopt; } - result[i] = value; + result[i] = *value; } return result; } - // template - // static std::optional - // getMatNFromJsonValue(const CesiumUtility::JsonValue& value) { - // if (!jsonValue.isArray()) { - // return std::nullopt; - // } + template + static std::optional + getMatN(const CesiumUtility::JsonValue& jsonValue) { + if (!jsonValue.isArray()) { + return std::nullopt; + } + + const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + constexpr glm::length_t N = MatType::length(); + if (array.size() != N * N) { + return std::nullopt; + } - // const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); - // if (array.size() != N) { - // return std::nullopt; - // } + using T = typename MatType::value_type; - // glm::vec result; - // for (glm::length_t i = 0; i < N; i++) { - // std::optional value = getValue(array[i]); - // if (!value) { - // return std::nullopt; - // } + MatType result; + for (glm::length_t i = 0; i < N; i++) { + // Try to parse each value in the column. + for (glm::length_t j = 0; j < N; j++) { + std::optional value = getScalar(array[i * N + j]); + if (!value) { + return std::nullopt; + } - // result[i] = value; - // } + result[i][j] = *value; + } + } - // return result; - //} + return result; + } }; template <> @@ -906,19 +1363,40 @@ class PropertyView> /** * @brief Constructs an empty property instance. */ - PropertyView() : _count(0), _required(false), _defaultValue(std::nullopt) {} + PropertyView() + : _status(PropertyViewStatus::ErrorNonexistentProperty), + _count(0), + _required(false), + _defaultValue(), + _size(0) {} /** * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _count(classProperty.count ? *classProperty.count : 0), + : _status(PropertyViewStatus::Valid), + _count(classProperty.count ? *classProperty.count : 0), _required(classProperty.required), - _defaultValue(std::nullopt) { - if (!_required) { - _defaultValue = classProperty.defaultProperty - ? getBooleanArrayValue(*classProperty.defaultProperty) - : std::nullopt; + _defaultValue(), + _size(0) { + if (classProperty.type != ClassProperty::Type::BOOLEAN) { + _status = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (!classProperty.array) { + _status = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + if (!_required && classProperty.defaultProperty) { + _defaultValue = + getBooleanArrayValue(*classProperty.defaultProperty, _size); + if (_size == 0 || (_count > 0 && _size != _count)) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; + } } } @@ -933,8 +1411,8 @@ class PropertyView> : PropertyView(classProperty) {} /** - * @brief Constructs a property instance from a property texture property and - * its class definition. + * @brief Constructs a property instance from a property texture property + * and its class definition. */ PropertyView( const ClassProperty& classProperty, @@ -942,6 +1420,13 @@ class PropertyView> : PropertyView(classProperty) {} public: + /** + * @copydoc IPropertyView::status + */ + virtual PropertyViewStatusType status() const noexcept override { + return _status; + } + /** * @copydoc IPropertyView::arrayCount */ @@ -1000,34 +1485,60 @@ class PropertyView> */ virtual std::optional> defaultValue() const noexcept override { - if (!_defaultValue) { - return std::nullopt; + if (_size > 0) { + return PropertyArrayView( + gsl::span( + _defaultValue.data(), + _defaultValue.size()), + /* bitOffset = */ 0, + _size); } - // Not as easy to construct a gsl::span for the boolean data (the .data() of - // a boolean vector is inaccessible). Just make a copy. - std::vector defaultValueCopy(*_defaultValue); - return PropertyArrayView(std::move(defaultValueCopy)); + + return std::nullopt; } private: + PropertyViewStatusType _status; int64_t _count; bool _required; - std::optional> _defaultValue; - static std::optional> - getBooleanArrayValue(const CesiumUtility::JsonValue& value) { - if (!value.isArray()) { - return std::nullopt; + std::vector _defaultValue; + int64_t _size; + + static std::vector getBooleanArrayValue( + const CesiumUtility::JsonValue& jsonValue, + int64_t& size) { + if (!jsonValue.isArray()) { + return std::vector(); } - const CesiumUtility::JsonValue::Array& array = value.getArray(); - std::vector values(array.size()); - for (size_t i = 0; i < values.size(); i++) { + const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + std::vector values; + values.reserve((array.size() / 8) + 1); + + size_t byteIndex = 0; + uint8_t bitIndex = 0; + + for (size_t i = 0; i < array.size(); i++, size++) { if (!array[i].isBool()) { - return std::nullopt; + size = 0; + return values; + } + + if (values.size() < byteIndex - 1) { + values.push_back(std::byte(0)); } - values[i] = array[i].getBool(); + std::byte value = std::byte(array[i].getBool() ? 1 : 0); + value = value << bitIndex; + + values[byteIndex] |= value; + + bitIndex++; + if (bitIndex > 7) { + byteIndex++; + bitIndex = 0; + } } return values; @@ -1041,23 +1552,68 @@ class PropertyView> /** * @brief Constructs an empty property instance. */ - PropertyView() : _count(0), _required(false), _noData(), _defaultValue() {} + PropertyView() + : _status(PropertyViewStatus::ErrorNonexistentProperty), + _count(0), + _required(false), + _noData(), + _noDataOffsets(), + _noDataOffsetType(PropertyComponentType::None), + _noDataSize(0), + _defaultValue(), + _defaultValueOffsets(), + _defaultValueOffsetType(PropertyComponentType::None), + _defaultValueSize(0) {} /** * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _count(classProperty.count ? *classProperty.count : 0), + : _status(PropertyViewStatus::Valid), + _count(classProperty.count ? *classProperty.count : 0), _required(classProperty.required), _noData(), - _defaultValue() { - if (!_required) { - _noData = classProperty.noData - ? getStringArrayValue(*classProperty.noData) - : std::nullopt; - _defaultValue = classProperty.defaultProperty - ? getStringArrayValue(*classProperty.defaultProperty) - : std::nullopt; + _noDataOffsets(), + _noDataOffsetType(PropertyComponentType::None), + _noDataSize(0), + _defaultValue(), + _defaultValueOffsets(), + _defaultValueOffsetType(PropertyComponentType::None), + _defaultValueSize(0) { + if (classProperty.type != ClassProperty::Type::STRING) { + _status = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (!classProperty.array) { + _status = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + if (!_required && classProperty.noData) { + _noData = getStringArrayValue( + *classProperty.noData, + _noDataOffsets, + _noDataOffsetType, + _noDataSize); + if (_noDataSize == 0 || (_count > 0 && _noDataSize != _count)) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; + } + } + + if (!_required && classProperty.defaultProperty) { + _defaultValue = getStringArrayValue( + *classProperty.defaultProperty, + _defaultValueOffsets, + _defaultValueOffsetType, + _defaultValueSize); + if (_defaultValueSize == 0 || (_count > 0 && _noDataSize != _count)) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; + } } } @@ -1072,8 +1628,8 @@ class PropertyView> : PropertyView(classProperty) {} /** - * @brief Constructs a property instance from a property texture property and - * its class definition. + * @brief Constructs a property instance from a property texture property + * and its class definition. */ PropertyView( const ClassProperty& classProperty, @@ -1081,6 +1637,13 @@ class PropertyView> : PropertyView(classProperty) {} public: + /** + * @copydoc IPropertyView::status + */ + virtual PropertyViewStatusType status() const noexcept override { + return _status; + } + /** * @copydoc IPropertyView::arrayCount */ @@ -1133,14 +1696,17 @@ class PropertyView> */ virtual std::optional> noData() const noexcept override { - if (!_noData) { - return std::nullopt; + if (_noDataSize > 0) { + return PropertyArrayView( + gsl::span(_noData.data(), _noData.size()), + gsl::span( + _noDataOffsets.data(), + _noDataOffsets.size()), + _noDataOffsetType, + _noDataSize); } - // Just copy the strings. Easier than iterating through all of the strings - // to generate an offsets buffer with a best-fitting offset type. - std::vector noDataCopy(*_noData); - return PropertyArrayView(std::move(noDataCopy)); + return std::nullopt; } /** @@ -1148,40 +1714,101 @@ class PropertyView> */ virtual std::optional> defaultValue() const noexcept override { - if (!_defaultValue) { - return std::nullopt; + if (_noDataSize > 0) { + return PropertyArrayView( + gsl::span( + _defaultValue.data(), + _defaultValue.size()), + gsl::span( + _defaultValueOffsets.data(), + _defaultValueOffsets.size()), + _defaultValueOffsetType, + _defaultValueSize); } - // Just copy the strings. Easier than iterating through all of the strings - // to generate an offsets buffer with a best-fitting offset type. - std::vector defaultValueCopy(*_defaultValue); - return PropertyArrayView(std::move(defaultValueCopy)); + return std::nullopt; } private: + PropertyViewStatusType _status; int64_t _count; bool _required; - std::optional> _noData; - std::optional> _defaultValue; - - static std::optional> - getStringArrayValue(const CesiumUtility::JsonValue& jsonValue) { + std::vector _noData; + std::vector _noDataOffsets; + PropertyComponentType _noDataOffsetType; + int64_t _noDataSize; + + std::vector _defaultValue; + std::vector _defaultValueOffsets; + PropertyComponentType _defaultValueOffsetType; + int64_t _defaultValueSize; + + static std::vector getStringArrayValue( + const CesiumUtility::JsonValue& jsonValue, + std::vector& offsets, + PropertyComponentType& offsetType, + int64_t& size) { if (!jsonValue.isArray()) { - return std::nullopt; + return std::vector(); } - std::vector result; + std::vector strings; + std::vector stringOffsets; + const auto array = jsonValue.getArray(); - result.reserve(array.size()); + strings.reserve(array.size()); + stringOffsets.reserve(array.size() + 1); + stringOffsets.push_back(static_cast(0)); for (size_t i = 0; i < array.size(); i++) { if (!array[i].isString()) { // The entire array is invalidated; return. - return std::nullopt; + return std::vector(); } - result.push_back(array[i].getString()); + const std::string& string = array[i].getString(); + strings.push_back(string); + stringOffsets.push_back(stringOffsets[i] + string.size()); + } + + uint64_t totalLength = stringOffsets.back(); + std::vector values(totalLength); + for (size_t i = 0; i < strings.size(); ++i) { + std::memcpy( + values.data() + stringOffsets[i], + strings[i].data(), + strings[i].size()); + }; + + if (totalLength <= std::numeric_limits::max()) { + offsets = narrowOffsetsBuffer(stringOffsets); + offsetType = PropertyComponentType::Uint8; + } else if (totalLength <= std::numeric_limits::max()) { + offsets = narrowOffsetsBuffer(stringOffsets); + offsetType = PropertyComponentType::Uint16; + } else if (totalLength <= std::numeric_limits::max()) { + offsets = narrowOffsetsBuffer(stringOffsets); + offsetType = PropertyComponentType::Uint32; + } else { + offsets.resize(stringOffsets.size() * sizeof(uint64_t)); + std::memcpy(offsets.data(), stringOffsets.data(), offsets.size()); + offsetType = PropertyComponentType::Uint64; + } + + size = static_cast(strings.size()); + + return values; + } + + template + static std::vector + narrowOffsetsBuffer(std::vector offsets) { + std::vector result(offsets.size() * sizeof(T)); + size_t bufferOffset = 0; + for (size_t i = 0; i < offsets.size(); i++, bufferOffset += sizeof(T)) { + T offset = static_cast(offsets[i]); + std::memcpy(result.data() + bufferOffset, &offset, sizeof(T)); } return result; diff --git a/CesiumGltf/src/PropertyTableView.cpp b/CesiumGltf/src/PropertyTableView.cpp index 77d137233..5ba0af589 100644 --- a/CesiumGltf/src/PropertyTableView.cpp +++ b/CesiumGltf/src/PropertyTableView.cpp @@ -2,13 +2,13 @@ namespace CesiumGltf { template -static PropertyTablePropertyViewStatus checkOffsetsBuffer( +static PropertyViewStatusType checkOffsetsBuffer( const gsl::span& offsetBuffer, size_t valueBufferSize, size_t instanceCount, bool checkBitSize, - PropertyTablePropertyViewStatus offsetsNotSortedError, - PropertyTablePropertyViewStatus offsetOutOfBoundsError) noexcept { + PropertyViewStatusType offsetsNotSortedError, + PropertyViewStatusType offsetOutOfBoundsError) noexcept { if (offsetBuffer.size() % sizeof(T) != 0) { return PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize; @@ -46,7 +46,7 @@ static PropertyTablePropertyViewStatus checkOffsetsBuffer( } template -static PropertyTablePropertyViewStatus checkStringAndArrayOffsetsBuffers( +static PropertyViewStatusType checkStringAndArrayOffsetsBuffers( const gsl::span& arrayOffsets, const gsl::span& stringOffsets, size_t valueBufferSize, @@ -147,7 +147,7 @@ PropertyTableView::getClassProperty(const std::string& propertyName) const { return &propertyIter->second; } -PropertyTablePropertyViewStatus PropertyTableView::getBufferSafe( +PropertyViewStatusType PropertyTableView::getBufferSafe( int32_t bufferViewIdx, gsl::span& buffer) const noexcept { buffer = {}; @@ -175,14 +175,14 @@ PropertyTablePropertyViewStatus PropertyTableView::getBufferSafe( return PropertyTablePropertyViewStatus::Valid; } -PropertyTablePropertyViewStatus PropertyTableView::getArrayOffsetsBufferSafe( +PropertyViewStatusType PropertyTableView::getArrayOffsetsBufferSafe( int32_t arrayOffsetsBufferView, PropertyComponentType arrayOffsetType, size_t valueBufferSize, size_t propertyTableCount, bool checkBitsSize, gsl::span& arrayOffsetsBuffer) const noexcept { - const PropertyTablePropertyViewStatus bufferStatus = + const PropertyViewStatusType bufferStatus = getBufferSafe(arrayOffsetsBufferView, arrayOffsetsBuffer); if (bufferStatus != PropertyTablePropertyViewStatus::Valid) { return bufferStatus; @@ -226,13 +226,13 @@ PropertyTablePropertyViewStatus PropertyTableView::getArrayOffsetsBufferSafe( } } -PropertyTablePropertyViewStatus PropertyTableView::getStringOffsetsBufferSafe( +PropertyViewStatusType PropertyTableView::getStringOffsetsBufferSafe( int32_t stringOffsetsBufferView, PropertyComponentType stringOffsetType, size_t valueBufferSize, size_t propertyTableCount, gsl::span& stringOffsetsBuffer) const noexcept { - const PropertyTablePropertyViewStatus bufferStatus = + const PropertyViewStatusType bufferStatus = getBufferSafe(stringOffsetsBufferView, stringOffsetsBuffer); if (bufferStatus != PropertyTablePropertyViewStatus::Valid) { return bufferStatus; diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp index 52b49d9d3..3bc1b9ec7 100644 --- a/CesiumGltf/test/TestPropertyView.cpp +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -5,20 +5,38 @@ using namespace CesiumGltf; using namespace CesiumUtility; -TEST_CASE("Constructs empty PropertyView") { - PropertyView view; - REQUIRE(view.arrayCount() == 0); - REQUIRE(!view.normalized()); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - REQUIRE(!view.required()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); -} - TEST_CASE("Boolean PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.array = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + SECTION("Ignores non-applicable properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; @@ -30,6 +48,7 @@ TEST_CASE("Boolean PropertyView") { classProperty.noData = true; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.normalized()); REQUIRE(!view.offset()); REQUIRE(!view.scale()); @@ -44,6 +63,7 @@ TEST_CASE("Boolean PropertyView") { classProperty.count = 5; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.arrayCount() == 0); } @@ -54,6 +74,7 @@ TEST_CASE("Boolean PropertyView") { classProperty.defaultProperty = false; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.defaultValue()); REQUIRE(!*view.defaultValue()); @@ -66,22 +87,73 @@ TEST_CASE("Boolean PropertyView") { classProperty.defaultProperty = false; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.required()); REQUIRE(!view.defaultValue()); } - SECTION("Returns nullopt for invalid types") { + SECTION("Reports default value invalid type") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.defaultProperty = 1; PropertyView view(classProperty); - REQUIRE(!view.required()); - REQUIRE(!view.defaultValue()); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); } } TEST_CASE("Scalar PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.normalized = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + } + SECTION("Constructs with non-optional properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; @@ -90,6 +162,7 @@ TEST_CASE("Scalar PropertyView") { classProperty.required = true; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.normalized()); REQUIRE(view.required()); @@ -109,6 +182,7 @@ TEST_CASE("Scalar PropertyView") { classProperty.count = 5; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.arrayCount() == 0); } @@ -122,6 +196,7 @@ TEST_CASE("Scalar PropertyView") { classProperty.min = -10; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); REQUIRE(view.scale()); REQUIRE(view.max()); @@ -133,42 +208,6 @@ TEST_CASE("Scalar PropertyView") { REQUIRE(*view.min() == -10); } - SECTION("Returns nullopt for out-of-bounds values") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.offset = 20; - classProperty.scale = 255; - classProperty.max = 127; - classProperty.min = -1000; - - PropertyView view(classProperty); - REQUIRE(view.offset()); - REQUIRE(view.max()); - - REQUIRE(*view.offset() == 20); - REQUIRE(*view.max() == 127); - - REQUIRE(!view.scale()); - REQUIRE(!view.min()); - } - - SECTION("Returns nullopt for invalid types") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.offset = "10"; - classProperty.scale = false; - classProperty.max = 5.5; - classProperty.min = JsonValue::Array{1}; - - PropertyView view(classProperty); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - } - SECTION("Constructs with noData and defaultProperty") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; @@ -199,9 +238,120 @@ TEST_CASE("Scalar PropertyView") { REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.defaultProperty = 2000; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = -129; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = -1000; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = 1000; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = 200; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = 1234; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.defaultProperty = JsonValue::Array{1}; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = "0"; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = -12.7f; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = 5.5; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = false; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = JsonValue::Array{}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } } TEST_CASE("VecN PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT8; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.normalized = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + } + SECTION("Constructs with non-optional properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC3; @@ -253,42 +403,6 @@ TEST_CASE("VecN PropertyView") { REQUIRE(*view.min() == glm::i16vec3(-11, -12, -13)); } - SECTION("Returns nullopt for out-of-bounds values") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC2; - classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.offset = JsonValue::Array{-1, 2}; - classProperty.scale = JsonValue::Array{1, 128}; - classProperty.max = JsonValue::Array{10, 5}; - classProperty.min = JsonValue::Array{-200, 0}; - - PropertyView view(classProperty); - REQUIRE(view.offset()); - REQUIRE(view.max()); - - REQUIRE(*view.offset() == glm::i8vec2(-1, 2)); - REQUIRE(*view.max() == glm::i8vec2(10, 5)); - - REQUIRE(!view.scale()); - REQUIRE(!view.min()); - } - - SECTION("Returns nullopt for invalid types") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC3; - classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.offset = "(1, 2, 3)"; - classProperty.scale = 1; - classProperty.max = JsonValue::Array{10, 20, 30, 40}; - classProperty.min = JsonValue::Array{-10, -1}; - - PropertyView view(classProperty); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - } - SECTION("Constructs with noData and defaultProperty") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC4; @@ -319,48 +433,161 @@ TEST_CASE("VecN PropertyView") { REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); } -} -TEST_CASE("MatN PropertyView") { - SECTION("Constructs with non-optional properties") { + SECTION("Reports errors for out-of-bounds values") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT3; - classProperty.componentType = ClassProperty::ComponentType::INT32; - classProperty.normalized = true; - classProperty.required = true; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.defaultProperty = JsonValue::Array{128, 129}; - PropertyView view(classProperty); - REQUIRE(view.normalized()); - REQUIRE(view.required()); + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = JsonValue::Array{-128, -129}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = JsonValue::Array{-200, 0}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = JsonValue::Array{10, 5}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = JsonValue::Array{1, 128}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = JsonValue::Array{-1, -222}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.defaultProperty = JsonValue::Array{1.0f, 20.9f}; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = "0"; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = JsonValue::Array{-10, -1}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = JsonValue::Array{10, 20, 30, 40}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + classProperty.scale = 1; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = "(1, 2, 3)"; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } +} + +TEST_CASE("MatN PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); REQUIRE(!view.offset()); REQUIRE(!view.scale()); REQUIRE(!view.max()); REQUIRE(!view.min()); + REQUIRE(!view.required()); REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); } - SECTION("Ignores count") { + SECTION("Reports type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT3; - classProperty.componentType = ClassProperty::ComponentType::INT32; - classProperty.count = 5; + classProperty.type = ClassProperty::Type::MAT4; - PropertyView view(classProperty); - REQUIRE(view.arrayCount() == 0); + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); } - SECTION("Constructs with offset, scale, max, and min") { + SECTION("Reports component type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT3; - classProperty.componentType = ClassProperty::ComponentType::INT32; - // clang-format off - classProperty.offset = JsonValue::Array{ - -1, 1, 2, - 3, -1, 4, - -5, -5, 0}; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.normalized = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Constructs with non-optional properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.normalized = true; + classProperty.required = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.normalized()); + REQUIRE(view.required()); + + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Ignores count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.count = 5; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.arrayCount() == 0); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + // clang-format off + classProperty.offset = JsonValue::Array{ + -1, 1, 2, + 3, -1, 4, + -5, -5, 0}; classProperty.scale = JsonValue::Array{ 1, 1, 1, 2, 2, 3, @@ -376,6 +603,7 @@ TEST_CASE("MatN PropertyView") { // clang-format on PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); REQUIRE(view.scale()); REQUIRE(view.max()); @@ -408,61 +636,6 @@ TEST_CASE("MatN PropertyView") { // clang-format on } - SECTION("Returns nullopt for out-of-bounds values") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT2; - classProperty.componentType = ClassProperty::ComponentType::INT8; - // clang-format off - classProperty.offset = JsonValue::Array{ - -1, 2, - 129, -2}; - classProperty.scale = JsonValue::Array{ - 1, 7, - 4, 6}; - classProperty.max = JsonValue::Array{ - 10, 240, - 1, 8}; - classProperty.min = JsonValue::Array{ - -29, -40, - -55, -43}; - // clang-format on - - PropertyView view(classProperty); - REQUIRE(view.scale()); - REQUIRE(view.min()); - - // clang-format off - glm::i8mat2x2 expectedScale( - 1, 7, - 4, 6); - REQUIRE(*view.scale() == expectedScale); - - glm::i8mat2x2 expectedMin( - -29, -40, - -55, -43); - REQUIRE(*view.min() == expectedMin); - // clang-format on - - REQUIRE(!view.offset()); - REQUIRE(!view.max()); - } - - SECTION("Returns nullopt for invalid types") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT2; - classProperty.componentType = ClassProperty::ComponentType::UINT8; - classProperty.offset = "(1, 2, 3, 4)"; - classProperty.scale = 1; - classProperty.max = JsonValue::Array{10, 20, 30, 40, 50}; - classProperty.min = JsonValue::Array{0, 0}; - - PropertyView view(classProperty); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - } - SECTION("Constructs with noData and defaultProperty") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT2; @@ -478,6 +651,7 @@ TEST_CASE("MatN PropertyView") { // clang-format on PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.noData()); REQUIRE(view.defaultValue()); @@ -509,13 +683,139 @@ TEST_CASE("MatN PropertyView") { // clang-format on PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.required()); REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + + // clang-format off + classProperty.defaultProperty = JsonValue::Array{ + 999, 1, + 2, 0}; + // clang-format on + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + // clang-format off + classProperty.noData = JsonValue::Array{ + 0, 0, + 1, -129}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + // clang-format off + classProperty.min = JsonValue::Array{ + -29, -40, + -55, -43}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + // clang-format off + classProperty.max = JsonValue::Array{ + 10, 240, + 1, 8}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + //clang-format off + classProperty.scale = JsonValue::Array{1, 197, 4, 6}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + // clang-format off + classProperty.offset = JsonValue::Array{ + -1, 2, + 129, -2}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + + // clang-format off + classProperty.defaultProperty = JsonValue::Array{ + JsonValue::Array{ + 999, 1, + 2, 0} + }; + // clang-format on + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + // clang-format off + classProperty.noData = JsonValue::Array{ + 0.45, 0.0, + 1.0, -1.4}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = JsonValue::Array{0, 0}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = JsonValue::Array{10, 20, 30, 40, 50}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = 1; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = "(1, 2, 3, 4)"; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } } TEST_CASE("String PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + SECTION("Ignores non-applicable properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; @@ -585,9 +885,42 @@ TEST_CASE("String PropertyView") { } TEST_CASE("Boolean Array PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView> view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = false; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + SECTION("Ignores non-applicable properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.array = true; classProperty.normalized = true; classProperty.offset = JsonValue::Array{true}; classProperty.scale = JsonValue::Array{true}; @@ -643,7 +976,7 @@ TEST_CASE("Boolean Array PropertyView") { REQUIRE(!view.defaultValue()); } - SECTION("Returns nullopt for invalid types") { + SECTION("Reports errors for invalid types") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.array = true; @@ -655,6 +988,198 @@ TEST_CASE("Boolean Array PropertyView") { } } +TEST_CASE("Scalar Array PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView> view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = false; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.normalized = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Constructs with non-optional properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + classProperty.normalized = true; + classProperty.required = true; + + PropertyView> view(classProperty); + REQUIRE(view.normalized()); + REQUIRE(view.required()); + + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Constructs with count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + classProperty.count = 5; + + PropertyView> view(classProperty); + REQUIRE(view.arrayCount() == *classProperty.count); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.array = true; + classProperty.offset = JsonValue::Array{5, 10}; + classProperty.scale = JsonValue::Array{2, 1}; + classProperty.max = JsonValue::Array{10, 20}; + classProperty.min = JsonValue::Array{-10, -1}; + + PropertyView> view(classProperty); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); + + PropertyArrayView offset = *view.offset(); + REQUIRE(offset.size() == 2); + REQUIRE(offset[0] == 5); + REQUIRE(offset[1] == 10); + + PropertyArrayView scale = *view.scale(); + REQUIRE(scale.size() == 2); + REQUIRE(scale[0] == 2); + REQUIRE(scale[1] == 1); + + PropertyArrayView max = *view.max(); + REQUIRE(max.size() == 2); + REQUIRE(max[0] == 10); + REQUIRE(max[1] == 20); + + PropertyArrayView min = *view.min(); + REQUIRE(min.size() == 2); + REQUIRE(min[0] == -10); + REQUIRE(min[1] == -1); + } + + SECTION("Returns nullopt for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.offset = 20; + classProperty.scale = 255; + classProperty.max = 127; + classProperty.min = -1000; + + PropertyView view(classProperty); + REQUIRE(view.offset()); + REQUIRE(view.max()); + + REQUIRE(*view.offset() == 20); + REQUIRE(*view.max() == 127); + + REQUIRE(!view.scale()); + REQUIRE(!view.min()); + } + + SECTION("Returns nullopt for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.offset = "10"; + classProperty.scale = false; + classProperty.max = 5.5; + classProperty.min = JsonValue::Array{1}; + + PropertyView view(classProperty); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.required = false; + classProperty.noData = 0; + classProperty.defaultProperty = 1; + + PropertyView view(classProperty); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + REQUIRE(*view.noData() == 0); + REQUIRE(*view.defaultValue() == 1); + } + + SECTION("Ignores noData and defaultProperty when required is true") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.required = true; + classProperty.noData = 0; + classProperty.defaultProperty = 1; + + PropertyView view(classProperty); + REQUIRE(view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } +} + TEST_CASE("String Array PropertyView") { SECTION("Ignores non-applicable properties") { ClassProperty classProperty; From 38a595537d985e2202ff0097639125734ca44c89 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 17 Aug 2023 15:38:17 -0400 Subject: [PATCH 075/121] Finish unit tests for PropertyView --- .../CesiumGltf/PropertyTablePropertyView.h | 6 +- CesiumGltf/include/CesiumGltf/PropertyView.h | 28 +- CesiumGltf/test/TestPropertyView.cpp | 848 +++++++++++++++--- 3 files changed, 770 insertions(+), 112 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 6c0d269b1..065fb0162 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -178,8 +178,7 @@ class PropertyTablePropertyView : public PropertyView { _arrayOffsetTypeSize{0}, _stringOffsets{}, _stringOffsetType{PropertyComponentType::None}, - _stringOffsetTypeSize{0} - { + _stringOffsetTypeSize{0} { assert( _status != PropertyTablePropertyViewStatus::Valid && "An empty property view should not be constructed with a valid status"); @@ -206,8 +205,7 @@ class PropertyTablePropertyView : public PropertyView { _arrayOffsetTypeSize{0}, _stringOffsets{}, _stringOffsetType{PropertyComponentType::None}, - _stringOffsetTypeSize{0} - {} + _stringOffsetTypeSize{0} {} /** * @brief Construct a valid instance pointing to the data specified by diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index e897be9b3..56fa1a6ac 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -243,14 +243,14 @@ class PropertyView : IPropertyView { PropertyComponentType componentType = TypeToPropertyType::component; switch (componentType) { - case PropertyComponentType::Uint8: case PropertyComponentType::Int8: - case PropertyComponentType::Uint16: + case PropertyComponentType::Uint8: case PropertyComponentType::Int16: - case PropertyComponentType::Uint32: + case PropertyComponentType::Uint16: case PropertyComponentType::Int32: - case PropertyComponentType::Uint64: + case PropertyComponentType::Uint32: case PropertyComponentType::Int64: + case PropertyComponentType::Uint64: break; default: _status = PropertyViewStatus::ErrorInvalidNormalization; @@ -947,9 +947,23 @@ class PropertyView> return; } - if (classProperty.normalized && !IsMetadataInteger::value) { - _status = PropertyViewStatus::ErrorInvalidNormalization; - return; + if (classProperty.normalized) { + PropertyComponentType componentType = + TypeToPropertyType::component; + switch (componentType) { + case PropertyComponentType::Int8: + case PropertyComponentType::Uint8: + case PropertyComponentType::Int16: + case PropertyComponentType::Uint16: + case PropertyComponentType::Int32: + case PropertyComponentType::Uint32: + case PropertyComponentType::Int64: + case PropertyComponentType::Uint64: + break; + default: + _status = PropertyViewStatus::ErrorInvalidNormalization; + return; + } } // If the property has its own values, override the class-provided values. diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp index 3bc1b9ec7..f6fc099c2 100644 --- a/CesiumGltf/test/TestPropertyView.cpp +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -217,6 +217,7 @@ TEST_CASE("Scalar PropertyView") { classProperty.defaultProperty = 1; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.noData()); REQUIRE(view.defaultValue()); @@ -234,6 +235,7 @@ TEST_CASE("Scalar PropertyView") { classProperty.defaultProperty = 1; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.required()); REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); @@ -360,6 +362,7 @@ TEST_CASE("VecN PropertyView") { classProperty.required = true; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.normalized()); REQUIRE(view.required()); @@ -379,6 +382,7 @@ TEST_CASE("VecN PropertyView") { classProperty.count = 5; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.arrayCount() == 0); } @@ -386,12 +390,13 @@ TEST_CASE("VecN PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC3; classProperty.componentType = ClassProperty::ComponentType::INT16; - classProperty.offset = JsonValue::Array{-1, 1, 2}; - classProperty.scale = JsonValue::Array{2, 1, 3}; - classProperty.max = JsonValue::Array{10, 5, 6}; - classProperty.min = JsonValue::Array{-11, -12, -13}; + classProperty.offset = {-1, 1, 2}; + classProperty.scale = {2, 1, 3}; + classProperty.max = {10, 5, 6}; + classProperty.min = {-11, -12, -13}; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); REQUIRE(view.scale()); REQUIRE(view.max()); @@ -408,10 +413,11 @@ TEST_CASE("VecN PropertyView") { classProperty.type = ClassProperty::Type::VEC4; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.required = false; - classProperty.noData = JsonValue::Array{0.0f, 0.0f, 0.0f, 0.0f}; - classProperty.defaultProperty = JsonValue::Array{1.0f, 2.0f, 3.0f, 4.0f}; + classProperty.noData = {0.0f, 0.0f, 0.0f, 0.0f}; + classProperty.defaultProperty = {1.0f, 2.0f, 3.0f, 4.0f}; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.noData()); REQUIRE(view.defaultValue()); @@ -425,10 +431,11 @@ TEST_CASE("VecN PropertyView") { classProperty.type = ClassProperty::Type::VEC4; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.required = true; - classProperty.noData = JsonValue::Array{0.0f, 0.0f, 0.0f, 0.0f}; - classProperty.defaultProperty = JsonValue::Array{1.0f, 2.0f, 3.0f, 4.0f}; + classProperty.noData = {0.0f, 0.0f, 0.0f, 0.0f}; + classProperty.defaultProperty = {1.0f, 2.0f, 3.0f, 4.0f}; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.required()); REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); @@ -438,28 +445,28 @@ TEST_CASE("VecN PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC2; classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.defaultProperty = JsonValue::Array{128, 129}; + classProperty.defaultProperty = {128, 129}; PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); - classProperty.noData = JsonValue::Array{-128, -129}; + classProperty.noData = {-128, -129}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); - classProperty.min = JsonValue::Array{-200, 0}; + classProperty.min = {-200, 0}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); - classProperty.max = JsonValue::Array{10, 5}; + classProperty.max = {10, 5}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); - classProperty.scale = JsonValue::Array{1, 128}; + classProperty.scale = {1, 128}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); - classProperty.offset = JsonValue::Array{-1, -222}; + classProperty.offset = {-1, -222}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } @@ -468,7 +475,7 @@ TEST_CASE("VecN PropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC2; classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.defaultProperty = JsonValue::Array{1.0f, 20.9f}; + classProperty.defaultProperty = {1.0f, 20.9f}; PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); @@ -477,11 +484,11 @@ TEST_CASE("VecN PropertyView") { view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); - classProperty.min = JsonValue::Array{-10, -1}; + classProperty.min = {-10, -1}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); - classProperty.max = JsonValue::Array{10, 20, 30, 40}; + classProperty.max = {10, 20, 30, 40}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); @@ -584,19 +591,19 @@ TEST_CASE("MatN PropertyView") { classProperty.type = ClassProperty::Type::MAT3; classProperty.componentType = ClassProperty::ComponentType::INT32; // clang-format off - classProperty.offset = JsonValue::Array{ + classProperty.offset = { -1, 1, 2, 3, -1, 4, -5, -5, 0}; - classProperty.scale = JsonValue::Array{ + classProperty.scale = { 1, 1, 1, 2, 2, 3, 3, 4, 5}; - classProperty.max = JsonValue::Array{ + classProperty.max = { 20, 5, 20, 30, 22, 43, 37, 1, 8}; - classProperty.min = JsonValue::Array{ + classProperty.min = { -10, -2, -3, 0, 20, 4, 9, 4, 5}; @@ -642,10 +649,10 @@ TEST_CASE("MatN PropertyView") { classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.required = false; // clang-format off - classProperty.noData = JsonValue::Array{ + classProperty.noData = { 0.0f, 0.0f, 0.0f, 0.0f}; - classProperty.defaultProperty = JsonValue::Array{ + classProperty.defaultProperty = { 1.0f, 2.0f, 3.0f, 4.0f}; // clang-format on @@ -674,10 +681,10 @@ TEST_CASE("MatN PropertyView") { classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.required = true; // clang-format off - classProperty.noData = JsonValue::Array{ + classProperty.noData = { 0.0f, 0.0f, 0.0f, 0.0f}; - classProperty.defaultProperty = JsonValue::Array{ + classProperty.defaultProperty = { 1.0f, 2.0f, 3.0f, 4.0f}; // clang-format on @@ -695,7 +702,7 @@ TEST_CASE("MatN PropertyView") { classProperty.componentType = ClassProperty::ComponentType::INT8; // clang-format off - classProperty.defaultProperty = JsonValue::Array{ + classProperty.defaultProperty = { 999, 1, 2, 0}; // clang-format on @@ -704,7 +711,7 @@ TEST_CASE("MatN PropertyView") { REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); // clang-format off - classProperty.noData = JsonValue::Array{ + classProperty.noData = { 0, 0, 1, -129}; // clang-format on @@ -712,7 +719,7 @@ TEST_CASE("MatN PropertyView") { REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); // clang-format off - classProperty.min = JsonValue::Array{ + classProperty.min = { -29, -40, -55, -43}; // clang-format on @@ -720,7 +727,7 @@ TEST_CASE("MatN PropertyView") { REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); // clang-format off - classProperty.max = JsonValue::Array{ + classProperty.max = { 10, 240, 1, 8}; // clang-format on @@ -728,13 +735,13 @@ TEST_CASE("MatN PropertyView") { REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); //clang-format off - classProperty.scale = JsonValue::Array{1, 197, 4, 6}; + classProperty.scale = {1, 197, 4, 6}; // clang-format on view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); // clang-format off - classProperty.offset = JsonValue::Array{ + classProperty.offset = { -1, 2, 129, -2}; // clang-format on @@ -748,29 +755,26 @@ TEST_CASE("MatN PropertyView") { classProperty.componentType = ClassProperty::ComponentType::INT8; // clang-format off - classProperty.defaultProperty = JsonValue::Array{ - JsonValue::Array{ - 999, 1, - 2, 0} - }; + classProperty.defaultProperty = + JsonValue::Array{JsonValue::Array{999, 1, 2, 0}}; // clang-format on PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); // clang-format off - classProperty.noData = JsonValue::Array{ + classProperty.noData = { 0.45, 0.0, 1.0, -1.4}; // clang-format on view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); - classProperty.min = JsonValue::Array{0, 0}; + classProperty.min = {0, 0}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); - classProperty.max = JsonValue::Array{10, 20, 30, 40, 50}; + classProperty.max = {10, 20, 30, 40, 50}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); @@ -826,6 +830,7 @@ TEST_CASE("String PropertyView") { classProperty.min = "min"; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.normalized()); REQUIRE(!view.offset()); REQUIRE(!view.scale()); @@ -839,6 +844,7 @@ TEST_CASE("String PropertyView") { classProperty.count = 5; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.arrayCount() == 0); } @@ -850,6 +856,7 @@ TEST_CASE("String PropertyView") { classProperty.defaultProperty = "default"; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.noData()); REQUIRE(view.defaultValue()); @@ -866,21 +873,23 @@ TEST_CASE("String PropertyView") { classProperty.defaultProperty = "default"; PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.required()); REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); } - SECTION("Returns nullopt for invalid types") { + SECTION("Reports errors for invalid types") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; - classProperty.noData = JsonValue::Array{"null"}; classProperty.defaultProperty = true; PropertyView view(classProperty); - REQUIRE(!view.required()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = JsonValue::Array{"null"}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); } } @@ -910,7 +919,7 @@ TEST_CASE("Boolean Array PropertyView") { SECTION("Reports array type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::STRING; + classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.array = false; PropertyView> view(classProperty); @@ -929,6 +938,7 @@ TEST_CASE("Boolean Array PropertyView") { classProperty.noData = JsonValue::Array{true}; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.normalized()); REQUIRE(!view.offset()); REQUIRE(!view.scale()); @@ -944,6 +954,7 @@ TEST_CASE("Boolean Array PropertyView") { classProperty.count = 5; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.arrayCount() == 5); } @@ -955,10 +966,11 @@ TEST_CASE("Boolean Array PropertyView") { classProperty.defaultProperty = JsonValue::Array{false, true}; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.defaultValue()); - const auto defaultValue = *view.defaultValue(); + PropertyArrayView defaultValue = *view.defaultValue(); REQUIRE(defaultValue.size() == 2); REQUIRE(!defaultValue[0]); REQUIRE(defaultValue[1]); @@ -972,6 +984,7 @@ TEST_CASE("Boolean Array PropertyView") { classProperty.defaultProperty = JsonValue::Array{false, true}; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.required()); REQUIRE(!view.defaultValue()); } @@ -983,8 +996,7 @@ TEST_CASE("Boolean Array PropertyView") { classProperty.defaultProperty = true; PropertyView> view(classProperty); - REQUIRE(!view.required()); - REQUIRE(!view.defaultValue()); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); } } @@ -1052,6 +1064,7 @@ TEST_CASE("Scalar Array PropertyView") { classProperty.required = true; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.normalized()); REQUIRE(view.required()); @@ -1072,6 +1085,7 @@ TEST_CASE("Scalar Array PropertyView") { classProperty.count = 5; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.arrayCount() == *classProperty.count); } @@ -1086,101 +1100,726 @@ TEST_CASE("Scalar Array PropertyView") { classProperty.min = JsonValue::Array{-10, -1}; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); REQUIRE(view.scale()); REQUIRE(view.max()); REQUIRE(view.min()); - PropertyArrayView offset = *view.offset(); - REQUIRE(offset.size() == 2); - REQUIRE(offset[0] == 5); - REQUIRE(offset[1] == 10); + PropertyArrayView value = *view.offset(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == 5); + REQUIRE(value[1] == 10); - PropertyArrayView scale = *view.scale(); - REQUIRE(scale.size() == 2); - REQUIRE(scale[0] == 2); - REQUIRE(scale[1] == 1); + value = *view.scale(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == 2); + REQUIRE(value[1] == 1); - PropertyArrayView max = *view.max(); - REQUIRE(max.size() == 2); - REQUIRE(max[0] == 10); - REQUIRE(max[1] == 20); + value = *view.max(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == 10); + REQUIRE(value[1] == 20); - PropertyArrayView min = *view.min(); - REQUIRE(min.size() == 2); - REQUIRE(min[0] == -10); - REQUIRE(min[1] == -1); + value = *view.min(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == -10); + REQUIRE(value[1] == -1); } - SECTION("Returns nullopt for out-of-bounds values") { + SECTION("Constructs with noData and defaultProperty") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + classProperty.required = false; + classProperty.noData = {0, 1}; + classProperty.defaultProperty = {2, 3}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + PropertyArrayView value = view.noData().value(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == 0); + REQUIRE(value[1] == 1); + + value = *view.defaultValue(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == 2); + REQUIRE(value[1] == 3); + } + + SECTION("Ignores noData and defaultProperty when required is true") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + classProperty.required = true; + classProperty.noData = {0, 1}; + classProperty.defaultProperty = {2, 3}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + classProperty.defaultProperty = {256, 256}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = {-1, 0}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = {0, -1}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {256, 255}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = {20, 300}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = {2, -100}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + classProperty.defaultProperty = "[256, 256]"; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = 0; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = false; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = JsonValue::Array{10.4, 30.0}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = JsonValue::Array{JsonValue::Array{2.3, 3.04}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = "10"; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } +} + +TEST_CASE("VecN Array PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView> view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.array = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.offset = 20; - classProperty.scale = 255; - classProperty.max = 127; - classProperty.min = -1000; + classProperty.array = true; - PropertyView view(classProperty); + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = false; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.normalized = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Constructs with non-optional properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.array = true; + classProperty.normalized = true; + classProperty.required = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.normalized()); + REQUIRE(view.required()); + + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Constructs with count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.array = true; + classProperty.count = 5; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.arrayCount() == classProperty.count); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + classProperty.offset = {{-1, 1, 2}, {4, 4, 0}}; + classProperty.scale = {{2, 1, 3}, {8, 2, 3}}; + classProperty.max = {{14, 28, 12}, {10, 5, 6}}; + classProperty.min = {{-11, -12, -13}, {-2, -4, 6}}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); + REQUIRE(view.scale()); REQUIRE(view.max()); + REQUIRE(view.min()); + + PropertyArrayView value = *view.offset(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8vec3(-1, 1, 2)); + REQUIRE(value[1] == glm::i8vec3(4, 4, 0)); + + value = *view.scale(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8vec3(2, 1, 3)); + REQUIRE(value[1] == glm::i8vec3(8, 2, 3)); + + value = *view.max(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8vec3(14, 28, 12)); + REQUIRE(value[1] == glm::i8vec3(10, 5, 6)); + + value = *view.min(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8vec3(-11, -12, -13)); + REQUIRE(value[1] == glm::i8vec3(-2, -4, 6)); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.required = false; + classProperty.noData = {{0.0f, 0.0f}, {1.0f, 2.0f}}; + classProperty.defaultProperty = {{3.0f, 4.0f}, {5.0f, 6.0f}}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + PropertyArrayView value = *view.noData(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::vec2(0.0f, 0.0f)); + REQUIRE(value[1] == glm::vec2(1.0f, 2.0f)); + + value = *view.defaultValue(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::vec2(3.0f, 4.0f)); + REQUIRE(value[1] == glm::vec2(5.0f, 6.0f)); + } + + SECTION("Ignores noData and defaultProperty when required is true") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.required = true; + classProperty.noData = {{0.0f, 0.0f}, {1.0f, 2.0f}}; + classProperty.defaultProperty = {{3.0f, 4.0f}, {5.0f, 6.0f}}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + classProperty.defaultProperty = {{128, 129}, {0, 2}}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = {{0, 0}, {-128, -129}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = {{-2, -3}, {-200, 0}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {{10, 5}, {808, 3}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = {{1, 128}, {2, 2}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = {{0, 0}, {-1, -222}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + classProperty.defaultProperty = {1, 20}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = JsonValue::Array{{2.0f, 5.4f}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); - REQUIRE(*view.offset() == 20); - REQUIRE(*view.max() == 127); + classProperty.min = {{-10, -1, 4}, {0, 0, 0}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {{10, 20, 30, 40}, {1, 2, 3, 4}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = 2; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = "(1, 2)"; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } +} +TEST_CASE("MatN Array PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView> view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); REQUIRE(!view.scale()); + REQUIRE(!view.max()); REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); } - SECTION("Returns nullopt for invalid types") { + SECTION("Reports type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::SCALAR; + classProperty.type = ClassProperty::Type::MAT4; + classProperty.array = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.offset = "10"; - classProperty.scale = false; - classProperty.max = 5.5; - classProperty.min = JsonValue::Array{1}; + classProperty.array = true; - PropertyView view(classProperty); + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = false; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.normalized = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Constructs with non-optional properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.normalized = true; + classProperty.required = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.normalized()); + REQUIRE(view.required()); + + REQUIRE(view.arrayCount() == 0); REQUIRE(!view.offset()); REQUIRE(!view.scale()); REQUIRE(!view.max()); REQUIRE(!view.min()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Constructs with count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.count = 5; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.arrayCount() == classProperty.count); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + // clang-format off + classProperty.offset = { + {-1, 1, + 0, 2}, + {2, 40, + 6, -8}, + }; + classProperty.scale = { + {1, 1, + 1, 0}, + {-2, 5, + 7, 1} + }; + classProperty.max = { + {2, 4, + 8, 0}, + {-7, 8, + 4, 4}, + }; + classProperty.min = { + {-1, -6, + -1, 2}, + {0, 1, + 2, 3}, + }; + // clang-format on + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); + + PropertyArrayView value = *view.offset(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8mat2x2(-1, 1, 0, 2)); + REQUIRE(value[1] == glm::i8mat2x2(2, 40, 6, -8)); + + value = *view.scale(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8mat2x2(1, 1, 1, 0)); + REQUIRE(value[1] == glm::i8mat2x2(-2, 5, 7, 1)); + + value = *view.max(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8mat2x2(2, 4, 8, 0)); + REQUIRE(value[1] == glm::i8mat2x2(-7, 8, 4, 4)); + + value = *view.min(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8mat2x2(-1, -6, -1, 2)); + REQUIRE(value[1] == glm::i8mat2x2(0, 1, 2, 3)); } SECTION("Constructs with noData and defaultProperty") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; classProperty.required = false; - classProperty.noData = 0; - classProperty.defaultProperty = 1; + // clang-format off + classProperty.noData = { + {0, 0, + 0, 0}, + {-1, -1, + -1, -1}, + }; + classProperty.defaultProperty = { + {1, 1, + 1, 1}, + {2, 2, + 2, 2}, + }; + // clang-format on - PropertyView view(classProperty); + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.noData()); REQUIRE(view.defaultValue()); - REQUIRE(*view.noData() == 0); - REQUIRE(*view.defaultValue() == 1); + PropertyArrayView value = *view.noData(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8mat2x2(0, 0, 0, 0)); + REQUIRE(value[1] == glm::i8mat2x2(-1, -1, -1, -1)); + + value = view.defaultValue().value(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8mat2x2(1, 1, 1, 1)); + REQUIRE(value[1] == glm::i8mat2x2(2, 2, 2, 2)); } SECTION("Ignores noData and defaultProperty when required is true") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; classProperty.required = true; - classProperty.noData = 0; - classProperty.defaultProperty = 1; + // clang-format off + classProperty.noData = { + {0, 0, + 0, 0}, + {-1, -1, + -1, -1}, + }; + classProperty.defaultProperty = { + {1, 1, + 1, 1}, + {2, 2, + 2, 2}, + }; + // clang-format on - PropertyView view(classProperty); + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.required()); REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + + // clang-format off + classProperty.defaultProperty = { + {1, 1, + 1, 290}, + {2, 2, + 2, 2}, + }; + // clang-format on + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + // clang-format off + classProperty.noData = { + {0, 0, + 0, 0}, + {-140, -1, + -1, -1}, + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + // clang-format off + classProperty.min = { + {-129, 0, + 0, 0}, + {-1, -1, + -1, -1}, + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + // clang-format off + classProperty.max = { + {-128, 189, + 20, 2}, + {10, 12, + 8, 4}, + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + //clang-format off + classProperty.scale = { + {1, 2, 3, 4}, + {256, 80, 9, 52}, + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + // clang-format off + classProperty.offset = { + {129, 0, + 0, 2}, + {4, 0, + 0, 8},}; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + classProperty.defaultProperty = {4, 1, 2, 0}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + // clang-format off + classProperty.noData = { + {0.45, 0.0, + 1.0, -1.4} + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = {{0, 1, 2, 3, 4, 5, 6}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {{0, 1, 2, 3}, false}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = 1; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = "[(1, 2, 3, 4)]"; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } } TEST_CASE("String Array PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView> view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.array = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = false; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + SECTION("Ignores non-applicable properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; @@ -1192,6 +1831,7 @@ TEST_CASE("String Array PropertyView") { classProperty.min = {"min"}; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.normalized()); REQUIRE(!view.offset()); REQUIRE(!view.scale()); @@ -1206,6 +1846,7 @@ TEST_CASE("String Array PropertyView") { classProperty.count = 5; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.arrayCount() == classProperty.count); } @@ -1214,10 +1855,11 @@ TEST_CASE("String Array PropertyView") { classProperty.type = ClassProperty::Type::STRING; classProperty.array = true; classProperty.required = false; - classProperty.noData = JsonValue::Array{"null", "0"}; - classProperty.defaultProperty = JsonValue::Array{"default1", "default2"}; + classProperty.noData = {"null", "0"}; + classProperty.defaultProperty = {"default1", "default2"}; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.noData()); REQUIRE(view.defaultValue()); @@ -1236,25 +1878,29 @@ TEST_CASE("String Array PropertyView") { SECTION("Ignores noData and defaultProperty when required is true") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; classProperty.required = true; - classProperty.noData = JsonValue::Array{"null", "0"}; - classProperty.defaultProperty = JsonValue::Array{"default1", "default2"}; + classProperty.noData = {"null", "0"}; + classProperty.defaultProperty = {"default1", "default2"}; PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.required()); REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); } - SECTION("Returns nullopt for invalid types") { + SECTION("Reports errors for invalid types") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; - classProperty.noData = JsonValue::Array{"null"}; + classProperty.array = true; classProperty.defaultProperty = true; - PropertyView view(classProperty); - REQUIRE(!view.required()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = JsonValue::Array{"null", 0}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); } } From 5da1ca3e789351b2c785209a693866f6693be7ac Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 18 Aug 2023 14:19:40 -0400 Subject: [PATCH 076/121] Add templating for normalization --- .../include/CesiumGltf/PropertyArrayView.h | 76 +++++++ .../CesiumGltf/PropertyTablePropertyView.h | 206 ++++++++++++++++-- .../include/CesiumGltf/PropertyTypeTraits.h | 12 + CesiumGltf/include/CesiumGltf/PropertyView.h | 164 +++++++------- CesiumGltf/test/TestPropertyView.cpp | 11 + 5 files changed, 378 insertions(+), 91 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index 987908925..0fa14eb77 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -56,6 +56,61 @@ template class PropertyArrayView { _values); } + bool operator==(const PropertyArrayView& other) const noexcept { + for (int64_t i = 0; i < size(); i++) { + if ((*this)[i] != other[i]) { + return false; + } + } + + return true; + } + + PropertyArrayView + operator*(const PropertyArrayView& other) { + int64_t clampedSize = std::min(this->size(), other.size()); + std::vector result(static_cast(this->size())); + if constexpr (IsMetadataMatN::value) { + // Do component-wise multiplication instead of actual matrix + // multiplication. + ElementType matN; + constexpr glm::length_t N = ElementType::length(); + for (int64_t i = 0; i < clampedSize; i++) { + for (glm::length_t j = 0; j < N; j++) { + matN[j] = (*this)[i][j] * other[i][j]; + } + result[i] = matN; + } + } else { + for (int64_t i = 0; i < clampedSize; i++) { + result[i] = (*this)[i] * other[i]; + } + } + + // Copy anything that didn't have a component to multiply against. + for (int64_t i = clampedSize(); i < this->size(); i++) { + result[i] = (*this)[i]; + } + + return PropertyArrayView(std::move(result)); + } + + PropertyArrayView + operator+(const PropertyArrayView& other) { + int64_t clampedSize = std::min(this->size(), other.size()); + std::vector result(static_cast(this->size())); + for (int64_t i = 0; i < clampedSize; i++) { + result[i] = (*this)[i] + other[i]; + } + + // Copy anything that didn't have a component to multiply against. + for (int64_t i = clampedSize(); i < this->size(); i++) { + result[i] = (*this)[i]; + } + + return PropertyArrayView(std::move(result)); + } + private: using ArrayType = std::variant, std::vector>; @@ -93,6 +148,16 @@ template <> class PropertyArrayView { int64_t size() const noexcept { return _size; } + bool operator==(const PropertyArrayView& other) const noexcept { + for (int64_t i = 0; i < size(); i++) { + if ((*this)[i] != other[i]) { + return false; + } + } + + return true; + } + private: gsl::span _values; int64_t _bitOffset = 0; @@ -142,6 +207,17 @@ template <> class PropertyArrayView { int64_t size() const noexcept { return _size; } + bool + operator==(const PropertyArrayView& other) const noexcept { + for (int64_t i = 0; i < size(); i++) { + if ((*this)[i] != other[i]) { + return false; + } + } + + return true; + } + private: gsl::span _values; gsl::span _stringOffsets; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 065fb0162..3bceaa7d4 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -1,6 +1,7 @@ #pragma once #include "CesiumGltf/PropertyArrayView.h" +//#include "CesiumGltf/PropertyConversions.h" #include "CesiumGltf/PropertyTypeTraits.h" #include "CesiumGltf/PropertyView.h" @@ -185,11 +186,12 @@ class PropertyTablePropertyView : public PropertyView { } /** - * @brief Construct a valid instance pointing to non-array data specified by - * a {@link PropertyTableProperty}. - * @param values The raw buffer specified by {@link PropertyTableProperty::values} + * @brief Construct an instance pointing to non-array data specified by a {@link PropertyTableProperty}. + * + * @param property The {@link PropertyTableProperty} + * @param classProperty The {@link ClassProperty} this property conforms to. * @param size The number of elements in the property table specified by {@link PropertyTable::count} - * @param normalized Whether this property has a normalized integer type. + * @param value The raw buffer specified by {@link PropertyTableProperty::values} */ PropertyTablePropertyView( const PropertyTableProperty& property, @@ -198,27 +200,32 @@ class PropertyTablePropertyView : public PropertyView { gsl::span values) noexcept : PropertyView(classProperty, property), _status{PropertyTablePropertyViewStatus::Valid}, - _values{values}, - _size{size}, + _values{}, + _size{}, _arrayOffsets{}, _arrayOffsetType{PropertyComponentType::None}, _arrayOffsetTypeSize{0}, _stringOffsets{}, _stringOffsetType{PropertyComponentType::None}, - _stringOffsetTypeSize{0} {} + _stringOffsetTypeSize{0} { + if (PropertyView::status() == PropertyTablePropertyViewStatus::Valid) { + _values = values; + _size = size; + } + } /** - * @brief Construct a valid instance pointing to the data specified by - * a {@link PropertyTableProperty}. + * @brief Construct an instance pointing to the data specified by a {@link PropertyTableProperty}. + * + * + * @param property The {@link PropertyTableProperty} + * @param classProperty The {@link ClassProperty} this property conforms to. + * @param size The number of elements in the property table specified by {@link PropertyTable::count} * @param values The raw buffer specified by {@link PropertyTableProperty::values} * @param arrayOffsets The raw buffer specified by {@link PropertyTableProperty::arrayOffsets} * @param stringOffsets The raw buffer specified by {@link PropertyTableProperty::stringOffsets} * @param offsetType The offset type of arrayOffsets specified by {@link PropertyTableProperty::arrayOffsetType} * @param offsetType The offset type of stringOffsets specified by {@link PropertyTableProperty::stringOffsetType} - * @param arrayCount The number of elements in each array value specified by {@link ClassProperty::count} - * @param size The number of elements in the property table specified by {@link PropertyTable::count} - * @param normalized Whether this property has a normalized integer - * type. */ PropertyTablePropertyView( const PropertyTableProperty& property, @@ -238,7 +245,12 @@ class PropertyTablePropertyView : public PropertyView { _stringOffsets{stringOffsets}, _stringOffsetType{stringOffsetType}, _stringOffsetTypeSize{getOffsetTypeSize(stringOffsetType)}, - _size{size} {} + _size{size} { + if (PropertyView::status() == PropertyTablePropertyViewStatus::Valid) { + _values = values; + _size = size; + } + } /** * @copydoc IPropertyView::status @@ -246,7 +258,12 @@ class PropertyTablePropertyView : public PropertyView { virtual int32_t status() const noexcept override { return _status; } /** - * @brief Get the value of an element of the {@link PropertyTable}. + * @brief Get the raw value of an element of the {@link PropertyTable}, + * without offset, scale, or normalization applied. + * + * If this property has a "no data" value defined, the raw value will still be + * returned, even if it equals the "no data" value. + * * @param index The element index * @return The value of the element */ @@ -286,6 +303,48 @@ class PropertyTablePropertyView : public PropertyView { } } + ///** + // * @brief Gets the value of an element in the {@link PropertyTable} as an instance + // * of T. If T is not the same as the ElementType of the property, then + // * this attempts to convert it to the desired type. If such a conversion is + // * not possible, this returns std::nullopt. + // * + // * If this property contains a "no data" sentinel value, then std::nullopt is + // * returned for any raw values that equal the sentinel value. If a default + // * value is supplied, then it will be returned instead. + // * + // * If this property is affected by offset, scale, and / or normalization, + // * the value will be transformed before conversion like so: + // * + // * transformedValue = offset + scale * normalize(value) + // * + // * The transformed value will then attempt to be converted to the desired type + // * T. + // * + // * @param index The element index + // * @return The value of the element as T, or std::nullopt if conversion fails. + // */ + //template + //std::optional getAs(int64_t index) const noexcept { + // assert( + // _status == PropertyTablePropertyViewStatus::Valid && + // "Check the status() first to make sure view is valid"); + // assert( + // size() > 0 && + // "Check the size() of the view to make sure it's not empty"); + // assert(index >= 0 && "index must be non-negative"); + // assert(index < size() && "index must be less than size"); + // ElementType result = getRaw(index); + + // if (noData() && result == *noData()) { + // return defaultValue() ? *defaultValue() : std::nullopt; + // } + + // // apply transform + + // return PropertyConversions::convert(result); + //} + /** * @brief Get the number of elements in this * PropertyTablePropertyView. If the view is valid, this returns @@ -428,4 +487,121 @@ class PropertyTablePropertyView : public PropertyView { PropertyComponentType _stringOffsetType; int64_t _stringOffsetTypeSize; }; + +/** + * @brief A view on the boolean data of the {@link PropertyTableProperty} that is created + * by a {@link PropertyTableView}. + * + * It provides utility to retrieve the actual data stored in the + * {@link PropertyTableProperty::values} like an array of elements. Data of each + * instance can be accessed through the {@link PropertyTablePropertyView::get} method. + */ +template <> class PropertyTablePropertyView : public PropertyView { +public: + /** + * @brief Constructs an invalid instance for a non-existent property. + */ + PropertyTablePropertyView() + : PropertyView(), + _status{PropertyTablePropertyViewStatus::ErrorNonexistentProperty}, + _values{}, + _size{0} {} + + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The value of {@link PropertyTablePropertyViewStatus} indicating the error with the property. + */ + PropertyTablePropertyView(PropertyViewStatusType status) + : PropertyView(), _status{status}, _values{}, _size{0} { + assert( + _status != PropertyTablePropertyViewStatus::Valid && + "An empty property view should not be constructed with a valid " + "status"); + } + + /** + * @brief Construct an instance pointing to the boolean data specified by a {@link PropertyTableProperty}. + * + * + * @param property The {@link PropertyTableProperty} + * @param classProperty The {@link ClassProperty} this property conforms to. + * @param values The raw buffer specified by {@link PropertyTableProperty::values} + * @param size The number of elements in the property table specified by {@link PropertyTable::count} + */ + PropertyTablePropertyView( + const PropertyTableProperty& property, + const ClassProperty& classProperty, + int64_t size, + gsl::span values) noexcept + : PropertyView(classProperty, property), + _status{PropertyView::status()}, + _values{values}, + _size{size} {} + + /** + * @copydoc IPropertyView::status + */ + virtual int32_t status() const noexcept override { return _status; } + + /** + * @brief Get the value of an element of the {@link PropertyTable}. + * + * @param index The element index + * @return The value of the element + */ + bool get(int64_t index) const noexcept { + assert( + _status == PropertyTablePropertyViewStatus::Valid && + "Check the status() first to make sure view is valid"); + assert( + size() > 0 && + "Check the size() of the view to make sure it's not empty"); + assert(index >= 0 && "index must be non-negative"); + assert(index < size() && "index must be less than size"); + + const int64_t byteIndex = index / 8; + const int64_t bitIndex = index % 8; + const int bitValue = static_cast(_values[byteIndex] >> bitIndex) & 1; + return bitValue == 1; + } + + /** + * @brief Gets the value of an element in the {@link PropertyTable} as an instance + * of T. If T is not the same as the ElementType of the property, then + * this attempts to convert it to the desired type. If such a conversion is + * not possible, this returns std::nullopt. + * + * @param index The element index + * @return The value of the element as T, or std::nullopt if conversion fails. + */ + template std::optional getAs(int64_t index) const noexcept { + assert( + _status == PropertyTablePropertyViewStatus::Valid && + "Check the status() first to make sure view is valid"); + assert( + size() > 0 && + "Check the size() of the view to make sure it's not empty"); + assert(index >= 0 && "index must be non-negative"); + assert(index < size() && "index must be less than size"); + + return PropertyConversions::convert(get(index)); + } + + /** + * @brief Get the number of elements in this + * PropertyTablePropertyView. If the view is valid, this returns + * {@link PropertyTable::count}. Otherwise, this returns 0. + * + * @return The number of elements in this PropertyTablePropertyView. + */ + int64_t size() const noexcept { + return status() == PropertyTablePropertyViewStatus::Valid ? _size : 0; + } + +private: + PropertyViewStatusType _status; + gsl::span _values; + int64_t _size; +}; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h index 999947f54..2c6aff53d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h @@ -264,4 +264,16 @@ template <> struct TypeToPropertyType { PropertyComponentType::None; static constexpr PropertyType value = PropertyType::String; }; + +template struct TypeToNormalizedType; + +template <> +struct TypeToNormalizedType { + using type = double; +}; + +template +struct TypeToNormalizedType> { + using type = glm::vec; +}; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 56fa1a6ac..047fd9079 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -2,6 +2,7 @@ #include "CesiumGltf/PropertyTableProperty.h" #include "CesiumGltf/PropertyTextureProperty.h" #include "CesiumGltf/PropertyTypeTraits.h" +#include "PropertyValue.h" #include #include @@ -10,6 +11,17 @@ namespace CesiumGltf { typedef int32_t PropertyViewStatusType; +/** + * @brief Indicates the status of a property view. + * + * The {@link PropertyView} constructor always completes successfully. + * However, there may be fundamental errors with the property definition. In + * such cases, this enumeration provides the reason. + * + * This is defined with a class of static consts as opposed to an enum, so that + * derived property view classes can extend the statuses with their own specific + * errors. + */ class PropertyViewStatus { public: /** @@ -81,13 +93,6 @@ class PropertyViewStatus { /** * @brief An interface for generic metadata property in EXT_structural_metadata. * - * Whether they belong to property tables, property textures, or property - * attributes, properties have their own sub-properties affecting the actual - * property values. Although they are typically defined via class property, they - * may be overridden by individual instances of the property. The constructor is - * responsible for resolving those differences. - * - * @tparam ElementType The C++ type of the values in this property */ template class IPropertyView { public: @@ -176,15 +181,22 @@ template class IPropertyView { virtual std::optional defaultValue() const noexcept = 0; }; +template +class PropertyView; + /** * @brief Represents a generic metadata property in EXT_structural_metadata. - * Implements the {@link IPropertyView} interface. * - * Child classes should validate that the class property type matches the - * "ElementType" before constructing a property view. + * Whether they belong to property tables, property textures, or property + * attributes, properties have their own sub-properties affecting the actual + * property values. Although they are typically defined via class property, they + * may be overridden by individual instances of the property themselves. The + * constructor is responsible for resolving those differences. + * + * @tparam ElementType The C++ type of the values in this property */ template -class PropertyView : IPropertyView { +class PropertyView { public: /** * @brief Constructs an empty property instance. @@ -330,7 +342,7 @@ class PropertyView : IPropertyView { return; } - // If the property has its own values, override the class-provided values. + // If the property has its own values, the class-provided values. if constexpr (IsMetadataNumeric::value) { if (property.offset) { _offset = getValue(*property.offset); @@ -382,7 +394,7 @@ class PropertyView : IPropertyView { return; } - // If the property has its own values, override the class-provided values. + // If the property has its own values, the class-provided values. if constexpr (IsMetadataNumeric::value) { if (property.offset) { _offset = getValue(*property.offset); @@ -426,64 +438,64 @@ class PropertyView : IPropertyView { /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept override { + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept override { return 0; } + virtual int64_t arrayCount() const noexcept { return 0; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept override { return _normalized; } + virtual bool normalized() const noexcept { return _normalized; } /** * @copydoc IPropertyView::offset */ - virtual std::optional offset() const noexcept override { + virtual std::optional offset() const noexcept { return _offset; } /** * @copydoc IPropertyView::scale */ - virtual std::optional scale() const noexcept override { + virtual std::optional scale() const noexcept { return _scale; } /** * @copydoc IPropertyView::max */ - virtual std::optional max() const noexcept override { + virtual std::optional max() const noexcept { return _max; } /** * @copydoc IPropertyView::min */ - virtual std::optional min() const noexcept override { + virtual std::optional min() const noexcept { return _min; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept override { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional noData() const noexcept override { + virtual std::optional noData() const noexcept { return _noData; } /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional defaultValue() const noexcept override { + virtual std::optional defaultValue() const noexcept { return _defaultValue; } @@ -655,64 +667,64 @@ template <> class PropertyView : IPropertyView { /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept override { + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept override { return 0; } + virtual int64_t arrayCount() const noexcept { return 0; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept override { return false; } + virtual bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ - virtual std::optional offset() const noexcept override { + virtual std::optional offset() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::scale */ - virtual std::optional scale() const noexcept override { + virtual std::optional scale() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::max */ - virtual std::optional max() const noexcept override { + virtual std::optional max() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::min */ - virtual std::optional min() const noexcept override { + virtual std::optional min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept override { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional noData() const noexcept override { + virtual std::optional noData() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional defaultValue() const noexcept override { + virtual std::optional defaultValue() const noexcept { return _defaultValue; } @@ -804,57 +816,57 @@ class PropertyView : IPropertyView { /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept override { + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept override { return 0; } + virtual int64_t arrayCount() const noexcept { return 0; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept override { return false; } + virtual bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ - virtual std::optional offset() const noexcept override { + virtual std::optional offset() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::scale */ - virtual std::optional scale() const noexcept override { + virtual std::optional scale() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::max */ - virtual std::optional max() const noexcept override { + virtual std::optional max() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::min */ - virtual std::optional min() const noexcept override { + virtual std::optional min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept override { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional noData() const noexcept override { + virtual std::optional noData() const noexcept { if (_noData) return std::string_view(*_noData); @@ -865,7 +877,7 @@ class PropertyView : IPropertyView { * @copydoc IPropertyView::defaultValue */ virtual std::optional - defaultValue() const noexcept override { + defaultValue() const noexcept { if (_defaultValue) return std::string_view(*_defaultValue); @@ -966,7 +978,7 @@ class PropertyView> } } - // If the property has its own values, override the class-provided values. + // If the property has its own values, the class-provided values. if constexpr (IsMetadataNumeric::value) { if (classProperty.offset) { _offset = getArrayValue(*classProperty.offset); @@ -1043,7 +1055,7 @@ class PropertyView> return; } - // If the property has its own values, override the class-provided values. + // If the property has its own values, the class-provided values. if constexpr (IsMetadataNumeric::value) { if (property.offset) { _offset = getArrayValue(*property.offset); @@ -1095,7 +1107,7 @@ class PropertyView> return; } - // If the property has its own values, override the class-provided values. + // If the property has its own values, the class-provided values. if constexpr (IsMetadataNumeric::value) { if (property.offset) { _offset = getArrayValue(*property.offset); @@ -1139,25 +1151,25 @@ class PropertyView> /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept override { + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept override { return _count; } + virtual int64_t arrayCount() const noexcept { return _count; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept override { return _normalized; } + virtual bool normalized() const noexcept { return _normalized; } /** * @copydoc IPropertyView::offset */ virtual std::optional> - offset() const noexcept override { + offset() const noexcept { if (!_offset) { return std::nullopt; } @@ -1170,7 +1182,7 @@ class PropertyView> * @copydoc IPropertyView::scale */ virtual std::optional> - scale() const noexcept override { + scale() const noexcept { if (!_scale) { return std::nullopt; } @@ -1183,7 +1195,7 @@ class PropertyView> * @copydoc IPropertyView::max */ virtual std::optional> - max() const noexcept override { + max() const noexcept { if (!_max) { return std::nullopt; } @@ -1196,7 +1208,7 @@ class PropertyView> * @copydoc IPropertyView::min */ virtual std::optional> - min() const noexcept override { + min() const noexcept { if (!_min) { return std::nullopt; } @@ -1208,13 +1220,13 @@ class PropertyView> /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept override { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ virtual std::optional> - noData() const noexcept override { + noData() const noexcept { if (!_noData) { return std::nullopt; } @@ -1227,7 +1239,7 @@ class PropertyView> * @copydoc IPropertyView::defaultValue */ virtual std::optional> - defaultValue() const noexcept override { + defaultValue() const noexcept { if (!_defaultValue) { return std::nullopt; } @@ -1437,25 +1449,25 @@ class PropertyView> /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept override { + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept override { return _count; } + virtual int64_t arrayCount() const noexcept { return _count; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept override { return false; } + virtual bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ virtual std::optional> - offset() const noexcept override { + offset() const noexcept { return std::nullopt; } @@ -1463,34 +1475,34 @@ class PropertyView> * @copydoc IPropertyView::scale */ virtual std::optional> - scale() const noexcept override { + scale() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::max */ - virtual std::optional> max() const noexcept override { + virtual std::optional> max() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::min */ - virtual std::optional> min() const noexcept override { + virtual std::optional> min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept override { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ virtual std::optional> - noData() const noexcept override { + noData() const noexcept { return std::nullopt; } @@ -1498,7 +1510,7 @@ class PropertyView> * @copydoc IPropertyView::defaultValue */ virtual std::optional> - defaultValue() const noexcept override { + defaultValue() const noexcept { if (_size > 0) { return PropertyArrayView( gsl::span( @@ -1654,25 +1666,25 @@ class PropertyView> /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept override { + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept override { return _count; } + virtual int64_t arrayCount() const noexcept { return _count; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept override { return false; } + virtual bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ virtual std::optional> - offset() const noexcept override { + offset() const noexcept { return std::nullopt; } @@ -1680,7 +1692,7 @@ class PropertyView> * @copydoc IPropertyView::scale */ virtual std::optional> - scale() const noexcept override { + scale() const noexcept { return std::nullopt; } @@ -1688,7 +1700,7 @@ class PropertyView> * @copydoc IPropertyView::max */ virtual std::optional> - max() const noexcept override { + max() const noexcept { return std::nullopt; } @@ -1696,20 +1708,20 @@ class PropertyView> * @copydoc IPropertyView::min */ virtual std::optional> - min() const noexcept override { + min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept override { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ virtual std::optional> - noData() const noexcept override { + noData() const noexcept { if (_noDataSize > 0) { return PropertyArrayView( gsl::span(_noData.data(), _noData.size()), @@ -1727,7 +1739,7 @@ class PropertyView> * @copydoc IPropertyView::defaultValue */ virtual std::optional> - defaultValue() const noexcept override { + defaultValue() const noexcept { if (_noDataSize > 0) { return PropertyArrayView( gsl::span( diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp index f6fc099c2..cedf023fa 100644 --- a/CesiumGltf/test/TestPropertyView.cpp +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -1,10 +1,21 @@ #include "CesiumGltf/PropertyView.h" +#include "CesiumGltf/PropertyValue.h" + #include using namespace CesiumGltf; using namespace CesiumUtility; +TEST_CASE("TEST") { TestPropertyTablePropertyView normalizedView; + REQUIRE(normalizedView.normalized()); + REQUIRE(normalizedView.getValue() == 1.0); + + TestPropertyTablePropertyView regView; + REQUIRE(!regView.normalized()); + REQUIRE(regView.getValue() == 1); +} + TEST_CASE("Boolean PropertyView") { SECTION("Constructs empty PropertyView") { PropertyView view; From 16565a209efea87deda877f6ca1576c30de3ab4a Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 18 Aug 2023 14:24:51 -0400 Subject: [PATCH 077/121] Remove unused file --- CesiumGltf/include/CesiumGltf/PropertyView.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 047fd9079..00300fd9f 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -2,7 +2,7 @@ #include "CesiumGltf/PropertyTableProperty.h" #include "CesiumGltf/PropertyTextureProperty.h" #include "CesiumGltf/PropertyTypeTraits.h" -#include "PropertyValue.h" +//#include "PropertyValue.h" #include #include From 43cd1a512efb85cfd2b886200942add667549270 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 18 Aug 2023 15:51:06 -0400 Subject: [PATCH 078/121] Try to get CI to compile --- .../include/CesiumGltf/PropertyArrayView.h | 88 +-- .../CesiumGltf/PropertyTablePropertyView.h | 142 +--- .../include/CesiumGltf/PropertyTypeTraits.h | 21 +- CesiumGltf/include/CesiumGltf/PropertyView.h | 723 +++++++++++------- CesiumGltf/test/TestPropertyTypeTraits.cpp | 442 +++++++---- CesiumGltf/test/TestPropertyView.cpp | 17 +- 6 files changed, 858 insertions(+), 575 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index 0fa14eb77..6f17cdeba 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -66,50 +66,50 @@ template class PropertyArrayView { return true; } - PropertyArrayView - operator*(const PropertyArrayView& other) { - int64_t clampedSize = std::min(this->size(), other.size()); - std::vector result(static_cast(this->size())); - if constexpr (IsMetadataMatN::value) { - // Do component-wise multiplication instead of actual matrix - // multiplication. - ElementType matN; - constexpr glm::length_t N = ElementType::length(); - for (int64_t i = 0; i < clampedSize; i++) { - for (glm::length_t j = 0; j < N; j++) { - matN[j] = (*this)[i][j] * other[i][j]; - } - result[i] = matN; - } - } else { - for (int64_t i = 0; i < clampedSize; i++) { - result[i] = (*this)[i] * other[i]; - } - } - - // Copy anything that didn't have a component to multiply against. - for (int64_t i = clampedSize(); i < this->size(); i++) { - result[i] = (*this)[i]; - } - - return PropertyArrayView(std::move(result)); - } - - PropertyArrayView - operator+(const PropertyArrayView& other) { - int64_t clampedSize = std::min(this->size(), other.size()); - std::vector result(static_cast(this->size())); - for (int64_t i = 0; i < clampedSize; i++) { - result[i] = (*this)[i] + other[i]; - } - - // Copy anything that didn't have a component to multiply against. - for (int64_t i = clampedSize(); i < this->size(); i++) { - result[i] = (*this)[i]; - } - - return PropertyArrayView(std::move(result)); - } + //PropertyArrayView + //operator*(const PropertyArrayView& other) { + // int64_t clampedSize = std::min(this->size(), other.size()); + // std::vector result(static_cast(this->size())); + // if constexpr (IsMetadataMatN::value) { + // // Do component-wise multiplication instead of actual matrix + // // multiplication. + // ElementType matN; + // constexpr glm::length_t N = ElementType::length(); + // for (int64_t i = 0; i < clampedSize; i++) { + // for (glm::length_t j = 0; j < N; j++) { + // matN[j] = (*this)[i][j] * other[i][j]; + // } + // result[i] = matN; + // } + // } else { + // for (int64_t i = 0; i < clampedSize; i++) { + // result[i] = (*this)[i] * other[i]; + // } + // } + + // // Copy anything that didn't have a component to multiply against. + // for (int64_t i = clampedSize(); i < this->size(); i++) { + // result[i] = (*this)[i]; + // } + + // return PropertyArrayView(std::move(result)); + //} + + //PropertyArrayView + //operator+(const PropertyArrayView& other) { + // int64_t clampedSize = std::min(this->size(), other.size()); + // std::vector result(static_cast(this->size())); + // for (int64_t i = 0; i < clampedSize; i++) { + // result[i] = (*this)[i] + other[i]; + // } + + // // Copy anything that didn't have a component to multiply against. + // for (int64_t i = clampedSize(); i < this->size(); i++) { + // result[i] = (*this)[i]; + // } + + // return PropertyArrayView(std::move(result)); + //} private: using ArrayType = diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 3bceaa7d4..177af879f 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -131,6 +131,9 @@ class PropertyTablePropertyViewStatus : public PropertyViewStatus { static const PropertyViewStatusType ErrorStringOffsetOutOfBounds = 29; }; +template +class PropertyTablePropertyView; + /** * @brief A view on the data of the {@link PropertyTableProperty} that is created * by a {@link PropertyTableView}. @@ -146,15 +149,16 @@ class PropertyTablePropertyViewStatus : public PropertyViewStatus { * one of the aforementioned types. */ template -class PropertyTablePropertyView : public PropertyView { +class PropertyTablePropertyView + : public PropertyView { public: /** * @brief Constructs an invalid instance for a non-existent property. */ PropertyTablePropertyView() - : PropertyView(), + : PropertyView(), _status{PropertyTablePropertyViewStatus::ErrorNonexistentProperty}, - _values, + _values{}, _size{0}, _arrayOffsets{}, _arrayOffsetType{PropertyComponentType::None}, @@ -170,7 +174,7 @@ class PropertyTablePropertyView : public PropertyView { * @param status The value of {@link PropertyTablePropertyViewStatus} indicating the error with the property. */ PropertyTablePropertyView(PropertyViewStatusType status) - : PropertyView(), + : PropertyView(), _status{status}, _values{}, _size{0}, @@ -309,7 +313,8 @@ class PropertyTablePropertyView : public PropertyView { // * this attempts to convert it to the desired type. If such a conversion is // * not possible, this returns std::nullopt. // * - // * If this property contains a "no data" sentinel value, then std::nullopt is + // * If this property contains a "no data" sentinel value, then std::nullopt + // is // * returned for any raw values that equal the sentinel value. If a default // * value is supplied, then it will be returned instead. // * @@ -318,14 +323,16 @@ class PropertyTablePropertyView : public PropertyView { // * // * transformedValue = offset + scale * normalize(value) // * - // * The transformed value will then attempt to be converted to the desired type + // * The transformed value will then attempt to be converted to the desired + // type // * T. // * // * @param index The element index - // * @return The value of the element as T, or std::nullopt if conversion fails. + // * @return The value of the element as T, or std::nullopt if conversion + // fails. // */ - //template - //std::optional getAs(int64_t index) const noexcept { + // template + // std::optional getAs(int64_t index) const noexcept { // assert( // _status == PropertyTablePropertyViewStatus::Valid && // "Check the status() first to make sure view is valid"); @@ -487,121 +494,4 @@ class PropertyTablePropertyView : public PropertyView { PropertyComponentType _stringOffsetType; int64_t _stringOffsetTypeSize; }; - -/** - * @brief A view on the boolean data of the {@link PropertyTableProperty} that is created - * by a {@link PropertyTableView}. - * - * It provides utility to retrieve the actual data stored in the - * {@link PropertyTableProperty::values} like an array of elements. Data of each - * instance can be accessed through the {@link PropertyTablePropertyView::get} method. - */ -template <> class PropertyTablePropertyView : public PropertyView { -public: - /** - * @brief Constructs an invalid instance for a non-existent property. - */ - PropertyTablePropertyView() - : PropertyView(), - _status{PropertyTablePropertyViewStatus::ErrorNonexistentProperty}, - _values{}, - _size{0} {} - - /** - * @brief Constructs an invalid instance for an erroneous property. - * - * @param status The value of {@link PropertyTablePropertyViewStatus} indicating the error with the property. - */ - PropertyTablePropertyView(PropertyViewStatusType status) - : PropertyView(), _status{status}, _values{}, _size{0} { - assert( - _status != PropertyTablePropertyViewStatus::Valid && - "An empty property view should not be constructed with a valid " - "status"); - } - - /** - * @brief Construct an instance pointing to the boolean data specified by a {@link PropertyTableProperty}. - * - * - * @param property The {@link PropertyTableProperty} - * @param classProperty The {@link ClassProperty} this property conforms to. - * @param values The raw buffer specified by {@link PropertyTableProperty::values} - * @param size The number of elements in the property table specified by {@link PropertyTable::count} - */ - PropertyTablePropertyView( - const PropertyTableProperty& property, - const ClassProperty& classProperty, - int64_t size, - gsl::span values) noexcept - : PropertyView(classProperty, property), - _status{PropertyView::status()}, - _values{values}, - _size{size} {} - - /** - * @copydoc IPropertyView::status - */ - virtual int32_t status() const noexcept override { return _status; } - - /** - * @brief Get the value of an element of the {@link PropertyTable}. - * - * @param index The element index - * @return The value of the element - */ - bool get(int64_t index) const noexcept { - assert( - _status == PropertyTablePropertyViewStatus::Valid && - "Check the status() first to make sure view is valid"); - assert( - size() > 0 && - "Check the size() of the view to make sure it's not empty"); - assert(index >= 0 && "index must be non-negative"); - assert(index < size() && "index must be less than size"); - - const int64_t byteIndex = index / 8; - const int64_t bitIndex = index % 8; - const int bitValue = static_cast(_values[byteIndex] >> bitIndex) & 1; - return bitValue == 1; - } - - /** - * @brief Gets the value of an element in the {@link PropertyTable} as an instance - * of T. If T is not the same as the ElementType of the property, then - * this attempts to convert it to the desired type. If such a conversion is - * not possible, this returns std::nullopt. - * - * @param index The element index - * @return The value of the element as T, or std::nullopt if conversion fails. - */ - template std::optional getAs(int64_t index) const noexcept { - assert( - _status == PropertyTablePropertyViewStatus::Valid && - "Check the status() first to make sure view is valid"); - assert( - size() > 0 && - "Check the size() of the view to make sure it's not empty"); - assert(index >= 0 && "index must be non-negative"); - assert(index < size() && "index must be less than size"); - - return PropertyConversions::convert(get(index)); - } - - /** - * @brief Get the number of elements in this - * PropertyTablePropertyView. If the view is valid, this returns - * {@link PropertyTable::count}. Otherwise, this returns 0. - * - * @return The number of elements in this PropertyTablePropertyView. - */ - int64_t size() const noexcept { - return status() == PropertyTablePropertyViewStatus::Valid ? _size : 0; - } - -private: - PropertyViewStatusType _status; - gsl::span _values; - int64_t _size; -}; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h index 2c6aff53d..fb002d937 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h @@ -265,15 +265,28 @@ template <> struct TypeToPropertyType { static constexpr PropertyType value = PropertyType::String; }; +/** + * @brief Convert an integer numeric type to the corresponding representation as + * a double type. Doubles are preferred over floats to maintain more precision. + */ template struct TypeToNormalizedType; -template <> -struct TypeToNormalizedType { - using type = double; -}; +template <> struct TypeToNormalizedType { using type = double; }; +template <> struct TypeToNormalizedType { using type = double; }; +template <> struct TypeToNormalizedType { using type = double; }; +template <> struct TypeToNormalizedType { using type = double; }; +template <> struct TypeToNormalizedType { using type = double; }; +template <> struct TypeToNormalizedType { using type = double; }; +template <> struct TypeToNormalizedType { using type = double; }; +template <> struct TypeToNormalizedType { using type = double; }; template struct TypeToNormalizedType> { using type = glm::vec; }; + +template +struct TypeToNormalizedType> { + using type = glm::mat; +}; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 00300fd9f..35d1aab3e 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -2,9 +2,9 @@ #include "CesiumGltf/PropertyTableProperty.h" #include "CesiumGltf/PropertyTextureProperty.h" #include "CesiumGltf/PropertyTypeTraits.h" -//#include "PropertyValue.h" #include +#include #include namespace CesiumGltf { @@ -90,11 +90,315 @@ class PropertyViewStatus { static const PropertyViewStatusType ErrorInvalidDefaultValue = 11; }; +template +class PropertyView; + +namespace { +template +static std::optional getScalar(const CesiumUtility::JsonValue& jsonValue) { + try { + return jsonValue.getSafeNumber(); + } catch (const CesiumUtility::JsonValueNotRealValue& /*error*/) { + return std::nullopt; + } catch (const gsl::narrowing_error& /*error*/) { + return std::nullopt; + } +} + +template +static std::optional +getVecN(const CesiumUtility::JsonValue& jsonValue) { + if (!jsonValue.isArray()) { + return std::nullopt; + } + + const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + constexpr glm::length_t N = VecType::length(); + if (array.size() != N) { + return std::nullopt; + } + + using T = typename VecType::value_type; + + VecType result; + for (glm::length_t i = 0; i < N; i++) { + std::optional value = getScalar(array[i]); + if (!value) { + return std::nullopt; + } + + result[i] = *value; + } + + return result; +} + +template +static std::optional +getMatN(const CesiumUtility::JsonValue& jsonValue) { + if (!jsonValue.isArray()) { + return std::nullopt; + } + + const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + constexpr glm::length_t N = MatType::length(); + if (array.size() != N * N) { + return std::nullopt; + } + + using T = typename MatType::value_type; + + MatType result; + for (glm::length_t i = 0; i < N; i++) { + // Try to parse each value in the column. + for (glm::length_t j = 0; j < N; j++) { + std::optional value = getScalar(array[i * N + j]); + if (!value) { + return std::nullopt; + } + + result[i][j] = *value; + } + } + + return result; +} + +} // namespace + /** - * @brief An interface for generic metadata property in EXT_structural_metadata. + * @brief Represents a non-normalized metadata property in + * EXT_structural_metadata. + * + * Whether they belong to property tables, property textures, or property + * attributes, properties have their own sub-properties affecting the actual + * property values. Although they are typically defined via class property, they + * may be overridden by individual instances of the property themselves. The + * constructor is responsible for resolving those differences. * + * @tparam ElementType The C++ type of the values in this property */ -template class IPropertyView { +template class PropertyView { +public: + /** + * @brief Constructs an empty property instance. + */ + PropertyView() + : _status(PropertyViewStatus::ErrorNonexistentProperty), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + + /** + * @brief Constructs a property instance from a class definition only. + */ + PropertyView(const ClassProperty& classProperty) + : _status(PropertyViewStatus::Valid), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(classProperty.required), + _noData(std::nullopt), + _defaultValue(std::nullopt) { + if (convertPropertyTypeToString(TypeToPropertyType::value) != + classProperty.type) { + _status = PropertyViewStatus::ErrorTypeMismatch; + return; + } + + if (!classProperty.componentType && + TypeToPropertyType::component != + PropertyComponentType::None) { + _status = PropertyViewStatus::ErrorComponentTypeMismatch; + return; + } + + if (classProperty.componentType && + convertPropertyComponentTypeToString( + TypeToPropertyType::component) != + *classProperty.componentType) { + _status = PropertyViewStatus::ErrorComponentTypeMismatch; + return; + } + + if (classProperty.array) { + _status = PropertyViewStatus::ErrorArrayTypeMismatch; + return; + } + + if (classProperty.normalized) { + _status = PropertyViewStatus::ErrorInvalidNormalization; + } + + if constexpr (IsMetadataNumeric::value) { + if (classProperty.offset) { + _offset = getValue(*classProperty.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (classProperty.scale) { + _scale = getValue(*classProperty.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (classProperty.max) { + _max = getValue(*classProperty.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (classProperty.min) { + _min = getValue(*classProperty.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + } + + if (!_required) { + if (classProperty.noData) { + _noData = getValue(*classProperty.noData); + if (!_noData) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; + } + } + + if (classProperty.defaultProperty) { + _defaultValue = getValue(*classProperty.defaultProperty); + if (!_defaultValue) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; + } + } + } + } + +protected: + /** + * @brief Constructs a property instance from a property table property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTableProperty& property) + : PropertyView(classProperty) { + if (_status != PropertyViewStatus::Valid) { + return; + } + + // If the property has its own values, the class-provided values. + if constexpr (IsMetadataNumeric::value) { + if (property.offset) { + _offset = getValue(*property.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (property.scale) { + _scale = getValue(*property.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (property.max) { + _max = getValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (property.min) { + _min = getValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + } + } + + /** + * @brief Constructs a property instance from a property texture property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& property) + : PropertyView(classProperty) { + if (_status != PropertyViewStatus::Valid) { + return; + } + + // If the property has its own values, the class-provided values. + if constexpr (IsMetadataNumeric::value) { + if (property.offset) { + _offset = getValue(*property.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (property.scale) { + _scale = getValue(*property.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (property.max) { + _max = getValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (property.min) { + _min = getValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + } + } + public: /** * @brief Gets the status of this property view, indicating whether an error @@ -102,7 +406,7 @@ template class IPropertyView { * * @return The status of this property view. */ - virtual PropertyViewStatusType status() const noexcept = 0; + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @brief Get the element count of the fixed-length arrays in this property. @@ -110,14 +414,14 @@ template class IPropertyView { * * @return The count of this property. */ - virtual int64_t arrayCount() const noexcept = 0; + virtual int64_t arrayCount() const noexcept { return 0; } /** * @brief Whether this property has a normalized integer type. * * @return Whether this property has a normalized integer type. */ - virtual bool normalized() const noexcept = 0; + virtual bool normalized() const noexcept { return false; } /** * @brief Gets the offset to apply to property values. Only applicable to @@ -126,7 +430,8 @@ template class IPropertyView { * * @returns The property's offset, or std::nullopt if it was not specified. */ - virtual std::optional offset() const noexcept = 0; + virtual std::optional offset() const noexcept { return _offset; } + /** * @brief Gets the scale to apply to property values. Only applicable to * SCALAR, VECN, and MATN types when the component type is FLOAT32 or @@ -134,7 +439,7 @@ template class IPropertyView { * * @returns The property's scale, or std::nullopt if it was not specified. */ - virtual std::optional scale() const noexcept = 0; + virtual std::optional scale() const noexcept { return _scale; } /** * @brief Gets the maximum allowed value for the property. Only applicable to @@ -145,7 +450,7 @@ template class IPropertyView { * @returns The property's maximum value, or std::nullopt if it was not * specified. */ - virtual std::optional max() const noexcept = 0; + virtual std::optional max() const noexcept { return _max; } /** * @brief Gets the minimum allowed value for the property. Only applicable to @@ -156,14 +461,14 @@ template class IPropertyView { * @returns The property's minimum value, or std::nullopt if it was not * specified. */ - virtual std::optional min() const noexcept = 0; + virtual std::optional min() const noexcept { return _min; } /** * @brief Whether the property must be present in every entity conforming to * the class. If not required, instances of the property may include "no data" * values, or the entire property may be omitted. */ - virtual bool required() const noexcept = 0; + virtual bool required() const noexcept { return _required; } /** * @brief Gets the "no data" value, i.e., the value representing missing data @@ -171,21 +476,57 @@ template class IPropertyView { * is given as the plain property value, without the transforms from the * normalized, offset, and scale properties. */ - virtual std::optional noData() const noexcept = 0; + virtual std::optional noData() const noexcept { return _noData; } /** * @brief Gets the default value to use when encountering a "no data" value or * an omitted property. The value is given in its final form, taking the * effect of normalized, offset, and scale properties into account. */ - virtual std::optional defaultValue() const noexcept = 0; -}; + virtual std::optional defaultValue() const noexcept { + return _defaultValue; + } -template -class PropertyView; +private: + PropertyViewStatusType _status; + bool _required; + + std::optional _offset; + std::optional _scale; + std::optional _max; + std::optional _min; + + std::optional _noData; + std::optional _defaultValue; + + /** + * @brief Attempts to parse from the given json value. + * + * If T is a type with multiple components, e.g. a VECN or MATN type, this + * will return std::nullopt if one or more components could not be parsed. + * + * @return The value as an instance of T, or std::nullopt if it could not be + * parsed. + */ + static std::optional + getValue(const CesiumUtility::JsonValue& jsonValue) { + if constexpr (IsMetadataScalar::value) { + return getScalar(jsonValue); + } + + if constexpr (IsMetadataVecN::value) { + return getVecN(jsonValue); + } + + if constexpr (IsMetadataMatN::value) { + return getMatN(jsonValue); + } + } +}; /** - * @brief Represents a generic metadata property in EXT_structural_metadata. + * @brief Represents a normalized metadata property in + * EXT_structural_metadata. * * Whether they belong to property tables, property textures, or property * attributes, properties have their own sub-properties affecting the actual @@ -195,15 +536,16 @@ class PropertyView; * * @tparam ElementType The C++ type of the values in this property */ -template -class PropertyView { +template class PropertyView { +private: + using NormalizedType = typename TypeToNormalizedType::type; + public: /** * @brief Constructs an empty property instance. */ PropertyView() : _status(PropertyViewStatus::ErrorNonexistentProperty), - _normalized(false), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -217,7 +559,6 @@ class PropertyView { */ PropertyView(const ClassProperty& classProperty) : _status(PropertyViewStatus::Valid), - _normalized(classProperty.normalized), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -251,28 +592,13 @@ class PropertyView { return; } - if (classProperty.normalized) { - PropertyComponentType componentType = - TypeToPropertyType::component; - switch (componentType) { - case PropertyComponentType::Int8: - case PropertyComponentType::Uint8: - case PropertyComponentType::Int16: - case PropertyComponentType::Uint16: - case PropertyComponentType::Int32: - case PropertyComponentType::Uint32: - case PropertyComponentType::Int64: - case PropertyComponentType::Uint64: - break; - default: - _status = PropertyViewStatus::ErrorInvalidNormalization; - return; - } + if (!classProperty.normalized) { + _status = PropertyViewStatus::ErrorInvalidNormalization; } if constexpr (IsMetadataNumeric::value) { if (classProperty.offset) { - _offset = getValue(*classProperty.offset); + _offset = getValue(*classProperty.offset); if (!_offset) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidOffset; @@ -281,7 +607,7 @@ class PropertyView { } if (classProperty.scale) { - _scale = getValue(*classProperty.scale); + _scale = getValue(*classProperty.scale); if (!_scale) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidScale; @@ -290,7 +616,7 @@ class PropertyView { } if (classProperty.max) { - _max = getValue(*classProperty.max); + _max = getValue(*classProperty.max); if (!_scale) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidMax; @@ -299,7 +625,7 @@ class PropertyView { } if (classProperty.min) { - _min = getValue(*classProperty.min); + _min = getValue(*classProperty.min); if (!_scale) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidMin; @@ -310,7 +636,7 @@ class PropertyView { if (!_required) { if (classProperty.noData) { - _noData = getValue(*classProperty.noData); + _noData = getValue(*classProperty.noData); if (!_noData) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidNoDataValue; @@ -319,7 +645,8 @@ class PropertyView { } if (classProperty.defaultProperty) { - _defaultValue = getValue(*classProperty.defaultProperty); + _defaultValue = + getValue(*classProperty.defaultProperty); if (!_defaultValue) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidDefaultValue; @@ -345,7 +672,7 @@ class PropertyView { // If the property has its own values, the class-provided values. if constexpr (IsMetadataNumeric::value) { if (property.offset) { - _offset = getValue(*property.offset); + _offset = getValue(*property.offset); if (!_offset) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidOffset; @@ -354,7 +681,7 @@ class PropertyView { } if (property.scale) { - _scale = getValue(*property.scale); + _scale = getValue(*property.scale); if (!_scale) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidScale; @@ -363,7 +690,7 @@ class PropertyView { } if (property.max) { - _max = getValue(*property.max); + _max = getValue(*property.max); if (!_scale) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidMax; @@ -372,7 +699,7 @@ class PropertyView { } if (property.min) { - _min = getValue(*property.min); + _min = getValue(*property.min); if (!_scale) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidMin; @@ -397,7 +724,7 @@ class PropertyView { // If the property has its own values, the class-provided values. if constexpr (IsMetadataNumeric::value) { if (property.offset) { - _offset = getValue(*property.offset); + _offset = getValue(*property.offset); if (!_offset) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidOffset; @@ -406,7 +733,7 @@ class PropertyView { } if (property.scale) { - _scale = getValue(*property.scale); + _scale = getValue(*property.scale); if (!_scale) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidScale; @@ -415,7 +742,7 @@ class PropertyView { } if (property.max) { - _max = getValue(*property.max); + _max = getValue(*property.max); if (!_scale) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidMax; @@ -424,7 +751,7 @@ class PropertyView { } if (property.min) { - _min = getValue(*property.min); + _min = getValue(*property.min); if (!_scale) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidMin; @@ -436,81 +763,75 @@ class PropertyView { public: /** - * @copydoc IPropertyView::status + * @brief Gets the status of this property view, indicating whether an error + * occurred. + * + * @return The status of this property view. */ - virtual PropertyViewStatusType status() const noexcept { - return _status; - } + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return 0; } + virtual int64_t arrayCount() const noexcept { return 0; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return _normalized; } + virtual bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ - virtual std::optional offset() const noexcept { + virtual std::optional offset() const noexcept { return _offset; } /** * @copydoc IPropertyView::scale */ - virtual std::optional scale() const noexcept { + virtual std::optional scale() const noexcept { return _scale; } /** * @copydoc IPropertyView::max */ - virtual std::optional max() const noexcept { - return _max; - } + virtual std::optional max() const noexcept { return _max; } /** * @copydoc IPropertyView::min */ - virtual std::optional min() const noexcept { - return _min; - } + virtual std::optional min() const noexcept { return _min; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional noData() const noexcept { - return _noData; - } + virtual std::optional noData() const noexcept { return _noData; } /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional defaultValue() const noexcept { + virtual std::optional defaultValue() const noexcept { return _defaultValue; } private: PropertyViewStatusType _status; - bool _normalized; + bool _required; - std::optional _offset; - std::optional _scale; - std::optional _max; - std::optional _min; + std::optional _offset; + std::optional _scale; + std::optional _max; + std::optional _min; - bool _required; std::optional _noData; - std::optional _defaultValue; + std::optional _defaultValue; /** * @brief Attempts to parse from the given json value. @@ -521,93 +842,23 @@ class PropertyView { * @return The value as an instance of T, or std::nullopt if it could not be * parsed. */ - static std::optional - getValue(const CesiumUtility::JsonValue& jsonValue) { - if constexpr (IsMetadataScalar::value) { - return getScalar(jsonValue); - } - - if constexpr (IsMetadataVecN::value) { - return getVecN(jsonValue); - } - - if constexpr (IsMetadataMatN::value) { - return getMatN(jsonValue); - } - } - template - static std::optional getScalar(const CesiumUtility::JsonValue& jsonValue) { - try { - return jsonValue.getSafeNumber(); - } catch (const CesiumUtility::JsonValueNotRealValue& /*error*/) { - return std::nullopt; - } catch (const gsl::narrowing_error& /*error*/) { - return std::nullopt; - } - } - - template - static std::optional - getVecN(const CesiumUtility::JsonValue& jsonValue) { - if (!jsonValue.isArray()) { - return std::nullopt; - } - - const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); - constexpr glm::length_t N = VecType::length(); - if (array.size() != N) { - return std::nullopt; - } - - using T = typename VecType::value_type; - - VecType result; - for (glm::length_t i = 0; i < N; i++) { - std::optional value = getScalar(array[i]); - if (!value) { - return std::nullopt; - } - - result[i] = *value; + static std::optional getValue(const CesiumUtility::JsonValue& jsonValue) { + if constexpr (IsMetadataScalar::value) { + return getScalar(jsonValue); } - return result; - } - - template - static std::optional - getMatN(const CesiumUtility::JsonValue& jsonValue) { - if (!jsonValue.isArray()) { - return std::nullopt; + if constexpr (IsMetadataVecN::value) { + return getVecN(jsonValue); } - const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); - constexpr glm::length_t N = MatType::length(); - if (array.size() != N * N) { - return std::nullopt; + if constexpr (IsMetadataMatN::value) { + return getMatN(jsonValue); } - - using T = typename MatType::value_type; - - MatType result; - for (glm::length_t i = 0; i < N; i++) { - // Try to parse each value in the column. - for (glm::length_t j = 0; j < N; j++) { - std::optional value = getScalar(array[i * N + j]); - if (!value) { - return std::nullopt; - } - - result[i][j] = *value; - } - } - - return result; } }; -template <> class PropertyView : IPropertyView { +template <> class PropertyView { public: /** * @brief Constructs an empty property instance. @@ -667,64 +918,52 @@ template <> class PropertyView : IPropertyView { /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept { - return _status; - } + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return 0; } + virtual int64_t arrayCount() const noexcept { return 0; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return false; } + virtual bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ - virtual std::optional offset() const noexcept { - return std::nullopt; - } + virtual std::optional offset() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::scale */ - virtual std::optional scale() const noexcept { - return std::nullopt; - } + virtual std::optional scale() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::max */ - virtual std::optional max() const noexcept { - return std::nullopt; - } + virtual std::optional max() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::min */ - virtual std::optional min() const noexcept { - return std::nullopt; - } + virtual std::optional min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional noData() const noexcept { - return std::nullopt; - } + virtual std::optional noData() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional defaultValue() const noexcept { + virtual std::optional defaultValue() const noexcept { return _defaultValue; } @@ -743,8 +982,7 @@ template <> class PropertyView : IPropertyView { } }; -template <> -class PropertyView : IPropertyView { +template <> class PropertyView { public: /** * @brief Constructs an empty property instance. @@ -816,57 +1054,55 @@ class PropertyView : IPropertyView { /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept { - return _status; - } + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return 0; } + virtual int64_t arrayCount() const noexcept { return 0; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return false; } + virtual bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ - virtual std::optional offset() const noexcept { + virtual std::optional offset() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::scale */ - virtual std::optional scale() const noexcept { + virtual std::optional scale() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::max */ - virtual std::optional max() const noexcept { + virtual std::optional max() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::min */ - virtual std::optional min() const noexcept { + virtual std::optional min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional noData() const noexcept { + virtual std::optional noData() const noexcept { if (_noData) return std::string_view(*_noData); @@ -876,8 +1112,7 @@ class PropertyView : IPropertyView { /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional - defaultValue() const noexcept { + virtual std::optional defaultValue() const noexcept { if (_defaultValue) return std::string_view(*_defaultValue); @@ -901,8 +1136,7 @@ class PropertyView : IPropertyView { }; template -class PropertyView> - : IPropertyView> { +class PropertyView> { public: /** * @brief Constructs an empty property instance. @@ -960,22 +1194,8 @@ class PropertyView> } if (classProperty.normalized) { - PropertyComponentType componentType = - TypeToPropertyType::component; - switch (componentType) { - case PropertyComponentType::Int8: - case PropertyComponentType::Uint8: - case PropertyComponentType::Int16: - case PropertyComponentType::Uint16: - case PropertyComponentType::Int32: - case PropertyComponentType::Uint32: - case PropertyComponentType::Int64: - case PropertyComponentType::Uint64: - break; - default: - _status = PropertyViewStatus::ErrorInvalidNormalization; - return; - } + _status = PropertyViewStatus::ErrorInvalidNormalization; + return; } // If the property has its own values, the class-provided values. @@ -1151,25 +1371,23 @@ class PropertyView> /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept { - return _status; - } + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return _count; } + virtual int64_t arrayCount() const noexcept { return _count; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return _normalized; } + virtual bool normalized() const noexcept { return _normalized; } /** * @copydoc IPropertyView::offset */ virtual std::optional> - offset() const noexcept { + offset() const noexcept { if (!_offset) { return std::nullopt; } @@ -1181,8 +1399,7 @@ class PropertyView> /** * @copydoc IPropertyView::scale */ - virtual std::optional> - scale() const noexcept { + virtual std::optional> scale() const noexcept { if (!_scale) { return std::nullopt; } @@ -1194,8 +1411,7 @@ class PropertyView> /** * @copydoc IPropertyView::max */ - virtual std::optional> - max() const noexcept { + virtual std::optional> max() const noexcept { if (!_max) { return std::nullopt; } @@ -1207,8 +1423,7 @@ class PropertyView> /** * @copydoc IPropertyView::min */ - virtual std::optional> - min() const noexcept { + virtual std::optional> min() const noexcept { if (!_min) { return std::nullopt; } @@ -1220,13 +1435,13 @@ class PropertyView> /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ virtual std::optional> - noData() const noexcept { + noData() const noexcept { if (!_noData) { return std::nullopt; } @@ -1239,7 +1454,7 @@ class PropertyView> * @copydoc IPropertyView::defaultValue */ virtual std::optional> - defaultValue() const noexcept { + defaultValue() const noexcept { if (!_defaultValue) { return std::nullopt; } @@ -1382,9 +1597,7 @@ class PropertyView> } }; -template <> -class PropertyView> - : IPropertyView> { +template <> class PropertyView> { public: /** * @brief Constructs an empty property instance. @@ -1449,68 +1662,62 @@ class PropertyView> /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept { - return _status; - } + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return _count; } + virtual int64_t arrayCount() const noexcept { return _count; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return false; } + virtual bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ - virtual std::optional> - offset() const noexcept { + virtual std::optional> offset() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::scale */ - virtual std::optional> - scale() const noexcept { + virtual std::optional> scale() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::max */ - virtual std::optional> max() const noexcept { + virtual std::optional> max() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::min */ - virtual std::optional> min() const noexcept { + virtual std::optional> min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional> - noData() const noexcept { + virtual std::optional> noData() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional> - defaultValue() const noexcept { + virtual std::optional> defaultValue() const noexcept { if (_size > 0) { return PropertyArrayView( gsl::span( @@ -1571,9 +1778,7 @@ class PropertyView> } }; -template <> -class PropertyView> - : IPropertyView> { +template <> class PropertyView> { public: /** * @brief Constructs an empty property instance. @@ -1666,25 +1871,23 @@ class PropertyView> /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept { - return _status; - } + virtual PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return _count; } + virtual int64_t arrayCount() const noexcept { return _count; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return false; } + virtual bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ virtual std::optional> - offset() const noexcept { + offset() const noexcept { return std::nullopt; } @@ -1692,7 +1895,7 @@ class PropertyView> * @copydoc IPropertyView::scale */ virtual std::optional> - scale() const noexcept { + scale() const noexcept { return std::nullopt; } @@ -1700,7 +1903,7 @@ class PropertyView> * @copydoc IPropertyView::max */ virtual std::optional> - max() const noexcept { + max() const noexcept { return std::nullopt; } @@ -1708,20 +1911,20 @@ class PropertyView> * @copydoc IPropertyView::min */ virtual std::optional> - min() const noexcept { + min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + virtual bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ virtual std::optional> - noData() const noexcept { + noData() const noexcept { if (_noDataSize > 0) { return PropertyArrayView( gsl::span(_noData.data(), _noData.size()), @@ -1739,7 +1942,7 @@ class PropertyView> * @copydoc IPropertyView::defaultValue */ virtual std::optional> - defaultValue() const noexcept { + defaultValue() const noexcept { if (_noDataSize > 0) { return PropertyArrayView( gsl::span( diff --git a/CesiumGltf/test/TestPropertyTypeTraits.cpp b/CesiumGltf/test/TestPropertyTypeTraits.cpp index caa8d1eaf..140a2bf2b 100644 --- a/CesiumGltf/test/TestPropertyTypeTraits.cpp +++ b/CesiumGltf/test/TestPropertyTypeTraits.cpp @@ -4,165 +4,165 @@ using namespace CesiumGltf; -TEST_CASE("Test PropertyTypeTraits") { - SECTION("IsScalar") { - REQUIRE(IsMetadataScalar::value); - REQUIRE(IsMetadataScalar::value); +TEST_CASE("Test IsMetadataScalar") { + REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); - REQUIRE(IsMetadataScalar::value); - REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); - REQUIRE(IsMetadataScalar::value); - REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); - REQUIRE(IsMetadataScalar::value); - REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); - REQUIRE(IsMetadataScalar::value); - REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); + REQUIRE(IsMetadataScalar::value); - REQUIRE(!IsMetadataScalar::value); - REQUIRE(!IsMetadataScalar::value); - REQUIRE(!IsMetadataScalar::value); - REQUIRE(!IsMetadataScalar::value); - } + REQUIRE(!IsMetadataScalar::value); + REQUIRE(!IsMetadataScalar::value); + REQUIRE(!IsMetadataScalar::value); + REQUIRE(!IsMetadataScalar::value); +} - SECTION("IsVecN") { - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); +TEST_CASE("Test IsMetadataVecN") { + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); - REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); + REQUIRE(IsMetadataVecN::value); - REQUIRE(!IsMetadataVecN::value); - REQUIRE(!IsMetadataVecN::value); - } + REQUIRE(!IsMetadataVecN::value); + REQUIRE(!IsMetadataVecN::value); +} - SECTION("IsMatN") { - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); +TEST_CASE("Test IsMetadataMatN") { + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); - REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); + REQUIRE(IsMetadataMatN::value); - REQUIRE(!IsMetadataMatN::value); - REQUIRE(!IsMetadataMatN::value); - } + REQUIRE(!IsMetadataMatN::value); + REQUIRE(!IsMetadataMatN::value); +} - SECTION("IsBoolean") { - REQUIRE(IsMetadataBoolean::value); - REQUIRE(!IsMetadataBoolean::value); - REQUIRE(!IsMetadataBoolean::value); - } +TEST_CASE("Test IsMetadataBoolean") { + REQUIRE(IsMetadataBoolean::value); + REQUIRE(!IsMetadataBoolean::value); + REQUIRE(!IsMetadataBoolean::value); +} - SECTION("IsString") { - REQUIRE(IsMetadataString::value); - REQUIRE(!IsMetadataString::value); - } +TEST_CASE("Test IsMetadataString") { + REQUIRE(IsMetadataString::value); + REQUIRE(!IsMetadataString::value); +} - SECTION("IsNumeric") { - REQUIRE(IsMetadataNumeric::value); - REQUIRE(IsMetadataNumeric::value); - REQUIRE(IsMetadataNumeric::value); - REQUIRE(IsMetadataNumeric::value); - REQUIRE(IsMetadataNumeric::value); - REQUIRE(IsMetadataNumeric::value); - REQUIRE(!IsMetadataNumeric::value); - REQUIRE(!IsMetadataNumeric::value); - } +TEST_CASE("Test IsMetadataNumeric") { + REQUIRE(IsMetadataNumeric::value); + REQUIRE(IsMetadataNumeric::value); + REQUIRE(IsMetadataNumeric::value); + REQUIRE(IsMetadataNumeric::value); + REQUIRE(IsMetadataNumeric::value); + REQUIRE(IsMetadataNumeric::value); + REQUIRE(!IsMetadataNumeric::value); + REQUIRE(!IsMetadataNumeric::value); +} - SECTION("IsNumericArray") { - REQUIRE(IsMetadataNumericArray>::value); - REQUIRE(IsMetadataNumericArray>::value); - REQUIRE(IsMetadataNumericArray>::value); - REQUIRE(!IsMetadataNumericArray>::value); - } +TEST_CASE("Test IsMetadataNumericArray") { + REQUIRE(IsMetadataNumericArray>::value); + REQUIRE(IsMetadataNumericArray>::value); + REQUIRE(IsMetadataNumericArray>::value); + REQUIRE(!IsMetadataNumericArray>::value); +} - SECTION("IsBooleanArray") { - REQUIRE(IsMetadataBooleanArray>::value); - REQUIRE(!IsMetadataBooleanArray>::value); - } +TEST_CASE("Test IsMetadataBooleanArray") { + REQUIRE(IsMetadataBooleanArray>::value); + REQUIRE(!IsMetadataBooleanArray>::value); +} - SECTION("IsStringArray") { - REQUIRE(IsMetadataStringArray>::value); - REQUIRE(!IsMetadataStringArray>::value); - REQUIRE(!IsMetadataStringArray>::value); - } +TEST_CASE("Test IsStringArray") { + REQUIRE(IsMetadataStringArray>::value); + REQUIRE(!IsMetadataStringArray>::value); + REQUIRE(!IsMetadataStringArray>::value); +} - SECTION("ArrayType") { - using type = MetadataArrayType>::type; - REQUIRE(std::is_same_v); - } +TEST_CASE("Test MetadataArrayType") { + using type = MetadataArrayType>::type; + REQUIRE(std::is_same_v); +} - SECTION("TypeToPropertyType scalar") { +TEST_CASE("TypeToPropertyType") { + SECTION("Works for scalar types") { REQUIRE(TypeToPropertyType::value == PropertyType::Scalar); REQUIRE( TypeToPropertyType::component == PropertyComponentType::Uint8); @@ -199,7 +199,7 @@ TEST_CASE("Test PropertyTypeTraits") { TypeToPropertyType::component == PropertyComponentType::Int64); } - SECTION("TypeToPropertyType vecN") { + SECTION("Works for vecN types") { // Vec2 REQUIRE(TypeToPropertyType::value == PropertyType::Vec2); REQUIRE( @@ -354,7 +354,7 @@ TEST_CASE("Test PropertyTypeTraits") { PropertyComponentType::Float64); } - SECTION("TypeToPropertyType matN") { + SECTION("Works for matN types") { // Mat2 REQUIRE(TypeToPropertyType::value == PropertyType::Mat2); REQUIRE( @@ -509,12 +509,12 @@ TEST_CASE("Test PropertyTypeTraits") { PropertyComponentType::Float64); } - SECTION("TypeToPropertyType boolean") { + SECTION("Works for boolean") { REQUIRE(TypeToPropertyType::value == PropertyType::Boolean); REQUIRE(TypeToPropertyType::component == PropertyComponentType::None); } - SECTION("TypeToPropertyType string") { + SECTION("Works for string") { REQUIRE( TypeToPropertyType::value == PropertyType::String); REQUIRE( @@ -522,3 +522,189 @@ TEST_CASE("Test PropertyTypeTraits") { PropertyComponentType::None); } } + +TEST_CASE("TypeToNormalizedType") { + SECTION("Works for scalars") { + REQUIRE(std::is_same_v::type, double>); + REQUIRE(std::is_same_v::type, double>); + REQUIRE(std::is_same_v::type, double>); + REQUIRE(std::is_same_v::type, double>); + REQUIRE(std::is_same_v::type, double>); + REQUIRE(std::is_same_v::type, double>); + REQUIRE(std::is_same_v::type, double>); + REQUIRE(std::is_same_v::type, double>); + REQUIRE(std::is_same_v::type, double>); + } + + SECTION("Works for vecNs") { + using ExpectedVec2Type = glm::dvec2; + using ExpectedVec3Type = glm::dvec3; + using ExpectedVec4Type = glm::dvec4; + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedVec4Type>); + } + + SECTION("Works for matNs") { + using ExpectedMat2Type = glm::dmat2; + using ExpectedMat3Type = glm::dmat3; + using ExpectedMat4Type = glm::dmat4; + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat4Type>); + + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat2Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat3Type>); + REQUIRE(std::is_same_v< + TypeToNormalizedType::type, + ExpectedMat4Type>); + } +} diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp index cedf023fa..a8be2978e 100644 --- a/CesiumGltf/test/TestPropertyView.cpp +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -1,21 +1,12 @@ #include "CesiumGltf/PropertyView.h" -#include "CesiumGltf/PropertyValue.h" +//#include "CesiumGltf/PropertyValue.h" #include using namespace CesiumGltf; using namespace CesiumUtility; -TEST_CASE("TEST") { TestPropertyTablePropertyView normalizedView; - REQUIRE(normalizedView.normalized()); - REQUIRE(normalizedView.getValue() == 1.0); - - TestPropertyTablePropertyView regView; - REQUIRE(!regView.normalized()); - REQUIRE(regView.getValue() == 1); -} - TEST_CASE("Boolean PropertyView") { SECTION("Constructs empty PropertyView") { PropertyView view; @@ -172,7 +163,7 @@ TEST_CASE("Scalar PropertyView") { classProperty.normalized = true; classProperty.required = true; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.normalized()); REQUIRE(view.required()); @@ -372,7 +363,7 @@ TEST_CASE("VecN PropertyView") { classProperty.normalized = true; classProperty.required = true; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.normalized()); REQUIRE(view.required()); @@ -572,7 +563,7 @@ TEST_CASE("MatN PropertyView") { classProperty.normalized = true; classProperty.required = true; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.normalized()); REQUIRE(view.required()); From 8cde08611fd1fbd4de528b6b2c7d4e5379493d19 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 18 Aug 2023 16:00:54 -0400 Subject: [PATCH 079/121] Add missing constructor qualifiers --- CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 177af879f..24e4b683b 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -165,7 +165,7 @@ class PropertyTablePropertyView _arrayOffsetTypeSize{0}, _stringOffsets{}, _stringOffsetType{PropertyComponentType::None}, - _stringOffsetTypeSize{0}, + _stringOffsetTypeSize{0} {} /** @@ -202,7 +202,7 @@ class PropertyTablePropertyView const ClassProperty& classProperty, int64_t size, gsl::span values) noexcept - : PropertyView(classProperty, property), + : PropertyView(classProperty, property), _status{PropertyTablePropertyViewStatus::Valid}, _values{}, _size{}, @@ -240,7 +240,7 @@ class PropertyTablePropertyView gsl::span stringOffsets, PropertyComponentType arrayOffsetType, PropertyComponentType stringOffsetType) noexcept - : PropertyView(classProperty, property), + : PropertyView(classProperty, property), _status{PropertyTablePropertyViewStatus::Valid}, _values{values}, _arrayOffsets{arrayOffsets}, From bf324061b60bfccd4560eb7a1508673d83a6cb35 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 18 Aug 2023 17:48:03 -0400 Subject: [PATCH 080/121] Start reworking property view for normalization --- .../CesiumGltf/PropertyTablePropertyView.h | 20 +- .../include/CesiumGltf/PropertyTypeTraits.h | 20 + CesiumGltf/include/CesiumGltf/PropertyView.h | 491 +++++++++++------- CesiumGltf/test/TestPropertyTypeTraits.cpp | 17 + CesiumGltf/test/TestPropertyView.cpp | 112 ++-- 5 files changed, 389 insertions(+), 271 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 24e4b683b..059336753 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -157,7 +157,6 @@ class PropertyTablePropertyView */ PropertyTablePropertyView() : PropertyView(), - _status{PropertyTablePropertyViewStatus::ErrorNonexistentProperty}, _values{}, _size{0}, _arrayOffsets{}, @@ -165,8 +164,7 @@ class PropertyTablePropertyView _arrayOffsetTypeSize{0}, _stringOffsets{}, _stringOffsetType{PropertyComponentType::None}, - _stringOffsetTypeSize{0} - {} + _stringOffsetTypeSize{0} {} /** * @brief Constructs an invalid instance for an erroneous property. @@ -174,8 +172,7 @@ class PropertyTablePropertyView * @param status The value of {@link PropertyTablePropertyViewStatus} indicating the error with the property. */ PropertyTablePropertyView(PropertyViewStatusType status) - : PropertyView(), - _status{status}, + : PropertyView(status), _values{}, _size{0}, _arrayOffsets{}, @@ -203,7 +200,6 @@ class PropertyTablePropertyView int64_t size, gsl::span values) noexcept : PropertyView(classProperty, property), - _status{PropertyTablePropertyViewStatus::Valid}, _values{}, _size{}, _arrayOffsets{}, @@ -212,7 +208,7 @@ class PropertyTablePropertyView _stringOffsets{}, _stringOffsetType{PropertyComponentType::None}, _stringOffsetTypeSize{0} { - if (PropertyView::status() == PropertyTablePropertyViewStatus::Valid) { + if (_status == PropertyTablePropertyViewStatus::Valid) { _values = values; _size = size; } @@ -241,7 +237,6 @@ class PropertyTablePropertyView PropertyComponentType arrayOffsetType, PropertyComponentType stringOffsetType) noexcept : PropertyView(classProperty, property), - _status{PropertyTablePropertyViewStatus::Valid}, _values{values}, _arrayOffsets{arrayOffsets}, _arrayOffsetType{arrayOffsetType}, @@ -250,17 +245,12 @@ class PropertyTablePropertyView _stringOffsetType{stringOffsetType}, _stringOffsetTypeSize{getOffsetTypeSize(stringOffsetType)}, _size{size} { - if (PropertyView::status() == PropertyTablePropertyViewStatus::Valid) { + if (_status == PropertyTablePropertyViewStatus::Valid) { _values = values; _size = size; } } - /** - * @copydoc IPropertyView::status - */ - virtual int32_t status() const noexcept override { return _status; } - /** * @brief Get the raw value of an element of the {@link PropertyTable}, * without offset, scale, or normalization applied. @@ -482,7 +472,7 @@ class PropertyTablePropertyView } } - PropertyViewStatusType _status; +// PropertyViewStatusType _status; gsl::span _values; int64_t _size; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h index fb002d937..b7400cbc6 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h @@ -265,6 +265,26 @@ template <> struct TypeToPropertyType { static constexpr PropertyType value = PropertyType::String; }; +/** + * @brief Check if a C++ type can be normalized. + */ +template struct CanBeNormalized; +template struct CanBeNormalized : std::false_type {}; +template <> struct CanBeNormalized : std::true_type {}; +template <> struct CanBeNormalized : std::true_type {}; +template <> struct CanBeNormalized : std::true_type {}; +template <> struct CanBeNormalized : std::true_type {}; +template <> struct CanBeNormalized : std::true_type {}; +template <> struct CanBeNormalized : std::true_type {}; +template <> struct CanBeNormalized : std::true_type {}; +template <> struct CanBeNormalized : std::true_type {}; + +template +struct CanBeNormalized> : CanBeNormalized {}; + +template +struct CanBeNormalized> : CanBeNormalized {}; + /** * @brief Convert an integer numeric type to the corresponding representation as * a double type. Doubles are preferred over floats to maintain more precision. diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 35d1aab3e..3db5165fa 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -94,6 +94,52 @@ template class PropertyView; namespace { +template +PropertyViewStatusType +validatePropertyType(const ClassProperty& classProperty) { + using ElementType = T; + if constexpr (IsMetadataArray::value) { + using ElementType = typename MetadataArrayType::type; + } + + if (TypeToPropertyType::value != + convertStringToPropertyType(classProperty.type)) { + return PropertyViewStatus::ErrorTypeMismatch; + } + + PropertyComponentType expectedComponentType = + TypeToPropertyType::component; + + if (!classProperty.componentType && + expectedComponentType != PropertyComponentType::None) { + return PropertyViewStatus::ErrorComponentTypeMismatch; + } + + if (classProperty.componentType && + expectedComponentType != + convertStringToPropertyComponentType(*classProperty.componentType)) { + return PropertyViewStatus::ErrorComponentTypeMismatch; + } + + if constexpr (IsMetadataArray::value) { + if (!classProperty.array) { + return PropertyViewStatus::ErrorArrayTypeMismatch; + } + } else { + if (classProperty.array) { + return PropertyViewStatus::ErrorArrayTypeMismatch; + } + } + + if (!CanBeNormalized::value) { + if (classProperty.normalized) { + return PropertyViewStatus::ErrorInvalidNormalization; + } + } + + return PropertyViewStatus::Valid; +} + template static std::optional getScalar(const CesiumUtility::JsonValue& jsonValue) { try { @@ -197,7 +243,7 @@ template class PropertyView { * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _status(PropertyViewStatus::Valid), + : _status(validatePropertyType(classProperty)), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -205,96 +251,113 @@ template class PropertyView { _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { - if (convertPropertyTypeToString(TypeToPropertyType::value) != - classProperty.type) { - _status = PropertyViewStatus::ErrorTypeMismatch; - return; - } - - if (!classProperty.componentType && - TypeToPropertyType::component != - PropertyComponentType::None) { - _status = PropertyViewStatus::ErrorComponentTypeMismatch; - return; - } - - if (classProperty.componentType && - convertPropertyComponentTypeToString( - TypeToPropertyType::component) != - *classProperty.componentType) { - _status = PropertyViewStatus::ErrorComponentTypeMismatch; - return; - } - - if (classProperty.array) { - _status = PropertyViewStatus::ErrorArrayTypeMismatch; + if (_status != PropertyViewStatus::Valid) { return; } if (classProperty.normalized) { _status = PropertyViewStatus::ErrorInvalidNormalization; + return; } - if constexpr (IsMetadataNumeric::value) { - if (classProperty.offset) { + if (classProperty.offset) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: _offset = getValue(*classProperty.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; + if (_offset) { + break; } + // If it does not break here, something went wrong. + default: + _status = PropertyViewStatus::ErrorInvalidOffset; + return; } + } - if (classProperty.scale) { + if (classProperty.scale) { + // Only floating point types can specify a scale. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: _scale = getValue(*classProperty.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; + if (_scale) { + break; } + // If it does not break here, something went wrong. + default: + _status = PropertyViewStatus::ErrorInvalidScale; + return; } + } - if (classProperty.max) { - _max = getValue(*classProperty.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } + if (classProperty.max) { + _max = getValue(*classProperty.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; } + } - if (classProperty.min) { - _min = getValue(*classProperty.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + if (classProperty.min) { + _min = getValue(*classProperty.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; } } - if (!_required) { + if (_required) { + // "noData" should not be defined if the property is required. if (classProperty.noData) { - _noData = getValue(*classProperty.noData); - if (!_noData) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidNoDataValue; - return; - } + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; } if (classProperty.defaultProperty) { - _defaultValue = getValue(*classProperty.defaultProperty); - if (!_defaultValue) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidDefaultValue; - return; - } + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; + } + } + + if (classProperty.noData) { + _noData = getValue(*classProperty.noData); + if (!_noData) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; + } + } + + if (classProperty.defaultProperty) { + _defaultValue = getValue(*classProperty.defaultProperty); + if (!_defaultValue) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; } } } protected: + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The value of {@link PropertyViewStatus} indicating the error with the property. + */ + PropertyView(PropertyViewStatusType status) + : _status(status), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + /** * @brief Constructs a property instance from a property table property and * its class definition. @@ -406,7 +469,7 @@ template class PropertyView { * * @return The status of this property view. */ - virtual PropertyViewStatusType status() const noexcept { return _status; } + PropertyViewStatusType status() const noexcept { return _status; } /** * @brief Get the element count of the fixed-length arrays in this property. @@ -414,14 +477,14 @@ template class PropertyView { * * @return The count of this property. */ - virtual int64_t arrayCount() const noexcept { return 0; } + int64_t arrayCount() const noexcept { return 0; } /** * @brief Whether this property has a normalized integer type. * * @return Whether this property has a normalized integer type. */ - virtual bool normalized() const noexcept { return false; } + bool normalized() const noexcept { return false; } /** * @brief Gets the offset to apply to property values. Only applicable to @@ -430,7 +493,7 @@ template class PropertyView { * * @returns The property's offset, or std::nullopt if it was not specified. */ - virtual std::optional offset() const noexcept { return _offset; } + std::optional offset() const noexcept { return _offset; } /** * @brief Gets the scale to apply to property values. Only applicable to @@ -439,7 +502,7 @@ template class PropertyView { * * @returns The property's scale, or std::nullopt if it was not specified. */ - virtual std::optional scale() const noexcept { return _scale; } + std::optional scale() const noexcept { return _scale; } /** * @brief Gets the maximum allowed value for the property. Only applicable to @@ -450,7 +513,7 @@ template class PropertyView { * @returns The property's maximum value, or std::nullopt if it was not * specified. */ - virtual std::optional max() const noexcept { return _max; } + std::optional max() const noexcept { return _max; } /** * @brief Gets the minimum allowed value for the property. Only applicable to @@ -461,14 +524,14 @@ template class PropertyView { * @returns The property's minimum value, or std::nullopt if it was not * specified. */ - virtual std::optional min() const noexcept { return _min; } + std::optional min() const noexcept { return _min; } /** * @brief Whether the property must be present in every entity conforming to * the class. If not required, instances of the property may include "no data" * values, or the entire property may be omitted. */ - virtual bool required() const noexcept { return _required; } + bool required() const noexcept { return _required; } /** * @brief Gets the "no data" value, i.e., the value representing missing data @@ -476,19 +539,21 @@ template class PropertyView { * is given as the plain property value, without the transforms from the * normalized, offset, and scale properties. */ - virtual std::optional noData() const noexcept { return _noData; } + std::optional noData() const noexcept { return _noData; } /** * @brief Gets the default value to use when encountering a "no data" value or * an omitted property. The value is given in its final form, taking the * effect of normalized, offset, and scale properties into account. */ - virtual std::optional defaultValue() const noexcept { + std::optional defaultValue() const noexcept { return _defaultValue; } -private: +protected: PropertyViewStatusType _status; + +private: bool _required; std::optional _offset; @@ -500,13 +565,14 @@ template class PropertyView { std::optional _defaultValue; /** - * @brief Attempts to parse from the given json value. + * @brief Attempts to parse an ElementType from the given json value. * - * If T is a type with multiple components, e.g. a VECN or MATN type, this - * will return std::nullopt if one or more components could not be parsed. - * - * @return The value as an instance of T, or std::nullopt if it could not be + * If ElementType is a type with multiple components, e.g. a VECN or MATN + * type, this will return std::nullopt if one or more components could not be * parsed. + * + * @return The value as an instance of ElementType, or std::nullopt if it + * could not be parsed. */ static std::optional getValue(const CesiumUtility::JsonValue& jsonValue) { @@ -534,7 +600,8 @@ template class PropertyView { * may be overridden by individual instances of the property themselves. The * constructor is responsible for resolving those differences. * - * @tparam ElementType The C++ type of the values in this property + * @tparam ElementType The C++ type of the values in this property. Must have an + * integer component type. */ template class PropertyView { private: @@ -657,6 +724,21 @@ template class PropertyView { } protected: + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The value of {@link PropertyViewStatus} indicating the error with the property. + */ + PropertyView(PropertyViewStatusType status) + : _status(status), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + /** * @brief Constructs a property instance from a property table property and * its class definition. @@ -768,61 +850,59 @@ template class PropertyView { * * @return The status of this property view. */ - virtual PropertyViewStatusType status() const noexcept { return _status; } + PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return 0; } + int64_t arrayCount() const noexcept { return 0; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return false; } + bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ - virtual std::optional offset() const noexcept { - return _offset; - } + std::optional offset() const noexcept { return _offset; } /** * @copydoc IPropertyView::scale */ - virtual std::optional scale() const noexcept { - return _scale; - } + std::optional scale() const noexcept { return _scale; } /** * @copydoc IPropertyView::max */ - virtual std::optional max() const noexcept { return _max; } + std::optional max() const noexcept { return _max; } /** * @copydoc IPropertyView::min */ - virtual std::optional min() const noexcept { return _min; } + std::optional min() const noexcept { return _min; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional noData() const noexcept { return _noData; } + std::optional noData() const noexcept { return _noData; } /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional defaultValue() const noexcept { + std::optional defaultValue() const noexcept { return _defaultValue; } -private: +protected: PropertyViewStatusType _status; + +private: bool _required; std::optional _offset; @@ -896,6 +976,14 @@ template <> class PropertyView { } protected: + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The value of {@link PropertyViewStatus} indicating the error with the property. + */ + PropertyView(PropertyViewStatusType status) + : _status(status), _required(false), _defaultValue(std::nullopt) {} + /** * @brief Constructs a property instance from a property table property and * its class definition. @@ -918,57 +1006,57 @@ template <> class PropertyView { /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept { return _status; } + PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return 0; } + int64_t arrayCount() const noexcept { return 0; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return false; } + bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ - virtual std::optional offset() const noexcept { return std::nullopt; } + std::optional offset() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::scale */ - virtual std::optional scale() const noexcept { return std::nullopt; } + std::optional scale() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::max */ - virtual std::optional max() const noexcept { return std::nullopt; } + std::optional max() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::min */ - virtual std::optional min() const noexcept { return std::nullopt; } + std::optional min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional noData() const noexcept { return std::nullopt; } + std::optional noData() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional defaultValue() const noexcept { - return _defaultValue; - } + std::optional defaultValue() const noexcept { return _defaultValue; } -private: +protected: PropertyViewStatusType _status; + +private: bool _required; std::optional _defaultValue; @@ -1032,6 +1120,17 @@ template <> class PropertyView { } protected: + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The value of {@link PropertyViewStatus} indicating the error with the property. + */ + PropertyView(PropertyViewStatusType status) + : _status(status), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + /** * @brief Constructs a property instance from a property table property and * its class definition. @@ -1054,55 +1153,51 @@ template <> class PropertyView { /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept { return _status; } + PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return 0; } + int64_t arrayCount() const noexcept { return 0; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return false; } + bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ - virtual std::optional offset() const noexcept { + std::optional offset() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::scale */ - virtual std::optional scale() const noexcept { + std::optional scale() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::max */ - virtual std::optional max() const noexcept { - return std::nullopt; - } + std::optional max() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::min */ - virtual std::optional min() const noexcept { - return std::nullopt; - } + std::optional min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional noData() const noexcept { + std::optional noData() const noexcept { if (_noData) return std::string_view(*_noData); @@ -1112,15 +1207,17 @@ template <> class PropertyView { /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional defaultValue() const noexcept { + std::optional defaultValue() const noexcept { if (_defaultValue) return std::string_view(*_defaultValue); return std::nullopt; } -private: +protected: PropertyViewStatusType _status; + +private: bool _required; std::optional _noData; std::optional _defaultValue; @@ -1263,6 +1360,22 @@ class PropertyView> { } protected: + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The value of {@link PropertyViewStatus} indicating the error with the property. + */ + PropertyView(PropertyViewStatusType status) + : _status(status), + _count(0), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + /** * @brief Constructs a property instance from a property table property and * its class definition. @@ -1371,23 +1484,22 @@ class PropertyView> { /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept { return _status; } + PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return _count; } + int64_t arrayCount() const noexcept { return _count; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return _normalized; } + bool normalized() const noexcept { return _normalized; } /** * @copydoc IPropertyView::offset */ - virtual std::optional> - offset() const noexcept { + std::optional> offset() const noexcept { if (!_offset) { return std::nullopt; } @@ -1399,7 +1511,7 @@ class PropertyView> { /** * @copydoc IPropertyView::scale */ - virtual std::optional> scale() const noexcept { + std::optional> scale() const noexcept { if (!_scale) { return std::nullopt; } @@ -1411,7 +1523,7 @@ class PropertyView> { /** * @copydoc IPropertyView::max */ - virtual std::optional> max() const noexcept { + std::optional> max() const noexcept { if (!_max) { return std::nullopt; } @@ -1423,7 +1535,7 @@ class PropertyView> { /** * @copydoc IPropertyView::min */ - virtual std::optional> min() const noexcept { + std::optional> min() const noexcept { if (!_min) { return std::nullopt; } @@ -1435,13 +1547,12 @@ class PropertyView> { /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional> - noData() const noexcept { + std::optional> noData() const noexcept { if (!_noData) { return std::nullopt; } @@ -1453,8 +1564,7 @@ class PropertyView> { /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional> - defaultValue() const noexcept { + std::optional> defaultValue() const noexcept { if (!_defaultValue) { return std::nullopt; } @@ -1464,8 +1574,10 @@ class PropertyView> { _defaultValue->size())); } -private: +protected: PropertyViewStatusType _status; + +private: int64_t _count; bool _normalized; @@ -1640,6 +1752,18 @@ template <> class PropertyView> { } protected: + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The value of {@link PropertyViewStatus} indicating the error with the property. + */ + PropertyView(PropertyViewStatusType status) + : _status(status), + _count(0), + _required(false), + _defaultValue(), + _size(0) {} + /** * @brief Constructs a property instance from a property table property and * its class definition. @@ -1662,62 +1786,62 @@ template <> class PropertyView> { /** * @copydoc IPropertyView::status */ - virtual PropertyViewStatusType status() const noexcept { return _status; } + PropertyViewStatusType status() const noexcept { return _status; } /** * @copydoc IPropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return _count; } + int64_t arrayCount() const noexcept { return _count; } /** * @copydoc IPropertyView::normalized */ - virtual bool normalized() const noexcept { return false; } + bool normalized() const noexcept { return false; } /** * @copydoc IPropertyView::offset */ - virtual std::optional> offset() const noexcept { + std::optional> offset() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::scale */ - virtual std::optional> scale() const noexcept { + std::optional> scale() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::max */ - virtual std::optional> max() const noexcept { + std::optional> max() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::min */ - virtual std::optional> min() const noexcept { + std::optional> min() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::required */ - virtual bool required() const noexcept { return _required; } + bool required() const noexcept { return _required; } /** * @copydoc IPropertyView::noData */ - virtual std::optional> noData() const noexcept { + std::optional> noData() const noexcept { return std::nullopt; } /** * @copydoc IPropertyView::defaultValue */ - virtual std::optional> defaultValue() const noexcept { + std::optional> defaultValue() const noexcept { if (_size > 0) { return PropertyArrayView( gsl::span( @@ -1730,8 +1854,10 @@ template <> class PropertyView> { return std::nullopt; } -private: +protected: PropertyViewStatusType _status; + +private: int64_t _count; bool _required; @@ -1850,8 +1976,26 @@ template <> class PropertyView> { protected: /** - * @brief Constructs a property instance from a property table property and - * its class definition. + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The value of {@link PropertyViewStatus} indicating the error with the property. + */ + PropertyView(PropertyViewStatusType status) + : _status(status), + _count(0), + _required(false), + _noData(), + _noDataOffsets(), + _noDataOffsetType(PropertyComponentType::None), + _noDataSize(0), + _defaultValue(), + _defaultValueOffsets(), + _defaultValueOffsetType(PropertyComponentType::None), + _defaultValueSize(0) {} + + /** + * @brief Constructs a property instance from a property table property + * and its class definition. */ PropertyView( const ClassProperty& classProperty, @@ -1869,62 +2013,57 @@ template <> class PropertyView> { public: /** - * @copydoc IPropertyView::status + * @copydoc PropertyView::status */ - virtual PropertyViewStatusType status() const noexcept { return _status; } + PropertyViewStatusType status() const noexcept { return _status; } /** - * @copydoc IPropertyView::arrayCount + * @copydoc PropertyView::arrayCount */ - virtual int64_t arrayCount() const noexcept { return _count; } + int64_t arrayCount() const noexcept { return _count; } /** - * @copydoc IPropertyView::normalized + * @copydoc PropertyView::normalized */ - virtual bool normalized() const noexcept { return false; } + bool normalized() const noexcept { return false; } /** - * @copydoc IPropertyView::offset + * @copydoc PropertyView::offset */ - virtual std::optional> - offset() const noexcept { + std::optional> offset() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::scale + * @copydoc PropertyView::scale */ - virtual std::optional> - scale() const noexcept { + std::optional> scale() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::max + * @copydoc PropertyView::max */ - virtual std::optional> - max() const noexcept { + std::optional> max() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::min + * @copydoc PropertyView::min */ - virtual std::optional> - min() const noexcept { + std::optional> min() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::required + * @copydoc PropertyView::required */ - virtual bool required() const noexcept { return _required; } + bool required() const noexcept { return _required; } /** - * @copydoc IPropertyView::noData + * @copydoc PropertyView::noData */ - virtual std::optional> - noData() const noexcept { + std::optional> noData() const noexcept { if (_noDataSize > 0) { return PropertyArrayView( gsl::span(_noData.data(), _noData.size()), @@ -1939,9 +2078,9 @@ template <> class PropertyView> { } /** - * @copydoc IPropertyView::defaultValue + * @copydoc PropertyView::defaultValue */ - virtual std::optional> + std::optional> defaultValue() const noexcept { if (_noDataSize > 0) { return PropertyArrayView( @@ -1958,8 +2097,10 @@ template <> class PropertyView> { return std::nullopt; } -private: +protected: PropertyViewStatusType _status; + +private: int64_t _count; bool _required; diff --git a/CesiumGltf/test/TestPropertyTypeTraits.cpp b/CesiumGltf/test/TestPropertyTypeTraits.cpp index 140a2bf2b..a6f7bafcf 100644 --- a/CesiumGltf/test/TestPropertyTypeTraits.cpp +++ b/CesiumGltf/test/TestPropertyTypeTraits.cpp @@ -523,6 +523,23 @@ TEST_CASE("TypeToPropertyType") { } } +TEST_CASE("Test CanBeNormalized") { + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); +} + TEST_CASE("TypeToNormalizedType") { SECTION("Works for scalars") { REQUIRE(std::is_same_v::type, double>); diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp index a8be2978e..98edab663 100644 --- a/CesiumGltf/test/TestPropertyView.cpp +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -156,27 +156,6 @@ TEST_CASE("Scalar PropertyView") { REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); } - SECTION("Constructs with non-optional properties") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::UINT8; - classProperty.normalized = true; - classProperty.required = true; - - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.normalized()); - REQUIRE(view.required()); - - REQUIRE(view.arrayCount() == 0); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); - } - SECTION("Ignores count") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; @@ -191,23 +170,23 @@ TEST_CASE("Scalar PropertyView") { SECTION("Constructs with offset, scale, max, and min") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::INT16; - classProperty.offset = 5; - classProperty.scale = 2; - classProperty.max = 10; - classProperty.min = -10; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.offset = 5.04f; + classProperty.scale = 2.2f; + classProperty.max = 10.5f; + classProperty.min = -10.5f; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); REQUIRE(view.scale()); REQUIRE(view.max()); REQUIRE(view.min()); - REQUIRE(*view.offset() == 5); - REQUIRE(*view.scale() == 2); - REQUIRE(*view.max() == 10); - REQUIRE(*view.min() == -10); + REQUIRE(*view.offset() == 5.04f); + REQUIRE(*view.scale() == 2.2f); + REQUIRE(*view.max() == 10.5f); + REQUIRE(*view.min() == -10.5f); } SECTION("Constructs with noData and defaultProperty") { @@ -228,19 +207,27 @@ TEST_CASE("Scalar PropertyView") { REQUIRE(*view.defaultValue() == 1); } - SECTION("Ignores noData and defaultProperty when required is true") { + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.required = true; - classProperty.noData = 0; classProperty.defaultProperty = 1; - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.required()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = 0; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.scale = 200; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = 1234; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } SECTION("Reports errors for out-of-bounds values") { @@ -263,43 +250,27 @@ TEST_CASE("Scalar PropertyView") { classProperty.max = 1000; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); - - classProperty.scale = 200; - view = PropertyView(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); - - classProperty.offset = 1234; - view = PropertyView(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } SECTION("Reports errors for invalid types") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.defaultProperty = JsonValue::Array{1}; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); classProperty.noData = "0"; - view = PropertyView(classProperty); + view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); - classProperty.min = -12.7f; - view = PropertyView(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); - - classProperty.max = 5.5; - view = PropertyView(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); - classProperty.scale = false; - view = PropertyView(classProperty); + view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); classProperty.offset = JsonValue::Array{}; - view = PropertyView(classProperty); + view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } } @@ -356,27 +327,6 @@ TEST_CASE("VecN PropertyView") { REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); } - SECTION("Constructs with non-optional properties") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC3; - classProperty.componentType = ClassProperty::ComponentType::INT16; - classProperty.normalized = true; - classProperty.required = true; - - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.normalized()); - REQUIRE(view.required()); - - REQUIRE(view.arrayCount() == 0); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); - } - SECTION("Ignores count") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC3; From 78099d3a70884e837aa6e915133f327ae03413a5 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 21 Aug 2023 15:33:05 -0400 Subject: [PATCH 081/121] Fix PropertyView and unit tests --- .../include/CesiumGltf/PropertyConversions.h | 55 + CesiumGltf/include/CesiumGltf/PropertyView.h | 1546 ++++++++----- CesiumGltf/test/TestPropertyView.cpp | 2011 +++++++++++++---- 3 files changed, 2550 insertions(+), 1062 deletions(-) create mode 100644 CesiumGltf/include/CesiumGltf/PropertyConversions.h diff --git a/CesiumGltf/include/CesiumGltf/PropertyConversions.h b/CesiumGltf/include/CesiumGltf/PropertyConversions.h new file mode 100644 index 000000000..9fef8b1cc --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/PropertyConversions.h @@ -0,0 +1,55 @@ +#pragma once + +#include "CesiumGltf/PropertyArrayView.h" +#include "CesiumGltf/PropertyTypeTraits.h" + +#include + +#include +#include +#include +#include +#include + +namespace CesiumGltf { +template < + typename TSigned, + std::enable_if_t< + IsMetadataInteger::value && std::is_signed_v>> +double normalize(TSigned value) { + double max = static_cast(std::numeric_limits::max()); + return std::max(static_cast(value) / max, -1.0); +} + +template < + typename TUnsigned, + std::enable_if_t< + IsMetadataInteger::value && std::is_unsigned_v>> +double normalize(TUnsigned value) { + double max = static_cast(std::numeric_limits::max()); + return static_cast(value) / max; +} + +template < + glm::length_t N, + typename TSigned, + glm::qualifier Q, + std::enable_if_t< + IsMetadataInteger::value && std::is_signed_v>> +glm::vec normalize(glm::vec value) { + double max = static_cast(std::numeric_limits::max()); + return glm::max(static_cast>(value) / max, -1.0); +} + +template < + glm::length_t N, + typename TUnsigned, + glm::qualifier Q, + std::enable_if_t< + IsMetadataInteger::value && std::is_unsigned_v>> +glm::mat normalize(glm::mat value) { + double max = static_cast(std::numeric_limits::max()); + return glm::max(static_cast>(value) / max, -1.0); +} + +} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 3db5165fa..a6013a835 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -1,4 +1,5 @@ #include "CesiumGltf/ClassProperty.h" +#include "CesiumGltf/PropertyConversions.h" #include "CesiumGltf/PropertyTableProperty.h" #include "CesiumGltf/PropertyTextureProperty.h" #include "CesiumGltf/PropertyTypeTraits.h" @@ -90,18 +91,40 @@ class PropertyViewStatus { static const PropertyViewStatusType ErrorInvalidDefaultValue = 11; }; -template -class PropertyView; - namespace { template PropertyViewStatusType validatePropertyType(const ClassProperty& classProperty) { - using ElementType = T; - if constexpr (IsMetadataArray::value) { - using ElementType = typename MetadataArrayType::type; + if (TypeToPropertyType::value != + convertStringToPropertyType(classProperty.type)) { + return PropertyViewStatus::ErrorTypeMismatch; + } + + PropertyComponentType expectedComponentType = + TypeToPropertyType::component; + + if (!classProperty.componentType && + expectedComponentType != PropertyComponentType::None) { + return PropertyViewStatus::ErrorComponentTypeMismatch; + } + + if (classProperty.componentType && + expectedComponentType != + convertStringToPropertyComponentType(*classProperty.componentType)) { + return PropertyViewStatus::ErrorComponentTypeMismatch; + } + + if (classProperty.array) { + return PropertyViewStatus::ErrorArrayTypeMismatch; } + return PropertyViewStatus::Valid; +} + +template +PropertyViewStatusType +validateArrayPropertyType(const ClassProperty& classProperty) { + using ElementType = typename MetadataArrayType::type; if (TypeToPropertyType::value != convertStringToPropertyType(classProperty.type)) { return PropertyViewStatus::ErrorTypeMismatch; @@ -121,20 +144,8 @@ validatePropertyType(const ClassProperty& classProperty) { return PropertyViewStatus::ErrorComponentTypeMismatch; } - if constexpr (IsMetadataArray::value) { - if (!classProperty.array) { - return PropertyViewStatus::ErrorArrayTypeMismatch; - } - } else { - if (classProperty.array) { - return PropertyViewStatus::ErrorArrayTypeMismatch; - } - } - - if (!CanBeNormalized::value) { - if (classProperty.normalized) { - return PropertyViewStatus::ErrorInvalidNormalization; - } + if (!classProperty.array) { + return PropertyViewStatus::ErrorArrayTypeMismatch; } return PropertyViewStatus::Valid; @@ -212,6 +223,12 @@ getMatN(const CesiumUtility::JsonValue& jsonValue) { } // namespace +/** + * @brief Represents a metadata property in EXT_structural_metadata. + */ +template +class PropertyView; + /** * @brief Represents a non-normalized metadata property in * EXT_structural_metadata. @@ -270,6 +287,7 @@ template class PropertyView { break; } // If it does not break here, something went wrong. + [[fallthrough]]; default: _status = PropertyViewStatus::ErrorInvalidOffset; return; @@ -286,6 +304,7 @@ template class PropertyView { break; } // If it does not break here, something went wrong. + [[fallthrough]]; default: _status = PropertyViewStatus::ErrorInvalidScale; return; @@ -310,21 +329,12 @@ template class PropertyView { } } - if (_required) { - // "noData" should not be defined if the property is required. - if (classProperty.noData) { - _status = PropertyViewStatus::ErrorInvalidNoDataValue; - return; - } - - if (classProperty.defaultProperty) { - _status = PropertyViewStatus::ErrorInvalidDefaultValue; - return; + if (classProperty.noData) { + if (!_required) { + // "noData" can only be defined if the property is required. + _noData = getValue(*classProperty.noData); } - } - if (classProperty.noData) { - _noData = getValue(*classProperty.noData); if (!_noData) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidNoDataValue; @@ -333,7 +343,11 @@ template class PropertyView { } if (classProperty.defaultProperty) { - _defaultValue = getValue(*classProperty.defaultProperty); + if (!_required) { + // "default" can only be defined if the property is required. + _defaultValue = getValue(*classProperty.defaultProperty); + } + if (!_defaultValue) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidDefaultValue; @@ -370,42 +384,57 @@ template class PropertyView { return; } - // If the property has its own values, the class-provided values. - if constexpr (IsMetadataNumeric::value) { - if (property.offset) { + // If the property has its own values, override the class-provided values. + + if (property.offset) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: _offset = getValue(*property.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; + if (_offset) { + break; } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + _status = PropertyViewStatus::ErrorInvalidOffset; + return; } + } - if (property.scale) { + if (property.scale) { + // Only floating point types can specify a scale. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: _scale = getValue(*property.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; + if (_scale) { + break; } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + _status = PropertyViewStatus::ErrorInvalidScale; + return; } + } - if (property.max) { - _max = getValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } + if (property.max) { + _max = getValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; } + } - if (property.min) { - _min = getValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + if (property.min) { + _min = getValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; } } } @@ -422,42 +451,57 @@ template class PropertyView { return; } - // If the property has its own values, the class-provided values. - if constexpr (IsMetadataNumeric::value) { - if (property.offset) { + // If the property has its own values, override the class-provided values. + + if (property.offset) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: _offset = getValue(*property.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; + if (_offset) { + break; } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + _status = PropertyViewStatus::ErrorInvalidOffset; + return; } + } - if (property.scale) { + if (property.scale) { + // Only floating point types can specify a scale. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: _scale = getValue(*property.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; + if (_scale) { + break; } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + _status = PropertyViewStatus::ErrorInvalidScale; + return; } + } - if (property.max) { - _max = getValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } + if (property.max) { + _max = getValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; } + } - if (property.min) { - _min = getValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + if (property.min) { + _min = getValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; } } } @@ -603,7 +647,11 @@ template class PropertyView { * @tparam ElementType The C++ type of the values in this property. Must have an * integer component type. */ -template class PropertyView { +template +class PropertyView< + ElementType, + true, + std::enable_if_t::value>> { private: using NormalizedType = typename TypeToNormalizedType::type; @@ -625,7 +673,7 @@ template class PropertyView { * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _status(PropertyViewStatus::Valid), + : _status(validatePropertyType(classProperty)), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -633,29 +681,7 @@ template class PropertyView { _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { - if (convertPropertyTypeToString(TypeToPropertyType::value) != - classProperty.type) { - _status = PropertyViewStatus::ErrorTypeMismatch; - return; - } - - if (!classProperty.componentType && - TypeToPropertyType::component != - PropertyComponentType::None) { - _status = PropertyViewStatus::ErrorComponentTypeMismatch; - return; - } - - if (classProperty.componentType && - convertPropertyComponentTypeToString( - TypeToPropertyType::component) != - *classProperty.componentType) { - _status = PropertyViewStatus::ErrorComponentTypeMismatch; - return; - } - - if (classProperty.array) { - _status = PropertyViewStatus::ErrorArrayTypeMismatch; + if (_status != PropertyViewStatus::Valid) { return; } @@ -663,62 +689,71 @@ template class PropertyView { _status = PropertyViewStatus::ErrorInvalidNormalization; } - if constexpr (IsMetadataNumeric::value) { - if (classProperty.offset) { - _offset = getValue(*classProperty.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } + if (classProperty.offset) { + _offset = getValue(*classProperty.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; } + } - if (classProperty.scale) { - _scale = getValue(*classProperty.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } + if (classProperty.scale) { + _scale = getValue(*classProperty.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; } + } - if (classProperty.max) { - _max = getValue(*classProperty.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } + if (classProperty.max) { + _max = getValue(*classProperty.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; } + } - if (classProperty.min) { - _min = getValue(*classProperty.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + if (classProperty.min) { + _min = getValue(*classProperty.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; } } - if (!_required) { + if (_required) { + // "noData" should not be defined if the property is required. if (classProperty.noData) { - _noData = getValue(*classProperty.noData); - if (!_noData) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidNoDataValue; - return; - } + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; } + // default value should not be defined if the property is required. if (classProperty.defaultProperty) { - _defaultValue = - getValue(*classProperty.defaultProperty); - if (!_defaultValue) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidDefaultValue; - return; - } + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; + } + } + + if (classProperty.noData) { + _noData = getValue(*classProperty.noData); + if (!_noData) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; + } + } + + if (classProperty.defaultProperty) { + _defaultValue = getValue(*classProperty.defaultProperty); + if (!_defaultValue) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; } } } @@ -751,42 +786,41 @@ template class PropertyView { return; } - // If the property has its own values, the class-provided values. - if constexpr (IsMetadataNumeric::value) { - if (property.offset) { - _offset = getValue(*property.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } + // If the property has its own values, override the class-provided values. + + if (property.offset) { + _offset = getValue(*property.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; } + } - if (property.scale) { - _scale = getValue(*property.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } + if (property.scale) { + _scale = getValue(*property.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; } + } - if (property.max) { - _max = getValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } + if (property.max) { + _max = getValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; } + } - if (property.min) { - _min = getValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + if (property.min) { + _min = getValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; } } } @@ -803,42 +837,41 @@ template class PropertyView { return; } - // If the property has its own values, the class-provided values. - if constexpr (IsMetadataNumeric::value) { - if (property.offset) { - _offset = getValue(*property.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } + // If the property has its own values, override the class-provided values. + + if (property.offset) { + _offset = getValue(*property.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; } + } - if (property.scale) { - _scale = getValue(*property.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } + if (property.scale) { + _scale = getValue(*property.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; } + } - if (property.max) { - _max = getValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } + if (property.max) { + _max = getValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; } + } - if (property.min) { - _min = getValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + if (property.min) { + _min = getValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; } } } @@ -853,47 +886,47 @@ template class PropertyView { PropertyViewStatusType status() const noexcept { return _status; } /** - * @copydoc IPropertyView::arrayCount + * @copydoc PropertyView::arrayCount */ int64_t arrayCount() const noexcept { return 0; } /** - * @copydoc IPropertyView::normalized + * @copydoc PropertyView::normalized */ - bool normalized() const noexcept { return false; } + bool normalized() const noexcept { return true; } /** - * @copydoc IPropertyView::offset + * @copydoc PropertyView::offset */ std::optional offset() const noexcept { return _offset; } /** - * @copydoc IPropertyView::scale + * @copydoc PropertyView::scale */ std::optional scale() const noexcept { return _scale; } /** - * @copydoc IPropertyView::max + * @copydoc PropertyView::max */ std::optional max() const noexcept { return _max; } /** - * @copydoc IPropertyView::min + * @copydoc PropertyView::min */ std::optional min() const noexcept { return _min; } /** - * @copydoc IPropertyView::required + * @copydoc PropertyView::required */ bool required() const noexcept { return _required; } /** - * @copydoc IPropertyView::noData + * @copydoc PropertyView::noData */ std::optional noData() const noexcept { return _noData; } /** - * @copydoc IPropertyView::defaultValue + * @copydoc PropertyView::defaultValue */ std::optional defaultValue() const noexcept { return _defaultValue; @@ -902,6 +935,11 @@ template class PropertyView { protected: PropertyViewStatusType _status; + NormalizedType applyValueTransforms(ElementType value) { + NormalizedType result = normalize(value); + return result; + } + private: bool _required; @@ -938,6 +976,10 @@ template class PropertyView { } }; +/** + * @brief Represents a boolean metadata property in + * EXT_structural_metadata. + */ template <> class PropertyView { public: /** @@ -952,21 +994,18 @@ template <> class PropertyView { * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _status(PropertyViewStatus::Valid), + : _status(validatePropertyType(classProperty)), _required(classProperty.required), _defaultValue(std::nullopt) { - if (classProperty.type != ClassProperty::Type::BOOLEAN) { - _status = PropertyViewStatus::ErrorTypeMismatch; + if (_status != PropertyViewStatus::Valid) { return; } - if (classProperty.array) { - _status = PropertyViewStatus::ErrorArrayTypeMismatch; - return; - } + if (classProperty.defaultProperty) { + if (!_required) { + _defaultValue = getBooleanValue(*classProperty.defaultProperty); + } - if (!_required && classProperty.defaultProperty) { - _defaultValue = getBooleanValue(*classProperty.defaultProperty); if (!_defaultValue) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidDefaultValue; @@ -1004,52 +1043,52 @@ template <> class PropertyView { public: /** - * @copydoc IPropertyView::status + * @copydoc PropertyView::status */ PropertyViewStatusType status() const noexcept { return _status; } /** - * @copydoc IPropertyView::arrayCount + * @copydoc PropertyView::arrayCount */ int64_t arrayCount() const noexcept { return 0; } /** - * @copydoc IPropertyView::normalized + * @copydoc PropertyView::normalized */ bool normalized() const noexcept { return false; } /** - * @copydoc IPropertyView::offset + * @copydoc PropertyView::offset */ std::optional offset() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::scale + * @copydoc PropertyView::scale */ std::optional scale() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::max + * @copydoc PropertyView::max */ std::optional max() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::min + * @copydoc PropertyView::min */ std::optional min() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::required + * @copydoc PropertyView::required */ bool required() const noexcept { return _required; } /** - * @copydoc IPropertyView::noData + * @copydoc PropertyView::noData */ std::optional noData() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::defaultValue + * @copydoc PropertyView::defaultValue */ std::optional defaultValue() const noexcept { return _defaultValue; } @@ -1070,6 +1109,10 @@ template <> class PropertyView { } }; +/** + * @brief Represents a string metadata property in + * EXT_structural_metadata. + */ template <> class PropertyView { public: /** @@ -1085,36 +1128,35 @@ template <> class PropertyView { * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _status(PropertyViewStatus::Valid), + : _status(validatePropertyType(classProperty)), _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { - if (classProperty.type != ClassProperty::Type::STRING) { - _status = PropertyViewStatus::ErrorTypeMismatch; - return; - } - - if (classProperty.array) { - _status = PropertyViewStatus::ErrorArrayTypeMismatch; + if (_status != PropertyViewStatus::Valid) { return; } - if (!_required) { - if (classProperty.noData) { + if (classProperty.noData) { + if (!_required) { _noData = getStringValue(*classProperty.noData); - if (!_noData) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidNoDataValue; - return; - } } - if (classProperty.defaultProperty) { + + if (!_noData) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; + } + } + + if (classProperty.defaultProperty) { + if (!_required) { _defaultValue = getStringValue(*classProperty.defaultProperty); - if (!_defaultValue) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidDefaultValue; - return; - } + } + + if (!_defaultValue) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; } } } @@ -1151,51 +1193,51 @@ template <> class PropertyView { public: /** - * @copydoc IPropertyView::status + * @copydoc PropertyView::status */ PropertyViewStatusType status() const noexcept { return _status; } /** - * @copydoc IPropertyView::arrayCount + * @copydoc PropertyView::arrayCount */ int64_t arrayCount() const noexcept { return 0; } /** - * @copydoc IPropertyView::normalized + * @copydoc PropertyView::normalized */ bool normalized() const noexcept { return false; } /** - * @copydoc IPropertyView::offset + * @copydoc PropertyView::offset */ std::optional offset() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::scale + * @copydoc PropertyView::scale */ std::optional scale() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::max + * @copydoc PropertyView::max */ std::optional max() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::min + * @copydoc PropertyView::min */ std::optional min() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::required + * @copydoc PropertyView::required */ bool required() const noexcept { return _required; } /** - * @copydoc IPropertyView::noData + * @copydoc PropertyView::noData */ std::optional noData() const noexcept { if (_noData) @@ -1205,7 +1247,7 @@ template <> class PropertyView { } /** - * @copydoc IPropertyView::defaultValue + * @copydoc PropertyView::defaultValue */ std::optional defaultValue() const noexcept { if (_defaultValue) @@ -1214,26 +1256,490 @@ template <> class PropertyView { return std::nullopt; } -protected: - PropertyViewStatusType _status; +protected: + PropertyViewStatusType _status; + +private: + bool _required; + std::optional _noData; + std::optional _defaultValue; + + static std::optional + getStringValue(const CesiumUtility::JsonValue& value) { + if (!value.isString()) { + return std::nullopt; + } + + return std::string(value.getString().c_str()); + } +}; + +/** + * @brief Represents a non-normalized array metadata property in + * EXT_structural_metadata. + * + * Whether they belong to property tables, property textures, or property + * attributes, properties have their own sub-properties affecting the actual + * property values. Although they are typically defined via class property, they + * may be overridden by individual instances of the property themselves. The + * constructor is responsible for resolving those differences. + * + * @tparam ElementType The C++ type of the elements in the array values for this + * property. + */ +template +class PropertyView> { +public: + /** + * @brief Constructs an empty property instance. + */ + PropertyView() + : _status(PropertyViewStatus::ErrorNonexistentProperty), + _count(0), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + + /** + * @brief Constructs a property instance from a class definition only. + */ + PropertyView(const ClassProperty& classProperty) + : _status(validateArrayPropertyType>( + classProperty)), + _count(_count = classProperty.count ? *classProperty.count : 0), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(classProperty.required), + _noData(std::nullopt), + _defaultValue(std::nullopt) { + if (_status != PropertyViewStatus::Valid) { + return; + } + + if (classProperty.normalized) { + _status = PropertyViewStatus::ErrorInvalidNormalization; + return; + } + + if (classProperty.offset) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: + _offset = getArrayValue(*classProperty.offset); + if (_offset && + (_count == 0 || _offset->size() == static_cast(_count))) { + break; + } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (classProperty.scale) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: + _scale = getArrayValue(*classProperty.scale); + if (_scale && + (_count == 0 || _scale->size() == static_cast(_count))) { + break; + } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (classProperty.max) { + _max = getArrayValue(*classProperty.max); + if (!_max || + (_count > 0 && _max->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (classProperty.min) { + _min = getArrayValue(*classProperty.min); + if (!_min || + (_count > 0 && _min->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + + if (classProperty.noData) { + if (!_required) { + _noData = getArrayValue(*classProperty.noData); + } + + if (!_noData) { + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; + } + } + + if (classProperty.defaultProperty) { + if (!_required) { + _defaultValue = getArrayValue(*classProperty.defaultProperty); + } + + if (!_defaultValue) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; + } + } + } + +protected: + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The value of {@link PropertyViewStatus} indicating the error with the property. + */ + PropertyView(PropertyViewStatusType status) + : _status(status), + _count(0), + _offset(std::nullopt), + _scale(std::nullopt), + _max(std::nullopt), + _min(std::nullopt), + _required(false), + _noData(std::nullopt), + _defaultValue(std::nullopt) {} + + /** + * @brief Constructs a property instance from a property table property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTableProperty& property) + : PropertyView(classProperty) { + if (_status != PropertyViewStatus::Valid) { + return; + } + + // If the property has its own values, override the class-provided values. + + if (property.offset) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: + _offset = getArrayValue(*property.offset); + if (_offset && + (_count == 0 || _offset->size() == static_cast(_count))) { + break; + } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (property.scale) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: + _scale = getArrayValue(*property.scale); + if (_scale && + (_count == 0 || _scale->size() == static_cast(_count))) { + break; + } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (property.max) { + _max = getArrayValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (property.min) { + _min = getArrayValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + } + + /** + * @brief Constructs a property instance from a property texture property and + * its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyTextureProperty& property) + : PropertyView(classProperty) { + if (_status != PropertyViewStatus::Valid) { + return; + } + + // If the property has its own values, override the class-provided values. + if (property.offset) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: + _offset = getArrayValue(*property.offset); + if (_offset && + (count == 0 || _offset->size() == static_cast(_count))) { + break; + } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (property.scale) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: + _scale = getArrayValue(*property.scale); + if (_scale && + (count == 0 || _scale->size() == static_cast(_count))) { + break; + } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (property.max) { + _max = getArrayValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (property.min) { + _min = getArrayValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + } + +public: + /** + * @copydoc PropertyView::status + */ + PropertyViewStatusType status() const noexcept { return _status; } + + /** + * @copydoc PropertyView::arrayCount + */ + int64_t arrayCount() const noexcept { return _count; } + + /** + * @copydoc PropertyView::normalized + */ + bool normalized() const noexcept { return false; } + + /** + * @copydoc PropertyView::offset + */ + std::optional> offset() const noexcept { + if (!_offset) { + return std::nullopt; + } + + return PropertyArrayView( + gsl::span(_offset->data(), _offset->size())); + } + + /** + * @copydoc PropertyView::scale + */ + std::optional> scale() const noexcept { + if (!_scale) { + return std::nullopt; + } + + return PropertyArrayView( + gsl::span(_scale->data(), _scale->size())); + } + + /** + * @copydoc PropertyView::max + */ + std::optional> max() const noexcept { + if (!_max) { + return std::nullopt; + } + + return PropertyArrayView( + gsl::span(_max->data(), _max->size())); + } + + /** + * @copydoc PropertyView::min + */ + std::optional> min() const noexcept { + if (!_min) { + return std::nullopt; + } + + return PropertyArrayView( + gsl::span(_min->data(), _min->size())); + } + + /** + * @copydoc PropertyView::required + */ + bool required() const noexcept { return _required; } + + /** + * @copydoc PropertyView::noData + */ + std::optional> noData() const noexcept { + if (!_noData) { + return std::nullopt; + } + + return PropertyArrayView( + gsl::span(_noData->data(), _noData->size())); + } + + /** + * @copydoc PropertyView::defaultValue + */ + std::optional> defaultValue() const noexcept { + if (!_defaultValue) { + return std::nullopt; + } + + return PropertyArrayView(gsl::span( + _defaultValue->data(), + _defaultValue->size())); + } + +protected: + PropertyViewStatusType _status; + +private: + int64_t _count; + + std::optional> _offset; + std::optional> _scale; + std::optional> _max; + std::optional> _min; + + bool _required; + std::optional> _noData; + std::optional> _defaultValue; + + static std::optional> + getArrayValue(const CesiumUtility::JsonValue& jsonValue) { + if (!jsonValue.isArray()) { + return std::nullopt; + } + + const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); + std::vector values; + values.reserve(array.size()); + + if constexpr (IsMetadataScalar::value) { + for (size_t i = 0; i < array.size(); i++) { + std::optional element = getScalar(array[i]); + if (!element) { + return std::nullopt; + } + + values.push_back(*element); + } + } + if constexpr (IsMetadataVecN::value) { + for (size_t i = 0; i < array.size(); i++) { + std::optional element = getVecN(array[i]); + if (!element) { + return std::nullopt; + } + + values.push_back(*element); + } + } -private: - bool _required; - std::optional _noData; - std::optional _defaultValue; + if constexpr (IsMetadataMatN::value) { + for (size_t i = 0; i < array.size(); i++) { + std::optional element = getMatN(array[i]); + if (!element) { + return std::nullopt; + } - static std::optional - getStringValue(const CesiumUtility::JsonValue& value) { - if (!value.isString()) { - return std::nullopt; + values.push_back(*element); + } } - return std::string(value.getString().c_str()); + std::vector result(values.size() * sizeof(ElementType)); + std::memcpy(result.data(), values.data(), result.size()); + + return result; } }; +/** + * @brief Represents a normalized array metadata property in + * EXT_structural_metadata. + * + * Whether they belong to property tables, property textures, or property + * attributes, properties have their own sub-properties affecting the actual + * property values. Although they are typically defined via class property, they + * may be overridden by individual instances of the property themselves. The + * constructor is responsible for resolving those differences. + * + * @tparam ElementType The C++ type of the elements in the array values for this + * property. Must have an integer component type. + */ template -class PropertyView> { +class PropertyView< + PropertyArrayView, + true, + std::enable_if_t::value>> { +private: + using NormalizedType = typename TypeToNormalizedType::type; + public: /** * @brief Constructs an empty property instance. @@ -1241,7 +1747,6 @@ class PropertyView> { PropertyView() : _status(PropertyViewStatus::ErrorNonexistentProperty), _count(0), - _normalized(false), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -1254,9 +1759,9 @@ class PropertyView> { * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _status(PropertyViewStatus::Valid), + : _status(validateArrayPropertyType>( + classProperty)), _count(_count = classProperty.count ? *classProperty.count : 0), - _normalized(classProperty.normalized), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -1264,97 +1769,75 @@ class PropertyView> { _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { - if (convertPropertyTypeToString(TypeToPropertyType::value) != - classProperty.type) { - _status = PropertyViewStatus::ErrorTypeMismatch; - return; - } - - if (!classProperty.componentType && - TypeToPropertyType::component != - PropertyComponentType::None) { - _status = PropertyViewStatus::ErrorComponentTypeMismatch; + if (_status != PropertyViewStatus::Valid) { return; } - if (classProperty.componentType && - convertPropertyComponentTypeToString( - TypeToPropertyType::component) != - *classProperty.componentType) { - _status = PropertyViewStatus::ErrorComponentTypeMismatch; + if (!classProperty.normalized) { + _status = PropertyViewStatus::ErrorInvalidNormalization; return; } - if (!classProperty.array) { - _status = PropertyViewStatus::ErrorArrayTypeMismatch; - return; + if (classProperty.offset) { + _offset = getArrayValue(*classProperty.offset); + if (!_offset || + (_count > 0 && _offset->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } } - if (classProperty.normalized) { - _status = PropertyViewStatus::ErrorInvalidNormalization; - return; + if (classProperty.scale) { + _scale = getArrayValue(*classProperty.scale); + if (!_scale || + (_count > 0 && _scale->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } } - // If the property has its own values, the class-provided values. - if constexpr (IsMetadataNumeric::value) { - if (classProperty.offset) { - _offset = getArrayValue(*classProperty.offset); - if (!_offset || - (_count > 0 && _offset->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } + if (classProperty.max) { + _max = getArrayValue(*classProperty.max); + if (!_max || + (_count > 0 && _max->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; } + } - if (classProperty.scale) { - _scale = getArrayValue(*classProperty.scale); - if (!_scale || - (_count > 0 && _scale->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } + if (classProperty.min) { + _min = getArrayValue(*classProperty.min); + if (!_min || + (_count > 0 && _min->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; } + } - if (classProperty.max) { - _max = getArrayValue(*classProperty.max); - if (!_max || - (_count > 0 && _max->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } + if (classProperty.noData) { + if (!_required) { + _noData = getArrayValue(*classProperty.noData); } - if (classProperty.min) { - _min = getArrayValue(*classProperty.min); - if (!_min || - (_count > 0 && _min->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + if (!_noData) { + _status = PropertyViewStatus::ErrorInvalidNoDataValue; + return; } } - if (!_required) { - if (classProperty.noData) { - _noData = getArrayValue(*classProperty.noData); - if (!_noData) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidNoDataValue; - return; - } + if (classProperty.defaultProperty) { + if (!_required) { + _defaultValue = + getArrayValue(*classProperty.defaultProperty); } - if (classProperty.defaultProperty) { - _defaultValue = getArrayValue(*classProperty.defaultProperty); - if (!_defaultValue) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidDefaultValue; - return; - } + if (!_defaultValue) { + _status = PropertyViewStatus::ErrorInvalidDefaultValue; + return; } } } @@ -1388,42 +1871,45 @@ class PropertyView> { return; } - // If the property has its own values, the class-provided values. - if constexpr (IsMetadataNumeric::value) { - if (property.offset) { - _offset = getArrayValue(*property.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } + // If the property has its own values, override the class-provided values. + + if (property.offset) { + _offset = getArrayValue(*property.offset); + if (!_offset || + (_count > 0 && _offset->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; } + } - if (property.scale) { - _scale = getArrayValue(*property.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } + if (property.scale) { + _scale = getArrayValue(*property.scale); + if (!_scale || + (_count > 0 || _scale->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; } + } - if (property.max) { - _max = getArrayValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } + if (property.max) { + _max = getArrayValue(*property.max); + if (!_max || + (_count > 0 && _max->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; } + } - if (property.min) { - _min = getArrayValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + if (property.min) { + _min = getArrayValue(*property.min); + if (!_min || + (_count > 0 && _min->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; } } } @@ -1440,117 +1926,120 @@ class PropertyView> { return; } - // If the property has its own values, the class-provided values. - if constexpr (IsMetadataNumeric::value) { - if (property.offset) { - _offset = getArrayValue(*property.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } + // If the property has its own values, override the class-provided values. + + if (property.offset) { + _offset = getArrayValue(*property.offset); + if (!_offset || + (_count > 0 && _offset->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; } + } - if (property.scale) { - _scale = getArrayValue(*property.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } + if (property.scale) { + _scale = getArrayValue(*property.scale); + if (!_scale || + (_count > 0 || _scale->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; } + } - if (property.max) { - _max = getArrayValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } + if (property.max) { + _max = getArrayValue(*property.max); + if (!_max || + (_count > 0 && _max->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; } + } - if (property.min) { - _min = getArrayValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + if (property.min) { + _min = getArrayValue(*property.min); + if (!_min || + (_count > 0 && _min->size() != static_cast(_count))) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; } } } public: /** - * @copydoc IPropertyView::status + * @copydoc PropertyView::status */ PropertyViewStatusType status() const noexcept { return _status; } /** - * @copydoc IPropertyView::arrayCount + * @copydoc PropertyView::arrayCount */ int64_t arrayCount() const noexcept { return _count; } /** - * @copydoc IPropertyView::normalized + * @copydoc PropertyView::normalized */ - bool normalized() const noexcept { return _normalized; } + bool normalized() const noexcept { return true; } /** - * @copydoc IPropertyView::offset + * @copydoc PropertyView::offset */ - std::optional> offset() const noexcept { + std::optional> offset() const noexcept { if (!_offset) { return std::nullopt; } - return PropertyArrayView( + return PropertyArrayView( gsl::span(_offset->data(), _offset->size())); } /** - * @copydoc IPropertyView::scale + * @copydoc PropertyView::scale */ - std::optional> scale() const noexcept { + std::optional> scale() const noexcept { if (!_scale) { return std::nullopt; } - return PropertyArrayView( + return PropertyArrayView( gsl::span(_scale->data(), _scale->size())); } /** - * @copydoc IPropertyView::max + * @copydoc PropertyView::max */ - std::optional> max() const noexcept { + std::optional> max() const noexcept { if (!_max) { return std::nullopt; } - return PropertyArrayView( + return PropertyArrayView( gsl::span(_max->data(), _max->size())); } /** - * @copydoc IPropertyView::min + * @copydoc PropertyView::min */ - std::optional> min() const noexcept { + std::optional> min() const noexcept { if (!_min) { return std::nullopt; } - return PropertyArrayView( + return PropertyArrayView( gsl::span(_min->data(), _min->size())); } /** - * @copydoc IPropertyView::required + * @copydoc PropertyView::required */ bool required() const noexcept { return _required; } /** - * @copydoc IPropertyView::noData + * @copydoc PropertyView::noData */ std::optional> noData() const noexcept { if (!_noData) { @@ -1562,14 +2051,15 @@ class PropertyView> { } /** - * @copydoc IPropertyView::defaultValue + * @copydoc PropertyView::defaultValue */ - std::optional> defaultValue() const noexcept { + std::optional> + defaultValue() const noexcept { if (!_defaultValue) { return std::nullopt; } - return PropertyArrayView(gsl::span( + return PropertyArrayView(gsl::span( _defaultValue->data(), _defaultValue->size())); } @@ -1579,7 +2069,6 @@ class PropertyView> { private: int64_t _count; - bool _normalized; std::optional> _offset; std::optional> _scale; @@ -1590,6 +2079,7 @@ class PropertyView> { std::optional> _noData; std::optional> _defaultValue; + template static std::optional> getArrayValue(const CesiumUtility::JsonValue& jsonValue) { if (!jsonValue.isArray()) { @@ -1597,12 +2087,12 @@ class PropertyView> { } const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); - std::vector values; + std::vector values; values.reserve(array.size()); - if constexpr (IsMetadataScalar::value) { + if constexpr (IsMetadataScalar::value) { for (size_t i = 0; i < array.size(); i++) { - std::optional element = getScalar(array[i]); + std::optional element = getScalar(array[i]); if (!element) { return std::nullopt; } @@ -1610,9 +2100,10 @@ class PropertyView> { values.push_back(*element); } } - if constexpr (IsMetadataVecN::value) { + + if constexpr (IsMetadataVecN::value) { for (size_t i = 0; i < array.size(); i++) { - std::optional element = getVecN(array[i]); + std::optional element = getVecN(array[i]); if (!element) { return std::nullopt; } @@ -1621,9 +2112,9 @@ class PropertyView> { } } - if constexpr (IsMetadataMatN::value) { + if constexpr (IsMetadataMatN::value) { for (size_t i = 0; i < array.size(); i++) { - std::optional element = getMatN(array[i]); + std::optional element = getMatN(array[i]); if (!element) { return std::nullopt; } @@ -1632,83 +2123,17 @@ class PropertyView> { } } - std::vector result(values.size() * sizeof(ElementType)); + std::vector result(values.size() * sizeof(T)); std::memcpy(result.data(), values.data(), result.size()); return result; } - - template - static std::optional getScalar(const CesiumUtility::JsonValue& jsonValue) { - try { - return jsonValue.getSafeNumber(); - } catch (const CesiumUtility::JsonValueNotRealValue& /*error*/) { - return std::nullopt; - } catch (const gsl::narrowing_error& /*error*/) { - return std::nullopt; - } - } - - template - static std::optional - getVecN(const CesiumUtility::JsonValue& jsonValue) { - if (!jsonValue.isArray()) { - return std::nullopt; - } - - const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); - constexpr glm::length_t N = VecType::length(); - if (array.size() != N) { - return std::nullopt; - } - - using T = typename VecType::value_type; - - VecType result; - for (glm::length_t i = 0; i < N; i++) { - std::optional value = getScalar(array[i]); - if (!value) { - return std::nullopt; - } - - result[i] = *value; - } - - return result; - } - - template - static std::optional - getMatN(const CesiumUtility::JsonValue& jsonValue) { - if (!jsonValue.isArray()) { - return std::nullopt; - } - - const CesiumUtility::JsonValue::Array& array = jsonValue.getArray(); - constexpr glm::length_t N = MatType::length(); - if (array.size() != N * N) { - return std::nullopt; - } - - using T = typename MatType::value_type; - - MatType result; - for (glm::length_t i = 0; i < N; i++) { - // Try to parse each value in the column. - for (glm::length_t j = 0; j < N; j++) { - std::optional value = getScalar(array[i * N + j]); - if (!value) { - return std::nullopt; - } - - result[i][j] = *value; - } - } - - return result; - } }; +/** + * @brief Represents a boolean array metadata property in + * EXT_structural_metadata. + */ template <> class PropertyView> { public: /** @@ -1725,26 +2150,23 @@ template <> class PropertyView> { * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _status(PropertyViewStatus::Valid), + : _status( + validateArrayPropertyType>(classProperty)), _count(classProperty.count ? *classProperty.count : 0), _required(classProperty.required), _defaultValue(), _size(0) { - if (classProperty.type != ClassProperty::Type::BOOLEAN) { - _status = PropertyViewStatus::ErrorTypeMismatch; + if (_status != PropertyViewStatus::Valid) { return; } - if (!classProperty.array) { - _status = PropertyViewStatus::ErrorArrayTypeMismatch; - return; - } + if (classProperty.defaultProperty) { + if (!_required) { + _defaultValue = + getBooleanArrayValue(*classProperty.defaultProperty, _size); + } - if (!_required && classProperty.defaultProperty) { - _defaultValue = - getBooleanArrayValue(*classProperty.defaultProperty, _size); if (_size == 0 || (_count > 0 && _size != _count)) { - // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidDefaultValue; return; } @@ -1784,62 +2206,62 @@ template <> class PropertyView> { public: /** - * @copydoc IPropertyView::status + * @copydoc PropertyView::status */ PropertyViewStatusType status() const noexcept { return _status; } /** - * @copydoc IPropertyView::arrayCount + * @copydoc PropertyView::arrayCount */ int64_t arrayCount() const noexcept { return _count; } /** - * @copydoc IPropertyView::normalized + * @copydoc PropertyView::normalized */ bool normalized() const noexcept { return false; } /** - * @copydoc IPropertyView::offset + * @copydoc PropertyView::offset */ std::optional> offset() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::scale + * @copydoc PropertyView::scale */ std::optional> scale() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::max + * @copydoc PropertyView::max */ std::optional> max() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::min + * @copydoc PropertyView::min */ std::optional> min() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::required + * @copydoc PropertyView::required */ bool required() const noexcept { return _required; } /** - * @copydoc IPropertyView::noData + * @copydoc PropertyView::noData */ std::optional> noData() const noexcept { return std::nullopt; } /** - * @copydoc IPropertyView::defaultValue + * @copydoc PropertyView::defaultValue */ std::optional> defaultValue() const noexcept { if (_size > 0) { @@ -1904,6 +2326,10 @@ template <> class PropertyView> { } }; +/** + * @brief Represents a string array metadata property in + * EXT_structural_metadata. + */ template <> class PropertyView> { public: /** @@ -1926,7 +2352,8 @@ template <> class PropertyView> { * @brief Constructs a property instance from a class definition only. */ PropertyView(const ClassProperty& classProperty) - : _status(PropertyViewStatus::Valid), + : _status(validateArrayPropertyType>( + classProperty)), _count(classProperty.count ? *classProperty.count : 0), _required(classProperty.required), _noData(), @@ -1937,35 +2364,34 @@ template <> class PropertyView> { _defaultValueOffsets(), _defaultValueOffsetType(PropertyComponentType::None), _defaultValueSize(0) { - if (classProperty.type != ClassProperty::Type::STRING) { - _status = PropertyViewStatus::ErrorTypeMismatch; + if (_status != PropertyViewStatus::Valid) { return; } - if (!classProperty.array) { - _status = PropertyViewStatus::ErrorArrayTypeMismatch; - return; - } + if (classProperty.noData) { + if (!_required) { + _noData = getStringArrayValue( + *classProperty.noData, + _noDataOffsets, + _noDataOffsetType, + _noDataSize); + } - if (!_required && classProperty.noData) { - _noData = getStringArrayValue( - *classProperty.noData, - _noDataOffsets, - _noDataOffsetType, - _noDataSize); if (_noDataSize == 0 || (_count > 0 && _noDataSize != _count)) { - // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidNoDataValue; return; } } - if (!_required && classProperty.defaultProperty) { - _defaultValue = getStringArrayValue( - *classProperty.defaultProperty, - _defaultValueOffsets, - _defaultValueOffsetType, - _defaultValueSize); + if (classProperty.defaultProperty) { + if (!_required) { + _defaultValue = getStringArrayValue( + *classProperty.defaultProperty, + _defaultValueOffsets, + _defaultValueOffsetType, + _defaultValueSize); + } + if (_defaultValueSize == 0 || (_count > 0 && _noDataSize != _count)) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidDefaultValue; diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp index 98edab663..c9cf11553 100644 --- a/CesiumGltf/test/TestPropertyView.cpp +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -1,7 +1,5 @@ #include "CesiumGltf/PropertyView.h" -//#include "CesiumGltf/PropertyValue.h" - #include using namespace CesiumGltf; @@ -39,36 +37,6 @@ TEST_CASE("Boolean PropertyView") { REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); } - SECTION("Ignores non-applicable properties") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::BOOLEAN; - classProperty.normalized = true; - classProperty.offset = true; - classProperty.scale = true; - classProperty.max = true; - classProperty.min = true; - classProperty.noData = true; - - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(!view.normalized()); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - REQUIRE(!view.noData()); - } - - SECTION("Ignores count") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::BOOLEAN; - classProperty.count = 5; - - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.arrayCount() == 0); - } - SECTION("Constructs with defaultProperty") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; @@ -82,16 +50,14 @@ TEST_CASE("Boolean PropertyView") { REQUIRE(!*view.defaultValue()); } - SECTION("Ignores defaultProperty when required is true") { + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.required = true; classProperty.defaultProperty = false; PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.required()); - REQUIRE(!view.defaultValue()); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); } SECTION("Reports default value invalid type") { @@ -149,24 +115,13 @@ TEST_CASE("Scalar PropertyView") { SECTION("Reports invalid normalization") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.normalized = true; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); } - SECTION("Ignores count") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::UINT8; - classProperty.count = 5; - - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.arrayCount() == 0); - } - SECTION("Constructs with offset, scale, max, and min") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; @@ -275,6 +230,151 @@ TEST_CASE("Scalar PropertyView") { } } +TEST_CASE("Scalar PropertyView (normalized)") { + SECTION("Constructs empty PropertyView") { + PropertyView view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.normalized = false; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.normalized = true; + classProperty.offset = 5.04f; + classProperty.scale = 2.2f; + classProperty.max = 10.5f; + classProperty.min = -10.5f; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); + + REQUIRE(*view.offset() == 5.04f); + REQUIRE(*view.scale() == 2.2f); + REQUIRE(*view.max() == 10.5f); + REQUIRE(*view.min() == -10.5f); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.normalized = true; + classProperty.required = false; + classProperty.noData = 0; + classProperty.defaultProperty = 1.5; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + REQUIRE(*view.noData() == 0); + REQUIRE(*view.defaultValue() == 1.5); + } + + SECTION("Reports errors for incorrectly defined properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.normalized = true; + classProperty.required = true; + classProperty.defaultProperty = 1.0; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = 0; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.normalized = true; + classProperty.noData = -129; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.normalized = true; + classProperty.defaultProperty = JsonValue::Array{1}; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = "0"; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.scale = false; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = JsonValue::Array{}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } +} + TEST_CASE("VecN PropertyView") { SECTION("Constructs empty PropertyView") { PropertyView view; @@ -320,44 +420,33 @@ TEST_CASE("VecN PropertyView") { SECTION("Reports invalid normalization") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC3; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.normalized = true; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); } - SECTION("Ignores count") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC3; - classProperty.componentType = ClassProperty::ComponentType::INT16; - classProperty.count = 5; - - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.arrayCount() == 0); - } - SECTION("Constructs with offset, scale, max, and min") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC3; - classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.offset = {-1, 1, 2}; classProperty.scale = {2, 1, 3}; classProperty.max = {10, 5, 6}; classProperty.min = {-11, -12, -13}; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); REQUIRE(view.scale()); REQUIRE(view.max()); REQUIRE(view.min()); - REQUIRE(*view.offset() == glm::i16vec3(-1, 1, 2)); - REQUIRE(*view.scale() == glm::i16vec3(2, 1, 3)); - REQUIRE(*view.max() == glm::i16vec3(10, 5, 6)); - REQUIRE(*view.min() == glm::i16vec3(-11, -12, -13)); + REQUIRE(*view.offset() == glm::vec3(-1, 1, 2)); + REQUIRE(*view.scale() == glm::vec3(2, 1, 3)); + REQUIRE(*view.max() == glm::vec3(10, 5, 6)); + REQUIRE(*view.min() == glm::vec3(-11, -12, -13)); } SECTION("Constructs with noData and defaultProperty") { @@ -378,19 +467,27 @@ TEST_CASE("VecN PropertyView") { REQUIRE(*view.defaultValue() == glm::vec4(1.0f, 2.0f, 3.0f, 4.0f)); } - SECTION("Ignores noData and defaultProperty when required is true") { + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC4; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.required = true; - classProperty.noData = {0.0f, 0.0f, 0.0f, 0.0f}; - classProperty.defaultProperty = {1.0f, 2.0f, 3.0f, 4.0f}; + classProperty.defaultProperty = {1, 2}; - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.required()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = {0, 0}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.scale = {3, 2}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = {12, 8}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } SECTION("Reports errors for out-of-bounds values") { @@ -413,53 +510,45 @@ TEST_CASE("VecN PropertyView") { classProperty.max = {10, 5}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); - - classProperty.scale = {1, 128}; - view = PropertyView(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); - - classProperty.offset = {-1, -222}; - view = PropertyView(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } SECTION("Reports errors for invalid types") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC2; - classProperty.componentType = ClassProperty::ComponentType::INT8; - classProperty.defaultProperty = {1.0f, 20.9f}; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.defaultProperty = true; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); classProperty.noData = "0"; - view = PropertyView(classProperty); + view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); - classProperty.min = {-10, -1}; - view = PropertyView(classProperty); + classProperty.min = JsonValue::Array{-10}; + view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); classProperty.max = {10, 20, 30, 40}; - view = PropertyView(classProperty); + view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); classProperty.scale = 1; - view = PropertyView(classProperty); + view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); classProperty.offset = "(1, 2, 3)"; - view = PropertyView(classProperty); + view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } } -TEST_CASE("MatN PropertyView") { +TEST_CASE("VecN PropertyView (normalized)") { SECTION("Constructs empty PropertyView") { - PropertyView view; + PropertyView view; REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); REQUIRE(view.arrayCount() == 0); - REQUIRE(!view.normalized()); + REQUIRE(view.normalized()); REQUIRE(!view.offset()); REQUIRE(!view.scale()); REQUIRE(!view.max()); @@ -471,77 +560,199 @@ TEST_CASE("MatN PropertyView") { SECTION("Reports type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT4; + classProperty.type = ClassProperty::Type::VEC2; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); } SECTION("Reports component type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT2; + classProperty.type = ClassProperty::Type::VEC3; classProperty.componentType = ClassProperty::ComponentType::INT8; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Reports array type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT2; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Reports invalid normalization") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT2; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; - classProperty.normalized = true; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.normalized = false; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); } - SECTION("Constructs with non-optional properties") { + SECTION("Constructs with offset, scale, max, and min") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT3; + classProperty.type = ClassProperty::Type::VEC3; classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.normalized = true; - classProperty.required = true; + classProperty.offset = {-1, 1, 2}; + classProperty.scale = {2, 1, 3}; + classProperty.max = {10, 5, 6}; + classProperty.min = {-11, -12, -13}; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.normalized()); - REQUIRE(view.required()); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); - REQUIRE(view.arrayCount() == 0); + REQUIRE(*view.offset() == glm::dvec3(-1, 1, 2)); + REQUIRE(*view.scale() == glm::dvec3(2, 1, 3)); + REQUIRE(*view.max() == glm::dvec3(10, 5, 6)); + REQUIRE(*view.min() == glm::dvec3(-11, -12, -13)); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC4; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.normalized = true; + classProperty.required = false; + classProperty.noData = {0, 0, -1, -1}; + classProperty.defaultProperty = {1.0, 2.0, 3.0, 4.5}; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + REQUIRE(*view.noData() == glm::i8vec4(0, 0, -1, -1)); + REQUIRE(*view.defaultValue() == glm::dvec4(1.0, 2.0, 3.0, 4.5)); + } + + SECTION("Reports errors for incorrectly defined properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.normalized = true; + classProperty.required = true; + classProperty.defaultProperty = {1, 2}; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = {0, 0}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.normalized = true; + classProperty.noData = {-128, -129}; + + PropertyView view(classProperty); + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.normalized = true; + classProperty.defaultProperty = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = "0"; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = JsonValue::Array{-10}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {10, 20, 30, 40}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = 1; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = "(1, 2, 3)"; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } +} + +TEST_CASE("MatN PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); REQUIRE(!view.offset()); REQUIRE(!view.scale()); REQUIRE(!view.max()); REQUIRE(!view.min()); + REQUIRE(!view.required()); REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); } - SECTION("Ignores count") { + SECTION("Reports type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT3; - classProperty.componentType = ClassProperty::ComponentType::INT32; - classProperty.count = 5; + classProperty.type = ClassProperty::Type::MAT4; - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.arrayCount() == 0); + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.normalized = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); } SECTION("Constructs with offset, scale, max, and min") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT3; - classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; // clang-format off classProperty.offset = { -1, 1, 2, @@ -561,7 +772,7 @@ TEST_CASE("MatN PropertyView") { 9, 4, 5}; // clang-format on - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); REQUIRE(view.scale()); @@ -569,25 +780,25 @@ TEST_CASE("MatN PropertyView") { REQUIRE(view.min()); // clang-format off - glm::imat3x3 expectedOffset( + glm::mat3 expectedOffset( -1, 1, 2, 3, -1, 4, -5, -5, 0); REQUIRE(*view.offset() == expectedOffset); - glm::imat3x3 expectedScale( + glm::mat3 expectedScale( 1, 1, 1, 2, 2, 3, 3, 4, 5); REQUIRE(*view.scale() == expectedScale); - glm::imat3x3 expectedMax( + glm::mat3 expectedMax( 20, 5, 20, 30, 22, 43, 37, 1, 8); REQUIRE(*view.max() == expectedMax); - glm::imat3x3 expectedMin( + glm::mat3 expectedMin( -10, -2, -3, 0, 20, 4, 9, 4, 5); @@ -606,7 +817,7 @@ TEST_CASE("MatN PropertyView") { 0.0f, 0.0f}; classProperty.defaultProperty = { 1.0f, 2.0f, - 3.0f, 4.0f}; + 3.0f, 4.5f}; // clang-format on PropertyView view(classProperty); @@ -623,29 +834,47 @@ TEST_CASE("MatN PropertyView") { glm::mat2 expectedDefaultValue( 1.0f, 2.0f, - 3.0f, 4.0f); + 3.0f, 4.5f); REQUIRE(*view.defaultValue() == expectedDefaultValue); } - SECTION("Ignores noData and defaultProperty when required is true") { + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT2; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.required = true; + // clang-format off - classProperty.noData = { - 0.0f, 0.0f, - 0.0f, 0.0f}; classProperty.defaultProperty = { - 1.0f, 2.0f, - 3.0f, 4.0f}; + 1, 2, + 3, 4}; // clang-format on + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.required()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); + // clang-format off + classProperty.noData = { + 0, 0, + 0, 0}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + // clang-format off + classProperty.scale = { + 1, 1, + -1, 1}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + // clang-format off + classProperty.offset = { + 0, 0, + 2, 1}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } SECTION("Reports errors for out-of-bounds values") { @@ -740,12 +969,12 @@ TEST_CASE("MatN PropertyView") { } } -TEST_CASE("String PropertyView") { +TEST_CASE("MatN PropertyView (normalized)") { SECTION("Constructs empty PropertyView") { - PropertyView view; + PropertyView view; REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); REQUIRE(view.arrayCount() == 0); - REQUIRE(!view.normalized()); + REQUIRE(view.normalized()); REQUIRE(!view.offset()); REQUIRE(!view.scale()); REQUIRE(!view.max()); @@ -757,80 +986,274 @@ TEST_CASE("String PropertyView") { SECTION("Reports type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::BOOLEAN; + classProperty.type = ClassProperty::Type::MAT4; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); } + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + SECTION("Reports array type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::STRING; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); } - SECTION("Ignores non-applicable properties") { + SECTION("Reports invalid normalization") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::STRING; - classProperty.normalized = true; - classProperty.offset = "offset"; - classProperty.scale = "scale"; - classProperty.max = "max"; - classProperty.min = "min"; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.normalized = false; - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(!view.normalized()); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); } - SECTION("Ignores count") { + SECTION("Constructs with offset, scale, max, and min") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::STRING; - classProperty.count = 5; + classProperty.type = ClassProperty::Type::MAT3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.normalized = true; + // clang-format off + classProperty.offset = { + -1, 1, 2, + 3, -1, 4, + -5, -5, 0}; + classProperty.scale = { + 1, 1, 1, + 2, 2, 3, + 3, 4, 5}; + classProperty.max = { + 20, 5, 20, + 30, 22, 43, + 37, 1, 8}; + classProperty.min = { + -10, -2, -3, + 0, 20, 4, + 9, 4, 5}; + // clang-format on - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.arrayCount() == 0); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); + + // clang-format off + glm::dmat3 expectedOffset( + -1, 1, 2, + 3, -1, 4, + -5, -5, 0); + REQUIRE(*view.offset() == expectedOffset); + + glm::dmat3 expectedScale( + 1, 1, 1, + 2, 2, 3, + 3, 4, 5); + REQUIRE(*view.scale() == expectedScale); + + glm::dmat3 expectedMax( + 20, 5, 20, + 30, 22, 43, + 37, 1, 8); + REQUIRE(*view.max() == expectedMax); + + glm::dmat3 expectedMin( + -10, -2, -3, + 0, 20, 4, + 9, 4, 5); + REQUIRE(*view.min() == expectedMin); + // clang-format on } SECTION("Constructs with noData and defaultProperty") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::STRING; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.normalized = true; classProperty.required = false; - classProperty.noData = "null"; - classProperty.defaultProperty = "default"; + // clang-format off + classProperty.noData = { + 0, 0, + 0, 0}; + classProperty.defaultProperty = { + 1.0, 2.0, + 3.0, 4.5}; + // clang-format on - PropertyView view(classProperty); + PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.noData()); REQUIRE(view.defaultValue()); - REQUIRE(*view.noData() == "null"); - REQUIRE(*view.defaultValue() == "default"); + glm::imat2x2 expectedNoData(0); + REQUIRE(*view.noData() == expectedNoData); + + // clang-format off + glm::dmat2 expectedDefaultValue( + 1.0, 2.0, + 3.0, 4.5); + REQUIRE(*view.defaultValue() == expectedDefaultValue); } - SECTION("Ignores noData and defaultProperty when required is true") { + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::STRING; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.normalized = true; classProperty.required = true; - classProperty.noData = "null"; - classProperty.defaultProperty = "default"; + // clang-format off + classProperty.defaultProperty = { + 1.0, 2.0, + 3.0, 4.5}; + // clang-format on - PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.required()); + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + // clang-format off + classProperty.noData = { + 0, 0, + 0, 0}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.normalized = true; + // clang-format off + classProperty.noData = { + 0, 0, + 1, -129}; + // clang-format on + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.normalized = true; + + // clang-format off + classProperty.defaultProperty = JsonValue::Array{ + JsonValue::Array{4, 1, 2, 0}, + JsonValue::Array{2, 3, 1, 1} + }; + // clang-format on + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + // clang-format off + classProperty.noData = { + 0.45, 0.0, + 1.0, -1.4}; + // clang-format on + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = {0, 0}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {10, 20, 30, 40, 50}; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = 1; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = "(1, 2, 3, 4)"; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } +} + +TEST_CASE("String PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); REQUIRE(!view.noData()); REQUIRE(!view.defaultValue()); } + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::BOOLEAN; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.required = false; + classProperty.noData = "null"; + classProperty.defaultProperty = "default"; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + REQUIRE(*view.noData() == "null"); + REQUIRE(*view.defaultValue() == "default"); + } + + SECTION("Reports errors for incorrectly defined properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.required = true; + classProperty.defaultProperty = "default"; + + PropertyView view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = "null"; + view = PropertyView(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + SECTION("Reports errors for invalid types") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; @@ -878,27 +1301,6 @@ TEST_CASE("Boolean Array PropertyView") { REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); } - SECTION("Ignores non-applicable properties") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::BOOLEAN; - classProperty.array = true; - classProperty.normalized = true; - classProperty.offset = JsonValue::Array{true}; - classProperty.scale = JsonValue::Array{true}; - classProperty.max = JsonValue::Array{true}; - classProperty.min = JsonValue::Array{true}; - classProperty.noData = JsonValue::Array{true}; - - PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(!view.normalized()); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - REQUIRE(!view.noData()); - } - SECTION("Constructs with count") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; @@ -928,7 +1330,7 @@ TEST_CASE("Boolean Array PropertyView") { REQUIRE(defaultValue[1]); } - SECTION("Ignores defaultProperty when required is true") { + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::BOOLEAN; classProperty.array = true; @@ -936,9 +1338,7 @@ TEST_CASE("Boolean Array PropertyView") { classProperty.defaultProperty = JsonValue::Array{false, true}; PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.required()); - REQUIRE(!view.defaultValue()); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); } SECTION("Reports errors for invalid types") { @@ -999,36 +1399,14 @@ TEST_CASE("Scalar Array PropertyView") { SECTION("Reports invalid normalization") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; classProperty.normalized = true; - PropertyView> view(classProperty); + PropertyView> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); } - SECTION("Constructs with non-optional properties") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::UINT8; - classProperty.array = true; - classProperty.normalized = true; - classProperty.required = true; - - PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.normalized()); - REQUIRE(view.required()); - - REQUIRE(view.arrayCount() == 0); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); - } - SECTION("Constructs with count") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; @@ -1044,39 +1422,39 @@ TEST_CASE("Scalar Array PropertyView") { SECTION("Constructs with offset, scale, max, and min") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; - classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.array = true; - classProperty.offset = JsonValue::Array{5, 10}; - classProperty.scale = JsonValue::Array{2, 1}; - classProperty.max = JsonValue::Array{10, 20}; - classProperty.min = JsonValue::Array{-10, -1}; + classProperty.offset = JsonValue::Array{5.0f, 10.0f}; + classProperty.scale = JsonValue::Array{2.0f, 1.0f}; + classProperty.max = JsonValue::Array{10.0f, 20.0f}; + classProperty.min = JsonValue::Array{-10.0f, -1.0f}; - PropertyView> view(classProperty); + PropertyView> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); REQUIRE(view.scale()); REQUIRE(view.max()); REQUIRE(view.min()); - PropertyArrayView value = *view.offset(); + PropertyArrayView value = *view.offset(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == 5); - REQUIRE(value[1] == 10); + REQUIRE(value[0] == 5.0f); + REQUIRE(value[1] == 10.0f); value = *view.scale(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == 2); - REQUIRE(value[1] == 1); + REQUIRE(value[0] == 2.0f); + REQUIRE(value[1] == 1.0f); value = *view.max(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == 10); - REQUIRE(value[1] == 20); + REQUIRE(value[0] == 10.0f); + REQUIRE(value[1] == 20.0f); value = *view.min(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == -10); - REQUIRE(value[1] == -1); + REQUIRE(value[0] == -10.0f); + REQUIRE(value[1] == -1.0f); } SECTION("Constructs with noData and defaultProperty") { @@ -1105,20 +1483,28 @@ TEST_CASE("Scalar Array PropertyView") { REQUIRE(value[1] == 3); } - SECTION("Ignores noData and defaultProperty when required is true") { + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; classProperty.required = true; - classProperty.noData = {0, 1}; classProperty.defaultProperty = {2, 3}; PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.required()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = {0, 1}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.scale = {1, 1}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = {0, 2}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } SECTION("Reports errors for out-of-bounds values") { @@ -1184,12 +1570,12 @@ TEST_CASE("Scalar Array PropertyView") { } } -TEST_CASE("VecN Array PropertyView") { +TEST_CASE("Scalar Array PropertyView (normalized)") { SECTION("Constructs empty PropertyView") { - PropertyView> view; + PropertyView, true> view; REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); REQUIRE(view.arrayCount() == 0); - REQUIRE(!view.normalized()); + REQUIRE(view.normalized()); REQUIRE(!view.offset()); REQUIRE(!view.scale()); REQUIRE(!view.max()); @@ -1201,156 +1587,339 @@ TEST_CASE("VecN Array PropertyView") { SECTION("Reports type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC2; + classProperty.type = ClassProperty::Type::STRING; classProperty.array = true; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); } SECTION("Reports component type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC3; + classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.array = true; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Reports array type mismatch") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC3; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = false; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Reports invalid normalization") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC3; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; - classProperty.normalized = true; + classProperty.normalized = false; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); } - SECTION("Constructs with non-optional properties") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC3; - classProperty.componentType = ClassProperty::ComponentType::INT16; - classProperty.array = true; - classProperty.normalized = true; - classProperty.required = true; - - PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.normalized()); - REQUIRE(view.required()); - - REQUIRE(view.arrayCount() == 0); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); - } - SECTION("Constructs with count") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC3; - classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; + classProperty.normalized = true; classProperty.count = 5; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.arrayCount() == classProperty.count); + REQUIRE(view.arrayCount() == *classProperty.count); } SECTION("Constructs with offset, scale, max, and min") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC3; - classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::INT16; classProperty.array = true; - classProperty.offset = {{-1, 1, 2}, {4, 4, 0}}; - classProperty.scale = {{2, 1, 3}, {8, 2, 3}}; - classProperty.max = {{14, 28, 12}, {10, 5, 6}}; - classProperty.min = {{-11, -12, -13}, {-2, -4, 6}}; + classProperty.normalized = true; + classProperty.offset = JsonValue::Array{5.0, 10.0}; + classProperty.scale = JsonValue::Array{2.0, 1.0}; + classProperty.max = JsonValue::Array{10.0, 20.0}; + classProperty.min = JsonValue::Array{-10.0, -1.0}; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); REQUIRE(view.scale()); REQUIRE(view.max()); REQUIRE(view.min()); - PropertyArrayView value = *view.offset(); + PropertyArrayView value = *view.offset(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::i8vec3(-1, 1, 2)); - REQUIRE(value[1] == glm::i8vec3(4, 4, 0)); + REQUIRE(value[0] == 5.0); + REQUIRE(value[1] == 10.0); value = *view.scale(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::i8vec3(2, 1, 3)); - REQUIRE(value[1] == glm::i8vec3(8, 2, 3)); + REQUIRE(value[0] == 2.0); + REQUIRE(value[1] == 1.0); value = *view.max(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::i8vec3(14, 28, 12)); - REQUIRE(value[1] == glm::i8vec3(10, 5, 6)); + REQUIRE(value[0] == 10.0); + REQUIRE(value[1] == 20.0); value = *view.min(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::i8vec3(-11, -12, -13)); - REQUIRE(value[1] == glm::i8vec3(-2, -4, 6)); + REQUIRE(value[0] == -10.0); + REQUIRE(value[1] == -1.0); } SECTION("Constructs with noData and defaultProperty") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC2; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; + classProperty.normalized = true; classProperty.required = false; - classProperty.noData = {{0.0f, 0.0f}, {1.0f, 2.0f}}; - classProperty.defaultProperty = {{3.0f, 4.0f}, {5.0f, 6.0f}}; + classProperty.noData = {0, 1}; + classProperty.defaultProperty = {2.5, 3.5}; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.noData()); REQUIRE(view.defaultValue()); - PropertyArrayView value = *view.noData(); - REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::vec2(0.0f, 0.0f)); - REQUIRE(value[1] == glm::vec2(1.0f, 2.0f)); + PropertyArrayView noData(*view.noData()); + REQUIRE(noData.size() == 2); + REQUIRE(noData[0] == 0); + REQUIRE(noData[1] == 1); - value = *view.defaultValue(); - REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::vec2(3.0f, 4.0f)); - REQUIRE(value[1] == glm::vec2(5.0f, 6.0f)); + PropertyArrayView defaultValue(*view.defaultValue()); + REQUIRE(defaultValue.size() == 2); + REQUIRE(defaultValue[0] == 2.5); + REQUIRE(defaultValue[1] == 3.5); } - SECTION("Ignores noData and defaultProperty when required is true") { + SECTION("Reports errors for incorrectly defined properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + classProperty.normalized = true; + classProperty.required = true; + classProperty.defaultProperty = {2, 3}; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = {0, 1}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + classProperty.normalized = true; + classProperty.noData = {-1, 0}; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + classProperty.normalized = true; + classProperty.defaultProperty = "[256, 256]"; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = 0; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = false; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = JsonValue::Array{10.4, "30.0"}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = + JsonValue::Array{JsonValue::Array{2.3}, JsonValue::Array{1.3}}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = "10"; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } +} + +TEST_CASE("VecN Array PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView> view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC2; + classProperty.array = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = false; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.array = true; - classProperty.required = true; + classProperty.normalized = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Constructs with count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT16; + classProperty.array = true; + classProperty.count = 5; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.arrayCount() == classProperty.count); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.offset = {{-1, 1, 2}, {4, 4, 0}}; + classProperty.scale = {{2, 1, 3}, {8, 2, 3}}; + classProperty.max = {{14, 28, 12}, {10, 5, 6}}; + classProperty.min = {{-11, -12, -13}, {-2, -4, 6}}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); + + PropertyArrayView value = *view.offset(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::vec3(-1, 1, 2)); + REQUIRE(value[1] == glm::vec3(4, 4, 0)); + + value = *view.scale(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::vec3(2, 1, 3)); + REQUIRE(value[1] == glm::vec3(8, 2, 3)); + + value = *view.max(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::vec3(14, 28, 12)); + REQUIRE(value[1] == glm::vec3(10, 5, 6)); + + value = *view.min(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::vec3(-11, -12, -13)); + REQUIRE(value[1] == glm::vec3(-2, -4, 6)); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.required = false; classProperty.noData = {{0.0f, 0.0f}, {1.0f, 2.0f}}; classProperty.defaultProperty = {{3.0f, 4.0f}, {5.0f, 6.0f}}; PropertyView> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.required()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + PropertyArrayView value = *view.noData(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::vec2(0.0f, 0.0f)); + REQUIRE(value[1] == glm::vec2(1.0f, 2.0f)); + + value = *view.defaultValue(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::vec2(3.0f, 4.0f)); + REQUIRE(value[1] == glm::vec2(5.0f, 6.0f)); + } + + SECTION("Reports errors for incorrectly defined properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.required = true; + classProperty.defaultProperty = {{3, 4}, {5, 6}}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = {{0, 0}, {1, 2}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.scale = {{1, 1}, {-1, -1}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = {{0, 0}, {-4, 7}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } SECTION("Reports errors for out-of-bounds values") { @@ -1360,68 +1929,589 @@ TEST_CASE("VecN Array PropertyView") { classProperty.array = true; classProperty.defaultProperty = {{128, 129}, {0, 2}}; - PropertyView> view(classProperty); + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = {{0, 0}, {-128, -129}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = {{-2, -3}, {-200, 0}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {{10, 5}, {808, 3}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = {{1, 128}, {2, 2}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = {{0, 0}, {-1, -222}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + classProperty.defaultProperty = {1, 20}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = JsonValue::Array{{2.0f, 5.4f}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = {{-10, -1, 4}, {0, 0, 0}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {{10, 20, 30, 40}, {1, 2, 3, 4}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = 2; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = "(1, 2)"; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } +} + +TEST_CASE("VecN Array PropertyView (normalized)") { + SECTION("Constructs empty PropertyView") { + PropertyView, true> view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.array = true; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = false; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.normalized = false; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Constructs with count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.count = 5; + classProperty.normalized = true; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.arrayCount() == classProperty.count); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.normalized = true; + classProperty.offset = {{-1, 1, 2}, {4, 4, 0}}; + classProperty.scale = {{2, 1, 3}, {8, 2, 3}}; + classProperty.max = {{14, 28, 12}, {10, 5, 6}}; + classProperty.min = {{-11, -12, -13}, {-2, -4, 6}}; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); + + PropertyArrayView value = *view.offset(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::dvec3(-1, 1, 2)); + REQUIRE(value[1] == glm::dvec3(4, 4, 0)); + + value = *view.scale(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::dvec3(2, 1, 3)); + REQUIRE(value[1] == glm::dvec3(8, 2, 3)); + + value = *view.max(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::dvec3(14, 28, 12)); + REQUIRE(value[1] == glm::dvec3(10, 5, 6)); + + value = *view.min(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::dvec3(-11, -12, -13)); + REQUIRE(value[1] == glm::dvec3(-2, -4, 6)); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.normalized = true; + classProperty.required = false; + classProperty.noData = {{0, 0}, {1, 2}}; + classProperty.defaultProperty = {{3.5, 4.5}, {5.0, 6.0}}; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + PropertyArrayView noData = *view.noData(); + REQUIRE(noData.size() == 2); + REQUIRE(noData[0] == glm::ivec2(0, 0)); + REQUIRE(noData[1] == glm::ivec2(1, 2)); + + PropertyArrayView defaultValue = *view.defaultValue(); + REQUIRE(defaultValue.size() == 2); + REQUIRE(defaultValue[0] == glm::dvec2(3.5, 4.5)); + REQUIRE(defaultValue[1] == glm::dvec2(5.0, 6.0)); + } + + SECTION("Reports errors for incorrectly defined properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.normalized = true; + classProperty.required = true; + classProperty.defaultProperty = {{3, 4}, {5, 6}}; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = {{0, 0}, {1, 2}}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.normalized = true; + classProperty.array = true; + classProperty.noData = {{0, 0}, {-128, -129}}; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + } + + SECTION("Reports errors for invalid types") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + classProperty.normalized = true; + classProperty.defaultProperty = {1, 20}; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = JsonValue::Array{{2.0f, 5.4f}, "not a vec2"}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + classProperty.min = {{-10, -1, 4}, {0, 0, 0}}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {{10, 20, 30, 40}, {1, 2, 3, 4}}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = 2; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = "(1, 2)"; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } +} + +TEST_CASE("MatN Array PropertyView") { + SECTION("Constructs empty PropertyView") { + PropertyView> view; + REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); + REQUIRE(view.arrayCount() == 0); + REQUIRE(!view.normalized()); + REQUIRE(!view.offset()); + REQUIRE(!view.scale()); + REQUIRE(!view.max()); + REQUIRE(!view.min()); + REQUIRE(!view.required()); + REQUIRE(!view.noData()); + REQUIRE(!view.defaultValue()); + } + + SECTION("Reports type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT4; + classProperty.array = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Reports component type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Reports array type mismatch") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = false; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Reports invalid normalization") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.normalized = true; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Constructs with count") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.count = 5; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.arrayCount() == classProperty.count); + } + + SECTION("Constructs with offset, scale, max, and min") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + // clang-format off + classProperty.offset = { + {-1, 1, + 0, 2}, + {2, 40, + 6, -8}, + }; + classProperty.scale = { + {1, 1, + 1, 0}, + {-2, 5, + 7, 1} + }; + classProperty.max = { + {2, 4, + 8, 0}, + {-7, 8, + 4, 4}, + }; + classProperty.min = { + {-1, -6, + -1, 2}, + {0, 1, + 2, 3}, + }; + // clang-format on + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(view.offset()); + REQUIRE(view.scale()); + REQUIRE(view.max()); + REQUIRE(view.min()); + + PropertyArrayView value = *view.offset(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::mat2(-1, 1, 0, 2)); + REQUIRE(value[1] == glm::mat2(2, 40, 6, -8)); + + value = *view.scale(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::mat2(1, 1, 1, 0)); + REQUIRE(value[1] == glm::mat2(-2, 5, 7, 1)); + + value = *view.max(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::mat2(2, 4, 8, 0)); + REQUIRE(value[1] == glm::mat2(-7, 8, 4, 4)); + + value = *view.min(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::mat2(-1, -6, -1, 2)); + REQUIRE(value[1] == glm::mat2(0, 1, 2, 3)); + } + + SECTION("Constructs with noData and defaultProperty") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + classProperty.required = false; + // clang-format off + classProperty.noData = { + {0, 0, + 0, 0}, + {-1, -1, + -1, -1}, + }; + classProperty.defaultProperty = { + {1, 1, + 1, 1}, + {2, 2, + 2, 2}, + }; + // clang-format on + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::Valid); + REQUIRE(!view.required()); + REQUIRE(view.noData()); + REQUIRE(view.defaultValue()); + + PropertyArrayView value = *view.noData(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8mat2x2(0, 0, 0, 0)); + REQUIRE(value[1] == glm::i8mat2x2(-1, -1, -1, -1)); + + value = view.defaultValue().value(); + REQUIRE(value.size() == 2); + REQUIRE(value[0] == glm::i8mat2x2(1, 1, 1, 1)); + REQUIRE(value[1] == glm::i8mat2x2(2, 2, 2, 2)); + } + + SECTION("Reports errors for incorrectly defined properties") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.required = true; + // clang-format off + classProperty.defaultProperty = { + {1, 1, + 1, 1}, + {2, 2, + 2, 2}, + }; + // clang-format on + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + // clang-format off + classProperty.noData = { + {0, 0, + 0, 0}, + {-1, -1, + -1, -1}, + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + + // clang-format off + classProperty.scale = { + {1, 0, + 0, 1}, + {-1, 0, + 0, -1}, + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + // clang-format off + classProperty.offset = { + {2, 2, + 1, 1}, + {0, 2, + 1, 2}, + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + + SECTION("Reports errors for out-of-bounds values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.array = true; + + // clang-format off + classProperty.defaultProperty = { + {1, 1, + 1, 290}, + {2, 2, + 2, 2}, + }; + // clang-format on + + PropertyView> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); - classProperty.noData = {{0, 0}, {-128, -129}}; - view = PropertyView>(classProperty); + // clang-format off + classProperty.noData = { + {0, 0, + 0, 0}, + {-140, -1, + -1, -1}, + }; + // clang-format on + view = PropertyView>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); - classProperty.min = {{-2, -3}, {-200, 0}}; - view = PropertyView>(classProperty); + // clang-format off + classProperty.min = { + {-129, 0, + 0, 0}, + {-1, -1, + -1, -1}, + }; + // clang-format on + view = PropertyView>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); - classProperty.max = {{10, 5}, {808, 3}}; - view = PropertyView>(classProperty); + // clang-format off + classProperty.max = { + {-128, 189, + 20, 2}, + {10, 12, + 8, 4}, + }; + // clang-format on + view = PropertyView>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); - classProperty.scale = {{1, 128}, {2, 2}}; - view = PropertyView>(classProperty); + //clang-format off + classProperty.scale = { + {1, 2, 3, 4}, + {256, 80, 9, 52}, + }; + // clang-format on + view = PropertyView>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); - classProperty.offset = {{0, 0}, {-1, -222}}; - view = PropertyView>(classProperty); + // clang-format off + classProperty.offset = { + {129, 0, + 0, 2}, + {4, 0, + 0, 8},}; + // clang-format on + view = PropertyView>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } SECTION("Reports errors for invalid types") { ClassProperty classProperty; - classProperty.type = ClassProperty::Type::VEC2; + classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.array = true; - classProperty.defaultProperty = {1, 20}; + classProperty.defaultProperty = {4, 1, 2, 0}; - PropertyView> view(classProperty); + PropertyView> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); - classProperty.noData = JsonValue::Array{{2.0f, 5.4f}}; - view = PropertyView>(classProperty); + // clang-format off + classProperty.noData = { + {0.45, 0.0, + 1.0, -1.4} + }; + // clang-format on + view = PropertyView>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); - classProperty.min = {{-10, -1, 4}, {0, 0, 0}}; - view = PropertyView>(classProperty); + classProperty.min = {{0, 1, 2, 3, 4, 5, 6}}; + view = PropertyView>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); - classProperty.max = {{10, 20, 30, 40}, {1, 2, 3, 4}}; - view = PropertyView>(classProperty); + classProperty.max = {{0, 1, 2, 3}, false}; + view = PropertyView>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); - classProperty.scale = 2; - view = PropertyView>(classProperty); + classProperty.scale = 1; + view = PropertyView>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); - classProperty.offset = "(1, 2)"; - view = PropertyView>(classProperty); + classProperty.offset = "[(1, 2, 3, 4)]"; + view = PropertyView>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } } -TEST_CASE("MatN Array PropertyView") { +TEST_CASE("MatN Array PropertyView (normalized)") { SECTION("Constructs empty PropertyView") { - PropertyView> view; + PropertyView, true> view; REQUIRE(view.status() == PropertyViewStatus::ErrorNonexistentProperty); REQUIRE(view.arrayCount() == 0); - REQUIRE(!view.normalized()); + REQUIRE(view.normalized()); REQUIRE(!view.offset()); REQUIRE(!view.scale()); REQUIRE(!view.max()); @@ -1436,7 +2526,7 @@ TEST_CASE("MatN Array PropertyView") { classProperty.type = ClassProperty::Type::MAT4; classProperty.array = true; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorTypeMismatch); } @@ -1446,51 +2536,29 @@ TEST_CASE("MatN Array PropertyView") { classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.array = true; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Reports array type mismatch") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT2; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = false; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); } SECTION("Reports invalid normalization") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT2; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; - classProperty.array = true; - classProperty.normalized = true; - - PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); - } - - SECTION("Constructs with non-optional properties") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::MAT3; classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; - classProperty.normalized = true; - classProperty.required = true; - - PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.normalized()); - REQUIRE(view.required()); + classProperty.normalized = false; - REQUIRE(view.arrayCount() == 0); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); } SECTION("Constructs with count") { @@ -1498,9 +2566,10 @@ TEST_CASE("MatN Array PropertyView") { classProperty.type = ClassProperty::Type::MAT3; classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; + classProperty.normalized = true; classProperty.count = 5; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.arrayCount() == classProperty.count); } @@ -1508,8 +2577,10 @@ TEST_CASE("MatN Array PropertyView") { SECTION("Constructs with offset, scale, max, and min") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT2; - classProperty.componentType = ClassProperty::ComponentType::INT8; + classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; + classProperty.normalized = true; + // clang-format off classProperty.offset = { {-1, 1, @@ -1537,32 +2608,32 @@ TEST_CASE("MatN Array PropertyView") { }; // clang-format on - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(view.offset()); REQUIRE(view.scale()); REQUIRE(view.max()); REQUIRE(view.min()); - PropertyArrayView value = *view.offset(); + PropertyArrayView value = *view.offset(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::i8mat2x2(-1, 1, 0, 2)); - REQUIRE(value[1] == glm::i8mat2x2(2, 40, 6, -8)); + REQUIRE(value[0] == glm::dmat2(-1, 1, 0, 2)); + REQUIRE(value[1] == glm::dmat2(2, 40, 6, -8)); value = *view.scale(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::i8mat2x2(1, 1, 1, 0)); - REQUIRE(value[1] == glm::i8mat2x2(-2, 5, 7, 1)); + REQUIRE(value[0] == glm::dmat2(1, 1, 1, 0)); + REQUIRE(value[1] == glm::dmat2(-2, 5, 7, 1)); value = *view.max(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::i8mat2x2(2, 4, 8, 0)); - REQUIRE(value[1] == glm::i8mat2x2(-7, 8, 4, 4)); + REQUIRE(value[0] == glm::dmat2(2, 4, 8, 0)); + REQUIRE(value[1] == glm::dmat2(-7, 8, 4, 4)); value = *view.min(); REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::i8mat2x2(-1, -6, -1, 2)); - REQUIRE(value[1] == glm::i8mat2x2(0, 1, 2, 3)); + REQUIRE(value[0] == glm::dmat2(-1, -6, -1, 2)); + REQUIRE(value[1] == glm::dmat2(0, 1, 2, 3)); } SECTION("Constructs with noData and defaultProperty") { @@ -1570,6 +2641,7 @@ TEST_CASE("MatN Array PropertyView") { classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.array = true; + classProperty.normalized = true; classProperty.required = false; // clang-format off classProperty.noData = { @@ -1586,36 +2658,31 @@ TEST_CASE("MatN Array PropertyView") { }; // clang-format on - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); REQUIRE(view.noData()); REQUIRE(view.defaultValue()); - PropertyArrayView value = *view.noData(); - REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::i8mat2x2(0, 0, 0, 0)); - REQUIRE(value[1] == glm::i8mat2x2(-1, -1, -1, -1)); + PropertyArrayView noData = *view.noData(); + REQUIRE(noData.size() == 2); + REQUIRE(noData[0] == glm::i8mat2x2(0, 0, 0, 0)); + REQUIRE(noData[1] == glm::i8mat2x2(-1, -1, -1, -1)); - value = view.defaultValue().value(); - REQUIRE(value.size() == 2); - REQUIRE(value[0] == glm::i8mat2x2(1, 1, 1, 1)); - REQUIRE(value[1] == glm::i8mat2x2(2, 2, 2, 2)); + PropertyArrayView defaultValue = *view.defaultValue(); + REQUIRE(defaultValue.size() == 2); + REQUIRE(defaultValue[0] == glm::dmat2(1, 1, 1, 1)); + REQUIRE(defaultValue[1] == glm::dmat2(2, 2, 2, 2)); } - SECTION("Ignores noData and defaultProperty when required is true") { + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT2; - classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; + classProperty.normalized = true; classProperty.required = true; // clang-format off - classProperty.noData = { - {0, 0, - 0, 0}, - {-1, -1, - -1, -1}, - }; classProperty.defaultProperty = { {1, 1, 1, 1}, @@ -1624,11 +2691,20 @@ TEST_CASE("MatN Array PropertyView") { }; // clang-format on - PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.required()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + // clang-format off + classProperty.noData = { + {0, 0, + 0, 0}, + {-1, -1, + -1, -1}, + }; + // clang-format on + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); + ; } SECTION("Reports errors for out-of-bounds values") { @@ -1636,18 +2712,7 @@ TEST_CASE("MatN Array PropertyView") { classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.array = true; - - // clang-format off - classProperty.defaultProperty = { - {1, 1, - 1, 290}, - {2, 2, - 2, 2}, - }; - // clang-format on - - PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + classProperty.normalized = true; // clang-format off classProperty.noData = { @@ -1657,49 +2722,8 @@ TEST_CASE("MatN Array PropertyView") { -1, -1}, }; // clang-format on - view = PropertyView>(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); - - // clang-format off - classProperty.min = { - {-129, 0, - 0, 0}, - {-1, -1, - -1, -1}, - }; - // clang-format on - view = PropertyView>(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); - - // clang-format off - classProperty.max = { - {-128, 189, - 20, 2}, - {10, 12, - 8, 4}, - }; - // clang-format on - view = PropertyView>(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); - - //clang-format off - classProperty.scale = { - {1, 2, 3, 4}, - {256, 80, 9, 52}, - }; - // clang-format on - view = PropertyView>(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); - - // clang-format off - classProperty.offset = { - {129, 0, - 0, 2}, - {4, 0, - 0, 8},}; - // clang-format on - view = PropertyView>(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } SECTION("Reports errors for invalid types") { @@ -1707,34 +2731,36 @@ TEST_CASE("MatN Array PropertyView") { classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.array = true; + classProperty.normalized = true; classProperty.defaultProperty = {4, 1, 2, 0}; - PropertyView> view(classProperty); + PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); // clang-format off classProperty.noData = { {0.45, 0.0, - 1.0, -1.4} + 1.0, -1.4}, + "not a matrix" }; // clang-format on - view = PropertyView>(classProperty); + view = PropertyView, true>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); classProperty.min = {{0, 1, 2, 3, 4, 5, 6}}; - view = PropertyView>(classProperty); + view = PropertyView, true>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); classProperty.max = {{0, 1, 2, 3}, false}; - view = PropertyView>(classProperty); + view = PropertyView, true>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); classProperty.scale = 1; - view = PropertyView>(classProperty); + view = PropertyView, true>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); classProperty.offset = "[(1, 2, 3, 4)]"; - view = PropertyView>(classProperty); + view = PropertyView, true>(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); } } @@ -1772,25 +2798,6 @@ TEST_CASE("String Array PropertyView") { REQUIRE(view.status() == PropertyViewStatus::ErrorArrayTypeMismatch); } - SECTION("Ignores non-applicable properties") { - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::STRING; - classProperty.array = true; - classProperty.normalized = true; - classProperty.offset = {"offset"}; - classProperty.scale = {"scale"}; - classProperty.max = {"max"}; - classProperty.min = {"min"}; - - PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(!view.normalized()); - REQUIRE(!view.offset()); - REQUIRE(!view.scale()); - REQUIRE(!view.max()); - REQUIRE(!view.min()); - } - SECTION("Constructs with count") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; @@ -1827,19 +2834,19 @@ TEST_CASE("String Array PropertyView") { REQUIRE(defaultValue[1] == "default2"); } - SECTION("Ignores noData and defaultProperty when required is true") { + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::STRING; classProperty.array = true; classProperty.required = true; - classProperty.noData = {"null", "0"}; classProperty.defaultProperty = {"default1", "default2"}; PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.required()); - REQUIRE(!view.noData()); - REQUIRE(!view.defaultValue()); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidDefaultValue); + + classProperty.noData = {"null", "0"}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNoDataValue); } SECTION("Reports errors for invalid types") { From e19cdae61cd89d9e793638d8edac3ea4646937ed Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 21 Aug 2023 16:51:24 -0400 Subject: [PATCH 082/121] Try to fix CI, add PropertyTransformations --- .../include/CesiumGltf/PropertyArrayView.h | 72 ++++------ .../include/CesiumGltf/PropertyConversions.h | 55 -------- .../CesiumGltf/PropertyTablePropertyView.h | 75 ++-------- .../CesiumGltf/PropertyTransformations.h | 129 ++++++++++++++++++ CesiumGltf/include/CesiumGltf/PropertyView.h | 54 +++++++- 5 files changed, 214 insertions(+), 171 deletions(-) delete mode 100644 CesiumGltf/include/CesiumGltf/PropertyConversions.h create mode 100644 CesiumGltf/include/CesiumGltf/PropertyTransformations.h diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index 6f17cdeba..f599ec58d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -66,50 +66,34 @@ template class PropertyArrayView { return true; } - //PropertyArrayView - //operator*(const PropertyArrayView& other) { - // int64_t clampedSize = std::min(this->size(), other.size()); - // std::vector result(static_cast(this->size())); - // if constexpr (IsMetadataMatN::value) { - // // Do component-wise multiplication instead of actual matrix - // // multiplication. - // ElementType matN; - // constexpr glm::length_t N = ElementType::length(); - // for (int64_t i = 0; i < clampedSize; i++) { - // for (glm::length_t j = 0; j < N; j++) { - // matN[j] = (*this)[i][j] * other[i][j]; - // } - // result[i] = matN; - // } - // } else { - // for (int64_t i = 0; i < clampedSize; i++) { - // result[i] = (*this)[i] * other[i]; - // } - // } - - // // Copy anything that didn't have a component to multiply against. - // for (int64_t i = clampedSize(); i < this->size(); i++) { - // result[i] = (*this)[i]; - // } - - // return PropertyArrayView(std::move(result)); - //} - - //PropertyArrayView - //operator+(const PropertyArrayView& other) { - // int64_t clampedSize = std::min(this->size(), other.size()); - // std::vector result(static_cast(this->size())); - // for (int64_t i = 0; i < clampedSize; i++) { - // result[i] = (*this)[i] + other[i]; - // } - - // // Copy anything that didn't have a component to multiply against. - // for (int64_t i = clampedSize(); i < this->size(); i++) { - // result[i] = (*this)[i]; - // } - - // return PropertyArrayView(std::move(result)); - //} + PropertyArrayView + operator*(const PropertyArrayView& other) { + int64_t clampedSize = std::min(this->size(), other.size()); + std::vector result(static_cast(this->size())); + if constexpr (IsMetadataMatN::value) { + // Do component-wise multiplication instead of actual matrix + // multiplication. + ElementType matN; + constexpr glm::length_t N = ElementType::length(); + for (int64_t i = 0; i < clampedSize; i++) { + for (glm::length_t j = 0; j < N; j++) { + matN[j] = (*this)[i][j] * other[i][j]; + } + result[i] = matN; + } + } else { + for (int64_t i = 0; i < clampedSize; i++) { + result[i] = (*this)[i] * other[i]; + } + } + + // Copy anything that didn't have a component to multiply against. + for (int64_t i = clampedSize(); i < this->size(); i++) { + result[i] = (*this)[i]; + } + + return PropertyArrayView(std::move(result)); + } private: using ArrayType = diff --git a/CesiumGltf/include/CesiumGltf/PropertyConversions.h b/CesiumGltf/include/CesiumGltf/PropertyConversions.h deleted file mode 100644 index 9fef8b1cc..000000000 --- a/CesiumGltf/include/CesiumGltf/PropertyConversions.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include "CesiumGltf/PropertyArrayView.h" -#include "CesiumGltf/PropertyTypeTraits.h" - -#include - -#include -#include -#include -#include -#include - -namespace CesiumGltf { -template < - typename TSigned, - std::enable_if_t< - IsMetadataInteger::value && std::is_signed_v>> -double normalize(TSigned value) { - double max = static_cast(std::numeric_limits::max()); - return std::max(static_cast(value) / max, -1.0); -} - -template < - typename TUnsigned, - std::enable_if_t< - IsMetadataInteger::value && std::is_unsigned_v>> -double normalize(TUnsigned value) { - double max = static_cast(std::numeric_limits::max()); - return static_cast(value) / max; -} - -template < - glm::length_t N, - typename TSigned, - glm::qualifier Q, - std::enable_if_t< - IsMetadataInteger::value && std::is_signed_v>> -glm::vec normalize(glm::vec value) { - double max = static_cast(std::numeric_limits::max()); - return glm::max(static_cast>(value) / max, -1.0); -} - -template < - glm::length_t N, - typename TUnsigned, - glm::qualifier Q, - std::enable_if_t< - IsMetadataInteger::value && std::is_unsigned_v>> -glm::mat normalize(glm::mat value) { - double max = static_cast(std::numeric_limits::max()); - return glm::max(static_cast>(value) / max, -1.0); -} - -} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 059336753..ad183f48b 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -1,7 +1,6 @@ #pragma once #include "CesiumGltf/PropertyArrayView.h" -//#include "CesiumGltf/PropertyConversions.h" #include "CesiumGltf/PropertyTypeTraits.h" #include "CesiumGltf/PropertyView.h" @@ -182,7 +181,7 @@ class PropertyTablePropertyView _stringOffsetType{PropertyComponentType::None}, _stringOffsetTypeSize{0} { assert( - _status != PropertyTablePropertyViewStatus::Valid && + this->_status != PropertyTablePropertyViewStatus::Valid && "An empty property view should not be constructed with a valid status"); } @@ -200,19 +199,15 @@ class PropertyTablePropertyView int64_t size, gsl::span values) noexcept : PropertyView(classProperty, property), - _values{}, - _size{}, + _values{values}, + _size{ + this->_status == PropertyTablePropertyViewStatus::Valid ? size : 0}, _arrayOffsets{}, _arrayOffsetType{PropertyComponentType::None}, _arrayOffsetTypeSize{0}, _stringOffsets{}, _stringOffsetType{PropertyComponentType::None}, - _stringOffsetTypeSize{0} { - if (_status == PropertyTablePropertyViewStatus::Valid) { - _values = values; - _size = size; - } - } + _stringOffsetTypeSize{0} {} /** * @brief Construct an instance pointing to the data specified by a {@link PropertyTableProperty}. @@ -238,18 +233,14 @@ class PropertyTablePropertyView PropertyComponentType stringOffsetType) noexcept : PropertyView(classProperty, property), _values{values}, + _size{ + this->_status == PropertyTablePropertyViewStatus::Valid ? size : 0}, _arrayOffsets{arrayOffsets}, _arrayOffsetType{arrayOffsetType}, _arrayOffsetTypeSize{getOffsetTypeSize(arrayOffsetType)}, _stringOffsets{stringOffsets}, _stringOffsetType{stringOffsetType}, - _stringOffsetTypeSize{getOffsetTypeSize(stringOffsetType)}, - _size{size} { - if (_status == PropertyTablePropertyViewStatus::Valid) { - _values = values; - _size = size; - } - } + _stringOffsetTypeSize{getOffsetTypeSize(stringOffsetType)} {} /** * @brief Get the raw value of an element of the {@link PropertyTable}, @@ -263,7 +254,7 @@ class PropertyTablePropertyView */ ElementType get(int64_t index) const noexcept { assert( - _status == PropertyTablePropertyViewStatus::Valid && + this->_status == PropertyTablePropertyViewStatus::Valid && "Check the status() first to make sure view is valid"); assert( size() > 0 && @@ -297,51 +288,6 @@ class PropertyTablePropertyView } } - ///** - // * @brief Gets the value of an element in the {@link PropertyTable} as an instance - // * of T. If T is not the same as the ElementType of the property, then - // * this attempts to convert it to the desired type. If such a conversion is - // * not possible, this returns std::nullopt. - // * - // * If this property contains a "no data" sentinel value, then std::nullopt - // is - // * returned for any raw values that equal the sentinel value. If a default - // * value is supplied, then it will be returned instead. - // * - // * If this property is affected by offset, scale, and / or normalization, - // * the value will be transformed before conversion like so: - // * - // * transformedValue = offset + scale * normalize(value) - // * - // * The transformed value will then attempt to be converted to the desired - // type - // * T. - // * - // * @param index The element index - // * @return The value of the element as T, or std::nullopt if conversion - // fails. - // */ - // template - // std::optional getAs(int64_t index) const noexcept { - // assert( - // _status == PropertyTablePropertyViewStatus::Valid && - // "Check the status() first to make sure view is valid"); - // assert( - // size() > 0 && - // "Check the size() of the view to make sure it's not empty"); - // assert(index >= 0 && "index must be non-negative"); - // assert(index < size() && "index must be less than size"); - // ElementType result = getRaw(index); - - // if (noData() && result == *noData()) { - // return defaultValue() ? *defaultValue() : std::nullopt; - // } - - // // apply transform - - // return PropertyConversions::convert(result); - //} - /** * @brief Get the number of elements in this * PropertyTablePropertyView. If the view is valid, this returns @@ -350,7 +296,7 @@ class PropertyTablePropertyView * @return The number of elements in this PropertyTablePropertyView. */ int64_t size() const noexcept { - return status() == PropertyTablePropertyViewStatus::Valid ? _size : 0; + return this->_status == PropertyTablePropertyViewStatus::Valid ? _size : 0; } private: @@ -472,7 +418,6 @@ class PropertyTablePropertyView } } -// PropertyViewStatusType _status; gsl::span _values; int64_t _size; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h new file mode 100644 index 000000000..f3523c1c0 --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h @@ -0,0 +1,129 @@ +#pragma once + +#include "CesiumGltf/PropertyArrayView.h" +#include "CesiumGltf/PropertyTypeTraits.h" + +#include + +#include +#include + +namespace CesiumGltf { +template < + typename TSigned, + std::enable_if_t< + IsMetadataInteger::value && std::is_signed_v>> +double normalize(TSigned value) { + double max = static_cast(std::numeric_limits::max()); + return std::max(static_cast(value) / max, -1.0); +} + +template < + typename TUnsigned, + std::enable_if_t< + IsMetadataInteger::value && std::is_unsigned_v>> +double normalize(TUnsigned value) { + double max = static_cast(std::numeric_limits::max()); + return static_cast(value) / max; +} + +template < + glm::length_t N, + typename TSigned, + glm::qualifier Q, + std::enable_if_t< + IsMetadataInteger::value && std::is_signed_v>> +glm::vec normalize(glm::vec value) { + double max = static_cast(std::numeric_limits::max()); + return glm::max(static_cast>(value) / max, -1.0); +} + +template < + glm::length_t N, + typename TUnsigned, + glm::qualifier Q, + std::enable_if_t< + IsMetadataInteger::value && std::is_unsigned_v>> +glm::vec normalize(glm::vec value) { + double max = static_cast(std::numeric_limits::max()); + return static_cast>(value) / max; +} + +template < + glm::length_t N, + typename TSigned, + glm::qualifier Q, + std::enable_if_t< + IsMetadataInteger::value && std::is_signed_v>> +glm::mat normalize(glm::mat value) { + double max = static_cast(std::numeric_limits::max()); + return glm::max(static_cast>(value) / max, -1.0); +} + +template < + glm::length_t N, + typename TUnsigned, + glm::qualifier Q, + std::enable_if_t< + IsMetadataInteger::value && std::is_unsigned_v>> +glm::mat normalize(glm::mat value) { + double max = static_cast(std::numeric_limits::max()); + return static_cast>(value) / max; +} + +template T applyScale(const T& value, const T& scale) { + if constexpr (IsMetadataMatN::value) { + // Do component-wise multiplication instead of actual matrix + // multiplication. + T matN; + constexpr glm::length_t N = T::length(); + for (glm::length_t i = 0; i < N; i++) { + matN[i] = value[i] * scale[i]; + } + return matN; + } else { + return value * scale; + } +} + +template +T applyOffsetAndScale( + const T& value, + const std::optional& offset, + const std::optional& scale) { + T result = value; + if (scale) { + result = applyScale(result, scale); + } + + if (offset) { + result += offset; + } + + return result; +} + +template +PropertyArrayView applyOffsetAndScale( + const PropertyArrayView& value, + const std::optional>& offset, + const std::optional>& scale) { + int64_t offsetSize = offset ? offset->size() : 0; + int64_t scaleSize = scale ? scale->size() : 0; + std::vector result(static_cast(value.size())); + for (int64_t i = 0; i < value.size(); i++) { + result[i] = value[i]; + + if (i < scaleSize) { + result = applyScale(result[i], scale[i]); + } + + if (i < offsetSize) { + result[i] = result[i] + offset[i]; + } + } + + return PropertyArrayView(std::move(result)); +} + +} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index a6013a835..a093d1407 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -1,7 +1,7 @@ #include "CesiumGltf/ClassProperty.h" -#include "CesiumGltf/PropertyConversions.h" #include "CesiumGltf/PropertyTableProperty.h" #include "CesiumGltf/PropertyTextureProperty.h" +#include "CesiumGltf/PropertyTransformations.h" #include "CesiumGltf/PropertyTypeTraits.h" #include @@ -597,6 +597,13 @@ template class PropertyView { protected: PropertyViewStatusType _status; + ElementType applyValueTransforms(ElementType value) { + if (_offset || _scale) { + return applyOffsetAndScale(value, _offset, _scale); + } + return value; + } + private: bool _required; @@ -937,6 +944,9 @@ class PropertyView< NormalizedType applyValueTransforms(ElementType value) { NormalizedType result = normalize(value); + if (_offset || _scale) { + return applyOffsetAndScale(result, _offset, _scale); + } return result; } @@ -1513,7 +1523,7 @@ class PropertyView> { case PropertyComponentType::Float64: _offset = getArrayValue(*property.offset); if (_offset && - (count == 0 || _offset->size() == static_cast(_count))) { + (_count == 0 || _offset->size() == static_cast(_count))) { break; } // If it does not break here, something went wrong. @@ -1531,7 +1541,7 @@ class PropertyView> { case PropertyComponentType::Float64: _scale = getArrayValue(*property.scale); if (_scale && - (count == 0 || _scale->size() == static_cast(_count))) { + (_count == 0 || _scale->size() == static_cast(_count))) { break; } // If it does not break here, something went wrong. @@ -1658,6 +1668,14 @@ class PropertyView> { protected: PropertyViewStatusType _status; + PropertyArrayView + applyValueTransforms(const PropertyArrayView& value) { + if (_offset || _scale) { + return applyOffsetAndScale(value, _offset, _scale); + } + return value; + } + private: int64_t _count; @@ -1929,7 +1947,7 @@ class PropertyView< // If the property has its own values, override the class-provided values. if (property.offset) { - _offset = getArrayValue(*property.offset); + _offset = getArrayValue(*property.offset); if (!_offset || (_count > 0 && _offset->size() != static_cast(_count))) { // The value was specified but something went wrong. @@ -1939,7 +1957,7 @@ class PropertyView< } if (property.scale) { - _scale = getArrayValue(*property.scale); + _scale = getArrayValue(*property.scale); if (!_scale || (_count > 0 || _scale->size() != static_cast(_count))) { // The value was specified but something went wrong. @@ -1949,7 +1967,7 @@ class PropertyView< } if (property.max) { - _max = getArrayValue(*property.max); + _max = getArrayValue(*property.max); if (!_max || (_count > 0 && _max->size() != static_cast(_count))) { // The value was specified but something went wrong. @@ -1959,7 +1977,7 @@ class PropertyView< } if (property.min) { - _min = getArrayValue(*property.min); + _min = getArrayValue(*property.min); if (!_min || (_count > 0 && _min->size() != static_cast(_count))) { // The value was specified but something went wrong. @@ -2067,6 +2085,28 @@ class PropertyView< protected: PropertyViewStatusType _status; + PropertyArrayView + applyValueTransforms(const PropertyArrayView& value) { + auto offset = this->offset(); + auto scale = this->scale(); + int64_t offsetSize = offset ? offset.size() : 0; + int64_t scaleSize = scale ? scale.size() : 0; + std::vector result(static_cast(value.size())); + for (int64_t i = 0; i < value.size(); i++) { + result[i] = normalize(value[i]); + + if (i < scaleSize) { + result = applyScale(result[i], scale[i]); + } + + if (i < offsetSize) { + result[i] = result[i] + offset[i]; + } + } + + return PropertyArrayView(std::move(result)); + } + private: int64_t _count; From 734c8cfbb647865f5670eafb138a59efc7428bc6 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 21 Aug 2023 17:43:23 -0400 Subject: [PATCH 083/121] Add get vs. getRaw to property view --- .../include/CesiumGltf/PropertyArrayView.h | 29 -- .../CesiumGltf/PropertyTablePropertyView.h | 269 +++++++++++++++++- .../CesiumGltf/PropertyTexturePropertyView.h | 2 +- .../CesiumGltf/PropertyTransformations.h | 3 +- .../include/CesiumGltf/PropertyTypeTraits.h | 36 +++ CesiumGltf/include/CesiumGltf/PropertyView.h | 1 - .../test/TestPropertyTablePropertyView.cpp | 24 +- CesiumGltf/test/TestPropertyTableView.cpp | 58 ++-- CesiumGltf/test/TestPropertyTypeTraits.cpp | 13 +- 9 files changed, 357 insertions(+), 78 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index f599ec58d..9be1867cf 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -66,35 +66,6 @@ template class PropertyArrayView { return true; } - PropertyArrayView - operator*(const PropertyArrayView& other) { - int64_t clampedSize = std::min(this->size(), other.size()); - std::vector result(static_cast(this->size())); - if constexpr (IsMetadataMatN::value) { - // Do component-wise multiplication instead of actual matrix - // multiplication. - ElementType matN; - constexpr glm::length_t N = ElementType::length(); - for (int64_t i = 0; i < clampedSize; i++) { - for (glm::length_t j = 0; j < N; j++) { - matN[j] = (*this)[i][j] * other[i][j]; - } - result[i] = matN; - } - } else { - for (int64_t i = 0; i < clampedSize; i++) { - result[i] = (*this)[i] * other[i]; - } - } - - // Copy anything that didn't have a component to multiply against. - for (int64_t i = clampedSize(); i < this->size(); i++) { - result[i] = (*this)[i]; - } - - return PropertyArrayView(std::move(result)); - } - private: using ArrayType = std::variant, std::vector>; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index ad183f48b..440e3dc43 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -219,8 +219,8 @@ class PropertyTablePropertyView * @param values The raw buffer specified by {@link PropertyTableProperty::values} * @param arrayOffsets The raw buffer specified by {@link PropertyTableProperty::arrayOffsets} * @param stringOffsets The raw buffer specified by {@link PropertyTableProperty::stringOffsets} - * @param offsetType The offset type of arrayOffsets specified by {@link PropertyTableProperty::arrayOffsetType} - * @param offsetType The offset type of stringOffsets specified by {@link PropertyTableProperty::stringOffsetType} + * @param arrayOffsetType The offset type of arrayOffsets specified by {@link PropertyTableProperty::arrayOffsetType} + * @param stringOffsetType The offset type of stringOffsets specified by {@link PropertyTableProperty::stringOffsetType} */ PropertyTablePropertyView( const PropertyTableProperty& property, @@ -242,9 +242,39 @@ class PropertyTablePropertyView _stringOffsetType{stringOffsetType}, _stringOffsetTypeSize{getOffsetTypeSize(stringOffsetType)} {} + /** + * @brief Get the value of an element in the {@link PropertyTable}, + * 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. + * + * If this property has a defined "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 index The element index + * @return The value of the element + */ + std::optional get(int64_t index) const noexcept { + ElementType value = getRaw(index); + + if (this->noData() && value == *(this->noData())) { + return this->defaultValue(); + } + + if constexpr ( + IsMetadataNumeric::value || + IsMetadataNumericArray::value) { + value = applyOffsetAndScale(value, this->offset(), this->scale()); + } + + return value; + } + /** * @brief Get the raw value of an element of the {@link PropertyTable}, - * without offset, scale, or normalization applied. + * without offset or scale applied. * * If this property has a "no data" value defined, the raw value will still be * returned, even if it equals the "no data" value. @@ -252,7 +282,7 @@ class PropertyTablePropertyView * @param index The element index * @return The value of the element */ - ElementType get(int64_t index) const noexcept { + ElementType getRaw(int64_t index) const noexcept { assert( this->_status == PropertyTablePropertyViewStatus::Valid && "Check the status() first to make sure view is valid"); @@ -429,4 +459,235 @@ class PropertyTablePropertyView PropertyComponentType _stringOffsetType; int64_t _stringOffsetTypeSize; }; + +/** + * @brief A view on the normalized data of the {@link PropertyTableProperty} + * that is created by a {@link PropertyTableView}. + * + * It provides utility to retrieve the actual data stored in the + * {@link PropertyTableProperty::values} like an array of elements. Data of each + * instance can be accessed through the {@link PropertyTablePropertyView::get} method. + * + * @param ElementType must be one of the following: an integer scalar (uint8_t, + * int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t), a glm vecN + * composed of one of the integer scalar types, a glm matN composed of one of + * the integer scalar types, or PropertyArrayView with T as one of the + * aforementioned types. + */ +// template +// class PropertyTablePropertyView +// : public PropertyView { +// private: +// using NormalizedType = typename TypeToNormalizedType::type; +// +// public: +// /** +// * @brief Constructs an invalid instance for a non-existent property. +// */ +// PropertyTablePropertyView() +// : PropertyView(), +// _values{}, +// _size{0}, +// _arrayOffsets{}, +// _arrayOffsetType{PropertyComponentType::None}, +// _arrayOffsetTypeSize{0} {} +// +// /** +// * @brief Constructs an invalid instance for an erroneous property. +// * +// * @param status The value of {@link PropertyTablePropertyViewStatus} indicating the error with the property. +// */ +// PropertyTablePropertyView(PropertyViewStatusType status) +// : PropertyView(status), +// _values{}, +// _size{0}, +// _arrayOffsets{}, +// _arrayOffsetType{PropertyComponentType::None}, +// _arrayOffsetTypeSize{0} { +// assert( +// this->_status != PropertyTablePropertyViewStatus::Valid && +// "An empty property view should not be constructed with a valid +// status"); +// } +// +// /** +// * @brief Construct an instance pointing to non-array data specified by a {@link PropertyTableProperty}. +// * +// * @param property The {@link PropertyTableProperty} +// * @param classProperty The {@link ClassProperty} this property conforms to. +// * @param size The number of elements in the property table specified by {@link PropertyTable::count} +// * @param value The raw buffer specified by {@link PropertyTableProperty::values} +// */ +// PropertyTablePropertyView( +// const PropertyTableProperty& property, +// const ClassProperty& classProperty, +// int64_t size, +// gsl::span values) noexcept +// : PropertyView(classProperty, property), +// _values{values}, +// _size{ +// this->_status == PropertyTablePropertyViewStatus::Valid ? size : +// 0}, +// _arrayOffsets{}, +// _arrayOffsetType{PropertyComponentType::None}, +// _arrayOffsetTypeSize{0} {} +// +// /** +// * @brief Construct an instance pointing to the data specified by a {@link PropertyTableProperty}. +// * +// * +// * @param property The {@link PropertyTableProperty} +// * @param classProperty The {@link ClassProperty} this property conforms to. +// * @param size The number of elements in the property table specified by {@link PropertyTable::count} +// * @param values The raw buffer specified by {@link PropertyTableProperty::values} +// * @param arrayOffsets The raw buffer specified by {@link PropertyTableProperty::arrayOffsets} +// * @param offsetType The offset type of arrayOffsets specified by {@link PropertyTableProperty::arrayOffsetType} +// */ +// PropertyTablePropertyView( +// const PropertyTableProperty& property, +// const ClassProperty& classProperty, +// int64_t size, +// gsl::span values, +// gsl::span arrayOffsets, +// PropertyComponentType arrayOffsetType) noexcept +// : PropertyView(classProperty, property), +// _values{values}, +// _size{ +// this->_status == PropertyTablePropertyViewStatus::Valid ? size : +// 0}, +// _arrayOffsets{arrayOffsets}, +// _arrayOffsetType{arrayOffsetType}, +// _arrayOffsetTypeSize{getOffsetTypeSize(arrayOffsetType)} {} +// +// /** +// * @brief Get the value of an element of the {@link PropertyTable}, +// * with all value transforms applied. This means the returned value will be +// * normalized. If the property specifies an offset and scale, they will be +// * applied to the value as well. +// * +// * If this property has a "no data" value defined, and the returned this +// returns the "default value". +// * +// * @param index The element index +// * @return The value of the element +// */ +// std::optional get(int64_t index) const noexcept { +// assert( +// this->_status == PropertyTablePropertyViewStatus::Valid && +// "Check the status() first to make sure view is valid"); +// assert( +// size() > 0 && +// "Check the size() of the view to make sure it's not empty"); +// assert(index >= 0 && "index must be non-negative"); +// assert(index < size() && "index must be less than size"); +// +// if constexpr (IsMetadataNumeric::value) { +// ElementType value = getValue(index); +// if (value == this->noData()) { +// +// } +// } +// +// if constexpr (IsMetadataNumericArray::value) { +// return getArrayValues::type>( +// index); +// } +// } +// +// /** +// * @brief Get the raw value of an element of the {@link PropertyTable}, +// * without offset, scale, or normalization applied. +// * +// * If this property has a "no data" value defined, the raw value will still +// be +// * returned, even if it equals the "no data" value. +// * +// * @param index The element index +// * @return The value of the element +// */ +// ElementType getRaw(int64_t index) const noexcept { +// assert( +// this->_status == PropertyTablePropertyViewStatus::Valid && +// "Check the status() first to make sure view is valid"); +// assert( +// size() > 0 && +// "Check the size() of the view to make sure it's not empty"); +// assert(index >= 0 && "index must be non-negative"); +// assert(index < size() && "index must be less than size"); +// +// if constexpr (IsMetadataNumeric::value) { +// return getValue(index); +// } +// +// if constexpr (IsMetadataNumericArray::value) { +// return getArrayValues::type>( +// index); +// } +// } +// +// /** +// * @brief Get the number of elements in this +// * PropertyTablePropertyView. If the view is valid, this returns +// * {@link PropertyTable::count}. Otherwise, this returns 0. +// * +// * @return The number of elements in this PropertyTablePropertyView. +// */ +// int64_t size() const noexcept { +// return this->_status == PropertyTablePropertyViewStatus::Valid ? _size : +// 0; +// } +// +// private: +// ElementType getValue(int64_t index) const noexcept { +// ElementType value = +// reinterpret_cast(_values.data())[index]; +// } +// +// template +// PropertyArrayView getArrayValues(int64_t index) const noexcept { +// size_t count = static_cast(this->arrayCount()); +// // Handle fixed-length arrays +// if (count > 0) { +// size_t arraySize = count * sizeof(T); +// const gsl::span values( +// _values.data() + index * arraySize, +// arraySize); +// return PropertyArrayView{values}; +// } +// +// // Handle variable-length arrays +// const size_t currentOffset = +// getOffsetFromOffsetsBuffer(index, _arrayOffsets, _arrayOffsetType); +// const size_t nextOffset = +// getOffsetFromOffsetsBuffer(index + 1, _arrayOffsets, +// _arrayOffsetType); +// const gsl::span values( +// _values.data() + currentOffset, +// nextOffset - currentOffset); +// return PropertyArrayView{values}; +// } +// +// static int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept +// { +// switch (offsetType) { +// case PropertyComponentType::Uint8: +// return sizeof(uint8_t); +// case PropertyComponentType::Uint16: +// return sizeof(uint16_t); +// case PropertyComponentType::Uint32: +// return sizeof(uint32_t); +// case PropertyComponentType::Uint64: +// return sizeof(uint64_t); +// default: +// return 0; +// } +// } +// +// gsl::span _values; +// int64_t _size; +// +// gsl::span _arrayOffsets; +// PropertyComponentType _arrayOffsetType; +// int64_t _arrayOffsetTypeSize; +//}; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 95417462a..cf5c16aaa 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -3,8 +3,8 @@ #include "CesiumGltf/ImageCesium.h" #include "CesiumGltf/PropertyTextureProperty.h" #include "CesiumGltf/PropertyTypeTraits.h" -#include "CesiumGltf/Sampler.h" #include "CesiumGltf/PropertyView.h" +#include "CesiumGltf/Sampler.h" #include #include diff --git a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h index f3523c1c0..6282400d1 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h @@ -7,6 +7,7 @@ #include #include +#include namespace CesiumGltf { template < @@ -56,7 +57,7 @@ template < std::enable_if_t< IsMetadataInteger::value && std::is_signed_v>> glm::mat normalize(glm::mat value) { - double max = static_cast(std::numeric_limits::max()); + double max = static_cast(std::numeric_limits::max()); return glm::max(static_cast>(value) / max, -1.0); } diff --git a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h index b7400cbc6..eff9ab37a 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h @@ -309,4 +309,40 @@ template struct TypeToNormalizedType> { using type = glm::mat; }; + +template <> struct TypeToNormalizedType> { + using type = PropertyArrayView; +}; +template <> struct TypeToNormalizedType> { + using type = PropertyArrayView; +}; +template <> struct TypeToNormalizedType> { + using type = PropertyArrayView; +}; +template <> struct TypeToNormalizedType> { + using type = PropertyArrayView; +}; +template <> struct TypeToNormalizedType> { + using type = PropertyArrayView; +}; +template <> struct TypeToNormalizedType> { + using type = PropertyArrayView; +}; +template <> struct TypeToNormalizedType> { + using type = PropertyArrayView; +}; +template <> struct TypeToNormalizedType> { + using type = PropertyArrayView; +}; + +template +struct TypeToNormalizedType>> { + using type = PropertyArrayView>; +}; + +template +struct TypeToNormalizedType>> { + using type = PropertyArrayView>; +}; + } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index a093d1407..fe9c3ca3d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -1,7 +1,6 @@ #include "CesiumGltf/ClassProperty.h" #include "CesiumGltf/PropertyTableProperty.h" #include "CesiumGltf/PropertyTextureProperty.h" -#include "CesiumGltf/PropertyTransformations.h" #include "CesiumGltf/PropertyTypeTraits.h" #include diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 8524cde90..22c24b4d1 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -34,7 +34,7 @@ template static void checkNumeric(const std::vector& expected) { gsl::span(data.data(), data.size())); for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.get(i) == expected[static_cast(i)]); + REQUIRE(property.getRaw(i) == expected[static_cast(i)]); } } @@ -84,7 +84,7 @@ static void checkVariableLengthArray( size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { - PropertyArrayView values = property.get(i); + PropertyArrayView values = property.getRaw(i); for (int64_t j = 0; j < values.size(); ++j) { REQUIRE(values[j] == data[expectedIdx]); ++expectedIdx; @@ -131,7 +131,7 @@ static void checkFixedLengthArray( size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { - PropertyArrayView values = property.get(i); + PropertyArrayView values = property.getRaw(i); for (int64_t j = 0; j < values.size(); ++j) { REQUIRE(values[j] == data[expectedIdx]); ++expectedIdx; @@ -276,7 +276,7 @@ TEST_CASE("Check boolean PropertyTablePropertyView") { gsl::span(data.data(), data.size())); for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.get(i) == bits[static_cast(i)]); + REQUIRE(property.getRaw(i) == bits[static_cast(i)]); } } @@ -332,7 +332,7 @@ TEST_CASE("Check string PropertyTablePropertyView") { PropertyComponentType::Uint32); for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.get(i) == strings[static_cast(i)]); + REQUIRE(property.getRaw(i) == strings[static_cast(i)]); } } @@ -900,7 +900,7 @@ TEST_CASE("Check fixed-length array of string") { size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { - PropertyArrayView values = property.get(i); + PropertyArrayView values = property.getRaw(i); for (int64_t j = 0; j < values.size(); ++j) { std::string_view v = values[j]; REQUIRE(v == strings[expectedIdx]); @@ -980,7 +980,7 @@ TEST_CASE("Check variable-length string array PropertyTablePropertyView") { size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { - PropertyArrayView values = property.get(i); + PropertyArrayView values = property.getRaw(i); for (int64_t j = 0; j < values.size(); ++j) { std::string_view v = values[j]; REQUIRE(v == strings[expectedIdx]); @@ -1016,7 +1016,7 @@ TEST_CASE("Check fixed-length boolean array PropertyTablePropertyView") { REQUIRE(property.size() == 2); REQUIRE(property.arrayCount() == classProperty.count); - PropertyArrayView val0 = property.get(0); + PropertyArrayView val0 = property.getRaw(0); REQUIRE(val0.size() == 12); REQUIRE(static_cast(val0[0]) == 1); REQUIRE(static_cast(val0[1]) == 1); @@ -1031,7 +1031,7 @@ TEST_CASE("Check fixed-length boolean array PropertyTablePropertyView") { REQUIRE(static_cast(val0[10]) == 0); REQUIRE(static_cast(val0[11]) == 1); - PropertyArrayView val1 = property.get(1); + PropertyArrayView val1 = property.getRaw(1); REQUIRE(static_cast(val1[0]) == 1); REQUIRE(static_cast(val1[1]) == 1); REQUIRE(static_cast(val1[2]) == 1); @@ -1075,13 +1075,13 @@ TEST_CASE("Check variable-length boolean array PropertyTablePropertyView") { REQUIRE(property.size() == 3); REQUIRE(property.arrayCount() == 0); - PropertyArrayView val0 = property.get(0); + PropertyArrayView val0 = property.getRaw(0); REQUIRE(val0.size() == 3); REQUIRE(static_cast(val0[0]) == 1); REQUIRE(static_cast(val0[1]) == 1); REQUIRE(static_cast(val0[2]) == 1); - PropertyArrayView val1 = property.get(1); + PropertyArrayView val1 = property.getRaw(1); REQUIRE(val1.size() == 9); REQUIRE(static_cast(val1[0]) == 1); REQUIRE(static_cast(val1[1]) == 0); @@ -1093,7 +1093,7 @@ TEST_CASE("Check variable-length boolean array PropertyTablePropertyView") { REQUIRE(static_cast(val1[7]) == 0); REQUIRE(static_cast(val1[8]) == 1); - PropertyArrayView val2 = property.get(2); + PropertyArrayView val2 = property.getRaw(2); REQUIRE(val2.size() == 16); REQUIRE(static_cast(val2[0]) == 1); REQUIRE(static_cast(val2[1]) == 1); diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index 4a625a350..b79cf2e9e 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -141,7 +141,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { REQUIRE(uint32Property.size() > 0); for (int64_t i = 0; i < uint32Property.size(); ++i) { - REQUIRE(uint32Property.get(i) == values[static_cast(i)]); + REQUIRE(uint32Property.getRaw(i) == values[static_cast(i)]); } } @@ -295,7 +295,7 @@ TEST_CASE("Test vecN PropertyTableProperty") { REQUIRE(ivec3Property.size() > 0); for (int64_t i = 0; i < ivec3Property.size(); ++i) { - REQUIRE(ivec3Property.get(i) == values[static_cast(i)]); + REQUIRE(ivec3Property.getRaw(i) == values[static_cast(i)]); } } @@ -467,7 +467,7 @@ TEST_CASE("Test matN PropertyTableProperty") { REQUIRE(u32mat2x2Property.size() > 0); for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { - REQUIRE(u32mat2x2Property.get(i) == values[static_cast(i)]); + REQUIRE(u32mat2x2Property.getRaw(i) == values[static_cast(i)]); } } @@ -641,7 +641,7 @@ TEST_CASE("Test boolean PropertyTableProperty") { REQUIRE(boolProperty.size() == instanceCount); for (int64_t i = 0; i < boolProperty.size(); ++i) { bool expectedValue = expected[static_cast(i)]; - REQUIRE(boolProperty.get(i) == expectedValue); + REQUIRE(boolProperty.getRaw(i) == expectedValue); } } @@ -724,7 +724,7 @@ TEST_CASE("Test string PropertyTableProperty") { view.getPropertyView("TestClassProperty"); REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { - REQUIRE(stringProperty.get(static_cast(i)) == expected[i]); + REQUIRE(stringProperty.getRaw(static_cast(i)) == expected[i]); } } @@ -846,7 +846,7 @@ TEST_CASE("Test fixed-length scalar array") { REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { - PropertyArrayView member = arrayProperty.get(i); + PropertyArrayView member = arrayProperty.getRaw(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 3 + j)]); } @@ -990,7 +990,7 @@ TEST_CASE("Test variable-length scalar array") { REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView valueMember = - property.get(static_cast(i)); + property.getRaw(static_cast(i)); REQUIRE(valueMember.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { REQUIRE(expected[i][j] == valueMember[static_cast(j)]); @@ -1122,7 +1122,7 @@ TEST_CASE("Test fixed-length vecN array") { REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { - PropertyArrayView member = arrayProperty.get(i); + PropertyArrayView member = arrayProperty.getRaw(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 2 + j)]); } @@ -1272,7 +1272,7 @@ TEST_CASE("Test variable-length vecN array") { REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView valueMember = - property.get(static_cast(i)); + property.getRaw(static_cast(i)); REQUIRE(valueMember.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { REQUIRE(expected[i][j] == valueMember[static_cast(j)]); @@ -1423,7 +1423,7 @@ TEST_CASE("Test fixed-length matN array") { REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { - PropertyArrayView member = arrayProperty.get(i); + PropertyArrayView member = arrayProperty.getRaw(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 2 + j)]); } @@ -1594,7 +1594,7 @@ TEST_CASE("Test variable-length matN array") { REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView valueMember = - property.get(static_cast(i)); + property.getRaw(static_cast(i)); REQUIRE(valueMember.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { REQUIRE(expected[i][j] == valueMember[static_cast(j)]); @@ -1746,7 +1746,7 @@ TEST_CASE("Test fixed-length boolean array") { REQUIRE(boolArrayProperty.size() == propertyTable.count); REQUIRE(boolArrayProperty.size() > 0); for (int64_t i = 0; i < boolArrayProperty.size(); ++i) { - PropertyArrayView valueMember = boolArrayProperty.get(i); + PropertyArrayView valueMember = boolArrayProperty.getRaw(i); for (int64_t j = 0; j < valueMember.size(); ++j) { REQUIRE(valueMember[j] == expected[static_cast(i * 3 + j)]); } @@ -1872,7 +1872,7 @@ TEST_CASE("Test variable-length boolean array") { boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView arrayMember = - boolArrayProperty.get(static_cast(i)); + boolArrayProperty.getRaw(static_cast(i)); REQUIRE(arrayMember.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { REQUIRE(expected[i][j] == arrayMember[static_cast(j)]); @@ -2028,17 +2028,17 @@ TEST_CASE("Test fixed-length arrays of strings") { REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(stringProperty.size() == 3); - PropertyArrayView v0 = stringProperty.get(0); + PropertyArrayView v0 = stringProperty.getRaw(0); REQUIRE(v0.size() == 2); REQUIRE(v0[0] == "What's up"); REQUIRE(v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); - PropertyArrayView v1 = stringProperty.get(1); + PropertyArrayView v1 = stringProperty.getRaw(1); REQUIRE(v1.size() == 2); REQUIRE(v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); - PropertyArrayView v2 = stringProperty.get(2); + PropertyArrayView v2 = stringProperty.getRaw(2); REQUIRE(v2.size() == 2); REQUIRE(v2[0] == "I love you, meat bags! ❤️"); REQUIRE(v2[1] == "Book in the freezer"); @@ -2198,7 +2198,7 @@ TEST_CASE("Test variable-length arrays of strings") { REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView stringArray = - stringProperty.get(static_cast(i)); + stringProperty.getRaw(static_cast(i)); for (size_t j = 0; j < expected[i].size(); ++j) { REQUIRE(stringArray[static_cast(j)] == expected[i][j]); } @@ -2472,7 +2472,7 @@ TEST_CASE("Test callback for scalar PropertyTableProperty") { for (int64_t i = 0; i < propertyValue.size(); ++i) { REQUIRE( - static_cast(propertyValue.get(i)) == + static_cast(propertyValue.getRaw(i)) == values[static_cast(i)]); } } else { @@ -2541,7 +2541,7 @@ TEST_CASE("Test callback for vecN PropertyTableProperty") { decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { REQUIRE( - static_cast(propertyValue.get(i)) == + static_cast(propertyValue.getRaw(i)) == values[static_cast(i)]); } } else { @@ -2619,7 +2619,7 @@ TEST_CASE("Test callback for matN PropertyTableProperty") { decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { REQUIRE( - static_cast(propertyValue.get(i)) == + static_cast(propertyValue.getRaw(i)) == values[static_cast(i)]); } } else { @@ -2702,7 +2702,7 @@ TEST_CASE("Test callback for boolean PropertyTableProperty") { decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { REQUIRE( - static_cast(propertyValue.get(i)) == + static_cast(propertyValue.getRaw(i)) == expected[static_cast(i)]); } } else { @@ -2792,7 +2792,7 @@ TEST_CASE("Test callback for string PropertyTableProperty") { decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { REQUIRE( - static_cast(propertyValue.get(i)) == + static_cast(propertyValue.getRaw(i)) == expected[static_cast(i)]); } } else { @@ -2861,7 +2861,7 @@ TEST_CASE("Test callback for scalar array PropertyTableProperty") { PropertyArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.get(i); + PropertyArrayView member = propertyValue.getRaw(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 3 + j)]); } @@ -2938,7 +2938,7 @@ TEST_CASE("Test callback for vecN array PropertyTableProperty") { PropertyArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.get(i); + PropertyArrayView member = propertyValue.getRaw(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 2 + j)]); } @@ -3029,7 +3029,7 @@ TEST_CASE("Test callback for matN array PropertyTableProperty") { PropertyArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.get(i); + PropertyArrayView member = propertyValue.getRaw(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == values[static_cast(i * 2 + j)]); } @@ -3120,7 +3120,7 @@ TEST_CASE("Test callback for boolean array PropertyTableProperty") { PropertyTablePropertyView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.get(i); + PropertyArrayView member = propertyValue.getRaw(i); for (int64_t j = 0; j < member.size(); ++j) { REQUIRE(member[j] == expected[static_cast(i * 3 + j)]); } @@ -3219,20 +3219,20 @@ TEST_CASE("Test callback for string array PropertyTableProperty") { PropertyTablePropertyView< PropertyArrayView>, decltype(propertyValue)>) { - PropertyArrayView v0 = propertyValue.get(0); + PropertyArrayView v0 = propertyValue.getRaw(0); REQUIRE(v0.size() == 2); REQUIRE(v0[0] == "What's up"); REQUIRE( v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); - PropertyArrayView v1 = propertyValue.get(1); + PropertyArrayView v1 = propertyValue.getRaw(1); REQUIRE(v1.size() == 2); REQUIRE( v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); - PropertyArrayView v2 = propertyValue.get(2); + PropertyArrayView v2 = propertyValue.getRaw(2); REQUIRE(v2.size() == 2); REQUIRE(v2[0] == "I love you, meat bags! ❤️"); REQUIRE(v2[1] == "Book in the freezer"); diff --git a/CesiumGltf/test/TestPropertyTypeTraits.cpp b/CesiumGltf/test/TestPropertyTypeTraits.cpp index a6f7bafcf..ff527cb7e 100644 --- a/CesiumGltf/test/TestPropertyTypeTraits.cpp +++ b/CesiumGltf/test/TestPropertyTypeTraits.cpp @@ -533,7 +533,6 @@ TEST_CASE("Test CanBeNormalized") { REQUIRE(CanBeNormalized::value); REQUIRE(CanBeNormalized::value); - REQUIRE(!CanBeNormalized::value); REQUIRE(!CanBeNormalized::value); REQUIRE(!CanBeNormalized::value); @@ -724,4 +723,16 @@ TEST_CASE("TypeToNormalizedType") { TypeToNormalizedType::type, ExpectedMat4Type>); } + + SECTION("Works for arrays") { + REQUIRE(std::is_same_v< + TypeToNormalizedType>::type, + PropertyArrayView>); + REQUIRE(std::is_same_v< + TypeToNormalizedType>::type, + PropertyArrayView>); + REQUIRE(std::is_same_v< + TypeToNormalizedType>::type, + PropertyArrayView>); + } } From 38001698e8ecf44fd19dc87e42124dc5173c1091 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 22 Aug 2023 12:43:48 -0400 Subject: [PATCH 084/121] Fix offset / scale etc. to only work for fixed-length arrays --- ...gradeBatchTableToExtStructuralMetadata.cpp | 8 +- .../CesiumGltf/PropertyTablePropertyView.h | 476 ++++++------ .../CesiumGltf/PropertyTransformations.h | 40 +- CesiumGltf/include/CesiumGltf/PropertyView.h | 680 ++++++------------ .../test/TestPropertyTablePropertyView.cpp | 254 ++++++- CesiumGltf/test/TestPropertyView.cpp | 229 +++++- 6 files changed, 939 insertions(+), 748 deletions(-) diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 46dc79b45..8a8a7509f 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -49,16 +49,16 @@ static void checkNonArrayProperty( for (int64_t i = 0; i < propertyView.size(); ++i) { if constexpr (std::is_same_v) { REQUIRE(Math::equalsEpsilon( - static_cast(propertyView.get(i)), + static_cast(propertyView.getRaw(i)), static_cast(expected[static_cast(i)]), Math::Epsilon6)); } else if constexpr ( std::is_same_v || std::is_same_v) { - REQUIRE(propertyView.get(i) == Approx(expected[static_cast(i)])); + REQUIRE(propertyView.getRaw(i) == Approx(expected[static_cast(i)])); } else { REQUIRE( - static_cast(propertyView.get(i)) == + static_cast(propertyView.getRaw(i)) == expected[static_cast(i)]); } } @@ -92,7 +92,7 @@ static void checkArrayProperty( REQUIRE(propertyView.size() == static_cast(expectedTotalInstances)); for (size_t i = 0; i < expectedTotalInstances; ++i) { PropertyArrayView value = - propertyView.get(static_cast(i)); + propertyView.getRaw(static_cast(i)); if (expectedCount > 0) { REQUIRE(value.size() == expectedCount); } diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 440e3dc43..e4fe2e9de 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -1,6 +1,7 @@ #pragma once #include "CesiumGltf/PropertyArrayView.h" +#include "CesiumGltf/PropertyTransformations.h" #include "CesiumGltf/PropertyTypeTraits.h" #include "CesiumGltf/PropertyView.h" @@ -130,6 +131,23 @@ class PropertyTablePropertyViewStatus : public PropertyViewStatus { static const PropertyViewStatusType ErrorStringOffsetOutOfBounds = 29; }; +namespace { +int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { + switch (offsetType) { + case PropertyComponentType::Uint8: + return sizeof(uint8_t); + case PropertyComponentType::Uint16: + return sizeof(uint16_t); + case PropertyComponentType::Uint32: + return sizeof(uint32_t); + case PropertyComponentType::Uint64: + return sizeof(uint64_t); + default: + return 0; + } +} +} // namespace + template class PropertyTablePropertyView; @@ -248,13 +266,14 @@ class PropertyTablePropertyView * offset and scale, they will be applied to the value before the value is * returned. * - * If this property has a defined "no data" value, and the retrieved element + * 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 index The element index - * @return The value of the element + * @return The value of the element, or std::nullopt if it matches the "no + * data" value */ std::optional get(int64_t index) const noexcept { ElementType value = getRaw(index); @@ -276,8 +295,8 @@ class PropertyTablePropertyView * @brief Get the raw value of an element of the {@link PropertyTable}, * without offset or scale applied. * - * If this property has a "no data" value defined, the raw value will still be - * returned, even if it equals the "no data" value. + * 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 index The element index * @return The value of the element @@ -433,21 +452,6 @@ class PropertyTablePropertyView return PropertyArrayView(buffer, currentOffset % 8, totalBits); } - static int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { - switch (offsetType) { - case PropertyComponentType::Uint8: - return sizeof(uint8_t); - case PropertyComponentType::Uint16: - return sizeof(uint16_t); - case PropertyComponentType::Uint32: - return sizeof(uint32_t); - case PropertyComponentType::Uint64: - return sizeof(uint64_t); - default: - return 0; - } - } - gsl::span _values; int64_t _size; @@ -474,220 +478,222 @@ class PropertyTablePropertyView * the integer scalar types, or PropertyArrayView with T as one of the * aforementioned types. */ -// template -// class PropertyTablePropertyView -// : public PropertyView { -// private: -// using NormalizedType = typename TypeToNormalizedType::type; -// -// public: -// /** -// * @brief Constructs an invalid instance for a non-existent property. -// */ -// PropertyTablePropertyView() -// : PropertyView(), -// _values{}, -// _size{0}, -// _arrayOffsets{}, -// _arrayOffsetType{PropertyComponentType::None}, -// _arrayOffsetTypeSize{0} {} -// -// /** -// * @brief Constructs an invalid instance for an erroneous property. -// * -// * @param status The value of {@link PropertyTablePropertyViewStatus} indicating the error with the property. -// */ -// PropertyTablePropertyView(PropertyViewStatusType status) -// : PropertyView(status), -// _values{}, -// _size{0}, -// _arrayOffsets{}, -// _arrayOffsetType{PropertyComponentType::None}, -// _arrayOffsetTypeSize{0} { -// assert( -// this->_status != PropertyTablePropertyViewStatus::Valid && -// "An empty property view should not be constructed with a valid -// status"); -// } -// -// /** -// * @brief Construct an instance pointing to non-array data specified by a {@link PropertyTableProperty}. -// * -// * @param property The {@link PropertyTableProperty} -// * @param classProperty The {@link ClassProperty} this property conforms to. -// * @param size The number of elements in the property table specified by {@link PropertyTable::count} -// * @param value The raw buffer specified by {@link PropertyTableProperty::values} -// */ -// PropertyTablePropertyView( -// const PropertyTableProperty& property, -// const ClassProperty& classProperty, -// int64_t size, -// gsl::span values) noexcept -// : PropertyView(classProperty, property), -// _values{values}, -// _size{ -// this->_status == PropertyTablePropertyViewStatus::Valid ? size : -// 0}, -// _arrayOffsets{}, -// _arrayOffsetType{PropertyComponentType::None}, -// _arrayOffsetTypeSize{0} {} -// -// /** -// * @brief Construct an instance pointing to the data specified by a {@link PropertyTableProperty}. -// * -// * -// * @param property The {@link PropertyTableProperty} -// * @param classProperty The {@link ClassProperty} this property conforms to. -// * @param size The number of elements in the property table specified by {@link PropertyTable::count} -// * @param values The raw buffer specified by {@link PropertyTableProperty::values} -// * @param arrayOffsets The raw buffer specified by {@link PropertyTableProperty::arrayOffsets} -// * @param offsetType The offset type of arrayOffsets specified by {@link PropertyTableProperty::arrayOffsetType} -// */ -// PropertyTablePropertyView( -// const PropertyTableProperty& property, -// const ClassProperty& classProperty, -// int64_t size, -// gsl::span values, -// gsl::span arrayOffsets, -// PropertyComponentType arrayOffsetType) noexcept -// : PropertyView(classProperty, property), -// _values{values}, -// _size{ -// this->_status == PropertyTablePropertyViewStatus::Valid ? size : -// 0}, -// _arrayOffsets{arrayOffsets}, -// _arrayOffsetType{arrayOffsetType}, -// _arrayOffsetTypeSize{getOffsetTypeSize(arrayOffsetType)} {} -// -// /** -// * @brief Get the value of an element of the {@link PropertyTable}, -// * with all value transforms applied. This means the returned value will be -// * normalized. If the property specifies an offset and scale, they will be -// * applied to the value as well. -// * -// * If this property has a "no data" value defined, and the returned this -// returns the "default value". -// * -// * @param index The element index -// * @return The value of the element -// */ -// std::optional get(int64_t index) const noexcept { -// assert( -// this->_status == PropertyTablePropertyViewStatus::Valid && -// "Check the status() first to make sure view is valid"); -// assert( -// size() > 0 && -// "Check the size() of the view to make sure it's not empty"); -// assert(index >= 0 && "index must be non-negative"); -// assert(index < size() && "index must be less than size"); -// -// if constexpr (IsMetadataNumeric::value) { -// ElementType value = getValue(index); -// if (value == this->noData()) { -// -// } -// } -// -// if constexpr (IsMetadataNumericArray::value) { -// return getArrayValues::type>( -// index); -// } -// } -// -// /** -// * @brief Get the raw value of an element of the {@link PropertyTable}, -// * without offset, scale, or normalization applied. -// * -// * If this property has a "no data" value defined, the raw value will still -// be -// * returned, even if it equals the "no data" value. -// * -// * @param index The element index -// * @return The value of the element -// */ -// ElementType getRaw(int64_t index) const noexcept { -// assert( -// this->_status == PropertyTablePropertyViewStatus::Valid && -// "Check the status() first to make sure view is valid"); -// assert( -// size() > 0 && -// "Check the size() of the view to make sure it's not empty"); -// assert(index >= 0 && "index must be non-negative"); -// assert(index < size() && "index must be less than size"); -// -// if constexpr (IsMetadataNumeric::value) { -// return getValue(index); -// } -// -// if constexpr (IsMetadataNumericArray::value) { -// return getArrayValues::type>( -// index); -// } -// } -// -// /** -// * @brief Get the number of elements in this -// * PropertyTablePropertyView. If the view is valid, this returns -// * {@link PropertyTable::count}. Otherwise, this returns 0. -// * -// * @return The number of elements in this PropertyTablePropertyView. -// */ -// int64_t size() const noexcept { -// return this->_status == PropertyTablePropertyViewStatus::Valid ? _size : -// 0; -// } -// -// private: -// ElementType getValue(int64_t index) const noexcept { -// ElementType value = -// reinterpret_cast(_values.data())[index]; -// } -// -// template -// PropertyArrayView getArrayValues(int64_t index) const noexcept { -// size_t count = static_cast(this->arrayCount()); -// // Handle fixed-length arrays -// if (count > 0) { -// size_t arraySize = count * sizeof(T); -// const gsl::span values( -// _values.data() + index * arraySize, -// arraySize); -// return PropertyArrayView{values}; -// } -// -// // Handle variable-length arrays -// const size_t currentOffset = -// getOffsetFromOffsetsBuffer(index, _arrayOffsets, _arrayOffsetType); -// const size_t nextOffset = -// getOffsetFromOffsetsBuffer(index + 1, _arrayOffsets, -// _arrayOffsetType); -// const gsl::span values( -// _values.data() + currentOffset, -// nextOffset - currentOffset); -// return PropertyArrayView{values}; -// } -// -// static int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept -// { -// switch (offsetType) { -// case PropertyComponentType::Uint8: -// return sizeof(uint8_t); -// case PropertyComponentType::Uint16: -// return sizeof(uint16_t); -// case PropertyComponentType::Uint32: -// return sizeof(uint32_t); -// case PropertyComponentType::Uint64: -// return sizeof(uint64_t); -// default: -// return 0; -// } -// } -// -// gsl::span _values; -// int64_t _size; -// -// gsl::span _arrayOffsets; -// PropertyComponentType _arrayOffsetType; -// int64_t _arrayOffsetTypeSize; -//}; +template +class PropertyTablePropertyView + : public PropertyView { +private: + using NormalizedType = typename TypeToNormalizedType::type; + +public: + /** + * @brief Constructs an invalid instance for a non-existent property. + */ + PropertyTablePropertyView() + : PropertyView(), + _values{}, + _size{0}, + _arrayOffsets{}, + _arrayOffsetType{PropertyComponentType::None}, + _arrayOffsetTypeSize{0} {} + + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The value of {@link PropertyTablePropertyViewStatus} indicating the error with the property. + */ + PropertyTablePropertyView(PropertyViewStatusType status) + : PropertyView(status), + _values{}, + _size{0}, + _arrayOffsets{}, + _arrayOffsetType{PropertyComponentType::None}, + _arrayOffsetTypeSize{0} { + assert( + this->_status != PropertyTablePropertyViewStatus::Valid && + "An empty property view should not be constructed with a valid status"); + } + + /** + * @brief Construct an instance pointing to non-array data specified by a {@link PropertyTableProperty}. + * + * @param property The {@link PropertyTableProperty} + * @param classProperty The {@link ClassProperty} this property conforms to. + * @param size The number of elements in the property table specified by {@link PropertyTable::count} + * @param value The raw buffer specified by {@link PropertyTableProperty::values} + */ + PropertyTablePropertyView( + const PropertyTableProperty& property, + const ClassProperty& classProperty, + int64_t size, + gsl::span values) noexcept + : PropertyView(classProperty, property), + _values{values}, + _size{ + this->_status == PropertyTablePropertyViewStatus::Valid ? size : 0}, + _arrayOffsets{}, + _arrayOffsetType{PropertyComponentType::None}, + _arrayOffsetTypeSize{0} {} + + /** + * @brief Construct an instance pointing to the data specified by a {@link PropertyTableProperty}. + * + * + * @param property The {@link PropertyTableProperty} + * @param classProperty The {@link ClassProperty} this property conforms to. + * @param size The number of elements in the property table specified by {@link PropertyTable::count} + * @param values The raw buffer specified by {@link PropertyTableProperty::values} + * @param arrayOffsets The raw buffer specified by {@link PropertyTableProperty::arrayOffsets} + * @param offsetType The offset type of arrayOffsets specified by {@link PropertyTableProperty::arrayOffsetType} + */ + PropertyTablePropertyView( + const PropertyTableProperty& property, + const ClassProperty& classProperty, + int64_t size, + gsl::span values, + gsl::span arrayOffsets, + PropertyComponentType arrayOffsetType) noexcept + : PropertyView(classProperty, property), + _values{values}, + _size{ + this->_status == PropertyTablePropertyViewStatus::Valid ? size : 0}, + _arrayOffsets{arrayOffsets}, + _arrayOffsetType{arrayOffsetType}, + _arrayOffsetTypeSize{getOffsetTypeSize(arrayOffsetType)} {} + + /** + * @brief Get the value of an element of the {@link PropertyTable}, + * with normalization and other value transforms applied. In other words, the + * value will be normalized, then transformed by the property's offset + * and scale, if they are defined. + * + * 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 index The element index + * @return The value of the element, or std::nullopt if it matches the "no + * data" value + */ + std::optional get(int64_t index) const noexcept { + assert( + this->_status == PropertyTablePropertyViewStatus::Valid && + "Check the status() first to make sure view is valid"); + assert( + size() > 0 && + "Check the size() of the view to make sure it's not empty"); + assert(index >= 0 && "index must be non-negative"); + assert(index < size() && "index must be less than size"); + + ElementType value = getRaw(index); + if (this->noData() && value == *(this->noData())) { + return this->defaultValue(); + } + + if constexpr (IsMetadataNumeric::value) { + return applyOffsetAndScale( + normalize(value), + this->offset(), + this->scale()); + } + + if constexpr (IsMetadataNumericArray::value) { + const auto offset = this->offset(); + const auto scale = this->scale(); + int64_t offsetSize = offset ? offset->size() : 0; + int64_t scaleSize = scale ? scale->size() : 0; + std::vector result(static_cast(value.size())); + for (int64_t i = 0; i < value.size(); i++) { + result[i] = value[i]; + + if (i < scaleSize) { + result = applyScale(result[i], scale[i]); + } + + if (i < offsetSize) { + result[i] = result[i] + offset[i]; + } + } + + return PropertyArrayView(std::move(result)); + } + } + + /** + * @brief Get the raw value of an element of the {@link PropertyTable}, + * without offset, scale, or normalization applied. + * + * 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 index The element index + * @return The value of the element + */ + ElementType getRaw(int64_t index) const noexcept { + assert( + this->_status == PropertyTablePropertyViewStatus::Valid && + "Check the status() first to make sure view is valid"); + assert( + size() > 0 && + "Check the size() of the view to make sure it's not empty"); + assert(index >= 0 && "index must be non-negative"); + assert(index < size() && "index must be less than size"); + + if constexpr (IsMetadataNumeric::value) { + return getValue(index); + } + + if constexpr (IsMetadataNumericArray::value) { + return getArrayValues::type>( + index); + } + } + + /** + * @brief Get the number of elements in this + * PropertyTablePropertyView. If the view is valid, this returns + * {@link PropertyTable::count}. Otherwise, this returns 0. + * + * @return The number of elements in this PropertyTablePropertyView. + */ + int64_t size() const noexcept { + return this->_status == PropertyTablePropertyViewStatus::Valid ? _size : 0; + } + +private: + ElementType getValue(int64_t index) const noexcept { + return reinterpret_cast(_values.data())[index]; + } + + template + PropertyArrayView getArrayValues(int64_t index) const noexcept { + size_t count = static_cast(this->arrayCount()); + // Handle fixed-length arrays + if (count > 0) { + size_t arraySize = count * sizeof(T); + const gsl::span values( + _values.data() + index * arraySize, + arraySize); + return PropertyArrayView{values}; + } + + // Handle variable-length arrays + const size_t currentOffset = + getOffsetFromOffsetsBuffer(index, _arrayOffsets, _arrayOffsetType); + const size_t nextOffset = + getOffsetFromOffsetsBuffer(index + 1, _arrayOffsets, _arrayOffsetType); + const gsl::span values( + _values.data() + currentOffset, + nextOffset - currentOffset); + return PropertyArrayView{values}; + } + + gsl::span _values; + int64_t _size; + + gsl::span _arrayOffsets; + PropertyComponentType _arrayOffsetType; + int64_t _arrayOffsetTypeSize; +}; + } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h index 6282400d1..e95b5ac1a 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h @@ -10,30 +10,21 @@ #include namespace CesiumGltf { -template < - typename TSigned, - std::enable_if_t< - IsMetadataInteger::value && std::is_signed_v>> -double normalize(TSigned value) { - double max = static_cast(std::numeric_limits::max()); - return std::max(static_cast(value) / max, -1.0); -} - -template < - typename TUnsigned, - std::enable_if_t< - IsMetadataInteger::value && std::is_unsigned_v>> -double normalize(TUnsigned value) { - double max = static_cast(std::numeric_limits::max()); - return static_cast(value) / max; +template +double normalize(T value) { + constexpr double max = static_cast(std::numeric_limits::max()); + if constexpr (std::is_signed_v) { + return std::max(static_cast(value) / max, -1.0); + } else { + return static_cast(value) / max; + } } template < glm::length_t N, typename TSigned, glm::qualifier Q, - std::enable_if_t< - IsMetadataInteger::value && std::is_signed_v>> + std::enable_if_t>> glm::vec normalize(glm::vec value) { double max = static_cast(std::numeric_limits::max()); return glm::max(static_cast>(value) / max, -1.0); @@ -43,8 +34,7 @@ template < glm::length_t N, typename TUnsigned, glm::qualifier Q, - std::enable_if_t< - IsMetadataInteger::value && std::is_unsigned_v>> + std::enable_if_t>> glm::vec normalize(glm::vec value) { double max = static_cast(std::numeric_limits::max()); return static_cast>(value) / max; @@ -54,8 +44,7 @@ template < glm::length_t N, typename TSigned, glm::qualifier Q, - std::enable_if_t< - IsMetadataInteger::value && std::is_signed_v>> + std::enable_if_t>> glm::mat normalize(glm::mat value) { double max = static_cast(std::numeric_limits::max()); return glm::max(static_cast>(value) / max, -1.0); @@ -65,8 +54,7 @@ template < glm::length_t N, typename TUnsigned, glm::qualifier Q, - std::enable_if_t< - IsMetadataInteger::value && std::is_unsigned_v>> + std::enable_if_t>> glm::mat normalize(glm::mat value) { double max = static_cast(std::numeric_limits::max()); return static_cast>(value) / max; @@ -94,11 +82,11 @@ T applyOffsetAndScale( const std::optional& scale) { T result = value; if (scale) { - result = applyScale(result, scale); + result = applyScale(result, *scale); } if (offset) { - result += offset; + result += *offset; } return result; diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index fe9c3ca3d..896189662 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -220,6 +220,14 @@ getMatN(const CesiumUtility::JsonValue& jsonValue) { return result; } +template +int64_t getCount(std::optional>& buffer) { + if (!buffer) { + return 0; + } + + return static_cast(buffer->size() / sizeof(ElementType)); +} } // namespace /** @@ -276,56 +284,9 @@ template class PropertyView { return; } - if (classProperty.offset) { - // Only floating point types can specify an offset. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _offset = getValue(*classProperty.offset); - if (_offset) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (classProperty.scale) { - // Only floating point types can specify a scale. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _scale = getValue(*classProperty.scale); - if (_scale) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (classProperty.max) { - _max = getValue(*classProperty.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (classProperty.min) { - _min = getValue(*classProperty.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + getNumericPropertyValues(classProperty); + if (_status != PropertyViewStatus::Valid) { + return; } if (classProperty.noData) { @@ -384,58 +345,7 @@ template class PropertyView { } // If the property has its own values, override the class-provided values. - - if (property.offset) { - // Only floating point types can specify an offset. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _offset = getValue(*property.offset); - if (_offset) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (property.scale) { - // Only floating point types can specify a scale. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _scale = getValue(*property.scale); - if (_scale) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (property.max) { - _max = getValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (property.min) { - _min = getValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } - } + getNumericPropertyValues(property); } /** @@ -451,58 +361,7 @@ template class PropertyView { } // If the property has its own values, override the class-provided values. - - if (property.offset) { - // Only floating point types can specify an offset. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _offset = getValue(*property.offset); - if (_offset) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (property.scale) { - // Only floating point types can specify a scale. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _scale = getValue(*property.scale); - if (_scale) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (property.max) { - _max = getValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (property.min) { - _min = getValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } - } + getNumericPropertyValues(property); } public: @@ -596,11 +455,64 @@ template class PropertyView { protected: PropertyViewStatusType _status; - ElementType applyValueTransforms(ElementType value) { - if (_offset || _scale) { - return applyOffsetAndScale(value, _offset, _scale); - } - return value; + using PropertyDefinitionType = std:: + variant; + void getNumericPropertyValues(const PropertyDefinitionType& inProperty) { + std::visit( + [this](auto property) { + if (property.offset) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: + this->_offset = getValue(*property.offset); + if (this->_offset) { + break; + } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + this->_status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (property.scale) { + // Only floating point types can specify a scale. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: + this->_scale = getValue(*property.scale); + if (this->_scale) { + break; + } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + this->_status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (property.max) { + this->_max = getValue(*property.max); + if (!this->_max) { + // The value was specified but something went wrong. + this->_status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (property.min) { + this->_min = getValue(*property.min); + if (!this->_min) { + // The value was specified but something went wrong. + this->_status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + }, + inProperty); } private: @@ -941,14 +853,6 @@ class PropertyView< protected: PropertyViewStatusType _status; - NormalizedType applyValueTransforms(ElementType value) { - NormalizedType result = normalize(value); - if (_offset || _scale) { - return applyOffsetAndScale(result, _offset, _scale); - } - return result; - } - private: bool _required; @@ -1336,60 +1240,9 @@ class PropertyView> { return; } - if (classProperty.offset) { - // Only floating point types can specify an offset. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _offset = getArrayValue(*classProperty.offset); - if (_offset && - (_count == 0 || _offset->size() == static_cast(_count))) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (classProperty.scale) { - // Only floating point types can specify an offset. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _scale = getArrayValue(*classProperty.scale); - if (_scale && - (_count == 0 || _scale->size() == static_cast(_count))) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (classProperty.max) { - _max = getArrayValue(*classProperty.max); - if (!_max || - (_count > 0 && _max->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (classProperty.min) { - _min = getArrayValue(*classProperty.min); - if (!_min || - (_count > 0 && _min->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + getNumericPropertyValues(classProperty); + if (_status != PropertyViewStatus::Valid) { + return; } if (classProperty.noData) { @@ -1446,60 +1299,7 @@ class PropertyView> { } // If the property has its own values, override the class-provided values. - - if (property.offset) { - // Only floating point types can specify an offset. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _offset = getArrayValue(*property.offset); - if (_offset && - (_count == 0 || _offset->size() == static_cast(_count))) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (property.scale) { - // Only floating point types can specify an offset. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _scale = getArrayValue(*property.scale); - if (_scale && - (_count == 0 || _scale->size() == static_cast(_count))) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (property.max) { - _max = getArrayValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (property.min) { - _min = getArrayValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } - } + getNumericPropertyValues(property); } /** @@ -1515,59 +1315,7 @@ class PropertyView> { } // If the property has its own values, override the class-provided values. - if (property.offset) { - // Only floating point types can specify an offset. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _offset = getArrayValue(*property.offset); - if (_offset && - (_count == 0 || _offset->size() == static_cast(_count))) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (property.scale) { - // Only floating point types can specify an offset. - switch (TypeToPropertyType::component) { - case PropertyComponentType::Float32: - case PropertyComponentType::Float64: - _scale = getArrayValue(*property.scale); - if (_scale && - (_count == 0 || _scale->size() == static_cast(_count))) { - break; - } - // If it does not break here, something went wrong. - [[fallthrough]]; - default: - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (property.max) { - _max = getArrayValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (property.min) { - _min = getArrayValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } - } + getNumericPropertyValues(property); } public: @@ -1667,14 +1415,6 @@ class PropertyView> { protected: PropertyViewStatusType _status; - PropertyArrayView - applyValueTransforms(const PropertyArrayView& value) { - if (_offset || _scale) { - return applyOffsetAndScale(value, _offset, _scale); - } - return value; - } - private: int64_t _count; @@ -1687,6 +1427,78 @@ class PropertyView> { std::optional> _noData; std::optional> _defaultValue; + using PropertyDefinitionType = std:: + variant; + void getNumericPropertyValues(const PropertyDefinitionType& inProperty) { + std::visit( + [this](auto property) { + if (property.offset) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: + if (this->_count > 0) { + this->_offset = getArrayValue(*property.offset); + } + if (this->_offset && + getCount(this->_offset) == this->_count) { + break; + } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + this->_status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (property.scale) { + // Only floating point types can specify an offset. + switch (TypeToPropertyType::component) { + case PropertyComponentType::Float32: + case PropertyComponentType::Float64: + if (_count > 0) { + this->_scale = getArrayValue(*property.scale); + } + if (this->_scale && + getCount(this->_scale) == this->_count) { + break; + } + // If it does not break here, something went wrong. + [[fallthrough]]; + default: + this->_status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (property.max) { + if (this->_count > 0) { + this->_max = getArrayValue(*property.max); + } + if (!this->_max || + getCount(this->_max) != this->_count) { + // The value was specified but something went wrong. + this->_status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (property.min) { + if (this->_count > 0) { + this->_min = getArrayValue(*property.min); + } + if (!this->_min || + getCount(this->_min) != this->_count) { + // The value was specified but something went wrong. + this->_status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + }, + inProperty); + } + static std::optional> getArrayValue(const CesiumUtility::JsonValue& jsonValue) { if (!jsonValue.isArray()) { @@ -1795,44 +1607,9 @@ class PropertyView< return; } - if (classProperty.offset) { - _offset = getArrayValue(*classProperty.offset); - if (!_offset || - (_count > 0 && _offset->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (classProperty.scale) { - _scale = getArrayValue(*classProperty.scale); - if (!_scale || - (_count > 0 && _scale->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (classProperty.max) { - _max = getArrayValue(*classProperty.max); - if (!_max || - (_count > 0 && _max->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (classProperty.min) { - _min = getArrayValue(*classProperty.min); - if (!_min || - (_count > 0 && _min->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } + getNumericPropertyValues(classProperty); + if (_status != PropertyViewStatus::Valid) { + return; } if (classProperty.noData) { @@ -1889,46 +1666,7 @@ class PropertyView< } // If the property has its own values, override the class-provided values. - - if (property.offset) { - _offset = getArrayValue(*property.offset); - if (!_offset || - (_count > 0 && _offset->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (property.scale) { - _scale = getArrayValue(*property.scale); - if (!_scale || - (_count > 0 || _scale->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (property.max) { - _max = getArrayValue(*property.max); - if (!_max || - (_count > 0 && _max->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (property.min) { - _min = getArrayValue(*property.min); - if (!_min || - (_count > 0 && _min->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } - } + getNumericPropertyValues(property); } /** @@ -1945,45 +1683,7 @@ class PropertyView< // If the property has its own values, override the class-provided values. - if (property.offset) { - _offset = getArrayValue(*property.offset); - if (!_offset || - (_count > 0 && _offset->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (property.scale) { - _scale = getArrayValue(*property.scale); - if (!_scale || - (_count > 0 || _scale->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (property.max) { - _max = getArrayValue(*property.max); - if (!_max || - (_count > 0 && _max->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (property.min) { - _min = getArrayValue(*property.min); - if (!_min || - (_count > 0 && _min->size() != static_cast(_count))) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } - } + getNumericPropertyValues(property); } public: @@ -2084,28 +1784,6 @@ class PropertyView< protected: PropertyViewStatusType _status; - PropertyArrayView - applyValueTransforms(const PropertyArrayView& value) { - auto offset = this->offset(); - auto scale = this->scale(); - int64_t offsetSize = offset ? offset.size() : 0; - int64_t scaleSize = scale ? scale.size() : 0; - std::vector result(static_cast(value.size())); - for (int64_t i = 0; i < value.size(); i++) { - result[i] = normalize(value[i]); - - if (i < scaleSize) { - result = applyScale(result[i], scale[i]); - } - - if (i < offsetSize) { - result[i] = result[i] + offset[i]; - } - } - - return PropertyArrayView(std::move(result)); - } - private: int64_t _count; @@ -2118,6 +1796,58 @@ class PropertyView< std::optional> _noData; std::optional> _defaultValue; + using PropertyDefinitionType = std:: + variant; + void getNumericPropertyValues(const PropertyDefinitionType& inProperty) { + std::visit( + [this](auto property) { + if (property.offset) { + if (_count > 0) { + _offset = getArrayValue(*property.offset); + } + if (!_offset || getCount(_offset) != _count) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (property.scale) { + if (_count > 0) { + _scale = getArrayValue(*property.scale); + } + if (!_scale || getCount(_scale) != _count) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (property.max) { + if (_count > 0) { + _max = getArrayValue(*property.max); + } + if (!_max || getCount(_max) != _count) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (property.min) { + if (_count > 0) { + _min = getArrayValue(*property.min); + } + if (!_min || getCount(_min) != _count) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + }, + inProperty); + } + template static std::optional> getArrayValue(const CesiumUtility::JsonValue& jsonValue) { diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 22c24b4d1..8e875aba5 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -35,6 +35,116 @@ template static void checkNumeric(const std::vector& expected) { for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == expected[static_cast(i)]); + REQUIRE(property.get(i)); + REQUIRE(*property.get(i) == property.getRaw(i)); + } +} + +template +static void checkNumeric( + const std::vector& values, + const std::vector>& expected, + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + std::vector data; + data.resize(values.size() * sizeof(T)); + std::memcpy(data.data(), values.data(), data.size()); + + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + if (componentType != PropertyComponentType::None) { + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + } + + if (offset) { + classProperty.offset = *offset; + } + + if (scale) { + classProperty.scale = *scale; + } + + if (noData) { + classProperty.noData = *noData; + } + + if (defaultValue) { + classProperty.defaultProperty = *defaultValue; + } + + PropertyTablePropertyView property( + propertyTableProperty, + classProperty, + static_cast(expected.size()), + gsl::span(data.data(), data.size())); + + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == values[static_cast(i)]); + if constexpr (IsMetadataFloating::value) { + REQUIRE(property.get(i)); + REQUIRE(*property.get(i) == Approx(*expected[static_cast(i)])); + } else { + REQUIRE(property.get(i) == expected[static_cast(i)]); + } + } +} + +template ::type> +static void checkNormalizedNumeric( + const std::vector& values, + const std::vector>& expected, + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + std::vector data; + data.resize(values.size() * sizeof(T)); + std::memcpy(data.data(), values.data(), data.size()); + + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.normalized = true; + + if (offset) { + classProperty.offset = *offset; + } + + if (scale) { + classProperty.scale = *scale; + } + + if (noData) { + classProperty.noData = *noData; + } + + if (defaultValue) { + classProperty.defaultProperty = *defaultValue; + } + + PropertyTablePropertyView property( + propertyTableProperty, + classProperty, + static_cast(expected.size()), + gsl::span(data.data(), data.size())); + + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == values[static_cast(i)]); + REQUIRE(property.get(i)); + REQUIRE(*property.get(i) == Approx(*expected[static_cast(i)])); } } @@ -142,22 +252,22 @@ static void checkFixedLengthArray( } TEST_CASE("Check scalar PropertyTablePropertyView") { - SECTION("Uint8 Scalar") { + SECTION("Uint8") { std::vector data{12, 33, 56, 67}; checkNumeric(data); } - SECTION("Int32 Scalar") { + SECTION("Int32") { std::vector data{111222, -11133, -56000, 670000}; checkNumeric(data); } - SECTION("Float Scalar") { + SECTION("Float") { std::vector data{12.3333f, -12.44555f, -5.6111f, 6.7421f}; checkNumeric(data); } - SECTION("Double Scalar") { + SECTION("Double") { std::vector data{ 12222.3302121, -12000.44555, @@ -165,6 +275,142 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { 6.7421}; checkNumeric(data); } + + SECTION("Normalized Uint8") { + std::vector values{0, 64, 128, 255}; + std::vector> expected{ + 0.0, + 64.0 / 255.0, + 128.0 / 255.0, + 1.0}; + checkNormalizedNumeric(values, expected); + } + + SECTION("Normalized Int16") { + std::vector values{-32768, 0, 16384, 32767}; + std::vector> expected{ + -1.0, + 0.0, + 16384.0 / 32767.0, + 1.0}; + checkNormalizedNumeric(values, expected); + } + + SECTION("Float with Offset / Scale") { + std::vector values{12.5f, -12.5f, -5.0f, 6.75f}; + std::optional offset = 1.0f; + std::optional scale = 2.0f; + std::vector> expected{26.0f, -24.0f, -9.0f, 14.5f}; + checkNumeric(values, expected, offset, scale); + } + + SECTION("Normalized Uint8 with Offset and Scale") { + std::vector values{0, 64, 128, 255}; + std::optional offset = 1.0; + std::optional scale = 2.0; + std::vector> expected{ + 1.0, + 1 + 2 * (64.0 / 255.0), + 1 + 2 * (128.0 / 255.0), + 3.0}; + checkNormalizedNumeric(values, expected, offset, scale); + } + + SECTION("Int16 with NoData") { + std::vector values{-1, 3, 7, -1}; + std::optional noData = -1; + std::vector> expected{ + std::nullopt, + 3, + 7, + std::nullopt}; + checkNumeric( + values, + expected, + std::nullopt, + std::nullopt, + noData, + std::nullopt); + }; + + SECTION("Int16 with NoData and Default") { + std::vector values{-1, 3, 7, -1}; + std::optional noData = -1; + std::optional defaultValue = 0; + std::vector> expected{0, 3, 7, 0}; + checkNumeric( + values, + expected, + std::nullopt, + std::nullopt, + noData, + defaultValue); + } + + SECTION("Normalized Uint8 with all properties") { + std::vector values{0, 64, 128, 255}; + std::optional offset = 1.0; + std::optional scale = 2.0; + std::optional noData = 0; + std::optional defaultValue = 10.0; + std::vector> expected{ + 10.0, + 1 + 2 * (64.0 / 255.0), + 1 + 2 * (128.0 / 255.0), + 3.0}; + checkNormalizedNumeric( + values, + expected, + offset, + scale, + noData, + defaultValue); + } + + SECTION("Overrides class property values") { + std::vector values{1.0f, 3.0f, 2.0f, 4.0f}; + std::vector data; + data.resize(values.size() * sizeof(float)); + std::memcpy(data.data(), values.data(), data.size()); + + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.offset = 0.0f; + classProperty.scale = 1.0f; + classProperty.min = 1.0f; + classProperty.max = 4.0f; + + PropertyTableProperty propertyTableProperty; + propertyTableProperty.offset = 1.0f; + propertyTableProperty.scale = 2.0f; + propertyTableProperty.min = 3.0f; + propertyTableProperty.max = 9.0f; + + PropertyTablePropertyView property( + propertyTableProperty, + classProperty, + static_cast(values.size()), + gsl::span(data.data(), data.size())); + + REQUIRE(property.offset()); + REQUIRE(*property.offset() == 1.0f); + REQUIRE(property.scale()); + REQUIRE(*property.scale() == 2.0f); + REQUIRE(property.min()); + REQUIRE(*property.min() == 3.0f); + REQUIRE(property.max()); + REQUIRE(*property.max() == 9.0f); + + std::vector expected{3.0, 7.0f, 5.0f, 9.0f}; + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == values[static_cast(i)]); + + std::optional transformedValue = property.get(i); + REQUIRE(transformedValue); + REQUIRE(*transformedValue == Approx(expected[static_cast(i)])); + } + } } TEST_CASE("Check vecN PropertyTablePropertyView") { diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp index c9cf11553..8aa81a9a9 100644 --- a/CesiumGltf/test/TestPropertyView.cpp +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -507,7 +507,7 @@ TEST_CASE("VecN PropertyView") { view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); - classProperty.max = {10, 5}; + classProperty.max = {0, 500}; view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); } @@ -901,8 +901,8 @@ TEST_CASE("MatN PropertyView") { // clang-format off classProperty.min = { - -29, -40, - -55, -43}; + -29, -240, + -155, -43}; // clang-format on view = PropertyView(classProperty); REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); @@ -1424,6 +1424,7 @@ TEST_CASE("Scalar Array PropertyView") { classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.array = true; + classProperty.count = 2; classProperty.offset = JsonValue::Array{5.0f, 10.0f}; classProperty.scale = JsonValue::Array{2.0f, 1.0f}; classProperty.max = JsonValue::Array{10.0f, 20.0f}; @@ -1462,6 +1463,7 @@ TEST_CASE("Scalar Array PropertyView") { classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; + classProperty.count = 2; classProperty.required = false; classProperty.noData = {0, 1}; classProperty.defaultProperty = {2, 3}; @@ -1483,11 +1485,36 @@ TEST_CASE("Scalar Array PropertyView") { REQUIRE(value[1] == 3); } + SECTION("Reports errors for defined properties on variable-length arrays") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.count = 0; + classProperty.min = {0, 0}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {5, 4}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = {1, 1}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = {0, 2}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; + classProperty.count = 2; classProperty.required = true; classProperty.defaultProperty = {2, 3}; @@ -1512,6 +1539,7 @@ TEST_CASE("Scalar Array PropertyView") { classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; + classProperty.count = 2; classProperty.defaultProperty = {256, 256}; PropertyView> view(classProperty); @@ -1543,6 +1571,7 @@ TEST_CASE("Scalar Array PropertyView") { classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; + classProperty.count = 2; classProperty.defaultProperty = "[256, 256]"; PropertyView> view(classProperty); @@ -1643,6 +1672,7 @@ TEST_CASE("Scalar Array PropertyView (normalized)") { classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::INT16; classProperty.array = true; + classProperty.count = 2; classProperty.normalized = true; classProperty.offset = JsonValue::Array{5.0, 10.0}; classProperty.scale = JsonValue::Array{2.0, 1.0}; @@ -1704,11 +1734,38 @@ TEST_CASE("Scalar Array PropertyView (normalized)") { REQUIRE(defaultValue[1] == 3.5); } + SECTION("Reports errors for defined properties on variable-length arrays") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + classProperty.count = 0; + classProperty.normalized = true; + classProperty.min = {0, 0}; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {5, 4}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = {1, 1}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = {0, 2}; + classProperty.offset = {0, 2}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; + classProperty.count = 2; classProperty.normalized = true; classProperty.required = true; classProperty.defaultProperty = {2, 3}; @@ -1726,6 +1783,7 @@ TEST_CASE("Scalar Array PropertyView (normalized)") { classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; + classProperty.count = 2; classProperty.normalized = true; classProperty.noData = {-1, 0}; @@ -1738,6 +1796,7 @@ TEST_CASE("Scalar Array PropertyView (normalized)") { classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::UINT8; classProperty.array = true; + classProperty.count = 2; classProperty.normalized = true; classProperty.defaultProperty = "[256, 256]"; @@ -1839,6 +1898,7 @@ TEST_CASE("VecN Array PropertyView") { classProperty.type = ClassProperty::Type::VEC3; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.array = true; + classProperty.count = 2; classProperty.offset = {{-1, 1, 2}, {4, 4, 0}}; classProperty.scale = {{2, 1, 3}, {8, 2, 3}}; classProperty.max = {{14, 28, 12}, {10, 5, 6}}; @@ -1898,6 +1958,30 @@ TEST_CASE("VecN Array PropertyView") { REQUIRE(value[1] == glm::vec2(5.0f, 6.0f)); } + SECTION("Reports errors for defined properties on variable-length arrays") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.count = 0; + classProperty.min = {{-11, -12, -13}, {-2, -4, 6}}; + + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {{14, 28, 12}, {10, 5, 6}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = {{2, 1, 3}, {8, 2, 3}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = {{-1, 1, 2}, {4, 4, 0}}; + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC2; @@ -2058,6 +2142,7 @@ TEST_CASE("VecN Array PropertyView (normalized)") { classProperty.type = ClassProperty::Type::VEC3; classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; + classProperty.count = 2; classProperty.normalized = true; classProperty.offset = {{-1, 1, 2}, {4, 4, 0}}; classProperty.scale = {{2, 1, 3}, {8, 2, 3}}; @@ -2119,11 +2204,37 @@ TEST_CASE("VecN Array PropertyView (normalized)") { REQUIRE(defaultValue[1] == glm::dvec2(5.0, 6.0)); } + SECTION("Reports errors for defined properties on variable-length arrays") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.count = 0; + classProperty.normalized = true; + classProperty.min = {{-11, -12, -13}, {-2, -4, 6}}; + + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + classProperty.max = {{14, 28, 12}, {10, 5, 6}}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + classProperty.scale = {{2, 1, 3}, {8, 2, 3}}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + classProperty.offset = {{-1, 1, 2}, {4, 4, 0}}; + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::VEC2; classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; + classProperty.count = 2; classProperty.normalized = true; classProperty.required = true; classProperty.defaultProperty = {{3, 4}, {5, 6}}; @@ -2253,6 +2364,7 @@ TEST_CASE("MatN Array PropertyView") { classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.array = true; + classProperty.count = 2; // clang-format off classProperty.offset = { {-1, 1, @@ -2313,6 +2425,7 @@ TEST_CASE("MatN Array PropertyView") { classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.array = true; + classProperty.count = 2; classProperty.required = false; // clang-format off classProperty.noData = { @@ -2346,11 +2459,63 @@ TEST_CASE("MatN Array PropertyView") { REQUIRE(value[1] == glm::i8mat2x2(2, 2, 2, 2)); } + SECTION("Reports errors for defined properties on variable-length arrays") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.array = true; + classProperty.count = 0; + // clang-format off + classProperty.min = { + {0, 0, + 0, 0}, + {-1, -1, + -1, -1}, + }; + // clang-format on + PropertyView> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + // clang-format off + classProperty.max = { + {1, 1, + 1, 1}, + {2, 2, + 2, 2}, + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + + // clang-format off + classProperty.scale = { + {1, 0, + 0, 1}, + {-1, 0, + 0, -1}, + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + // clang-format off + classProperty.offset = { + {2, 2, + 1, 1}, + {0, 2, + 1, 2}, + }; + // clang-format on + view = PropertyView>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } + SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; + classProperty.count = 2; classProperty.required = true; // clang-format off classProperty.defaultProperty = { @@ -2403,6 +2568,7 @@ TEST_CASE("MatN Array PropertyView") { classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.array = true; + classProperty.count = 2; // clang-format off classProperty.defaultProperty = { @@ -2474,6 +2640,7 @@ TEST_CASE("MatN Array PropertyView") { classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.array = true; + classProperty.count = 2; classProperty.defaultProperty = {4, 1, 2, 0}; PropertyView> view(classProperty); @@ -2566,8 +2733,8 @@ TEST_CASE("MatN Array PropertyView (normalized)") { classProperty.type = ClassProperty::Type::MAT3; classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; - classProperty.normalized = true; classProperty.count = 5; + classProperty.normalized = true; PropertyView, true> view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); @@ -2579,6 +2746,7 @@ TEST_CASE("MatN Array PropertyView (normalized)") { classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; + classProperty.count = 2; classProperty.normalized = true; // clang-format off @@ -2641,6 +2809,7 @@ TEST_CASE("MatN Array PropertyView (normalized)") { classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT8; classProperty.array = true; + classProperty.count = 2; classProperty.normalized = true; classProperty.required = false; // clang-format off @@ -2674,12 +2843,64 @@ TEST_CASE("MatN Array PropertyView (normalized)") { REQUIRE(defaultValue[0] == glm::dmat2(1, 1, 1, 1)); REQUIRE(defaultValue[1] == glm::dmat2(2, 2, 2, 2)); } + SECTION("Reports errors for defined properties on variable-length arrays") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::INT32; + classProperty.array = true; + classProperty.count = 0; + classProperty.normalized = true; + // clang-format off + classProperty.min = { + {0, 0, + 0, 0}, + {-1, -1, + -1, -1}, + }; + + // clang-format on + PropertyView, true> view(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMin); + + // clang-format off + classProperty.max = { + {1, 1, + 1, 1}, + {2, 2, + 2, 2}, + }; + // clang-format on + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidMax); + // clang-format off + classProperty.scale = { + {1, 0, + 0, 1}, + {-1, 0, + 0, -1}, + }; + // clang-format on + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidScale); + + // clang-format off + classProperty.offset = { + {2, 2, + 1, 1}, + {0, 2, + 1, 2}, + }; + // clang-format on + view = PropertyView, true>(classProperty); + REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidOffset); + } SECTION("Reports errors for incorrectly defined properties") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::INT32; classProperty.array = true; + classProperty.count = 2; classProperty.normalized = true; classProperty.required = true; // clang-format off From d43d7138afe8efa37768230eb8d890d2882c12b0 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 22 Aug 2023 18:31:09 -0400 Subject: [PATCH 085/121] Start adding tests for PropertyTablePropertyView --- .../CesiumGltf/PropertyTablePropertyView.h | 68 +- .../CesiumGltf/PropertyTransformations.h | 154 +- .../include/CesiumGltf/PropertyTypeTraits.h | 2 + CesiumGltf/include/CesiumGltf/PropertyView.h | 14 +- .../test/TestPropertyTablePropertyView.cpp | 1383 +++++++++++++++-- CesiumGltf/test/TestPropertyTypeTraits.cpp | 120 +- 6 files changed, 1517 insertions(+), 224 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index e4fe2e9de..c63f6e661 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -148,7 +148,7 @@ int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { } } // namespace -template +template class PropertyTablePropertyView; /** @@ -282,10 +282,12 @@ class PropertyTablePropertyView return this->defaultValue(); } - if constexpr ( - IsMetadataNumeric::value || - IsMetadataNumericArray::value) { - value = applyOffsetAndScale(value, this->offset(), this->scale()); + if constexpr (IsMetadataNumeric::value) { + value = transformValue(value, this->offset(), this->scale()); + } + + if constexpr (IsMetadataNumericArray::value) { + value = transformArray(value, this->offset(), this->scale()); } return value; @@ -590,32 +592,50 @@ class PropertyTablePropertyView return this->defaultValue(); } - if constexpr (IsMetadataNumeric::value) { - return applyOffsetAndScale( + if constexpr (IsMetadataScalar::value) { + return transformValue( normalize(value), this->offset(), this->scale()); } - if constexpr (IsMetadataNumericArray::value) { - const auto offset = this->offset(); - const auto scale = this->scale(); - int64_t offsetSize = offset ? offset->size() : 0; - int64_t scaleSize = scale ? scale->size() : 0; - std::vector result(static_cast(value.size())); - for (int64_t i = 0; i < value.size(); i++) { - result[i] = value[i]; - - if (i < scaleSize) { - result = applyScale(result[i], scale[i]); - } - - if (i < offsetSize) { - result[i] = result[i] + offset[i]; - } + if constexpr (IsMetadataVecN::value) { + constexpr glm::length_t N = ElementType::length(); + using T = typename ElementType::value_type; + using NormalizedT = typename NormalizedType::value_type; + return transformVecN( + normalize(value), + this->offset(), + this->scale()); + } + + if constexpr (IsMetadataMatN::value) { + constexpr glm::length_t N = ElementType::length(); + using T = typename ElementType::value_type; + using NormalizedT = typename NormalizedType::value_type; + return transformMatN( + normalize(value), + this->offset(), + this->scale()); + } + + if constexpr (IsMetadataArray::value) { + using ArrayElementType = typename MetadataArrayType::type; + if constexpr (IsMetadataScalar::value) { + return transformNormalizedArray( + value, + this->offset(), + this->scale()); } - return PropertyArrayView(std::move(result)); + if constexpr (IsMetadataVecN::value) { + constexpr glm::length_t N = ArrayElementType::length(); + using T = typename ArrayElementType::value_type; + return transformNormalizedVecNArray( + value, + this->offset(), + this->scale()); + } } } diff --git a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h index e95b5ac1a..9716520a9 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h @@ -10,8 +10,7 @@ #include namespace CesiumGltf { -template -double normalize(T value) { +template double normalize(T value) { constexpr double max = static_cast(std::numeric_limits::max()); if constexpr (std::is_signed_v) { return std::max(static_cast(value) / max, -1.0); @@ -20,44 +19,31 @@ double normalize(T value) { } } -template < - glm::length_t N, - typename TSigned, - glm::qualifier Q, - std::enable_if_t>> -glm::vec normalize(glm::vec value) { - double max = static_cast(std::numeric_limits::max()); - return glm::max(static_cast>(value) / max, -1.0); -} - -template < - glm::length_t N, - typename TUnsigned, - glm::qualifier Q, - std::enable_if_t>> -glm::vec normalize(glm::vec value) { - double max = static_cast(std::numeric_limits::max()); - return static_cast>(value) / max; -} - -template < - glm::length_t N, - typename TSigned, - glm::qualifier Q, - std::enable_if_t>> -glm::mat normalize(glm::mat value) { - double max = static_cast(std::numeric_limits::max()); - return glm::max(static_cast>(value) / max, -1.0); +template +glm::vec normalize(glm::vec value) { + constexpr double max = static_cast(std::numeric_limits::max()); + if constexpr (std::is_signed_v) { + return glm::max(static_cast>(value) / max, -1.0); + } else { + return static_cast>(value) / max; + } } -template < - glm::length_t N, - typename TUnsigned, - glm::qualifier Q, - std::enable_if_t>> -glm::mat normalize(glm::mat value) { - double max = static_cast(std::numeric_limits::max()); - return static_cast>(value) / max; +template +glm::mat normalize(glm::mat value) { + constexpr double max = static_cast(std::numeric_limits::max()); + // No max() implementation for matrices, so we have to write our own. + glm::mat result; + for (glm::length_t i = 0; i < N; i++) { + for (glm::length_t j = 0; j < N; j++) { + if constexpr (std::is_signed_v) { + result[i][j] = glm::max(static_cast(value[i][j]) / max, -1.0); + } else { + result[i][j] = static_cast(value[i][j]) / max; + } + } + } + return result; } template T applyScale(const T& value, const T& scale) { @@ -76,7 +62,7 @@ template T applyScale(const T& value, const T& scale) { } template -T applyOffsetAndScale( +T transformValue( const T& value, const std::optional& offset, const std::optional& scale) { @@ -92,27 +78,103 @@ T applyOffsetAndScale( return result; } +template +glm::vec transformVecN( + const glm::vec& value, + const std::optional>& offset, + const std::optional>& scale) { + glm::vec result = value; + if (scale) { + result = applyScale>(result, *scale); + } + + if (offset) { + result += *offset; + } + + return result; +} + +template +glm::mat transformMatN( + const glm::mat& value, + const std::optional>& offset, + const std::optional>& scale) { + glm::mat result = value; + if (scale) { + result = applyScale>(result, *scale); + } + + if (offset) { + result += *offset; + } + + return result; +} + template -PropertyArrayView applyOffsetAndScale( +PropertyArrayView transformArray( const PropertyArrayView& value, const std::optional>& offset, const std::optional>& scale) { - int64_t offsetSize = offset ? offset->size() : 0; - int64_t scaleSize = scale ? scale->size() : 0; std::vector result(static_cast(value.size())); for (int64_t i = 0; i < value.size(); i++) { result[i] = value[i]; - if (i < scaleSize) { - result = applyScale(result[i], scale[i]); + if (scale) { + result[i] = applyScale(result[i], (*scale)[i]); } - if (i < offsetSize) { - result[i] = result[i] + offset[i]; + if (offset) { + result[i] = result[i] + (*offset)[i]; } } return PropertyArrayView(std::move(result)); } +template < + typename T, + typename NormalizedType = typename TypeToNormalizedType::type> +PropertyArrayView transformNormalizedArray( + const PropertyArrayView& value, + const std::optional>& offset, + const std::optional>& scale) { + std::vector result(static_cast(value.size())); + for (int64_t i = 0; i < value.size(); i++) { + result[i] = normalize(value[i]); + + if (scale) { + result[i] = applyScale(result[i], (*scale)[i]); + } + + if (offset) { + result[i] = result[i] + (*offset)[i]; + } + } + + return PropertyArrayView(std::move(result)); +} + +template +PropertyArrayView> transformNormalizedVecNArray( + const PropertyArrayView>& value, + const std::optional>>& offset, + const std::optional>>& scale) { + std::vector> result(static_cast(value.size())); + for (int64_t i = 0; i < value.size(); i++) { + result[i] = normalize(value[i]); + + if (scale) { + result[i] = applyScale>(result[i], (*scale)[i]); + } + + if (offset) { + result[i] = result[i] + (*offset)[i]; + } + } + + return PropertyArrayView>(std::move(result)); +} + } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h index eff9ab37a..286cb0609 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h @@ -285,6 +285,8 @@ struct CanBeNormalized> : CanBeNormalized {}; template struct CanBeNormalized> : CanBeNormalized {}; +template +struct CanBeNormalized> : CanBeNormalized {}; /** * @brief Convert an integer numeric type to the corresponding representation as * a double type. Doubles are preferred over floats to maintain more precision. diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 896189662..469f8392d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -233,8 +233,7 @@ int64_t getCount(std::optional>& buffer) { /** * @brief Represents a metadata property in EXT_structural_metadata. */ -template -class PropertyView; +template class PropertyView; /** * @brief Represents a non-normalized metadata property in @@ -565,11 +564,7 @@ template class PropertyView { * @tparam ElementType The C++ type of the values in this property. Must have an * integer component type. */ -template -class PropertyView< - ElementType, - true, - std::enable_if_t::value>> { +template class PropertyView { private: using NormalizedType = typename TypeToNormalizedType::type; @@ -1562,10 +1557,7 @@ class PropertyView> { * property. Must have an integer component type. */ template -class PropertyView< - PropertyArrayView, - true, - std::enable_if_t::value>> { +class PropertyView, true> { private: using NormalizedType = typename TypeToNormalizedType::type; diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 8e875aba5..8094f00c8 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -10,6 +10,31 @@ #include using namespace CesiumGltf; +using namespace CesiumUtility; + +#pragma region Utility + +template +JsonValue::Array getArrayFromVecN(glm::vec vecN) { + JsonValue::Array values(N); + for (glm::length_t i = 0; i < N; i++) { + values[i] = vecN[i]; + } + + return values; +} + +template +JsonValue::Array getArrayFromMatN(glm::mat matN) { + JsonValue::Array values(N * N); + for (glm::length_t i = 0; i < N; i++) { + for (glm::length_t j = 0; j < N; j++) { + values[N * i + j] = matN[i][j]; + } + } + + return values; +} template static void checkNumeric(const std::vector& expected) { std::vector data; @@ -33,6 +58,8 @@ template static void checkNumeric(const std::vector& expected) { static_cast(expected.size()), gsl::span(data.data(), data.size())); + REQUIRE(property.size() == static_cast(expected.size())); + for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == expected[static_cast(i)]); REQUIRE(property.get(i)); @@ -41,7 +68,7 @@ template static void checkNumeric(const std::vector& expected) { } template -static void checkNumeric( +static void checkScalar( const std::vector& values, const std::vector>& expected, const std::optional offset = std::nullopt, @@ -58,10 +85,8 @@ static void checkNumeric( convertPropertyTypeToString(TypeToPropertyType::value); PropertyComponentType componentType = TypeToPropertyType::component; - if (componentType != PropertyComponentType::None) { - classProperty.componentType = - convertPropertyComponentTypeToString(componentType); - } + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); if (offset) { classProperty.offset = *offset; @@ -85,6 +110,8 @@ static void checkNumeric( static_cast(expected.size()), gsl::span(data.data(), data.size())); + REQUIRE(property.size() == static_cast(expected.size())); + for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == values[static_cast(i)]); if constexpr (IsMetadataFloating::value) { @@ -96,14 +123,116 @@ static void checkNumeric( } } -template ::type> -static void checkNormalizedNumeric( +template +static void checkVecN( + const std::vector>& values, + const std::vector>>& expected, + const std::optional> offset = std::nullopt, + const std::optional> scale = std::nullopt, + const std::optional> noData = std::nullopt, + const std::optional> defaultValue = std::nullopt) { + std::vector data; + data.resize(values.size() * sizeof(glm::vec)); + std::memcpy(data.data(), values.data(), data.size()); + + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType>::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + if (offset) { + classProperty.offset = getArrayFromVecN(*offset); + } + + if (scale) { + classProperty.scale = getArrayFromVecN(*scale); + } + + if (noData) { + classProperty.noData = getArrayFromVecN(*noData); + } + + if (defaultValue) { + classProperty.defaultProperty = getArrayFromVecN(*defaultValue); + } + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + static_cast(expected.size()), + gsl::span(data.data(), data.size())); + + REQUIRE(property.size() == static_cast(expected.size())); + + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == values[static_cast(i)]); + REQUIRE(property.get(i) == expected[static_cast(i)]); + } +} + +template +static void checkMatN( + const std::vector>& values, + const std::vector>>& expected, + const std::optional> offset = std::nullopt, + const std::optional> scale = std::nullopt, + const std::optional> noData = std::nullopt, + const std::optional> defaultValue = std::nullopt) { + std::vector data; + data.resize(values.size() * sizeof(glm::mat)); + std::memcpy(data.data(), values.data(), data.size()); + + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType>::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + if (offset) { + classProperty.offset = getArrayFromMatN(*offset); + } + + if (scale) { + classProperty.scale = getArrayFromMatN(*scale); + } + + if (noData) { + classProperty.noData = getArrayFromMatN(*noData); + } + + if (defaultValue) { + classProperty.defaultProperty = getArrayFromMatN(*defaultValue); + } + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + static_cast(expected.size()), + gsl::span(data.data(), data.size())); + + REQUIRE(property.size() == static_cast(expected.size())); + + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == values[static_cast(i)]); + REQUIRE(property.get(i) == expected[static_cast(i)]); + } +} + +template +static void checkNormalizedScalar( const std::vector& values, - const std::vector>& expected, - const std::optional offset = std::nullopt, - const std::optional scale = std::nullopt, + const std::vector>& expected, + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, const std::optional noData = std::nullopt, - const std::optional defaultValue = std::nullopt) { + const std::optional defaultValue = std::nullopt) { std::vector data; data.resize(values.size() * sizeof(T)); std::memcpy(data.data(), values.data(), data.size()); @@ -141,10 +270,117 @@ static void checkNormalizedNumeric( static_cast(expected.size()), gsl::span(data.data(), data.size())); + REQUIRE(property.size() == static_cast(expected.size())); + for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == values[static_cast(i)]); - REQUIRE(property.get(i)); - REQUIRE(*property.get(i) == Approx(*expected[static_cast(i)])); + REQUIRE(property.get(i) == expected[static_cast(i)]); + } +} + +template +static void checkNormalizedVecN( + const std::vector>& values, + const std::vector>>& expected, + const std::optional> offset = std::nullopt, + const std::optional> scale = std::nullopt, + const std::optional> noData = std::nullopt, + const std::optional> defaultValue = std::nullopt) { + std::vector data; + data.resize(values.size() * sizeof(glm::vec)); + std::memcpy(data.data(), values.data(), data.size()); + + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType>::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.normalized = true; + + if (offset) { + classProperty.offset = getArrayFromVecN(*offset); + } + + if (scale) { + classProperty.scale = getArrayFromVecN(*scale); + } + + if (noData) { + classProperty.noData = getArrayFromVecN(*noData); + } + + if (defaultValue) { + classProperty.defaultProperty = getArrayFromVecN(*defaultValue); + } + + PropertyTablePropertyView, true> property( + propertyTableProperty, + classProperty, + static_cast(expected.size()), + gsl::span(data.data(), data.size())); + + REQUIRE(property.size() == static_cast(expected.size())); + + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == values[static_cast(i)]); + REQUIRE(property.get(i) == expected[static_cast(i)]); + } +} + +template +static void checkNormalizedMatN( + const std::vector>& values, + const std::vector>>& expected, + const std::optional> offset = std::nullopt, + const std::optional> scale = std::nullopt, + const std::optional> noData = std::nullopt, + const std::optional> defaultValue = std::nullopt) { + std::vector data; + data.resize(values.size() * sizeof(glm::mat)); + std::memcpy(data.data(), values.data(), data.size()); + + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType>::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.normalized = true; + + if (offset) { + classProperty.offset = getArrayFromMatN(*offset); + } + + if (scale) { + classProperty.scale = getArrayFromMatN(*scale); + } + + if (noData) { + classProperty.noData = getArrayFromMatN(*noData); + } + + if (defaultValue) { + classProperty.defaultProperty = getArrayFromMatN(*defaultValue); + } + + PropertyTablePropertyView, true> property( + propertyTableProperty, + classProperty, + static_cast(expected.size()), + gsl::span(data.data(), data.size())); + + REQUIRE(property.size() == static_cast(expected.size())); + + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == values[static_cast(i)]); + REQUIRE(property.get(i) == expected[static_cast(i)]); } } @@ -207,11 +443,13 @@ static void checkVariableLengthArray( template static void checkFixedLengthArray( const std::vector& data, - int64_t fixedLengthArrayCount, - int64_t instanceCount) { + int64_t fixedLengthArrayCount) { + int64_t instanceCount = + static_cast(data.size()) / fixedLengthArrayCount; + std::vector buffer; buffer.resize(data.size() * sizeof(T)); - std::memcpy(buffer.data(), data.data(), data.size() * sizeof(T)); + std::memcpy(buffer.data(), data.data(), buffer.size()); PropertyTableProperty propertyTableProperty; ClassProperty classProperty; @@ -250,81 +488,229 @@ static void checkFixedLengthArray( REQUIRE(expectedIdx == data.size()); } +template +static void checkFixedLengthArrayWithProperties( + const std::vector& data, + int64_t fixedLengthArrayCount, + const std::vector>>& expected, + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + int64_t instanceCount = + static_cast(data.size()) / fixedLengthArrayCount; -TEST_CASE("Check scalar PropertyTablePropertyView") { - SECTION("Uint8") { - std::vector data{12, 33, 56, 67}; - checkNumeric(data); - } + std::vector buffer; + buffer.resize(data.size() * sizeof(T)); + std::memcpy(buffer.data(), data.data(), buffer.size()); - SECTION("Int32") { - std::vector data{111222, -11133, -56000, 670000}; - checkNumeric(data); - } + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); - SECTION("Float") { - std::vector data{12.3333f, -12.44555f, -5.6111f, 6.7421f}; - checkNumeric(data); + PropertyComponentType componentType = TypeToPropertyType::component; + if (componentType != PropertyComponentType::None) { + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); } - SECTION("Double") { - std::vector data{ - 12222.3302121, - -12000.44555, - -5000.6113111, - 6.7421}; - checkNumeric(data); - } + classProperty.array = true; + classProperty.count = fixedLengthArrayCount; + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; - SECTION("Normalized Uint8") { - std::vector values{0, 64, 128, 255}; - std::vector> expected{ - 0.0, - 64.0 / 255.0, - 128.0 / 255.0, - 1.0}; - checkNormalizedNumeric(values, expected); - } + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + instanceCount, + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None); - SECTION("Normalized Int16") { - std::vector values{-32768, 0, 16384, 32767}; - std::vector> expected{ - -1.0, - 0.0, - 16384.0 / 32767.0, - 1.0}; - checkNormalizedNumeric(values, expected); - } + REQUIRE(property.arrayCount() == fixedLengthArrayCount); - SECTION("Float with Offset / Scale") { - std::vector values{12.5f, -12.5f, -5.0f, 6.75f}; - std::optional offset = 1.0f; - std::optional scale = 2.0f; - std::vector> expected{26.0f, -24.0f, -9.0f, 14.5f}; - checkNumeric(values, expected, offset, scale); + // Check raw values first + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView rawValues = property.getRaw(i); + for (int64_t j = 0; j < rawValues.size(); ++j) { + REQUIRE(rawValues[j] == data[expectedIdx]); + ++expectedIdx; + } } - SECTION("Normalized Uint8 with Offset and Scale") { - std::vector values{0, 64, 128, 255}; - std::optional offset = 1.0; - std::optional scale = 2.0; - std::vector> expected{ - 1.0, - 1 + 2 * (64.0 / 255.0), - 1 + 2 * (128.0 / 255.0), - 3.0}; - checkNormalizedNumeric(values, expected, offset, scale); + REQUIRE(expectedIdx == data.size()); + + // Check values with properties applied + for (int64_t i = 0; i < property.size(); ++i) { + std::optional> maybeValues = property.get(i); + std::optional> expectedValues = + expected[static_cast(i)]; + REQUIRE(maybeValues.has_value() == expectedValues.has_value()); + if (!maybeValues) { + continue; + } + + auto values = *maybeValues; + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == (*expectedValues)[static_cast(j)]); + } } +} - SECTION("Int16 with NoData") { - std::vector values{-1, 3, 7, -1}; - std::optional noData = -1; - std::vector> expected{ - std::nullopt, +template ::type> +static void checkNormalizedFixedLengthArray( + const std::vector& data, + int64_t fixedLengthArrayCount, + const std::vector>>& expected, + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + int64_t instanceCount = + static_cast(data.size()) / fixedLengthArrayCount; + + std::vector buffer; + buffer.resize(data.size() * sizeof(T)); + std::memcpy(buffer.data(), data.data(), buffer.size()); + + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.array = true; + classProperty.count = fixedLengthArrayCount; + classProperty.normalized = true; + + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; + + PropertyTablePropertyView, true> property( + propertyTableProperty, + classProperty, + instanceCount, + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + PropertyComponentType::None); + + REQUIRE(property.arrayCount() == fixedLengthArrayCount); + + // Check raw values first + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView rawValues = property.getRaw(i); + for (int64_t j = 0; j < rawValues.size(); ++j) { + REQUIRE(rawValues[j] == data[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == data.size()); + + // Check values with properties applied + for (int64_t i = 0; i < property.size(); ++i) { + std::optional> maybeValues = property.get(i); + if (!maybeValues) { + REQUIRE(!expected[static_cast(i)]); + } + + auto values = *maybeValues; + auto expectedValues = *expected[static_cast(i)]; + + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == expectedValues[static_cast(j)]); + } + } +} + +#pragma endregion + +TEST_CASE("Check scalar PropertyTablePropertyView") { + SECTION("Uint8") { + std::vector data{12, 33, 56, 67}; + checkNumeric(data); + } + + SECTION("Int32") { + std::vector data{111222, -11133, -56000, 670000}; + checkNumeric(data); + } + + SECTION("Float") { + std::vector data{12.3333f, -12.44555f, -5.6111f, 6.7421f}; + checkNumeric(data); + } + + SECTION("Double") { + std::vector data{ + 12222.3302121, + -12000.44555, + -5000.6113111, + 6.7421}; + checkNumeric(data); + } + + SECTION("Normalized Uint8") { + std::vector values{0, 64, 128, 255}; + std::vector> expected{ + 0.0, + 64.0 / 255.0, + 128.0 / 255.0, + 1.0}; + checkNormalizedScalar(values, expected); + } + + SECTION("Normalized Int16") { + std::vector values{-32768, 0, 16384, 32767}; + std::vector> expected{ + -1.0, + 0.0, + 16384.0 / 32767.0, + 1.0}; + checkNormalizedScalar(values, expected); + } + + SECTION("Float with Offset / Scale") { + std::vector values{12.5f, -12.5f, -5.0f, 6.75f}; + std::optional offset = 1.0f; + std::optional scale = 2.0f; + std::vector> expected{26.0f, -24.0f, -9.0f, 14.5f}; + checkScalar(values, expected, offset, scale); + } + + SECTION("Normalized Uint8 with Offset and Scale") { + std::vector values{0, 64, 128, 255}; + std::optional offset = 1.0; + std::optional scale = 2.0; + std::vector> expected{ + 1.0, + 1 + 2 * (64.0 / 255.0), + 1 + 2 * (128.0 / 255.0), + 3.0}; + checkNormalizedScalar(values, expected, offset, scale); + } + + SECTION("Int16 with NoData") { + std::vector values{-1, 3, 7, -1}; + std::optional noData = -1; + std::vector> expected{ + std::nullopt, 3, 7, std::nullopt}; - checkNumeric( + checkScalar( values, expected, std::nullopt, @@ -338,7 +724,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { std::optional noData = -1; std::optional defaultValue = 0; std::vector> expected{0, 3, 7, 0}; - checkNumeric( + checkScalar( values, expected, std::nullopt, @@ -358,7 +744,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { 1 + 2 * (64.0 / 255.0), 1 + 2 * (128.0 / 255.0), 3.0}; - checkNormalizedNumeric( + checkNormalizedScalar( values, expected, offset, @@ -440,6 +826,169 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::u8vec4(0, 0, 0, 1)}; checkNumeric(data); } + + SECTION("Normalized Uint8 Vec2") { + std::vector values{ + glm::u8vec2(0, 64), + glm::u8vec2(128, 255), + glm::u8vec2(255, 0)}; + std::vector> expected{ + glm::dvec2(0.0, 64.0 / 255.0), + glm::dvec2(128.0 / 255.0, 1.0), + glm::dvec2(1.0, 0.0)}; + checkNormalizedVecN(values, expected); + } + + SECTION("Normalized Int16 Vec2") { + std::vector values{ + glm::i16vec2(-32768, 0), + glm::i16vec2(16384, 32767), + glm::i16vec2(32767, -32768)}; + std::vector> expected{ + glm::dvec2(-1.0, 0.0), + glm::dvec2(16384.0 / 32767.0, 1.0), + glm::dvec2(1.0, -1.0), + }; + checkNormalizedVecN(values, expected); + } + + SECTION("Float Vec3 with Offset / Scale") { + std::vector values{ + glm::vec3(0.0f, -1.5f, -5.0f), + glm::vec3(6.5f, 2.0f, 4.0f), + glm::vec3(8.0f, -3.0f, 1.0f), + }; + std::optional offset = glm::vec3(1.0f, 2.0, 3.0f); + std::optional scale = glm::vec3(2.0f, 1.0f, 2.0f); + std::vector> expected{ + glm::vec3(1.0f, 0.5f, -7.0f), + glm::vec3(14.0f, 4.0f, 11.0f), + glm::vec3(17.0f, -1.0f, 5.0f), + }; + checkVecN(values, expected, offset, scale); + } + + SECTION("Normalized Uint8 Vec2 with Offset and Scale") { + std::vector values{ + glm::u8vec2(0, 64), + glm::u8vec2(128, 255), + glm::u8vec2(255, 0)}; + std::optional offset = glm::dvec2(0.0, 1.0); + std::optional scale = glm::dvec2(2.0, 1.0); + std::vector> expected{ + glm::dvec2(0.0, 1 + (64.0 / 255.0)), + glm::dvec2(2 * (128.0 / 255.0), 2.0), + glm::dvec2(2.0, 1.0)}; + checkNormalizedVecN(values, expected, offset, scale); + } + + SECTION("Int16 Vec2 with NoData") { + std::vector values{ + glm::i16vec2(-1, 3), + glm::i16vec2(-1, -1), + glm::i16vec2(7, 0)}; + std::optional noData = glm::i16vec2(-1, -1); + std::vector> expected{ + glm::i16vec2(-1, 3), + std::nullopt, + glm::i16vec2(7, 0)}; + checkVecN<2, glm::i16>( + values, + expected, + std::nullopt, + std::nullopt, + noData, + std::nullopt); + }; + + SECTION("Int16 Vec2 with NoData and Default") { + std::vector values{ + glm::i16vec2(-1, 3), + glm::i16vec2(-1, -1), + glm::i16vec2(7, 0)}; + std::optional noData = glm::i16vec2(-1, -1); + std::optional defaultValue = glm::i16vec2(0, 1); + std::vector> expected{ + glm::i16vec2(-1, 3), + glm::i16vec2(0, 1), + glm::i16vec2(7, 0)}; + checkVecN<2, glm::i16>( + values, + expected, + std::nullopt, + std::nullopt, + noData, + defaultValue); + }; + + SECTION("Normalized Uint8 Vec2 with all properties") { + std::vector values{ + glm::u8vec2(0, 64), + glm::u8vec2(128, 255), + glm::u8vec2(255, 0), + glm::u8vec2(0, 0)}; + std::optional offset = glm::dvec2(0.0, 1.0); + std::optional scale = glm::dvec2(2.0, 1.0); + std::optional noData = glm::u8vec2(0, 0); + std::optional defaultValue = glm::dvec2(5.0, 15.0); + std::vector> expected{ + glm::dvec2(0.0, 1 + (64.0 / 255.0)), + glm::dvec2(2 * (128.0 / 255.0), 2.0), + glm::dvec2(2.0, 1.0), + glm::dvec2(5.0, 15.0)}; + checkNormalizedVecN(values, expected, offset, scale, noData, defaultValue); + } + + SECTION("Overrides class property values") { + std::vector values{ + glm::vec2(1.0f, 3.0f), + glm::vec2(2.5f, 2.5f), + glm::vec2(2.0f, 4.0f)}; + std::vector data; + data.resize(values.size() * sizeof(glm::vec2)); + std::memcpy(data.data(), values.data(), data.size()); + + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.offset = {0.0f, 0.0f}; + classProperty.scale = {1.0f, 1.0f}; + classProperty.min = {1.0f, 2.5f}; + classProperty.max = {2.5f, 4.0f}; + + PropertyTableProperty propertyTableProperty; + propertyTableProperty.offset = {1.0f, 0.5f}; + propertyTableProperty.scale = {2.0f, 1.0f}; + propertyTableProperty.min = {3.0f, 3.0f}; + propertyTableProperty.max = {6.0f, 4.5f}; + + PropertyTablePropertyView property( + propertyTableProperty, + classProperty, + static_cast(values.size()), + gsl::span(data.data(), data.size())); + + REQUIRE(property.offset()); + REQUIRE(*property.offset() == glm::vec2(1.0f, 0.5f)); + REQUIRE(property.scale()); + REQUIRE(*property.scale() == glm::vec2(2.0f, 1.0f)); + REQUIRE(property.min()); + REQUIRE(*property.min() == glm::vec2(3.0f, 3.0f)); + REQUIRE(property.max()); + REQUIRE(*property.max() == glm::vec2(6.0f, 4.5f)); + + std::vector expected{ + glm::vec2(3.0f, 3.5f), + glm::vec2(6.0f, 3.0f), + glm::vec2(5.0f, 4.5f)}; + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == values[static_cast(i)]); + + std::optional transformedValue = property.get(i); + REQUIRE(transformedValue); + REQUIRE(*transformedValue == expected[static_cast(i)]); + } + } } TEST_CASE("Check matN PropertyTablePropertyView") { @@ -502,6 +1051,192 @@ TEST_CASE("Check matN PropertyTablePropertyView") { // clang-format on checkNumeric(data); } + + SECTION("Normalized Uint8 Mat2") { + std::vector values{ + glm::u8mat2x2(0, 64, 255, 255), + glm::u8mat2x2(255, 0, 128, 0)}; + std::vector> expected{ + glm::dmat2(0.0, 64.0 / 255.0, 1.0, 1.0), + glm::dmat2(1.0, 0.0, 128.0 / 255.0, 0.0)}; + checkNormalizedMatN(values, expected); + } + + SECTION("Normalized Int16 Mat2") { + std::vector values{ + glm::i16mat2x2(-32768, 0, 16384, 32767), + glm::i16mat2x2(0, 32767, 32767, -32768)}; + std::vector> expected{ + glm::dmat2(-1.0, 0.0, 16384.0 / 32767.0, 1.0), + glm::dmat2(0.0, 1.0, 1.0, -1.0), + }; + checkNormalizedMatN(values, expected); + } + + SECTION("Float Mat2 with Offset / Scale") { + std::vector values{ + glm::mat2(1.0f, 3.0f, 4.0f, 2.0f), + glm::mat2(6.5f, 2.0f, -2.0f, 0.0f), + glm::mat2(8.0f, -1.0f, -3.0f, 1.0f), + }; + std::optional offset = glm::mat2(1.0f, 2.0, 3.0f, 1.0f); + std::optional scale = glm::mat2(2.0f, 0.0f, 0.0f, 2.0f); + std::vector> expected{ + glm::mat2(3.0f, 2.0f, 3.0f, 5.0f), + glm::mat2(14.0f, 2.0f, 3.0f, 1.0f), + glm::mat2(17.0f, 2.0f, 3.0f, 3.0f), + }; + checkMatN(values, expected, offset, scale); + } + + SECTION("Normalized Uint8 Mat2 with Offset and Scale") { + std::vector values{ + glm::u8mat2x2(0, 64, 255, 255), + glm::u8mat2x2(255, 0, 128, 0)}; + std::optional offset = glm::dmat2(0.0, 1.0, 1.0, 0.0); + std::optional scale = glm::dmat2(2.0, 1.0, 0.0, 2.0); + std::vector> expected{ + glm::dmat2(0.0, 1 + 64.0 / 255.0, 1.0, 2.0), + glm::dmat2(2.0, 1.0, 1.0, 0.0)}; + checkNormalizedMatN(values, expected, offset, scale); + } + + SECTION("Int16 Mat3 with NoData") { + // clang-format off + std::vector values{ + glm::i16mat3x3( + 1, 2, 3, + -1, -2, -3, + 0, 1, 0), + glm::i16mat3x3( + 1, -1, 0, + 0, 1, 2, + 0, 4, 5), + glm::i16mat3x3( + -1, -1, -1, + 0, 0, 0, + 1, 1, 1)}; + std::optional noData = + glm::i16mat3x3( + -1, -1, -1, + 0, 0, 0, + 1, 1, 1); + // clang-format on + std::vector> expected{ + values[0], + values[1], + std::nullopt}; + checkMatN<3, glm::i16>( + values, + expected, + std::nullopt, + std::nullopt, + noData, + std::nullopt); + }; + + SECTION("Int16 Mat3 with NoData") { + // clang-format off + std::vector values{ + glm::i16mat3x3( + 1, 2, 3, + -1, -2, -3, + 0, 1, 0), + glm::i16mat3x3( + 1, -1, 0, + 0, 1, 2, + 0, 4, 5), + glm::i16mat3x3( + -1, -1, -1, + 0, 0, 0, + 1, 1, 1)}; + std::optional noData = + glm::i16mat3x3( + -1, -1, -1, + 0, 0, 0, + 1, 1, 1); + // clang-format on + std::optional default = glm::i16mat3x3(1); + std::vector> expected{ + values[0], + values[1], + default}; + checkMatN<3, glm::i16>( + values, + expected, + std::nullopt, + std::nullopt, + noData, + default); + }; + + SECTION("Normalized Uint8 Mat2 with all properties") { + std::vector values{ + glm::u8mat2x2(0, 64, 255, 255), + glm::u8mat2x2(0), + glm::u8mat2x2(255, 0, 128, 0)}; + std::optional offset = glm::dmat2(0.0, 1.0, 1.0, 0.0); + std::optional scale = glm::dmat2(2.0, 1.0, 0.0, 2.0); + std::optional noData = glm::u8mat2x2(0); + std::optional defaultValue = glm::dmat2(1.0); + + std::vector> expected{ + glm::dmat2(0.0, 1 + 64.0 / 255.0, 1.0, 2.0), + glm::dmat2(1.0), + glm::dmat2(2.0, 1.0, 1.0, 0.0)}; + checkNormalizedMatN(values, expected, offset, scale, noData, defaultValue); + } + + SECTION("Overrides class property values") { + std::vector values{ + glm::mat2(1.0f), + glm::mat2(2.5f, 1.0f, 1.0f, 2.5f), + glm::mat2(3.0f)}; + std::vector data; + data.resize(values.size() * sizeof(glm::mat2)); + std::memcpy(data.data(), values.data(), data.size()); + + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + classProperty.offset = {0.0f, 0.0f, 0.0f, 0.0f}; + classProperty.scale = {1.0f, 1.0f, 1.0f, 1.0f}; + classProperty.min = {1.0f, 0.0f, 0.0f, 1.0f}; + classProperty.max = {3.0f, 0.0f, 0.0f, 3.0f}; + + PropertyTableProperty propertyTableProperty; + propertyTableProperty.offset = {1.0f, 0.5f, 0.5f, 1.0f}; + propertyTableProperty.scale = {2.0f, 1.0f, 0.0f, 1.0f}; + propertyTableProperty.min = {3.0f, 0.5f, 0.5f, 2.0f}; + propertyTableProperty.max = {7.0f, 1.5f, 0.5f, 4.0f}; + + PropertyTablePropertyView property( + propertyTableProperty, + classProperty, + static_cast(values.size()), + gsl::span(data.data(), data.size())); + + REQUIRE(property.offset()); + REQUIRE(*property.offset() == glm::mat2(1.0f, 0.5f, 0.5f, 1.0f)); + REQUIRE(property.scale()); + REQUIRE(*property.scale() == glm::mat2(2.0f, 1.0f, 0.0f, 1.0f)); + REQUIRE(property.min()); + REQUIRE(*property.min() == glm::mat2(3.0f, 0.5f, 0.5f, 2.0f)); + REQUIRE(property.max()); + REQUIRE(*property.max() == glm::mat2(7.0f, 1.5f, 0.5f, 4.0f)); + + std::vector expected{ + glm::mat2(3.0f, 0.5f, 0.5f, 2.0f), + glm::mat2(6.0f, 1.5f, 0.5f, 3.5f), + glm::mat2(7.0f, 0.5f, 0.5f, 4.0f)}; + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == values[static_cast(i)]); + + std::optional transformedValue = property.get(i); + REQUIRE(transformedValue); + REQUIRE(*transformedValue == expected[static_cast(i)]); + } + } } TEST_CASE("Check boolean PropertyTablePropertyView") { @@ -563,36 +1298,95 @@ TEST_CASE("Check string PropertyTablePropertyView") { ¤tOffset, sizeof(uint32_t)); - PropertyTableProperty propertyTableProperty; - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::STRING; + SECTION("Returns correct values") { + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; - PropertyTablePropertyView property( - propertyTableProperty, - classProperty, - static_cast(strings.size()), - gsl::span(buffer.data(), buffer.size()), - gsl::span(), - gsl::span(offsetBuffer.data(), offsetBuffer.size()), - PropertyComponentType::None, - PropertyComponentType::Uint32); + PropertyTablePropertyView property( + propertyTableProperty, + classProperty, + static_cast(strings.size()), + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(offsetBuffer.data(), offsetBuffer.size()), + PropertyComponentType::None, + PropertyComponentType::Uint32); - for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.getRaw(i) == strings[static_cast(i)]); + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == strings[static_cast(i)]); + REQUIRE(property.get(i)); + REQUIRE(*property.get(i) == strings[static_cast(i)]); + } + } + + SECTION("Uses NoData value") { + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.noData = "What's going on"; + + PropertyTablePropertyView property( + propertyTableProperty, + classProperty, + static_cast(strings.size()), + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(offsetBuffer.data(), offsetBuffer.size()), + PropertyComponentType::None, + PropertyComponentType::Uint32); + + std::vector> expected{ + strings[0], + std::nullopt, + strings[2]}; + + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == strings[static_cast(i)]); + REQUIRE(property.get(i) == expected[static_cast(i)]); + } + } + + SECTION("Uses NoData and Default value") { + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.noData = "What's going on"; + classProperty.defaultProperty = "Hello"; + + PropertyTablePropertyView property( + propertyTableProperty, + classProperty, + static_cast(strings.size()), + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(offsetBuffer.data(), offsetBuffer.size()), + PropertyComponentType::None, + PropertyComponentType::Uint32); + + std::vector> expected{ + strings[0], + "Hello", + strings[2]}; + + for (int64_t i = 0; i < property.size(); ++i) { + REQUIRE(property.getRaw(i) == strings[static_cast(i)]); + REQUIRE(property.get(i) == expected[static_cast(i)]); + } } } TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { - SECTION("Fixed-length array of 4 uint8_ts") { + SECTION("Array of 4 uint8_ts") { // clang-format off std::vector data{ 210, 211, 3, 42, 122, 22, 1, 45}; // clang-format on - checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + checkFixedLengthArray(data, 4); } - SECTION("Fixed-length array of 3 int8_ts") { + SECTION("Array of 3 int8_ts") { // clang-format off std::vector data{ 122, -12, 3, @@ -600,10 +1394,10 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { 5, 6, -22, 5, 6, 1}; // clang-format on - checkFixedLengthArray(data, 3, static_cast(data.size() / 3)); + checkFixedLengthArray(data, 3); } - SECTION("Fixed-length array of 4 int16_ts") { + SECTION("Array of 4 int16_ts") { // clang-format off std::vector data{ -122, 12, 3, 44, @@ -611,10 +1405,10 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { 119, 30, 51, 200, 22000, -500, 6000, 1}; // clang-format on - checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + checkFixedLengthArray(data, 4); } - SECTION("Fixed-length array of 6 uint32_ts") { + SECTION("Array of 6 uint32_ts") { // clang-format off std::vector data{ 122, 12, 3, 44, 34444, 2222, @@ -622,58 +1416,228 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { 119, 30, 51, 200, 12534, 11, 22000, 500, 6000, 1, 3, 7}; // clang-format on - checkFixedLengthArray(data, 6, static_cast(data.size() / 6)); + checkFixedLengthArray(data, 6); } - SECTION("Fixed-length array of 2 int32_ts") { + SECTION("Array of 2 int32_ts") { // clang-format off - std::vector data{ + std::vector data{ 122, 12, - 3, 44}; + -3, 44}; // clang-format on - checkFixedLengthArray(data, 2, static_cast(data.size() / 2)); + checkFixedLengthArray(data, 2); } - SECTION("Fixed-length array of 4 uint64_ts") { + SECTION("Array of 4 uint64_ts") { // clang-format off std::vector data{ 10022, 120000, 2422, 1111, 3, 440000, 333, 1455}; // clang-format on - checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + checkFixedLengthArray(data, 4); } - SECTION("Fixed-length array of 4 int64_ts") { + SECTION("Array of 4 int64_ts") { // clang-format off std::vector data{ 10022, -120000, 2422, 1111, 3, 440000, -333, 1455}; // clang-format on - checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + checkFixedLengthArray(data, 4); } - SECTION("Fixed-length array of 4 floats") { + SECTION("Array of 4 floats") { // clang-format off std::vector data{ 10.022f, -12.43f, 242.2f, 1.111f, 3.333f, 440000.1f, -33.3f, 14.55f}; // clang-format on - checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + checkFixedLengthArray(data, 4); } - SECTION("Fixed-length array of 4 double") { + SECTION("Array of 4 double") { // clang-format off std::vector data{ 10.022, -12.43, 242.2, 1.111, 3.333, 440000.1, -33.3, 14.55}; // clang-format on - checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + checkFixedLengthArray(data, 4); + } + + SECTION("Array of 4 uint8_ts") { + // clang-format off + std::vector data{ + 210, 211, 3, 42, + 122, 22, 1, 45}; + // clang-format on + checkFixedLengthArray(data, 4); + } + + SECTION("Array of 4 normalized uint8_ts") { + // clang-format off + std::vector data{ + 255, 64, 0, 255, + 128, 0, 255, 0}; + // clang-format on + std::vector>> expected{ + std::vector{1.0, 64.0 / 255.0, 0.0, 1.0}, + std::vector{128.0 / 255.0, 0.0, 1.0, 0.0}}; + checkNormalizedFixedLengthArray(data, 4, expected); + } + + SECTION("Array of 4 floats with offset / scale") { + // clang-format off + std::vector data{ + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, -1.0f, 0.0f, 2.0f + }; + // clang-format on + + std::optional offset = + JsonValue::Array{1.0f, 0.0f, -1.0f, 0.0f}; + std::optional scale = + JsonValue::Array{1.0f, 2.0f, 1.0f, 2.0f}; + + std::vector>> expected{ + std::vector{2.0f, 4.0f, 2.0f, 8.0f}, + std::vector{6.0f, -2.0f, -1.0f, 4.0f}}; + checkFixedLengthArrayWithProperties(data, 4, expected, offset, scale); + } + + SECTION("Array of 2 int32_ts with noData value") { + // clang-format off + std::vector data{ + 122, 12, + -1, -1, + -3, 44}; + // clang-format on + std::optional noData = JsonValue::Array{-1, -1}; + std::vector>> expected{ + std::vector{122, 12}, + std::nullopt, + std::vector{-3, 44}}; + checkFixedLengthArrayWithProperties( + data, + 2, + expected, + std::nullopt, + std::nullopt, + noData, + std::nullopt); + } + + SECTION("Array of 2 int32_ts with noData and default value") { + // clang-format off + std::vector data{ + 122, 12, + -1, -1, + -3, 44}; + // clang-format on + std::optional noData = JsonValue::Array{-1, -1}; + std::optional defaultValue = JsonValue::Array{0, 1}; + std::vector>> expected{ + std::vector{122, 12}, + std::vector{0, 1}, + std::vector{-3, 44}}; + checkFixedLengthArrayWithProperties( + data, + 2, + expected, + std::nullopt, + std::nullopt, + noData, + defaultValue); + } + + SECTION("Array of 3 normalized int8_ts with all properties") { + // clang-format off + std::vector data{ + -128, 0, 64, + -64, 127, -128, + 0, 0, 0}; + // clang-format on + std::optional offset = JsonValue::Array{0, 1, 1}; + std::optional scale = JsonValue::Array{1, -1, 2}; + std::optional noData = JsonValue::Array{0, 0, 0}; + std::optional defaultValue = JsonValue::Array{10, 8, 2}; + + std::vector>> expected{ + std::vector{-1.0, 1.0, 1 + 2 * (64.0 / 127.0)}, + std::vector{-64.0 / 127.0, 0.0, -1.0}, + std::vector{10.0, 8.0, 2.0}, + }; + checkNormalizedFixedLengthArray( + data, + 3, + expected, + offset, + scale, + noData, + defaultValue); + } + + SECTION("Overrides class property values") { + // clang-format off + std::vector data{ + 1.0f, 2.0f, 3.0f, 4.0f, + 0.0f, -1.0f, 1.0f, -2.0f}; + // clang-format on + const int64_t count = 4; + const int64_t instanceCount = 2; + + std::vector buffer; + buffer.resize(data.size() * sizeof(float)); + std::memcpy(buffer.data(), data.data(), buffer.size()); + + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + + classProperty.array = true; + classProperty.count = count; + classProperty.offset = {0, 0, 0, 0}; + classProperty.scale = {1, 1, 1, 1}; + classProperty.min = {0.0f, -1.0f, 1.0f, -2.0f}; + classProperty.max = {1.0f, 2.0f, 3.0f, 4.0f}; + + PropertyTableProperty propertyTableProperty; + propertyTableProperty.offset = {2, 1, 0, -1}; + propertyTableProperty.scale = {1, 0, 1, -1}; + propertyTableProperty.min = {0.0f, 1.0f, 1.0f, -2.0f}; + propertyTableProperty.max = {1.0f, 1.0f, 3.0f, 4.0f}; + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + instanceCount, + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None); + + REQUIRE(property.arrayCount() == count); + REQUIRE(property.size() == instanceCount); + + std::vector> expected{ + {3.0f, 1.0, 3.0f, -5.0f}, + {2.0f, 1.0f, 1.0f, 1.0f}}; + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView rawValues = property.getRaw(i); + auto values = property.get(i); + REQUIRE(values); + for (int64_t j = 0; j < rawValues.size(); ++j) { + REQUIRE(rawValues[j] == data[expectedIdx]); + REQUIRE((*values)[j] == expected[i][j]); + ++expectedIdx; + } + } } } TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { - SECTION("Fixed-length array of 4 u8vec2s") { - // clang-format off + SECTION("Array of 4 u8vec2s") { std::vector data{ glm::u8vec2(10, 21), glm::u8vec2(3, 42), @@ -683,12 +1647,10 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { glm::u8vec2(32, 12), glm::u8vec2(8, 19), glm::u8vec2(6, 5)}; - // clang-format on - checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + checkFixedLengthArray(data, 4); } - SECTION("Fixed-length array of 2 i8vec3s") { - // clang-format off + SECTION("Array of 2 i8vec3s") { std::vector data{ glm::i8vec3(122, -12, 3), glm::i8vec3(44, 11, -2), @@ -696,12 +1658,10 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { glm::i8vec3(5, 6, 1), glm::i8vec3(8, -7, 7), glm::i8vec3(-4, 36, 17)}; - // clang-format on - checkFixedLengthArray(data, 2, static_cast(data.size() / 2)); + checkFixedLengthArray(data, 2); } - SECTION("Fixed-length array of 3 vec4s") { - // clang-format off + SECTION("Array of 3 vec4s") { std::vector data{ glm::vec4(40.2f, -1.2f, 8.8f, 1.0f), glm::vec4(1.4f, 0.11, 34.0f, 0.0f), @@ -709,13 +1669,178 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { glm::vec4(1.0f, 2.0f, 3.0f, 6.0f), glm::vec4(1.08f, -3.71f, 18.0f, -7.0f), glm::vec4(-17.0f, 33.0f, 8.0f, -3.0f)}; + checkFixedLengthArray(data, 3); + } + + SECTION("Array of 2 normalized u8vec2s") { + std::vector data{ + glm::u8vec2(255, 64), + glm::u8vec2(0, 255), + glm::u8vec2(128, 0), + glm::u8vec2(255, 0)}; + std::vector>> expected{ + std::vector{ + glm::dvec2(1.0, 64.0 / 255.0), + glm::dvec2(0.0, 1.0)}, + std::vector{ + glm::dvec2(128.0 / 255.0, 0.0), + glm::dvec2(1.0, 0.0)}}; + checkNormalizedFixedLengthArray(data, 2, expected); + } + + SECTION("Array of 4 floats with offset / scale") { + // clang-format off + std::vector data{ + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, -1.0f, 0.0f, 2.0f + }; // clang-format on - checkFixedLengthArray(data, 3, static_cast(data.size() / 3)); + + std::optional offset = + JsonValue::Array{1.0f, 0.0f, -1.0f, 0.0f}; + std::optional scale = + JsonValue::Array{1.0f, 2.0f, 1.0f, 2.0f}; + + std::vector>> expected{ + std::vector{2.0f, 4.0f, 2.0f, 8.0f}, + std::vector{6.0f, -2.0f, -1.0f, 4.0f}}; + checkFixedLengthArrayWithProperties(data, 4, expected, offset, scale); + } + + SECTION("Array of 2 int32_ts with noData value") { + // clang-format off + std::vector data{ + 122, 12, + -1, -1, + -3, 44}; + // clang-format on + std::optional noData = JsonValue::Array{-1, -1}; + std::vector>> expected{ + std::vector{122, 12}, + std::nullopt, + std::vector{-3, 44}}; + checkFixedLengthArrayWithProperties( + data, + 2, + expected, + std::nullopt, + std::nullopt, + noData, + std::nullopt); + } + + SECTION("Array of 2 int32_ts with noData and default value") { + // clang-format off + std::vector data{ + 122, 12, + -1, -1, + -3, 44}; + // clang-format on + std::optional noData = JsonValue::Array{-1, -1}; + std::optional defaultValue = JsonValue::Array{0, 1}; + std::vector>> expected{ + std::vector{122, 12}, + std::vector{0, 1}, + std::vector{-3, 44}}; + checkFixedLengthArrayWithProperties( + data, + 2, + expected, + std::nullopt, + std::nullopt, + noData, + defaultValue); + } + + SECTION("Array of 3 normalized int8_ts with all properties") { + // clang-format off + std::vector data{ + -128, 0, 64, + -64, 127, -128, + 0, 0, 0}; + // clang-format on + std::optional offset = JsonValue::Array{0, 1, 1}; + std::optional scale = JsonValue::Array{1, -1, 2}; + std::optional noData = JsonValue::Array{0, 0, 0}; + std::optional defaultValue = JsonValue::Array{10, 8, 2}; + + std::vector>> expected{ + std::vector{-1.0, 1.0, 1 + 2 * (64.0 / 127.0)}, + std::vector{-64.0 / 127.0, 0.0, -1.0}, + std::vector{10.0, 8.0, 2.0}, + }; + checkNormalizedFixedLengthArray( + data, + 3, + expected, + offset, + scale, + noData, + defaultValue); + } + + SECTION("Overrides class property values") { + // clang-format off + std::vector data{ + 1.0f, 2.0f, 3.0f, 4.0f, + 0.0f, -1.0f, 1.0f, -2.0f}; + // clang-format on + const int64_t count = 4; + const int64_t instanceCount = 2; + + std::vector buffer; + buffer.resize(data.size() * sizeof(float)); + std::memcpy(buffer.data(), data.data(), buffer.size()); + + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + + classProperty.array = true; + classProperty.count = count; + classProperty.offset = {0, 0, 0, 0}; + classProperty.scale = {1, 1, 1, 1}; + classProperty.min = {0.0f, -1.0f, 1.0f, -2.0f}; + classProperty.max = {1.0f, 2.0f, 3.0f, 4.0f}; + + PropertyTableProperty propertyTableProperty; + propertyTableProperty.offset = {2, 1, 0, -1}; + propertyTableProperty.scale = {1, 0, 1, -1}; + propertyTableProperty.min = {0.0f, 1.0f, 1.0f, -2.0f}; + propertyTableProperty.max = {1.0f, 1.0f, 3.0f, 4.0f}; + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + instanceCount, + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None); + + REQUIRE(property.arrayCount() == count); + REQUIRE(property.size() == instanceCount); + + std::vector> expected{ + {3.0f, 1.0, 3.0f, -5.0f}, + {2.0f, 1.0f, 1.0f, 1.0f}}; + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView rawValues = property.getRaw(i); + auto values = property.get(i); + REQUIRE(values); + for (int64_t j = 0; j < rawValues.size(); ++j) { + REQUIRE(rawValues[j] == data[expectedIdx]); + REQUIRE((*values)[j] == expected[i][j]); + ++expectedIdx; + } + } } } TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { - SECTION("Fixed-length array of 4 i8mat2x2") { + SECTION("Array of 4 i8mat2x2") { // clang-format off std::vector data{ glm::i8mat2x2( @@ -743,10 +1868,10 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { 6, 16, 2, 5)}; // clang-format on - checkFixedLengthArray(data, 4, static_cast(data.size() / 4)); + checkFixedLengthArray(data, 4); } - SECTION("Fixed-length array of 2 dmat3s") { + SECTION("Array of 2 dmat3s") { // clang-format off std::vector data{ glm::dmat3( @@ -774,10 +1899,10 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { 5.5, 3.09, 0.301, 4.5, 52.4, 1.05)}; // clang-format on - checkFixedLengthArray(data, 2, static_cast(data.size() / 2)); + checkFixedLengthArray(data, 2); } - SECTION("Fixed-length array of 3 u8mat4x4") { + SECTION("Array of 3 u8mat4x4") { // clang-format off std::vector data{ glm::u8mat4x4( @@ -811,7 +1936,7 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { 8, 7, 6, 5, 4, 3, 2, 1),}; // clang-format on - checkFixedLengthArray(data, 3, static_cast(data.size() / 3)); + checkFixedLengthArray(data, 3); } } diff --git a/CesiumGltf/test/TestPropertyTypeTraits.cpp b/CesiumGltf/test/TestPropertyTypeTraits.cpp index ff527cb7e..2ed90612d 100644 --- a/CesiumGltf/test/TestPropertyTypeTraits.cpp +++ b/CesiumGltf/test/TestPropertyTypeTraits.cpp @@ -523,20 +523,112 @@ TEST_CASE("TypeToPropertyType") { } } -TEST_CASE("Test CanBeNormalized") { - REQUIRE(CanBeNormalized::value); - REQUIRE(CanBeNormalized::value); - REQUIRE(CanBeNormalized::value); - REQUIRE(CanBeNormalized::value); - REQUIRE(CanBeNormalized::value); - REQUIRE(CanBeNormalized::value); - REQUIRE(CanBeNormalized::value); - REQUIRE(CanBeNormalized::value); - - REQUIRE(!CanBeNormalized::value); - REQUIRE(!CanBeNormalized::value); - REQUIRE(!CanBeNormalized::value); - REQUIRE(!CanBeNormalized::value); +TEST_CASE("CanBeNormalized") { + SECTION("Works for scalars") { + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + } + + SECTION("Works for vecNs") { + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + } + + SECTION("Works for matN") { + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + REQUIRE(CanBeNormalized::value); + + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + REQUIRE(!CanBeNormalized::value); + } + + SECTION("Works for arrays") { + REQUIRE(CanBeNormalized>::value); + REQUIRE(CanBeNormalized>::value); + REQUIRE(CanBeNormalized>::value); + } } TEST_CASE("TypeToNormalizedType") { From bc9dd9e6e5f2cecd609ce62dc426963a5712ea2b Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 23 Aug 2023 09:58:02 -0400 Subject: [PATCH 086/121] Add static casts for integer optionals --- ...gradeBatchTableToExtStructuralMetadata.cpp | 3 +- .../CesiumGltf/PropertyTablePropertyView.h | 4 +- .../CesiumGltf/PropertyTransformations.h | 55 +++++++------------ .../test/TestPropertyTablePropertyView.cpp | 8 +-- 4 files changed, 29 insertions(+), 41 deletions(-) diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 8a8a7509f..3efdfec28 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -55,7 +55,8 @@ static void checkNonArrayProperty( } else if constexpr ( std::is_same_v || std::is_same_v) { - REQUIRE(propertyView.getRaw(i) == Approx(expected[static_cast(i)])); + REQUIRE( + propertyView.getRaw(i) == Approx(expected[static_cast(i)])); } else { REQUIRE( static_cast(propertyView.getRaw(i)) == diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index c63f6e661..2830305b9 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -603,7 +603,7 @@ class PropertyTablePropertyView constexpr glm::length_t N = ElementType::length(); using T = typename ElementType::value_type; using NormalizedT = typename NormalizedType::value_type; - return transformVecN( + return transformValue>( normalize(value), this->offset(), this->scale()); @@ -613,7 +613,7 @@ class PropertyTablePropertyView constexpr glm::length_t N = ElementType::length(); using T = typename ElementType::value_type; using NormalizedT = typename NormalizedType::value_type; - return transformMatN( + return transformValue>( normalize(value), this->offset(), this->scale()); diff --git a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h index 9716520a9..4f4b9ce3d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h @@ -78,40 +78,6 @@ T transformValue( return result; } -template -glm::vec transformVecN( - const glm::vec& value, - const std::optional>& offset, - const std::optional>& scale) { - glm::vec result = value; - if (scale) { - result = applyScale>(result, *scale); - } - - if (offset) { - result += *offset; - } - - return result; -} - -template -glm::mat transformMatN( - const glm::mat& value, - const std::optional>& offset, - const std::optional>& scale) { - glm::mat result = value; - if (scale) { - result = applyScale>(result, *scale); - } - - if (offset) { - result += *offset; - } - - return result; -} - template PropertyArrayView transformArray( const PropertyArrayView& value, @@ -177,4 +143,25 @@ PropertyArrayView> transformNormalizedVecNArray( return PropertyArrayView>(std::move(result)); } + +template +PropertyArrayView> transformNormalizedMatNArray( + const PropertyArrayView>& value, + const std::optional>>& offset, + const std::optional>>& scale) { + std::vector> result(static_cast(value.size())); + for (int64_t i = 0; i < value.size(); i++) { + result[i] = normalize(value[i]); + + if (scale) { + result[i] = applyScale>(result[i], (*scale)[i]); + } + + if (offset) { + result[i] = result[i] + (*offset)[i]; + } + } + + return PropertyArrayView>(std::move(result)); +} } // namespace CesiumGltf diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 8094f00c8..332251ecc 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -704,7 +704,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Int16 with NoData") { std::vector values{-1, 3, 7, -1}; - std::optional noData = -1; + std::optional noData = static_cast(-1); std::vector> expected{ std::nullopt, 3, @@ -721,8 +721,8 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Int16 with NoData and Default") { std::vector values{-1, 3, 7, -1}; - std::optional noData = -1; - std::optional defaultValue = 0; + std::optional noData = static_cast(-1); + std::optional defaultValue = static_cast(0); std::vector> expected{0, 3, 7, 0}; checkScalar( values, @@ -737,7 +737,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { std::vector values{0, 64, 128, 255}; std::optional offset = 1.0; std::optional scale = 2.0; - std::optional noData = 0; + std::optional noData = static_cast(0); std::optional defaultValue = 10.0; std::vector> expected{ 10.0, From 4f37e7a2172dc1b437dfb6a6fe9ce4642dcec331 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 23 Aug 2023 10:32:28 -0400 Subject: [PATCH 087/121] Try to fix CI errors --- .../test/TestPropertyTablePropertyView.cpp | 354 +++++++----------- 1 file changed, 138 insertions(+), 216 deletions(-) diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 332251ecc..94af0a123 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -12,30 +12,6 @@ using namespace CesiumGltf; using namespace CesiumUtility; -#pragma region Utility - -template -JsonValue::Array getArrayFromVecN(glm::vec vecN) { - JsonValue::Array values(N); - for (glm::length_t i = 0; i < N; i++) { - values[i] = vecN[i]; - } - - return values; -} - -template -JsonValue::Array getArrayFromMatN(glm::mat matN) { - JsonValue::Array values(N * N); - for (glm::length_t i = 0; i < N; i++) { - for (glm::length_t j = 0; j < N; j++) { - values[N * i + j] = matN[i][j]; - } - } - - return values; -} - template static void checkNumeric(const std::vector& expected) { std::vector data; data.resize(expected.size() * sizeof(T)); @@ -71,10 +47,10 @@ template static void checkScalar( const std::vector& values, const std::vector>& expected, - const std::optional offset = std::nullopt, - const std::optional scale = std::nullopt, - const std::optional noData = std::nullopt, - const std::optional defaultValue = std::nullopt) { + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { std::vector data; data.resize(values.size() * sizeof(T)); std::memcpy(data.data(), values.data(), data.size()); @@ -88,21 +64,10 @@ static void checkScalar( classProperty.componentType = convertPropertyComponentTypeToString(componentType); - if (offset) { - classProperty.offset = *offset; - } - - if (scale) { - classProperty.scale = *scale; - } - - if (noData) { - classProperty.noData = *noData; - } - - if (defaultValue) { - classProperty.defaultProperty = *defaultValue; - } + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; PropertyTablePropertyView property( propertyTableProperty, @@ -127,10 +92,10 @@ template static void checkVecN( const std::vector>& values, const std::vector>>& expected, - const std::optional> offset = std::nullopt, - const std::optional> scale = std::nullopt, - const std::optional> noData = std::nullopt, - const std::optional> defaultValue = std::nullopt) { + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { std::vector data; data.resize(values.size() * sizeof(glm::vec)); std::memcpy(data.data(), values.data(), data.size()); @@ -144,21 +109,10 @@ static void checkVecN( classProperty.componentType = convertPropertyComponentTypeToString(componentType); - if (offset) { - classProperty.offset = getArrayFromVecN(*offset); - } - - if (scale) { - classProperty.scale = getArrayFromVecN(*scale); - } - - if (noData) { - classProperty.noData = getArrayFromVecN(*noData); - } - - if (defaultValue) { - classProperty.defaultProperty = getArrayFromVecN(*defaultValue); - } + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; PropertyTablePropertyView> property( propertyTableProperty, @@ -178,10 +132,10 @@ template static void checkMatN( const std::vector>& values, const std::vector>>& expected, - const std::optional> offset = std::nullopt, - const std::optional> scale = std::nullopt, - const std::optional> noData = std::nullopt, - const std::optional> defaultValue = std::nullopt) { + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { std::vector data; data.resize(values.size() * sizeof(glm::mat)); std::memcpy(data.data(), values.data(), data.size()); @@ -195,21 +149,10 @@ static void checkMatN( classProperty.componentType = convertPropertyComponentTypeToString(componentType); - if (offset) { - classProperty.offset = getArrayFromMatN(*offset); - } - - if (scale) { - classProperty.scale = getArrayFromMatN(*scale); - } - - if (noData) { - classProperty.noData = getArrayFromMatN(*noData); - } - - if (defaultValue) { - classProperty.defaultProperty = getArrayFromMatN(*defaultValue); - } + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; PropertyTablePropertyView> property( propertyTableProperty, @@ -229,10 +172,10 @@ template static void checkNormalizedScalar( const std::vector& values, const std::vector>& expected, - const std::optional offset = std::nullopt, - const std::optional scale = std::nullopt, - const std::optional noData = std::nullopt, - const std::optional defaultValue = std::nullopt) { + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { std::vector data; data.resize(values.size() * sizeof(T)); std::memcpy(data.data(), values.data(), data.size()); @@ -248,21 +191,10 @@ static void checkNormalizedScalar( classProperty.normalized = true; - if (offset) { - classProperty.offset = *offset; - } - - if (scale) { - classProperty.scale = *scale; - } - - if (noData) { - classProperty.noData = *noData; - } - - if (defaultValue) { - classProperty.defaultProperty = *defaultValue; - } + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; PropertyTablePropertyView property( propertyTableProperty, @@ -282,10 +214,10 @@ template static void checkNormalizedVecN( const std::vector>& values, const std::vector>>& expected, - const std::optional> offset = std::nullopt, - const std::optional> scale = std::nullopt, - const std::optional> noData = std::nullopt, - const std::optional> defaultValue = std::nullopt) { + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { std::vector data; data.resize(values.size() * sizeof(glm::vec)); std::memcpy(data.data(), values.data(), data.size()); @@ -301,21 +233,10 @@ static void checkNormalizedVecN( classProperty.normalized = true; - if (offset) { - classProperty.offset = getArrayFromVecN(*offset); - } - - if (scale) { - classProperty.scale = getArrayFromVecN(*scale); - } - - if (noData) { - classProperty.noData = getArrayFromVecN(*noData); - } - - if (defaultValue) { - classProperty.defaultProperty = getArrayFromVecN(*defaultValue); - } + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; PropertyTablePropertyView, true> property( propertyTableProperty, @@ -335,10 +256,10 @@ template static void checkNormalizedMatN( const std::vector>& values, const std::vector>>& expected, - const std::optional> offset = std::nullopt, - const std::optional> scale = std::nullopt, - const std::optional> noData = std::nullopt, - const std::optional> defaultValue = std::nullopt) { + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { std::vector data; data.resize(values.size() * sizeof(glm::mat)); std::memcpy(data.data(), values.data(), data.size()); @@ -354,21 +275,10 @@ static void checkNormalizedMatN( classProperty.normalized = true; - if (offset) { - classProperty.offset = getArrayFromMatN(*offset); - } - - if (scale) { - classProperty.scale = getArrayFromMatN(*scale); - } - - if (noData) { - classProperty.noData = getArrayFromMatN(*noData); - } - - if (defaultValue) { - classProperty.defaultProperty = getArrayFromMatN(*defaultValue); - } + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; PropertyTablePropertyView, true> property( propertyTableProperty, @@ -635,8 +545,6 @@ static void checkNormalizedFixedLengthArray( } } -#pragma endregion - TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Uint8") { std::vector data{12, 33, 56, 67}; @@ -684,16 +592,16 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Float with Offset / Scale") { std::vector values{12.5f, -12.5f, -5.0f, 6.75f}; - std::optional offset = 1.0f; - std::optional scale = 2.0f; + std::optional offset = 1.0f; + std::optional scale = 2.0f; std::vector> expected{26.0f, -24.0f, -9.0f, 14.5f}; checkScalar(values, expected, offset, scale); } SECTION("Normalized Uint8 with Offset and Scale") { std::vector values{0, 64, 128, 255}; - std::optional offset = 1.0; - std::optional scale = 2.0; + std::optional offset = 1.0; + std::optional scale = 2.0; std::vector> expected{ 1.0, 1 + 2 * (64.0 / 255.0), @@ -704,7 +612,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Int16 with NoData") { std::vector values{-1, 3, 7, -1}; - std::optional noData = static_cast(-1); + std::optional noData = -1; std::vector> expected{ std::nullopt, 3, @@ -721,8 +629,8 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Int16 with NoData and Default") { std::vector values{-1, 3, 7, -1}; - std::optional noData = static_cast(-1); - std::optional defaultValue = static_cast(0); + std::optional noData = -1; + std::optional defaultValue = 0; std::vector> expected{0, 3, 7, 0}; checkScalar( values, @@ -735,10 +643,10 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Normalized Uint8 with all properties") { std::vector values{0, 64, 128, 255}; - std::optional offset = 1.0; - std::optional scale = 2.0; - std::optional noData = static_cast(0); - std::optional defaultValue = 10.0; + std::optional offset = 1.0; + std::optional scale = 2.0; + std::optional noData = 0; + std::optional defaultValue = 10.0; std::vector> expected{ 10.0, 1 + 2 * (64.0 / 255.0), @@ -858,8 +766,8 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::vec3(6.5f, 2.0f, 4.0f), glm::vec3(8.0f, -3.0f, 1.0f), }; - std::optional offset = glm::vec3(1.0f, 2.0, 3.0f); - std::optional scale = glm::vec3(2.0f, 1.0f, 2.0f); + std::optional offset = JsonValue::Array{1.0f, 2.0f, 3.0f}; + std::optional scale = JsonValue::Array{2.0f, 1.0f, 2.0f}; std::vector> expected{ glm::vec3(1.0f, 0.5f, -7.0f), glm::vec3(14.0f, 4.0f, 11.0f), @@ -873,8 +781,8 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::u8vec2(0, 64), glm::u8vec2(128, 255), glm::u8vec2(255, 0)}; - std::optional offset = glm::dvec2(0.0, 1.0); - std::optional scale = glm::dvec2(2.0, 1.0); + std::optional offset = JsonValue::Array{0.0, 1.0}; + std::optional scale = JsonValue::Array{2.0, 1.0}; std::vector> expected{ glm::dvec2(0.0, 1 + (64.0 / 255.0)), glm::dvec2(2 * (128.0 / 255.0), 2.0), @@ -887,7 +795,7 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::i16vec2(-1, 3), glm::i16vec2(-1, -1), glm::i16vec2(7, 0)}; - std::optional noData = glm::i16vec2(-1, -1); + std::optional noData = JsonValue::Array{-1, -1}; std::vector> expected{ glm::i16vec2(-1, 3), std::nullopt, @@ -906,8 +814,8 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::i16vec2(-1, 3), glm::i16vec2(-1, -1), glm::i16vec2(7, 0)}; - std::optional noData = glm::i16vec2(-1, -1); - std::optional defaultValue = glm::i16vec2(0, 1); + std::optional noData = JsonValue::Array{-1, -1}; + std::optional defaultValue = JsonValue::Array{0, 1}; std::vector> expected{ glm::i16vec2(-1, 3), glm::i16vec2(0, 1), @@ -927,10 +835,10 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::u8vec2(128, 255), glm::u8vec2(255, 0), glm::u8vec2(0, 0)}; - std::optional offset = glm::dvec2(0.0, 1.0); - std::optional scale = glm::dvec2(2.0, 1.0); - std::optional noData = glm::u8vec2(0, 0); - std::optional defaultValue = glm::dvec2(5.0, 15.0); + std::optional offset = JsonValue::Array{0.0, 1.0}; + std::optional scale = JsonValue::Array{2.0, 1.0}; + std::optional noData = JsonValue::Array{0, 0}; + std::optional defaultValue = JsonValue::Array{5.0, 15.0}; std::vector> expected{ glm::dvec2(0.0, 1 + (64.0 / 255.0)), glm::dvec2(2 * (128.0 / 255.0), 2.0), @@ -1079,8 +987,10 @@ TEST_CASE("Check matN PropertyTablePropertyView") { glm::mat2(6.5f, 2.0f, -2.0f, 0.0f), glm::mat2(8.0f, -1.0f, -3.0f, 1.0f), }; - std::optional offset = glm::mat2(1.0f, 2.0, 3.0f, 1.0f); - std::optional scale = glm::mat2(2.0f, 0.0f, 0.0f, 2.0f); + std::optional offset = + JsonValue::Array{1.0f, 2.0f, 3.0f, 1.0f}; + std::optional scale = + JsonValue::Array{2.0f, 0.0f, 0.0f, 2.0f}; std::vector> expected{ glm::mat2(3.0f, 2.0f, 3.0f, 5.0f), glm::mat2(14.0f, 2.0f, 3.0f, 1.0f), @@ -1093,8 +1003,10 @@ TEST_CASE("Check matN PropertyTablePropertyView") { std::vector values{ glm::u8mat2x2(0, 64, 255, 255), glm::u8mat2x2(255, 0, 128, 0)}; - std::optional offset = glm::dmat2(0.0, 1.0, 1.0, 0.0); - std::optional scale = glm::dmat2(2.0, 1.0, 0.0, 2.0); + std::optional offset = + JsonValue::Array{0.0, 1.0, 1.0, 0.0}; + std::optional scale = + JsonValue::Array{2.0, 1.0, 0.0, 2.0}; std::vector> expected{ glm::dmat2(0.0, 1 + 64.0 / 255.0, 1.0, 2.0), glm::dmat2(2.0, 1.0, 1.0, 0.0)}; @@ -1116,11 +1028,11 @@ TEST_CASE("Check matN PropertyTablePropertyView") { -1, -1, -1, 0, 0, 0, 1, 1, 1)}; - std::optional noData = - glm::i16mat3x3( + std::optional noData = + JsonValue::Array{ -1, -1, -1, 0, 0, 0, - 1, 1, 1); + 1, 1, 1}; // clang-format on std::vector> expected{ values[0], @@ -1150,24 +1062,26 @@ TEST_CASE("Check matN PropertyTablePropertyView") { -1, -1, -1, 0, 0, 0, 1, 1, 1)}; - std::optional noData = - glm::i16mat3x3( - -1, -1, -1, - 0, 0, 0, - 1, 1, 1); + std::optional noData = JsonValue::Array{ + -1, -1, -1, + 0, 0, 0, + 1, 1, 1}; + std::optional defaultValue = JsonValue::Array{ + 1, 0, 0, + 0, 1, 0, + 0, 0, 1}; // clang-format on - std::optional default = glm::i16mat3x3(1); std::vector> expected{ values[0], values[1], - default}; + glm::i16mat3x3(1)}; checkMatN<3, glm::i16>( values, expected, std::nullopt, std::nullopt, noData, - default); + defaultValue); }; SECTION("Normalized Uint8 Mat2 with all properties") { @@ -1175,10 +1089,13 @@ TEST_CASE("Check matN PropertyTablePropertyView") { glm::u8mat2x2(0, 64, 255, 255), glm::u8mat2x2(0), glm::u8mat2x2(255, 0, 128, 0)}; - std::optional offset = glm::dmat2(0.0, 1.0, 1.0, 0.0); - std::optional scale = glm::dmat2(2.0, 1.0, 0.0, 2.0); - std::optional noData = glm::u8mat2x2(0); - std::optional defaultValue = glm::dmat2(1.0); + std::optional offset = + JsonValue::Array{0.0, 1.0, 1.0, 0.0}; + std::optional scale = + JsonValue::Array{2.0, 1.0, 0.0, 2.0}; + std::optional noData = JsonValue::Array{0, 0, 0, 0}; + std::optional defaultValue = + JsonValue::Array{1.0, 0.0, 0.0, 1.0}; std::vector> expected{ glm::dmat2(0.0, 1 + 64.0 / 255.0, 1.0, 2.0), @@ -1629,7 +1546,9 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { REQUIRE(values); for (int64_t j = 0; j < rawValues.size(); ++j) { REQUIRE(rawValues[j] == data[expectedIdx]); - REQUIRE((*values)[j] == expected[i][j]); + REQUIRE( + (*values)[j] == + expected[static_cast(i)][static_cast(j)]); ++expectedIdx; } } @@ -1688,38 +1607,38 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { checkNormalizedFixedLengthArray(data, 2, expected); } - SECTION("Array of 4 floats with offset / scale") { + SECTION("Array of 2 vec2s with offset / scale") { // clang-format off - std::vector data{ - 1.0f, 2.0f, 3.0f, 4.0f, - 5.0f, -1.0f, 0.0f, 2.0f + std::vector data{ + glm::vec2(1.0f, 2.0f), glm::vec2(3.0f, 4.0f), + glm::vec2(5.0f, -1.0f), glm::vec2(0.0f, 2.0f) }; // clang-format on std::optional offset = - JsonValue::Array{1.0f, 0.0f, -1.0f, 0.0f}; + JsonValue::Array{{1.0f, 0.0f}, {-1.0f, 0.0f}}; std::optional scale = - JsonValue::Array{1.0f, 2.0f, 1.0f, 2.0f}; + JsonValue::Array{{1.0f, 2.0f}, {1.0f, 2.0f}}; - std::vector>> expected{ - std::vector{2.0f, 4.0f, 2.0f, 8.0f}, - std::vector{6.0f, -2.0f, -1.0f, 4.0f}}; - checkFixedLengthArrayWithProperties(data, 4, expected, offset, scale); + std::vector>> expected{ + std::vector{glm::vec2(2.0f, 4.0f), glm::vec2(2.0f, 8.0f)}, + std::vector{glm::vec2(6.0f, -2.0f), glm::vec2(-1.0f, 4.0f)}}; + checkFixedLengthArrayWithProperties(data, 2, expected, offset, scale); } - SECTION("Array of 2 int32_ts with noData value") { + SECTION("Array of 2 ivec2 with noData value") { // clang-format off - std::vector data{ - 122, 12, - -1, -1, - -3, 44}; + std::vector data{ + glm::ivec2(122, 12), glm::ivec2(-1, -1), + glm::ivec2( -3, 44), glm::ivec2(0, 7), + glm::ivec2(-1, -1), glm::ivec2(0, 0)}; // clang-format on - std::optional noData = JsonValue::Array{-1, -1}; - std::vector>> expected{ - std::vector{122, 12}, - std::nullopt, - std::vector{-3, 44}}; - checkFixedLengthArrayWithProperties( + std::optional noData = JsonValue::Array{{-1, -1}, {0, 0}}; + std::vector>> expected{ + std::vector{glm::ivec2(122, 12), glm::ivec2(-1, -1)}, + std::vector{glm::ivec2(-3, 44), glm::ivec2(0, 7)}, + std::nullopt}; + checkFixedLengthArrayWithProperties( data, 2, expected, @@ -1729,20 +1648,21 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { std::nullopt); } - SECTION("Array of 2 int32_ts with noData and default value") { + SECTION("Array of 2 ivec2 with noData and default value") { // clang-format off - std::vector data{ - 122, 12, - -1, -1, - -3, 44}; + std::vector data{ + glm::ivec2(122, 12), glm::ivec2(-1, -1), + glm::ivec2( -3, 44), glm::ivec2(0, 7), + glm::ivec2(-1, -1), glm::ivec2(0, 0)}; // clang-format on - std::optional noData = JsonValue::Array{-1, -1}; - std::optional defaultValue = JsonValue::Array{0, 1}; - std::vector>> expected{ - std::vector{122, 12}, - std::vector{0, 1}, - std::vector{-3, 44}}; - checkFixedLengthArrayWithProperties( + std::optional noData = JsonValue::Array{{-1, -1}, {0, 0}}; + std::optional defaultValue = + JsonValue::Array{{1, 1}, {1, 2}}; + std::vector>> expected{ + std::vector{glm::ivec2(122, 12), glm::ivec2(-1, -1)}, + std::vector{glm::ivec2(-3, 44), glm::ivec2(0, 7)}, + std::vector{glm::ivec2(1, 1), glm::ivec2(1, 2)}}; + checkFixedLengthArrayWithProperties( data, 2, expected, @@ -1832,7 +1752,9 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { REQUIRE(values); for (int64_t j = 0; j < rawValues.size(); ++j) { REQUIRE(rawValues[j] == data[expectedIdx]); - REQUIRE((*values)[j] == expected[i][j]); + REQUIRE( + (*values)[j] == + expected[static_cast(i)][static_cast(j)]); ++expectedIdx; } } From fc190004b614528e267ef7a9cf08c9c18c27e300 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 23 Aug 2023 11:17:12 -0400 Subject: [PATCH 088/121] Reinitialize const ints outside of class to avoid errors --- CesiumGltf/src/PropertyTablePropertyView.cpp | 42 +++++++ CesiumGltf/src/PropertyView.cpp | 18 +++ .../test/TestPropertyTablePropertyView.cpp | 106 ++++++++++++------ 3 files changed, 133 insertions(+), 33 deletions(-) create mode 100644 CesiumGltf/src/PropertyTablePropertyView.cpp create mode 100644 CesiumGltf/src/PropertyView.cpp diff --git a/CesiumGltf/src/PropertyTablePropertyView.cpp b/CesiumGltf/src/PropertyTablePropertyView.cpp new file mode 100644 index 000000000..48f162915 --- /dev/null +++ b/CesiumGltf/src/PropertyTablePropertyView.cpp @@ -0,0 +1,42 @@ +#include "CesiumGltf/PropertyTablePropertyView.h" + +using namespace CesiumGltf; + +// Re-initialize consts here to avoid "undefined reference" errors with GCC / +// Clang. +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetBufferView; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetBufferView; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetBuffer; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetBuffer; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorBufferViewSizeNotDivisibleByTypeSize; +const PropertyViewStatusType PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferDontExist; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds; +const PropertyViewStatusType + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds; diff --git a/CesiumGltf/src/PropertyView.cpp b/CesiumGltf/src/PropertyView.cpp new file mode 100644 index 000000000..030469450 --- /dev/null +++ b/CesiumGltf/src/PropertyView.cpp @@ -0,0 +1,18 @@ +#include "CesiumGltf/PropertyView.h" + +using namespace CesiumGltf; + +// Re-initialize consts here to avoid "undefined reference" errors with GCC / +// Clang. +const PropertyViewStatusType PropertyViewStatus::Valid; +const PropertyViewStatusType PropertyViewStatus::ErrorNonexistentProperty; +const PropertyViewStatusType PropertyViewStatus::ErrorTypeMismatch; +const PropertyViewStatusType PropertyViewStatus::ErrorComponentTypeMismatch; +const PropertyViewStatusType PropertyViewStatus::ErrorArrayTypeMismatch; +const PropertyViewStatusType PropertyViewStatus::ErrorInvalidNormalization; +const PropertyViewStatusType PropertyViewStatus::ErrorInvalidOffset; +const PropertyViewStatusType PropertyViewStatus::ErrorInvalidScale; +const PropertyViewStatusType PropertyViewStatus::ErrorInvalidMax; +const PropertyViewStatusType PropertyViewStatus::ErrorInvalidMin; +const PropertyViewStatusType PropertyViewStatus::ErrorInvalidNoDataValue; +const PropertyViewStatusType PropertyViewStatus::ErrorInvalidDefaultValue; diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 94af0a123..7009dc0f1 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -12,6 +12,15 @@ using namespace CesiumGltf; using namespace CesiumUtility; +template +static void +checkArrayEqual(PropertyArrayView arrayView, std::vector expected) { + REQUIRE(arrayView.size() == static_cast(expected.size())); + for (int64_t i = 0; i < arrayView.size(); i++) { + REQUIRE(arrayView[i] == expected[static_cast(i)]); + } +} + template static void checkNumeric(const std::vector& expected) { std::vector data; data.resize(expected.size() * sizeof(T)); @@ -1536,6 +1545,18 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { REQUIRE(property.arrayCount() == count); REQUIRE(property.size() == instanceCount); + REQUIRE(property.offset()); + checkArrayEqual(*property.offset(), {2, 1, 0, -1}); + + REQUIRE(property.scale()); + checkArrayEqual(*property.scale(), {1, 0, 1, -1}); + + REQUIRE(property.min()); + checkArrayEqual(*property.min(), {0.0f, 1.0f, 1.0f, -2.0f}); + + REQUIRE(property.max()); + checkArrayEqual(*property.max(), {1.0f, 1.0f, 3.0f, 4.0f}); + std::vector> expected{ {3.0f, 1.0, 3.0f, -5.0f}, {2.0f, 1.0f, 1.0f, 1.0f}}; @@ -1672,26 +1693,29 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { defaultValue); } - SECTION("Array of 3 normalized int8_ts with all properties") { + SECTION("Array of 2 normalized i8vec2 with all properties") { // clang-format off - std::vector data{ - -128, 0, 64, - -64, 127, -128, - 0, 0, 0}; + std::vector data{ + glm::i8vec2(-128, 0), glm::i8vec2(64, -64), + glm::i8vec2(127, -128), glm::i8vec2(0, 0), + glm::i8vec2(0), glm::i8vec2(0)}; // clang-format on - std::optional offset = JsonValue::Array{0, 1, 1}; - std::optional scale = JsonValue::Array{1, -1, 2}; - std::optional noData = JsonValue::Array{0, 0, 0}; - std::optional defaultValue = JsonValue::Array{10, 8, 2}; + std::optional offset = JsonValue::Array{{0, 1}, {1, 2}}; + std::optional scale = JsonValue::Array{{1, -1}, {2, 1}}; + std::optional noData = JsonValue::Array{{0, 0}, {0, 0}}; + std::optional defaultValue = + JsonValue::Array{{10, 2}, {4, 8}}; - std::vector>> expected{ - std::vector{-1.0, 1.0, 1 + 2 * (64.0 / 127.0)}, - std::vector{-64.0 / 127.0, 0.0, -1.0}, - std::vector{10.0, 8.0, 2.0}, + std::vector>> expected{ + std::vector{ + glm::dvec2(-1.0, 1.0), + glm::dvec2(1 + 2 * (64.0 / 127.0), 2 - (64.0 / 127.0))}, + std::vector{glm::dvec2(1, 2), glm::dvec2(1, 2)}, + std::vector{glm::dvec2(10, 2), glm::dvec2(4, 8)}, }; checkNormalizedFixedLengthArray( data, - 3, + 2, expected, offset, scale, @@ -1701,35 +1725,35 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { SECTION("Overrides class property values") { // clang-format off - std::vector data{ - 1.0f, 2.0f, 3.0f, 4.0f, - 0.0f, -1.0f, 1.0f, -2.0f}; + std::vector data{ + glm::vec2(1.0f, 2.0f), glm::vec2(3.0f, 4.0f), + glm::vec2(0.0f, -1.0f), glm::vec2(1.0f, -2.0f)}; // clang-format on - const int64_t count = 4; + const int64_t count = 2; const int64_t instanceCount = 2; std::vector buffer; - buffer.resize(data.size() * sizeof(float)); + buffer.resize(data.size() * sizeof(glm::vec2)); std::memcpy(buffer.data(), data.data(), buffer.size()); ClassProperty classProperty; - classProperty.type = ClassProperty::Type::SCALAR; + classProperty.type = ClassProperty::Type::VEC2; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; classProperty.array = true; classProperty.count = count; - classProperty.offset = {0, 0, 0, 0}; - classProperty.scale = {1, 1, 1, 1}; - classProperty.min = {0.0f, -1.0f, 1.0f, -2.0f}; - classProperty.max = {1.0f, 2.0f, 3.0f, 4.0f}; + classProperty.offset = JsonValue::Array{{0, 0}, {0, 0}}; + classProperty.scale = JsonValue::Array{{1, 1}, {1, 1}}; + classProperty.min = JsonValue::Array{{0.0f, -1.0f}, {1.0f, -2.0f}}; + classProperty.max = JsonValue::Array{{1.0f, 2.0f}, {3.0f, 4.0f}}; PropertyTableProperty propertyTableProperty; - propertyTableProperty.offset = {2, 1, 0, -1}; - propertyTableProperty.scale = {1, 0, 1, -1}; - propertyTableProperty.min = {0.0f, 1.0f, 1.0f, -2.0f}; - propertyTableProperty.max = {1.0f, 1.0f, 3.0f, 4.0f}; + propertyTableProperty.offset = JsonValue::Array{{2, 1}, {0, -1}}; + propertyTableProperty.scale = JsonValue::Array{{1, 0}, {1, -1}}; + propertyTableProperty.min = JsonValue::Array{{0.0f, 1.0f}, {1.0f, -2.0f}}; + propertyTableProperty.max = JsonValue::Array{{1.0f, 1.0f}, {3.0f, 4.0f}}; - PropertyTablePropertyView> property( + PropertyTablePropertyView> property( propertyTableProperty, classProperty, instanceCount, @@ -1742,12 +1766,28 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { REQUIRE(property.arrayCount() == count); REQUIRE(property.size() == instanceCount); - std::vector> expected{ - {3.0f, 1.0, 3.0f, -5.0f}, - {2.0f, 1.0f, 1.0f, 1.0f}}; + REQUIRE(property.offset()); + checkArrayEqual(*property.offset(), {glm::vec2{2, 1}, glm::vec2{0, -1}}); + + REQUIRE(property.scale()); + checkArrayEqual(*property.scale(), {glm::vec2{1, 0}, glm::vec2{1, -1}}); + + REQUIRE(property.min()); + checkArrayEqual( + *property.min(), + {glm::vec2{0.0f, 1.0f}, glm::vec2{1.0f, -2.0f}}); + + REQUIRE(property.max()); + checkArrayEqual( + *property.max(), + {glm::vec2(1.0f, 1.0f), glm::vec2(3.0f, 4.0f)}); + + std::vector> expected{ + {glm::vec2(3.0f, 1.0), glm::vec2(3.0f, -5.0f)}, + {glm::vec2(2.0f, 1.0f), glm::vec2(1.0f, 1.0f)}}; size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { - PropertyArrayView rawValues = property.getRaw(i); + PropertyArrayView rawValues = property.getRaw(i); auto values = property.get(i); REQUIRE(values); for (int64_t j = 0; j < rawValues.size(); ++j) { From 12d1bbcaaa5b0a6035c7d1038b4fa22429b2f2f9 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 23 Aug 2023 14:55:48 -0400 Subject: [PATCH 089/121] Finish PropertyTablePropertyView tests --- .../include/CesiumGltf/PropertyArrayView.h | 12 + .../CesiumGltf/PropertyTablePropertyView.h | 9 + .../CesiumGltf/PropertyTransformations.h | 19 +- CesiumGltf/include/CesiumGltf/PropertyView.h | 2 +- .../test/TestPropertyTablePropertyView.cpp | 1647 +++++++++++++++-- 5 files changed, 1523 insertions(+), 166 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index 9be1867cf..80d8bbc61 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -57,6 +57,10 @@ template class PropertyArrayView { } bool operator==(const PropertyArrayView& other) const noexcept { + if (this->size() != other.size()) { + return false; + } + for (int64_t i = 0; i < size(); i++) { if ((*this)[i] != other[i]) { return false; @@ -104,6 +108,10 @@ template <> class PropertyArrayView { int64_t size() const noexcept { return _size; } bool operator==(const PropertyArrayView& other) const noexcept { + if (this->size() != other.size()) { + return false; + } + for (int64_t i = 0; i < size(); i++) { if ((*this)[i] != other[i]) { return false; @@ -164,6 +172,10 @@ template <> class PropertyArrayView { bool operator==(const PropertyArrayView& other) const noexcept { + if (this->size() != other.size()) { + return false; + } + for (int64_t i = 0; i < size(); i++) { if ((*this)[i] != other[i]) { return false; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 2830305b9..a071ee15e 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -636,6 +636,15 @@ class PropertyTablePropertyView this->offset(), this->scale()); } + + if constexpr (IsMetadataMatN::value) { + constexpr glm::length_t N = ArrayElementType::length(); + using T = typename ArrayElementType::value_type; + return transformNormalizedMatNArray( + value, + this->offset(), + this->scale()); + } } } diff --git a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h index 4f4b9ce3d..440e39454 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTransformations.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTransformations.h @@ -111,7 +111,7 @@ PropertyArrayView transformNormalizedArray( result[i] = normalize(value[i]); if (scale) { - result[i] = applyScale(result[i], (*scale)[i]); + result[i] = result[i] * (*scale)[i]; } if (offset) { @@ -132,7 +132,7 @@ PropertyArrayView> transformNormalizedVecNArray( result[i] = normalize(value[i]); if (scale) { - result[i] = applyScale>(result[i], (*scale)[i]); + result[i] = result[i] * (*scale)[i]; } if (offset) { @@ -143,18 +143,17 @@ PropertyArrayView> transformNormalizedVecNArray( return PropertyArrayView>(std::move(result)); } - template -PropertyArrayView> transformNormalizedMatNArray( - const PropertyArrayView>& value, - const std::optional>>& offset, - const std::optional>>& scale) { - std::vector> result(static_cast(value.size())); +PropertyArrayView> transformNormalizedMatNArray( + const PropertyArrayView>& value, + const std::optional>>& offset, + const std::optional>>& scale) { + std::vector> result(static_cast(value.size())); for (int64_t i = 0; i < value.size(); i++) { result[i] = normalize(value[i]); if (scale) { - result[i] = applyScale>(result[i], (*scale)[i]); + result[i] = applyScale>(result[i], (*scale)[i]); } if (offset) { @@ -162,6 +161,6 @@ PropertyArrayView> transformNormalizedMatNArray( } } - return PropertyArrayView>(std::move(result)); + return PropertyArrayView>(std::move(result)); } } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 469f8392d..4beb9aebf 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -2269,7 +2269,7 @@ template <> class PropertyView> { */ std::optional> defaultValue() const noexcept { - if (_noDataSize > 0) { + if (_defaultValueSize > 0) { return PropertyArrayView( gsl::span( _defaultValue.data(), diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 7009dc0f1..016fd5bf5 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -306,7 +306,7 @@ static void checkNormalizedMatN( template static void checkVariableLengthArray( const std::vector& data, - const std::vector offsets, + const std::vector& offsets, PropertyComponentType offsetType, int64_t instanceCount) { // copy data to buffer @@ -359,6 +359,163 @@ static void checkVariableLengthArray( REQUIRE(expectedIdx == data.size()); } +template +static void checkVariableLengthArrayWithProperties( + const std::vector& data, + const std::vector& offsets, + PropertyComponentType offsetType, + int64_t instanceCount, + const std::vector>>& expected, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + // copy data to buffer + std::vector buffer; + buffer.resize(data.size() * sizeof(DataType)); + std::memcpy(buffer.data(), data.data(), data.size() * sizeof(DataType)); + + // copy offset to buffer + std::vector offsetBuffer; + offsetBuffer.resize(offsets.size() * sizeof(OffsetType)); + std::memcpy( + offsetBuffer.data(), + offsets.data(), + offsets.size() * sizeof(OffsetType)); + + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + if (componentType != PropertyComponentType::None) { + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + } + + classProperty.array = true; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + instanceCount, + gsl::span(buffer.data(), buffer.size()), + gsl::span(offsetBuffer.data(), offsetBuffer.size()), + gsl::span(), + offsetType, + PropertyComponentType::None); + + REQUIRE(property.arrayCount() == 0); + + // Check raw values first + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView values = property.getRaw(i); + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == data[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == data.size()); + + // Check values with properties applied + for (int64_t i = 0; i < property.size(); ++i) { + std::optional> maybeValues = property.get(i); + if (!maybeValues) { + REQUIRE(!expected[static_cast(i)]); + continue; + } + + auto values = *maybeValues; + auto expectedValues = *expected[static_cast(i)]; + + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == expectedValues[static_cast(j)]); + } + } +} + +template < + typename DataType, + typename OffsetType, + typename NormalizedType = typename TypeToNormalizedType::type> +static void checkNormalizedVariableLengthArray( + const std::vector& data, + const std::vector offsets, + PropertyComponentType offsetType, + int64_t instanceCount, + const std::vector>>& expected, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + // copy data to buffer + std::vector buffer; + buffer.resize(data.size() * sizeof(DataType)); + std::memcpy(buffer.data(), data.data(), data.size() * sizeof(DataType)); + + // copy offset to buffer + std::vector offsetBuffer; + offsetBuffer.resize(offsets.size() * sizeof(OffsetType)); + std::memcpy( + offsetBuffer.data(), + offsets.data(), + offsets.size() * sizeof(OffsetType)); + + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.array = true; + classProperty.normalized = true; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; + + PropertyTablePropertyView, true> property( + propertyTableProperty, + classProperty, + instanceCount, + gsl::span(buffer.data(), buffer.size()), + gsl::span(offsetBuffer.data(), offsetBuffer.size()), + offsetType); + + REQUIRE(property.arrayCount() == 0); + + // Check raw values first + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView values = property.getRaw(i); + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == data[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == data.size()); + + // Check values with properties applied + for (int64_t i = 0; i < property.size(); ++i) { + std::optional> maybeValues = + property.get(i); + if (!maybeValues) { + REQUIRE(!expected[static_cast(i)]); + continue; + } + + auto values = *maybeValues; + auto expectedValues = *expected[static_cast(i)]; + + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == expectedValues[static_cast(j)]); + } + } +} + template static void checkFixedLengthArray( const std::vector& data, @@ -468,16 +625,16 @@ static void checkFixedLengthArrayWithProperties( // Check values with properties applied for (int64_t i = 0; i < property.size(); ++i) { std::optional> maybeValues = property.get(i); - std::optional> expectedValues = - expected[static_cast(i)]; - REQUIRE(maybeValues.has_value() == expectedValues.has_value()); if (!maybeValues) { + REQUIRE(!expected[static_cast(i)]); continue; } auto values = *maybeValues; + auto expectedValues = *expected[static_cast(i)]; + for (int64_t j = 0; j < values.size(); ++j) { - REQUIRE(values[j] == (*expectedValues)[static_cast(j)]); + REQUIRE(values[j] == expectedValues[static_cast(j)]); } } } @@ -543,6 +700,7 @@ static void checkNormalizedFixedLengthArray( std::optional> maybeValues = property.get(i); if (!maybeValues) { REQUIRE(!expected[static_cast(i)]); + continue; } auto values = *maybeValues; @@ -970,55 +1128,103 @@ TEST_CASE("Check matN PropertyTablePropertyView") { } SECTION("Normalized Uint8 Mat2") { + // clang-format off std::vector values{ - glm::u8mat2x2(0, 64, 255, 255), - glm::u8mat2x2(255, 0, 128, 0)}; + glm::u8mat2x2( + 0, 64, + 255, 255), + glm::u8mat2x2( + 255, 0, + 128, 0)}; std::vector> expected{ - glm::dmat2(0.0, 64.0 / 255.0, 1.0, 1.0), - glm::dmat2(1.0, 0.0, 128.0 / 255.0, 0.0)}; + glm::dmat2( + 0.0, 64.0 / 255.0, + 1.0, 1.0), + glm::dmat2( + 1.0, 0.0, + 128.0 / 255.0, 0.0)}; + // clang-format on checkNormalizedMatN(values, expected); } SECTION("Normalized Int16 Mat2") { + // clang-format off std::vector values{ - glm::i16mat2x2(-32768, 0, 16384, 32767), - glm::i16mat2x2(0, 32767, 32767, -32768)}; + glm::i16mat2x2( + -32768, 0, + 16384, 32767), + glm::i16mat2x2( + 0, 32767, + 32767, -32768)}; std::vector> expected{ - glm::dmat2(-1.0, 0.0, 16384.0 / 32767.0, 1.0), - glm::dmat2(0.0, 1.0, 1.0, -1.0), + glm::dmat2( + -1.0, 0.0, + 16384.0 / 32767.0, 1.0), + glm::dmat2( + 0.0, 1.0, + 1.0, -1.0), }; + // clang-format on checkNormalizedMatN(values, expected); } SECTION("Float Mat2 with Offset / Scale") { + // clang-format off std::vector values{ - glm::mat2(1.0f, 3.0f, 4.0f, 2.0f), - glm::mat2(6.5f, 2.0f, -2.0f, 0.0f), - glm::mat2(8.0f, -1.0f, -3.0f, 1.0f), + glm::mat2( + 1.0f, 3.0f, + 4.0f, 2.0f), + glm::mat2( + 6.5f, 2.0f, + -2.0f, 0.0f), + glm::mat2( + 8.0f, -1.0f, + -3.0f, 1.0f), }; - std::optional offset = - JsonValue::Array{1.0f, 2.0f, 3.0f, 1.0f}; - std::optional scale = - JsonValue::Array{2.0f, 0.0f, 0.0f, 2.0f}; + std::optional offset = JsonValue::Array{ + 1.0f, 2.0f, + 3.0f, 1.0f}; + std::optional scale = JsonValue::Array{ + 2.0f, 0.0f, + 0.0f, 2.0f}; std::vector> expected{ - glm::mat2(3.0f, 2.0f, 3.0f, 5.0f), - glm::mat2(14.0f, 2.0f, 3.0f, 1.0f), - glm::mat2(17.0f, 2.0f, 3.0f, 3.0f), + glm::mat2( + 3.0f, 2.0f, + 3.0f, 5.0f), + glm::mat2( + 14.0f, 2.0f, + 3.0f, 1.0f), + glm::mat2( + 17.0f, 2.0f, + 3.0f, 3.0f), }; + // clang-format on checkMatN(values, expected, offset, scale); } SECTION("Normalized Uint8 Mat2 with Offset and Scale") { + // clang-format off std::vector values{ - glm::u8mat2x2(0, 64, 255, 255), - glm::u8mat2x2(255, 0, 128, 0)}; - std::optional offset = - JsonValue::Array{0.0, 1.0, 1.0, 0.0}; - std::optional scale = - JsonValue::Array{2.0, 1.0, 0.0, 2.0}; + glm::u8mat2x2( + 0, 64, + 255, 255), + glm::u8mat2x2( + 255, 0, + 128, 0)}; + std::optional offset = JsonValue::Array{ + 0.0, 1.0, + 1.0, 0.0}; + std::optional scale = JsonValue::Array{ + 2.0, 1.0, + 0.0, 2.0}; std::vector> expected{ - glm::dmat2(0.0, 1 + 64.0 / 255.0, 1.0, 2.0), - glm::dmat2(2.0, 1.0, 1.0, 0.0)}; + glm::dmat2( + 0.0, 1 + 64.0 / 255.0, + 1.0, 2.0), + glm::dmat2( + 2.0, 1.0, + 1.0, 0.0)}; + // clang-format on checkNormalizedMatN(values, expected, offset, scale); } @@ -1094,30 +1300,47 @@ TEST_CASE("Check matN PropertyTablePropertyView") { }; SECTION("Normalized Uint8 Mat2 with all properties") { + // clang-format off std::vector values{ - glm::u8mat2x2(0, 64, 255, 255), + glm::u8mat2x2( + 0, 64, + 255, 255), glm::u8mat2x2(0), - glm::u8mat2x2(255, 0, 128, 0)}; - std::optional offset = - JsonValue::Array{0.0, 1.0, 1.0, 0.0}; - std::optional scale = - JsonValue::Array{2.0, 1.0, 0.0, 2.0}; - std::optional noData = JsonValue::Array{0, 0, 0, 0}; - std::optional defaultValue = - JsonValue::Array{1.0, 0.0, 0.0, 1.0}; + glm::u8mat2x2( + 255, 0, + 128, 0)}; + std::optional offset = JsonValue::Array{ + 0.0, 1.0, + 1.0, 0.0}; + std::optional scale = JsonValue::Array{ + 2.0, 1.0, + 0.0, 2.0}; + std::optional noData = JsonValue::Array{ + 0, 0, + 0, 0}; + std::optional defaultValue = JsonValue::Array{ + 1.0, 0.0, + 0.0, 1.0}; std::vector> expected{ - glm::dmat2(0.0, 1 + 64.0 / 255.0, 1.0, 2.0), + glm::dmat2( + 0.0, 1 + 64.0 / 255.0, + 1.0, 2.0), glm::dmat2(1.0), - glm::dmat2(2.0, 1.0, 1.0, 0.0)}; + glm::dmat2( + 2.0, 1.0, + 1.0, 0.0)}; + // clang-format on checkNormalizedMatN(values, expected, offset, scale, noData, defaultValue); } SECTION("Overrides class property values") { + // clang-fomrat off std::vector values{ glm::mat2(1.0f), glm::mat2(2.5f, 1.0f, 1.0f, 2.5f), glm::mat2(3.0f)}; + // clang-format on std::vector data; data.resize(values.size() * sizeof(glm::mat2)); std::memcpy(data.data(), values.data(), data.size()); @@ -1125,16 +1348,20 @@ TEST_CASE("Check matN PropertyTablePropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + // clang-fomrat off classProperty.offset = {0.0f, 0.0f, 0.0f, 0.0f}; classProperty.scale = {1.0f, 1.0f, 1.0f, 1.0f}; classProperty.min = {1.0f, 0.0f, 0.0f, 1.0f}; classProperty.max = {3.0f, 0.0f, 0.0f, 3.0f}; + // clang-fomrat on PropertyTableProperty propertyTableProperty; + // clang-fomrat off propertyTableProperty.offset = {1.0f, 0.5f, 0.5f, 1.0f}; propertyTableProperty.scale = {2.0f, 1.0f, 0.0f, 1.0f}; propertyTableProperty.min = {3.0f, 0.5f, 0.5f, 2.0f}; propertyTableProperty.max = {7.0f, 1.5f, 0.5f, 4.0f}; + // clang-fomrat on PropertyTablePropertyView property( propertyTableProperty, @@ -1142,19 +1369,35 @@ TEST_CASE("Check matN PropertyTablePropertyView") { static_cast(values.size()), gsl::span(data.data(), data.size())); + // clang-format off REQUIRE(property.offset()); - REQUIRE(*property.offset() == glm::mat2(1.0f, 0.5f, 0.5f, 1.0f)); + REQUIRE(*property.offset() == glm::mat2( + 1.0f, 0.5f, + 0.5f, 1.0f)); REQUIRE(property.scale()); - REQUIRE(*property.scale() == glm::mat2(2.0f, 1.0f, 0.0f, 1.0f)); + REQUIRE(*property.scale() == glm::mat2( + 2.0f, 1.0f, + 0.0f, 1.0f)); REQUIRE(property.min()); - REQUIRE(*property.min() == glm::mat2(3.0f, 0.5f, 0.5f, 2.0f)); + REQUIRE(*property.min() == glm::mat2( + 3.0f, 0.5f, + 0.5f, 2.0f)); REQUIRE(property.max()); - REQUIRE(*property.max() == glm::mat2(7.0f, 1.5f, 0.5f, 4.0f)); + REQUIRE(*property.max() == glm::mat2( + 7.0f, 1.5f, + 0.5f, 4.0f)); std::vector expected{ - glm::mat2(3.0f, 0.5f, 0.5f, 2.0f), - glm::mat2(6.0f, 1.5f, 0.5f, 3.5f), - glm::mat2(7.0f, 0.5f, 0.5f, 4.0f)}; + glm::mat2( + 3.0f, 0.5f, + 0.5f, 2.0f), + glm::mat2( + 6.0f, 1.5f, + 0.5f, 3.5f), + glm::mat2( + 7.0f, 0.5f, + 0.5f, 4.0f)}; + // clang-format on for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == values[static_cast(i)]); @@ -1783,7 +2026,7 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { {glm::vec2(1.0f, 1.0f), glm::vec2(3.0f, 4.0f)}); std::vector> expected{ - {glm::vec2(3.0f, 1.0), glm::vec2(3.0f, -5.0f)}, + {glm::vec2(3.0f, 1.0f), glm::vec2(3.0f, -5.0f)}, {glm::vec2(2.0f, 1.0f), glm::vec2(1.0f, 1.0f)}}; size_t expectedIdx = 0; for (int64_t i = 0; i < property.size(); ++i) { @@ -1900,81 +2143,609 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { // clang-format on checkFixedLengthArray(data, 3); } -} -TEST_CASE("Check variable-length scalar array PropertyTablePropertyView") { - SECTION("Variable-length array of uint8_t") { + SECTION("Array of 2 normalized u8mat2x2s") { // clang-format off - std::vector data{ - 3, 2, - 0, 45, 2, 1, 4, - 1, 3, 2, - 1, 3, 4, 1 - }; - std::vector offsets{ - 0, 2, 7, 10, 14 - }; + std::vector data{ + glm::u8mat2x2( + 255, 64, + 0, 255), + glm::u8mat2x2( + 0, 255, + 64, 128), + glm::u8mat2x2( + 128, 0, + 0, 255), + glm::u8mat2x2( + 255, 32, + 255, 0)}; + + std::vector>> expected{ + std::vector{ + glm::dmat2( + 1.0, 64.0 / 255.0, + 0.0, 1.0), + glm::dmat2( + 0.0, 1.0, + 64.0 / 255.0, 128.0 / 255.0), + }, + std::vector{ + glm::dmat2( + 128.0 / 255.0, 0.0, + 0.0, 1.0), + glm::dmat2( + 1.0, 32.0 / 255.0, + 1.0, 0.0), + }}; // clang-format on - checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); + checkNormalizedFixedLengthArray(data, 2, expected); } - SECTION("Variable-length array of int32_t") { + SECTION("Array of 2 mat2s with offset / scale") { // clang-format off - std::vector data{ - 3, 200, - 0, 450, 200, 1, 4, - 1, 3, 2, - 1, 3, 4, 1 - }; - std::vector offsets{ - 0, 2 * sizeof(int32_t), 7 * sizeof(int32_t), 10 * sizeof(int32_t), 14 - * sizeof(int32_t) - }; - // clang-format on + std::vector data{ + glm::mat2( + 1.0f, 2.0f, + 3.0f, 4.0f), + glm::mat2( + 5.0f, -1.0f, + 0.0f, 2.0f), + glm::mat2( + -1.0f, -1.0f, + 0.0f, -2.0f), + glm::mat2( + 0.0f, -2.0f, + 4.0f, 3.0f)}; - checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); + std::optional offset = + JsonValue::Array{ + {1.0f, 0.0f, + 2.0f, 3.0f}, + {-1.0f, 0.0f, + 0.0f, 2.0f}}; + std::optional scale = + JsonValue::Array{ + {1.0f, 2.0f, + 1.0f, 0.0f}, + {1.0f, -1.0f, + -1.0f, 2.0f}}; + + std::vector>> expected{ + std::vector{ + glm::mat2( + 2.0f, 4.0f, + 5.0f, 3.0f), + glm::mat2( + 4.0f, 1.0f, + 0.0f, 6.0f)}, + std::vector{ + glm::mat2( + 0.0f, -2.0f, + 2.0f, 3.0f), + glm::mat2( + -1.0f, 2.0f, + -4.0f, 8.0f)}}; + // clang-format on + checkFixedLengthArrayWithProperties(data, 2, expected, offset, scale); } - SECTION("Variable-length array of double") { + SECTION("Array of 2 imat2x2 with noData value") { // clang-format off - std::vector data{ - 3.333, 200.2, - 0.1122, 4.50, 2.30, 1.22, 4.444, - 1.4, 3.3, 2.2, - 1.11, 3.2, 4.111, 1.44 - }; - std::vector offsets{ - 0, 2 * sizeof(double), 7 * sizeof(double), 10 * sizeof(double), 14 * - sizeof(double) - }; + std::vector data{ + glm::imat2x2( + 122, 12, + 4, 6), + glm::imat2x2(-1), + glm::imat2x2( + -3, 44, + 7, 8), + glm::imat2x2( + 0, 7, + -1, 0), + glm::imat2x2(-1), + glm::imat2x2(0)}; + std::optional noData = JsonValue::Array{ + {-1, 0, + 0, -1}, + {0, 0, + 0, 0}}; + std::vector>> expected{ + std::vector{ + glm::imat2x2( + 122, 12, + 4, 6), + glm::imat2x2(-1)}, + std::vector{ + glm::imat2x2( + -3, 44, + 7, 8), + glm::imat2x2( + 0, 7, + -1, 0)}, + std::nullopt}; // clang-format on - - checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); + checkFixedLengthArrayWithProperties( + data, + 2, + expected, + std::nullopt, + std::nullopt, + noData, + std::nullopt); } -} -TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { - SECTION("Variable-length array of ivec2") { + SECTION("Array of 2 imat2x2 with noData and default value") { // clang-format off - std::vector data{ - glm::ivec2(3, -2), glm::ivec2(20, 3), - glm::ivec2(0, 45), glm::ivec2(-10, 2), glm::ivec2(4, 4), glm::ivec2(1, -1), - glm::ivec2(3, 1), glm::ivec2(3, 2), glm::ivec2(0, -5), - glm::ivec2(-9, 10), glm::ivec2(8, -2) + std::vector data{ + glm::imat2x2( + 122, 12, + 4, 6), + glm::imat2x2(-1), + glm::imat2x2( + -3, 44, + 7, 8), + glm::imat2x2( + 0, 7, + -1, 0), + glm::imat2x2(-1), + glm::imat2x2(0)}; + std::optional noData = JsonValue::Array{ + {-1, 0, + 0, -1}, + {0, 0, + 0, 0}}; + std::optional defaultValue = JsonValue::Array{ + {2, 0, + 0, 2}, + {1, 0, + 0, 1} }; + std::vector>> expected{ + std::vector{ + glm::imat2x2( + 122, 12, + 4, 6), + glm::imat2x2(-1)}, + std::vector{ + glm::imat2x2( + -3, 44, + 7, 8), + glm::imat2x2( + 0, 7, + -1, 0)}, + std::vector{ + glm::imat2x2(2), + glm::imat2x2(1) + }}; // clang-format on - std::vector offsets{ - 0, - 2 * sizeof(glm::ivec2), - 6 * sizeof(glm::ivec2), + checkFixedLengthArrayWithProperties( + data, + 2, + expected, + std::nullopt, + std::nullopt, + noData, + defaultValue); + } + + SECTION("Array of 2 normalized i8mat2x2 with all properties") { + // clang-format off + std::vector data{ + glm::i8mat2x2(-128), + glm::i8mat2x2( + 64, -64, + 0, 255), + glm::i8mat2x2( + 127, -128, + -128, 0), + glm::i8mat2x2(0), + glm::i8mat2x2(0), + glm::i8mat2x2( + -128, -128, + -128, -128)}; + std::optional offset = JsonValue::Array{ + {0, 1, + 2, 3}, + {1, 2, + 0, -2}}; + std::optional scale = JsonValue::Array{ + {1, -1, + 0, 1}, + {2, 1, + -1, 0}}; + std::optional noData = JsonValue::Array{ + {0, 0, + 0, 0}, + {-128, -128, + -128, -128}}; + std::optional defaultValue = JsonValue::Array{ + {1, 0, + 0, 1}, + {2, 0, + 0, 2}}; + + std::vector>> expected{ + std::vector{ + glm::dmat2( + -1.0, 1.0, + 2.0, 2.0), + glm::dmat2( + 1 + 2 * (64.0 / 127.0), 2 - (64.0 / 127.0), + 0, -2)}, + std::vector{ + glm::dmat2( + 1.0, 2.0, + 2.0, 3.0), + glm::dmat2( + 1.0, 2.0, + 0.0, -2.0)}, + std::vector{ + glm::dmat2(1), + glm::dmat2(2)}, + }; + // clang-format on + checkNormalizedFixedLengthArray( + data, + 2, + expected, + offset, + scale, + noData, + defaultValue); + } + + SECTION("Overrides class property values") { + // clang-format off + std::vector data{ + glm::mat2(1.0f), + glm::mat2(2.0f), + glm::mat2(3.0f), + glm::mat2(4.0f)}; + // clang-format on + const int64_t count = 2; + const int64_t instanceCount = 2; + + std::vector buffer; + buffer.resize(data.size() * sizeof(glm::mat2)); + std::memcpy(buffer.data(), data.data(), buffer.size()); + + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::MAT2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + + classProperty.array = true; + classProperty.count = count; + // clang-format off + classProperty.offset = JsonValue::Array{ + {0, 0, + 0, 0}, + {0, 0, + 0, 0}}; + classProperty.scale = JsonValue::Array{ + {1, 1, + 1, 1}, + {1, 1, + 1, 1}}; + classProperty.min = JsonValue::Array{ + {1.0f, 0.0f, + 0.0f, 1.0f}, + {2.0f, 0.0f, + 0.0f, 2.0f}}; + classProperty.max = JsonValue::Array{ + {3.0f, 0.0f, + 0.0f, 3.0f}, + {4.0f, 0.0f, + 0.0f, 4.0f}}; + // clang-format on + + PropertyTableProperty propertyTableProperty; + // clang-format off + propertyTableProperty.offset = JsonValue::Array{ + {2, 1, + -1, -2}, + {0, -1, + 4, 0}}; + propertyTableProperty.scale = JsonValue::Array{ + {1, 0, + 1, 2}, + {1, -1, + 3, 2}}; + propertyTableProperty.min = JsonValue::Array{ + {2.0f, 1.0f, + -1.0f, 0.0f}, + {2.0f, -1.0f, + -4.0f, 4.0f}}; + propertyTableProperty.max = JsonValue::Array{ + {5.0f, 1.0f, + -1.0f, 4.0f}, + {4.0f, -1.0f, + 4.0f, 8.0f}}; + // clang-format on + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + instanceCount, + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None); + + REQUIRE(property.arrayCount() == count); + REQUIRE(property.size() == instanceCount); + + // clang-format off + REQUIRE(property.offset()); + checkArrayEqual(*property.offset(), { + glm::mat2( + 2, 1, + -1, -2), + glm::mat2( + 0, -1, + 4, 0)}); + + REQUIRE(property.scale()); + checkArrayEqual(*property.scale(), { + glm::mat2( + 1, 0, + 1, 2), + glm::mat2( + 1, -1, + 3, 2)}); + + REQUIRE(property.min()); + checkArrayEqual(*property.min(), { + glm::mat2{ + 2.0f, 1.0f, + -1.0f, 0.0f}, + glm::mat2{ + 2.0f, -1.0f, + -4.0f, 4.0f}}); + + REQUIRE(property.max()); + checkArrayEqual( *property.max(), { + glm::mat2( + 5.0f, 1.0f, + -1.0f, 4.0f), + glm::mat2( + 4.0f, -1.0f, + 4.0f, 8.0f)}); + + std::vector> expected{ + {glm::mat2( + 3.0f, 1.0f, + -1.0f, 0.0f), + glm::mat2( + 2.0f, -1.0f, + 4.0f, 4.0f)}, + {glm::mat2( + 5.0f, 1.0f, + -1.0f, 4.0f), + glm::mat2( + 4.0f, -1.0f, + 4.0f, 8.0f)}}; + // clang-format on + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView rawValues = property.getRaw(i); + auto values = property.get(i); + REQUIRE(values); + for (int64_t j = 0; j < rawValues.size(); ++j) { + REQUIRE(rawValues[j] == data[expectedIdx]); + REQUIRE( + (*values)[j] == + expected[static_cast(i)][static_cast(j)]); + ++expectedIdx; + } + } + } +} + +TEST_CASE("Check variable-length scalar array PropertyTablePropertyView") { + SECTION("Array of uint8_t") { + // clang-format off + std::vector data{ + 3, 2, + 0, 45, 2, 1, 4, + 1, 3, 2, + 1, 3, 4, 1 + }; + std::vector offsets{ + 0, 2, 7, 10, 14 + }; + // clang-format on + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); + } + + SECTION("Array of int32_t") { + // clang-format off + std::vector data{ + 3, 200, + 0, 450, 200, 1, 4, + 1, 3, 2, + 1, 3, 4, 1 + }; + std::vector offsets{ + 0, 2 * sizeof(int32_t), 7 * sizeof(int32_t), 10 * sizeof(int32_t), 14 + * sizeof(int32_t) + }; + // clang-format on + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); + } + + SECTION("Array of double") { + // clang-format off + std::vector data{ + 3.333, 200.2, + 0.1122, 4.50, 2.30, 1.22, 4.444, + 1.4, 3.3, 2.2, + 1.11, 3.2, 4.111, 1.44 + }; + std::vector offsets{ + 0, 2 * sizeof(double), 7 * sizeof(double), 10 * sizeof(double), 14 * + sizeof(double) + }; + // clang-format on + + checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); + } + + SECTION("Array of normalized uint8_t") { + // clang-format off + std::vector data{ + 255, 0, + 0, 255, 128, + 64, + }; + std::vector offsets{ + 0, 2, 5, 6 + }; + // clang-format on + + std::vector>> expected{ + std::vector{1.0, 0.0}, + std::vector{0.0, 1.0, 128.0 / 255.0}, + std::vector{64.0 / 255.0}, + }; + checkNormalizedVariableLengthArray( + data, + offsets, + PropertyComponentType::Uint32, + 3, + expected); + } + + SECTION("Array of int32_t with NoData") { + // clang-format off + std::vector data{ + 3, 200, + 0, 450, 200, 1, 4, + 1, 3, 2, + 0, + 1, 3, 4, 1 + }; + // clang-format on + std::vector offsets{ + 0, + 2 * sizeof(int32_t), + 7 * sizeof(int32_t), + 10 * sizeof(int32_t), + 11 * sizeof(int32_t), + 15 * sizeof(int32_t)}; + + std::optional noData = JsonValue::Array{0}; + + std::vector>> expected{ + std::vector{3, 200}, + std::vector{0, 450, 200, 1, 4}, + std::vector{1, 3, 2}, + std::nullopt, + std::vector{1, 3, 4, 1}}; + checkVariableLengthArrayWithProperties( + data, + offsets, + PropertyComponentType::Uint32, + 5, + expected, + noData); + } + + SECTION("Array of int32_t with NoData and DefaultValue") { + // clang-format off + std::vector data{ + 3, 200, + 0, 450, 200, 1, 4, + 1, 3, 2, + 0, + 1, 3, 4, 1 + }; + // clang-format on + std::vector offsets{ + 0, + 2 * sizeof(int32_t), + 7 * sizeof(int32_t), + 10 * sizeof(int32_t), + 11 * sizeof(int32_t), + 15 * sizeof(int32_t)}; + + std::optional noData = JsonValue::Array{0}; + std::optional defaultValue = JsonValue::Array{1}; + + std::vector>> expected{ + std::vector{3, 200}, + std::vector{0, 450, 200, 1, 4}, + std::vector{1, 3, 2}, + std::vector{1}, + std::vector{1, 3, 4, 1}}; + checkVariableLengthArrayWithProperties( + data, + offsets, + PropertyComponentType::Uint32, + 5, + expected, + noData, + defaultValue); + } + + SECTION("Array of normalized uint8_t with NoData and DefaultValue") { + // clang-format off + std::vector data{ + 255, 0, + 0, 255, 128, + 64, + 255, 255 + }; + std::vector offsets{ + 0, 2, 5, 6, 8 + }; + // clang-format on + + std::optional noData = JsonValue::Array{255, 255}; + std::optional defaultValue = JsonValue::Array{-1.0}; + + std::vector>> expected{ + std::vector{1.0, 0.0}, + std::vector{0.0, 1.0, 128.0 / 255.0}, + std::vector{64.0 / 255}, + std::vector{-1.0}, + }; + + checkNormalizedVariableLengthArray( + data, + offsets, + PropertyComponentType::Uint32, + 4, + expected, + noData, + defaultValue); + } +} + +TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { + SECTION("Array of ivec2") { + // clang-format off + std::vector data{ + glm::ivec2(3, -2), glm::ivec2(20, 3), + glm::ivec2(0, 45), glm::ivec2(-10, 2), glm::ivec2(4, 4), glm::ivec2(1, -1), + glm::ivec2(3, 1), glm::ivec2(3, 2), glm::ivec2(0, -5), + glm::ivec2(-9, 10), glm::ivec2(8, -2) + }; + // clang-format on + std::vector offsets{ + 0, + 2 * sizeof(glm::ivec2), + 6 * sizeof(glm::ivec2), 9 * sizeof(glm::ivec2), 11 * sizeof(glm::ivec2)}; checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 4); } - SECTION("Variable-length array of dvec3") { + SECTION("Array of dvec3") { // clang-format off std::vector data{ glm::dvec3(-0.02, 2.0, 1.0), glm::dvec3(9.92, 9.0, -8.0), @@ -1995,7 +2766,7 @@ TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 5); } - SECTION("Variable-length array of u8vec4") { + SECTION("Array of u8vec4") { // clang-format off std::vector data{ glm::u8vec4(1, 2, 3, 4), glm::u8vec4(5, 6, 7, 8), @@ -2016,10 +2787,162 @@ TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 5); } + + SECTION("Array of normalized u8vec2") { + // clang-format off + std::vector data{ + glm::u8vec2(255, 0), glm::u8vec2(0, 64), + glm::u8vec2(0, 0), + glm::u8vec2(128, 255), glm::u8vec2(255, 255), glm::u8vec2(32, 64) + }; + // clang-format on + std::vector offsets{ + 0 * sizeof(glm::u8vec2), + 2 * sizeof(glm::u8vec2), + 3 * sizeof(glm::u8vec2), + 6 * sizeof(glm::u8vec2)}; + + std::vector>> expected{ + std::vector{ + glm::dvec2(1.0, 0.0), + glm::dvec2(0.0, 64.0 / 255.0)}, + std::vector{glm::dvec2(0.0, 0.0)}, + std::vector{ + glm::dvec2(128.0 / 255.0, 1.0), + glm::dvec2(1.0, 1.0), + glm::dvec2(32.0 / 255.0, 64.0 / 255.0)}, + }; + checkNormalizedVariableLengthArray( + data, + offsets, + PropertyComponentType::Uint32, + 3, + expected); + } + + SECTION("Array of ivec3 with NoData") { + // clang-format off + std::vector data{ + glm::ivec3(3, 200, 1), glm::ivec3(2, 4, 6), + glm::ivec3(-1, 0, -450), + glm::ivec3(200, 1, 4), glm::ivec3(1, 3, 2), glm::ivec3(0), + glm::ivec3(-1), + glm::ivec3(1, 3, 4), glm::ivec3(1, 0, 1) + }; + // clang-format on + std::vector offsets{ + 0, + 2 * sizeof(glm::ivec3), + 3 * sizeof(glm::ivec3), + 6 * sizeof(glm::ivec3), + 7 * sizeof(glm::ivec3), + 9 * sizeof(glm::ivec3)}; + + std::optional noData = JsonValue::Array{}; + noData->push_back(JsonValue::Array{-1, -1, -1}); + + std::vector>> expected{ + std::vector{glm::ivec3(3, 200, 1), glm::ivec3(2, 4, 6)}, + std::vector{glm::ivec3(-1, 0, -450)}, + std::vector{ + glm::ivec3(200, 1, 4), + glm::ivec3(1, 3, 2), + glm::ivec3(0)}, + std::nullopt, + std::vector{glm::ivec3(1, 3, 4), glm::ivec3(1, 0, 1)}}; + checkVariableLengthArrayWithProperties( + data, + offsets, + PropertyComponentType::Uint32, + 5, + expected, + noData); + } + + SECTION("Array of ivec3 with NoData and DefaultValue") { + // clang-format off + std::vector data{ + glm::ivec3(3, 200, 1), glm::ivec3(2, 4, 6), + glm::ivec3(-1, 0, -450), + glm::ivec3(200, 1, 4), glm::ivec3(1, 3, 2), glm::ivec3(0), + glm::ivec3(-1), + glm::ivec3(1, 3, 4), glm::ivec3(1, 0, 1) + }; + // clang-format on + std::vector offsets{ + 0, + 2 * sizeof(glm::ivec3), + 3 * sizeof(glm::ivec3), + 6 * sizeof(glm::ivec3), + 7 * sizeof(glm::ivec3), + 9 * sizeof(glm::ivec3)}; + + std::optional noData = JsonValue::Array{}; + noData->push_back(JsonValue::Array{-1, -1, -1}); + std::optional defaultValue = JsonValue::Array{}; + defaultValue->push_back(JsonValue::Array{0, 0, 0}); + + std::vector>> expected{ + std::vector{glm::ivec3(3, 200, 1), glm::ivec3(2, 4, 6)}, + std::vector{glm::ivec3(-1, 0, -450)}, + std::vector{ + glm::ivec3(200, 1, 4), + glm::ivec3(1, 3, 2), + glm::ivec3(0)}, + std::vector{glm::ivec3(0)}, + std::vector{glm::ivec3(1, 3, 4), glm::ivec3(1, 0, 1)}}; + checkVariableLengthArrayWithProperties( + data, + offsets, + PropertyComponentType::Uint32, + 5, + expected, + noData, + defaultValue); + } + + SECTION("Array of normalized u8vec2 with NoData and DefaultValue") { + // clang-format off + std::vector data{ + glm::u8vec2(255, 0), glm::u8vec2(0, 64), + glm::u8vec2(0, 0), + glm::u8vec2(128, 255), glm::u8vec2(255, 255), glm::u8vec2(32, 64) + }; + // clang-format on + std::vector offsets{ + 0 * sizeof(glm::u8vec2), + 2 * sizeof(glm::u8vec2), + 3 * sizeof(glm::u8vec2), + 6 * sizeof(glm::u8vec2)}; + + std::optional noData = JsonValue::Array{}; + noData->push_back(JsonValue::Array{0, 0}); + std::optional defaultValue = JsonValue::Array{}; + defaultValue->push_back(JsonValue::Array{-1.0, -1.0}); + + std::vector>> expected{ + std::vector{ + glm::dvec2(1.0, 0.0), + glm::dvec2(0.0, 64.0 / 255.0)}, + std::vector{glm::dvec2(-1.0)}, + std::vector{ + glm::dvec2(128.0 / 255.0, 1.0), + glm::dvec2(1.0, 1.0), + glm::dvec2(32.0 / 255.0, 64.0 / 255.0)}, + }; + checkNormalizedVariableLengthArray( + data, + offsets, + PropertyComponentType::Uint32, + 3, + expected, + noData, + defaultValue); + } } TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { - SECTION("Variable-length array of dmat2") { + SECTION("Array of dmat2") { // clang-format off std::vector data0{ glm::dmat2( @@ -2063,7 +2986,7 @@ TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 3); } - SECTION("Variable-length array of i16mat3x3") { + SECTION("Array of i16mat3x3") { // clang-format off std::vector data0{ glm::i16mat3x3( @@ -2112,7 +3035,7 @@ TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 3); } - SECTION("Variable-length array of u8mat4x4") { + SECTION("Array of u8mat4x4") { // clang-format off std::vector data0{ glm::u8mat4x4( @@ -2166,6 +3089,172 @@ TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 3); } + + SECTION("Array of normalized u8mat2x2") { + // clang-format off + std::vector data{ + glm::u8mat2x2(255), glm::u8mat2x2(64), + glm::u8mat2x2(0), + glm::u8mat2x2(128), glm::u8mat2x2(255), glm::u8mat2x2(32) + }; + // clang-format on + std::vector offsets{ + 0 * sizeof(glm::u8mat2x2), + 2 * sizeof(glm::u8mat2x2), + 3 * sizeof(glm::u8mat2x2), + 6 * sizeof(glm::u8mat2x2)}; + + std::vector>> expected{ + std::vector{glm::dmat2(1.0), glm::dmat2(64.0 / 255.0)}, + std::vector{glm::dmat2(0.0)}, + std::vector{ + glm::dmat2(128.0 / 255.0), + glm::dmat2(1.0), + glm::dmat2(32.0 / 255.0)}, + }; + checkNormalizedVariableLengthArray( + data, + offsets, + PropertyComponentType::Uint32, + 3, + expected); + } + + SECTION("Array of imat3x3 with NoData") { + // clang-format off + std::vector data{ + glm::imat3x3(3), glm::imat3x3(2), + glm::imat3x3(-1), + glm::imat3x3(200), glm::imat3x3(1), glm::imat3x3(0), + glm::imat3x3(-1), + glm::imat3x3(1), glm::imat3x3(24) + }; + // clang-format on + std::vector offsets{ + 0, + 2 * sizeof(glm::imat3x3), + 3 * sizeof(glm::imat3x3), + 6 * sizeof(glm::imat3x3), + 7 * sizeof(glm::imat3x3), + 9 * sizeof(glm::imat3x3)}; + + // clang-format off + std::optional noData = JsonValue::Array{}; + noData->push_back(JsonValue::Array{ + -1, 0, 0, + 0, -1, 0, + 0, 0, -1}); + // clang-format on + + std::vector>> expected{ + std::vector{glm::imat3x3(3), glm::imat3x3(2)}, + std::nullopt, + std::vector{ + glm::imat3x3(200), + glm::imat3x3(1), + glm::imat3x3(0)}, + std::nullopt, + std::vector{glm::imat3x3(1), glm::imat3x3(24)}}; + checkVariableLengthArrayWithProperties( + data, + offsets, + PropertyComponentType::Uint32, + 5, + expected, + noData); + } + + SECTION("Array of imat3x3 with NoData and DefaultValue") { + // clang-format off + std::vector data{ + glm::imat3x3(3), glm::imat3x3(2), + glm::imat3x3(-1), + glm::imat3x3(200), glm::imat3x3(1), glm::imat3x3(0), + glm::imat3x3(-1), + glm::imat3x3(1), glm::imat3x3(24) + }; + // clang-format on + std::vector offsets{ + 0, + 2 * sizeof(glm::imat3x3), + 3 * sizeof(glm::imat3x3), + 6 * sizeof(glm::imat3x3), + 7 * sizeof(glm::imat3x3), + 9 * sizeof(glm::imat3x3)}; + + // clang-format off + std::optional noData = JsonValue::Array{}; + noData->push_back(JsonValue::Array{ + -1, 0, 0, + 0, -1, 0, + 0, 0, -1}); + std::optional defaultValue = JsonValue::Array{}; + defaultValue->push_back(JsonValue::Array{ + 99, 0, 0, + 0, 99, 0, + 0, 0, 99}); + // clang-format on + + std::vector>> expected{ + std::vector{glm::imat3x3(3), glm::imat3x3(2)}, + std::vector{glm::imat3x3(99)}, + std::vector{ + glm::imat3x3(200), + glm::imat3x3(1), + glm::imat3x3(0)}, + std::vector{glm::imat3x3(99)}, + std::vector{glm::imat3x3(1), glm::imat3x3(24)}}; + checkVariableLengthArrayWithProperties( + data, + offsets, + PropertyComponentType::Uint32, + 5, + expected, + noData, + defaultValue); + } + + SECTION("Array of normalized u8mat2x2 with NoData and DefaultValue") { + // clang-format off + std::vector data{ + glm::u8mat2x2(255), glm::u8mat2x2(64), + glm::u8mat2x2(0), + glm::u8mat2x2(128), glm::u8mat2x2(255), glm::u8mat2x2(32) + }; + // clang-format on + std::vector offsets{ + 0 * sizeof(glm::u8mat2x2), + 2 * sizeof(glm::u8mat2x2), + 3 * sizeof(glm::u8mat2x2), + 6 * sizeof(glm::u8mat2x2)}; + + // clang-format off + std::optional noData = JsonValue::Array{}; + noData->push_back(JsonValue::Array{ + 0, 0, + 0, 0}); + std::optional defaultValue = JsonValue::Array{}; + defaultValue->push_back(JsonValue::Array{ + -1.0, 0.0, + 0.0, -1.0}); + // clang-format on + std::vector>> expected{ + std::vector{glm::dmat2(1.0), glm::dmat2(64.0 / 255.0)}, + std::vector{glm::dmat2(-1.0)}, + std::vector{ + glm::dmat2(128.0 / 255.0), + glm::dmat2(1.0), + glm::dmat2(32.0 / 255.0)}, + }; + checkNormalizedVariableLengthArray( + data, + offsets, + PropertyComponentType::Uint32, + 3, + expected, + noData, + defaultValue); + } } TEST_CASE("Check fixed-length array of string") { @@ -2213,35 +3302,155 @@ TEST_CASE("Check fixed-length array of string") { ¤tStringOffset, sizeof(uint32_t)); - PropertyTableProperty propertyTableProperty; - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::STRING; - classProperty.array = true; - classProperty.count = 3; + SECTION("Returns correct values") { + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + classProperty.count = 3; - PropertyTablePropertyView> property( - propertyTableProperty, - classProperty, - static_cast(stringCount / 3), - gsl::span(buffer.data(), buffer.size()), - gsl::span(), - gsl::span(stringOffsets.data(), stringOffsets.size()), - PropertyComponentType::None, - PropertyComponentType::Uint32); + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + static_cast(stringCount / 3), + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(stringOffsets.data(), stringOffsets.size()), + PropertyComponentType::None, + PropertyComponentType::Uint32); - REQUIRE(property.arrayCount() == classProperty.count); + REQUIRE(property.arrayCount() == classProperty.count); - size_t expectedIdx = 0; - for (int64_t i = 0; i < property.size(); ++i) { - PropertyArrayView values = property.getRaw(i); - for (int64_t j = 0; j < values.size(); ++j) { - std::string_view v = values[j]; - REQUIRE(v == strings[expectedIdx]); - ++expectedIdx; + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView values = property.getRaw(i); + auto maybeValues = property.get(i); + REQUIRE(maybeValues); + + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == strings[expectedIdx]); + REQUIRE((*maybeValues)[j] == strings[expectedIdx]); + ++expectedIdx; + } } + + REQUIRE(expectedIdx == stringCount); } - REQUIRE(expectedIdx == stringCount); + SECTION("Uses NoData value") { + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + classProperty.count = 3; + classProperty.noData = {"Test 1", "Test 2", "Test 3"}; + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + static_cast(stringCount / 3), + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(stringOffsets.data(), stringOffsets.size()), + PropertyComponentType::None, + PropertyComponentType::Uint32); + + REQUIRE(property.arrayCount() == classProperty.count); + + std::vector>> expected{ + std::nullopt, + std::vector{"Test 4", "Test 5", "Test 6"}, + std::vector{ + "This is a fine test", + "What's going on", + "Good morning"}}; + + // Check raw values first + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView values = property.getRaw(i); + for (int64_t j = 0; j < values.size(); ++j) { + std::string_view v = values[j]; + REQUIRE(v == strings[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == stringCount); + + // Check values with properties + for (int64_t i = 0; i < property.size(); ++i) { + auto maybeValues = property.get(i); + if (!maybeValues) { + REQUIRE(!expected[static_cast(i)]); + continue; + } + + auto values = *maybeValues; + auto expectedValues = *expected[static_cast(i)]; + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == expectedValues[j]); + } + } + } + + SECTION("Uses NoData and DefaultValue") { + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + classProperty.count = 3; + classProperty.noData = {"Test 1", "Test 2", "Test 3"}; + classProperty.defaultProperty = {"Default 1", "Default 2", "Default 3"}; + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + static_cast(stringCount / 3), + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(stringOffsets.data(), stringOffsets.size()), + PropertyComponentType::None, + PropertyComponentType::Uint32); + + REQUIRE(property.arrayCount() == classProperty.count); + + std::vector>> expected{ + std::vector{"Default 1", "Default 2", "Default 3"}, + std::vector{"Test 4", "Test 5", "Test 6"}, + std::vector{ + "This is a fine test", + "What's going on", + "Good morning"}}; + + // Check raw values first + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView values = property.getRaw(i); + for (int64_t j = 0; j < values.size(); ++j) { + std::string_view v = values[j]; + REQUIRE(v == strings[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == stringCount); + + // Check values with properties + for (int64_t i = 0; i < property.size(); ++i) { + auto maybeValues = property.get(i); + if (!maybeValues) { + REQUIRE(!expected[static_cast(i)]); + continue; + } + + auto values = *maybeValues; + auto expectedValues = *expected[static_cast(i)]; + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == expectedValues[j]); + } + } + } } TEST_CASE("Check variable-length string array PropertyTablePropertyView") { @@ -2250,13 +3459,15 @@ TEST_CASE("Check variable-length string array PropertyTablePropertyView") { 0, 4 * sizeof(uint32_t), 7 * sizeof(uint32_t), - 11 * sizeof(uint32_t) + 8 * sizeof(uint32_t), + 12 * sizeof(uint32_t) }; std::vector strings{ "Test 1", "Test 2", "Test 3", "Test 4", "Test 5", "Test 6", "Test 7", - "test 8", "Test 9", "Test 10", "Test 11" + "Null", + "Test 8", "Test 9", "Test 10", "Test 11" }; // clang-format on @@ -2292,36 +3503,162 @@ TEST_CASE("Check variable-length string array PropertyTablePropertyView") { ¤tOffset, sizeof(uint32_t)); - PropertyTableProperty propertyTableProperty; - ClassProperty classProperty; - classProperty.type = ClassProperty::Type::STRING; - classProperty.array = true; + SECTION("Returns correct values") { + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; - PropertyTablePropertyView> property( - propertyTableProperty, - classProperty, - 3, - gsl::span(buffer.data(), buffer.size()), - gsl::span( - reinterpret_cast(arrayOffsets.data()), - arrayOffsets.size() * sizeof(uint32_t)), - gsl::span(stringOffsets.data(), stringOffsets.size()), - PropertyComponentType::Uint32, - PropertyComponentType::Uint32); + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + 4, + gsl::span(buffer.data(), buffer.size()), + gsl::span( + reinterpret_cast(arrayOffsets.data()), + arrayOffsets.size() * sizeof(uint32_t)), + gsl::span(stringOffsets.data(), stringOffsets.size()), + PropertyComponentType::Uint32, + PropertyComponentType::Uint32); - REQUIRE(property.arrayCount() == 0); + REQUIRE(property.arrayCount() == 0); - size_t expectedIdx = 0; - for (int64_t i = 0; i < property.size(); ++i) { - PropertyArrayView values = property.getRaw(i); - for (int64_t j = 0; j < values.size(); ++j) { - std::string_view v = values[j]; - REQUIRE(v == strings[expectedIdx]); - ++expectedIdx; + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView values = property.getRaw(i); + auto maybeValues = property.get(i); + REQUIRE(maybeValues); + + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == strings[expectedIdx]); + REQUIRE((*maybeValues)[j] == strings[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == stringCount); + } + + SECTION("Uses NoData Value") { + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + classProperty.noData = JsonValue::Array{"Null"}; + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + 4, + gsl::span(buffer.data(), buffer.size()), + gsl::span( + reinterpret_cast(arrayOffsets.data()), + arrayOffsets.size() * sizeof(uint32_t)), + gsl::span(stringOffsets.data(), stringOffsets.size()), + PropertyComponentType::Uint32, + PropertyComponentType::Uint32); + + REQUIRE(property.arrayCount() == 0); + + std::vector>> expected{ + std::vector{"Test 1", "Test 2", "Test 3", "Test 4"}, + std::vector{"Test 5", "Test 6", "Test 7"}, + std::nullopt, + std::vector{ + "Test 8", + "Test 9", + "Test 10", + "Test 11"}}; + + // Check raw values first + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView values = property.getRaw(i); + for (int64_t j = 0; j < values.size(); ++j) { + std::string_view v = values[j]; + REQUIRE(v == strings[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == stringCount); + + // Check values with properties + for (int64_t i = 0; i < property.size(); ++i) { + auto maybeValues = property.get(i); + if (!maybeValues) { + REQUIRE(!expected[static_cast(i)]); + continue; + } + + auto values = *maybeValues; + auto expectedValues = *expected[static_cast(i)]; + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == expectedValues[j]); + } } } - REQUIRE(expectedIdx == stringCount); + SECTION("Uses NoData and DefaultValue") { + PropertyTableProperty propertyTableProperty; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::STRING; + classProperty.array = true; + classProperty.noData = JsonValue::Array{"Null"}; + classProperty.defaultProperty = JsonValue::Array{"Default"}; + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + 4, + gsl::span(buffer.data(), buffer.size()), + gsl::span( + reinterpret_cast(arrayOffsets.data()), + arrayOffsets.size() * sizeof(uint32_t)), + gsl::span(stringOffsets.data(), stringOffsets.size()), + PropertyComponentType::Uint32, + PropertyComponentType::Uint32); + + REQUIRE(property.arrayCount() == 0); + + std::vector>> expected{ + std::vector{"Test 1", "Test 2", "Test 3", "Test 4"}, + std::vector{"Test 5", "Test 6", "Test 7"}, + std::vector{"Default"}, + std::vector{ + "Test 8", + "Test 9", + "Test 10", + "Test 11"}}; + + // Check raw values first + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView values = property.getRaw(i); + for (int64_t j = 0; j < values.size(); ++j) { + std::string_view v = values[j]; + REQUIRE(v == strings[expectedIdx]); + ++expectedIdx; + } + } + + REQUIRE(expectedIdx == stringCount); + + // Check values with properties + for (int64_t i = 0; i < property.size(); ++i) { + auto maybeValues = property.get(i); + if (!maybeValues) { + REQUIRE(!expected[static_cast(i)]); + continue; + } + + auto values = *maybeValues; + auto expectedValues = *expected[static_cast(i)]; + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE(values[j] == expectedValues[j]); + } + } + } } TEST_CASE("Check fixed-length boolean array PropertyTablePropertyView") { From 53bc30391a082b1d83b54dbb31e8f6428ad2ed60 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 24 Aug 2023 10:55:43 -0400 Subject: [PATCH 090/121] Integrate normalization with PropertyTableView --- CHANGES.md | 2 + .../CesiumGltf/PropertyTablePropertyView.h | 20 +- .../PropertyTablePropertyViewType.h | 285 +++++++++ .../include/CesiumGltf/PropertyTableView.h | 548 +++++++++++------- .../CesiumGltf/PropertyTexturePropertyView.h | 70 +-- .../include/CesiumGltf/PropertyTextureView.h | 11 +- CesiumGltf/include/CesiumGltf/PropertyView.h | 2 +- CesiumGltf/src/PropertyTableView.cpp | 84 +++ CesiumGltf/src/PropertyTextureView.cpp | 8 +- .../test/TestPropertyTablePropertyView.cpp | 8 +- CesiumGltf/test/TestPropertyTableView.cpp | 109 ++-- 11 files changed, 802 insertions(+), 345 deletions(-) create mode 100644 CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewType.h diff --git a/CHANGES.md b/CHANGES.md index 91672f6d1..178e949bf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ - 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`. +- Replaced `MetadataPropertyView` with `PropertyTablePropertyView`, which is a templated view of a `PropertyTableProperty` in `EXT_structural_metadata`. This takes two template parameters: a typename `T` , and a `bool` indicating whether or not the values are normalized. - Renamed `MetadataArrayView` to `PropertyArrayView`. - Replaced `FeatureTextureView` with `PropertyTextureView`, which views a `PropertyTexture` in `EXT_structural_metadata`. - Renamed `FeatureTextureViewStatus` to `PropertyTextureViewStatus`. @@ -24,6 +25,7 @@ - Added `PropertyTableViewStatus` to indicate whether a `PropertyTableView` is valid. - Added `PropertyComponentType` to reflect the values of `componentType` in a `ClassProperty` from `EXT_structural_metadata`. +- Added `PropertyView`, which acts as a base class for all metadata property views. This takes two template parameters: a typename `T` , and a `bool` indicating whether or not the values are normalized. ### v0.25.0 - 2023-06-01 diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index a071ee15e..4c1c42cae 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -148,6 +148,10 @@ int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { } } // namespace +/** + * @brief A view on the data of the {@link PropertyTableProperty} that is created + * by a {@link PropertyTableView}. + */ template class PropertyTablePropertyView; @@ -166,14 +170,14 @@ class PropertyTablePropertyView; * one of the aforementioned types. */ template -class PropertyTablePropertyView - : public PropertyView { +class PropertyTablePropertyView + : public PropertyView { public: /** * @brief Constructs an invalid instance for a non-existent property. */ PropertyTablePropertyView() - : PropertyView(), + : PropertyView(), _values{}, _size{0}, _arrayOffsets{}, @@ -189,7 +193,7 @@ class PropertyTablePropertyView * @param status The value of {@link PropertyTablePropertyViewStatus} indicating the error with the property. */ PropertyTablePropertyView(PropertyViewStatusType status) - : PropertyView(status), + : PropertyView(status), _values{}, _size{0}, _arrayOffsets{}, @@ -204,7 +208,8 @@ class PropertyTablePropertyView } /** - * @brief Construct an instance pointing to non-array data specified by a {@link PropertyTableProperty}. + * @brief Construct an instance pointing to data specified by a {@link PropertyTableProperty}. + * Used for non-array or fixed-length array data. * * @param property The {@link PropertyTableProperty} * @param classProperty The {@link ClassProperty} this property conforms to. @@ -230,7 +235,6 @@ class PropertyTablePropertyView /** * @brief Construct an instance pointing to the data specified by a {@link PropertyTableProperty}. * - * * @param property The {@link PropertyTableProperty} * @param classProperty The {@link ClassProperty} this property conforms to. * @param size The number of elements in the property table specified by {@link PropertyTable::count} @@ -516,7 +520,8 @@ class PropertyTablePropertyView } /** - * @brief Construct an instance pointing to non-array data specified by a {@link PropertyTableProperty}. + * @brief Construct an instance pointing to data specified by a {@link PropertyTableProperty}. + * Used for non-array or fixed-length array data. * * @param property The {@link PropertyTableProperty} * @param classProperty The {@link ClassProperty} this property conforms to. @@ -562,6 +567,7 @@ class PropertyTablePropertyView _arrayOffsetType{arrayOffsetType}, _arrayOffsetTypeSize{getOffsetTypeSize(arrayOffsetType)} {} + /** * @brief Get the value of an element of the {@link PropertyTable}, * with normalization and other value transforms applied. In other words, the diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewType.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewType.h new file mode 100644 index 000000000..e879c1973 --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewType.h @@ -0,0 +1,285 @@ +#pragma once + +#include "CesiumGltf/PropertyTablePropertyView.h" + +#include + +#include +#include +#include +#include +#include + +namespace CesiumGltf { + +#define View PropertyTablePropertyView + +/** + * @brief An alias for all of the potential types of + * {@link PropertyTablePropertyView} possible, with and without normalization. + * Can be useful for applications that want to implement abstract + * representations of PropertyTablePropertyView, without the mess of templated + * types. + */ +typedef std::variant< + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View>, + View>, + View>, + View>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>>, + View>>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>>, + View>>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>>, + View>>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>>, + View>>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>>, + View>>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, false>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>>, + View>>> + PropertyTablePropertyViewType; + +#undef View + +} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h index 1f5fb9a31..4688b9e4d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -10,6 +10,7 @@ #include namespace CesiumGltf { + /** * @brief Indicates the status of a property table view. * @@ -107,21 +108,21 @@ class PropertyTableView { * @return A {@link PropertyTablePropertyView} of the property. If no valid property is * found, the property view will be invalid. */ - template - PropertyTablePropertyView + template + PropertyTablePropertyView getPropertyView(const std::string& propertyName) const { if (this->size() <= 0) { - return PropertyTablePropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); } const ClassProperty* pClassProperty = getClassProperty(propertyName); if (!pClassProperty) { - return PropertyTablePropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorNonexistentProperty); } - return getPropertyViewImpl(propertyName, *pClassProperty); + return getPropertyViewImpl(propertyName, *pClassProperty); } /** @@ -170,47 +171,121 @@ class PropertyTableView { convertStringToPropertyComponentType(*pClassProperty->componentType); } + bool normalized = pClassProperty->normalized; + if (normalized) { + switch (componentType) { + case PropertyComponentType::Int8: + case PropertyComponentType::Uint8: + case PropertyComponentType::Int16: + case PropertyComponentType::Uint16: + case PropertyComponentType::Int32: + case PropertyComponentType::Uint32: + case PropertyComponentType::Int64: + case PropertyComponentType::Uint64: + break; + default: + callback( + propertyName, + PropertyTablePropertyView( + PropertyTablePropertyViewStatus::ErrorInvalidNormalization)); + return; + } + } + if (pClassProperty->array) { - getArrayPropertyViewImpl( - propertyName, - *pClassProperty, - type, - componentType, - std::forward(callback)); - } else if (type == PropertyType::Scalar) { - getScalarPropertyViewImpl( - propertyName, - *pClassProperty, - componentType, - std::forward(callback)); - } else if (isPropertyTypeVecN(type)) { - getVecNPropertyViewImpl( - propertyName, - *pClassProperty, - type, - componentType, - std::forward(callback)); - } else if (isPropertyTypeMatN(type)) { - getMatNPropertyViewImpl( - propertyName, - *pClassProperty, - type, - componentType, - std::forward(callback)); - } else if (type == PropertyType::String) { - callback( - propertyName, - getPropertyViewImpl(propertyName, *pClassProperty)); - } else if (type == PropertyType::Boolean) { + if (normalized) { + getArrayPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } else { + getArrayPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } + return; + } + + if (type == PropertyType::Scalar) { + if (normalized) { + getScalarPropertyViewImpl( + propertyName, + *pClassProperty, + componentType, + std::forward(callback)); + } else { + getScalarPropertyViewImpl( + propertyName, + *pClassProperty, + componentType, + std::forward(callback)); + } + return; + } + + if (isPropertyTypeVecN(type)) { + if (normalized) { + getVecNPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } else { + getVecNPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } + return; + } + + if (isPropertyTypeMatN(type)) { + if (normalized) { + getMatNPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } else { + getMatNPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } + return; + } + + if (type == PropertyType::String) { callback( propertyName, - getPropertyViewImpl(propertyName, *pClassProperty)); - } else { + getPropertyViewImpl( + propertyName, + *pClassProperty)); + return; + } + + if (type == PropertyType::Boolean) { callback( propertyName, - PropertyTablePropertyView( - PropertyTablePropertyViewStatus::ErrorTypeMismatch)); + getPropertyViewImpl(propertyName, *pClassProperty)); + return; } + + callback( + propertyName, + PropertyTablePropertyView( + PropertyTablePropertyViewStatus::ErrorTypeMismatch)); } /** @@ -220,9 +295,9 @@ class PropertyTableView { * * This method will validate the EXT_structural_metadata format to ensure * {@link PropertyTablePropertyView} retrieves the correct data. T must be one of the - * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, - * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar - * types, a glm matN composed of one of the scalar types, bool, + * following: a scalar (uint8_t, int8_t, uint16_t, int16_t, uint32_t, + * int32_t, uint64_t, int64_t, float, double), a glm vecN composed of one of + * the scalar types, a glm matN composed of one of the scalar types, bool, * std::string_view, or {@link PropertyArrayView} with T as one of the * aforementioned types. If the property is invalid, an empty * {@link PropertyTablePropertyView} with an error status code will be passed to the @@ -240,7 +315,7 @@ class PropertyTableView { } private: - template + template void getScalarArrayPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -250,70 +325,70 @@ class PropertyTableView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Int32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Int64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, false>( propertyName, classProperty)); break; case PropertyComponentType::Float64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, false>( propertyName, classProperty)); break; @@ -326,7 +401,7 @@ class PropertyTableView { } } - template + template void getVecNArrayPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -336,70 +411,70 @@ class PropertyTableView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Int32: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Int64: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Uint64: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>, false>( propertyName, classProperty)); break; case PropertyComponentType::Float64: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>, false>( propertyName, classProperty)); break; @@ -412,7 +487,7 @@ class PropertyTableView { } } - template + template void getVecNArrayPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -422,21 +497,21 @@ class PropertyTableView { glm::length_t N = getDimensionsFromPropertyType(type); switch (N) { case 2: - getVecNArrayPropertyViewImpl( + getVecNArrayPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); break; case 3: - getVecNArrayPropertyViewImpl( + getVecNArrayPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); break; case 4: - getVecNArrayPropertyViewImpl( + getVecNArrayPropertyViewImpl( propertyName, classProperty, componentType, @@ -451,7 +526,7 @@ class PropertyTableView { } } - template + template void getMatNArrayPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -461,70 +536,70 @@ class PropertyTableView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Int32: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Int64: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Uint64: callback( propertyName, - getPropertyViewImpl>>( - propertyName, - classProperty)); + getPropertyViewImpl< + PropertyArrayView>, + Normalized>(propertyName, classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>, false>( propertyName, classProperty)); break; case PropertyComponentType::Float64: callback( propertyName, - getPropertyViewImpl>>( + getPropertyViewImpl>, false>( propertyName, classProperty)); break; @@ -537,7 +612,7 @@ class PropertyTableView { } } - template + template void getMatNArrayPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -547,21 +622,21 @@ class PropertyTableView { const glm::length_t N = getDimensionsFromPropertyType(type); switch (N) { case 2: - getMatNArrayPropertyViewImpl( + getMatNArrayPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); break; case 3: - getMatNArrayPropertyViewImpl( + getMatNArrayPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); break; case 4: - getMatNArrayPropertyViewImpl( + getMatNArrayPropertyViewImpl( propertyName, classProperty, componentType, @@ -576,7 +651,7 @@ class PropertyTableView { } } - template + template void getArrayPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -584,20 +659,20 @@ class PropertyTableView { PropertyComponentType componentType, Callback&& callback) const { if (type == PropertyType::Scalar) { - getScalarArrayPropertyViewImpl( + getScalarArrayPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); } else if (isPropertyTypeVecN(type)) { - getVecNArrayPropertyViewImpl( + getVecNArrayPropertyViewImpl( propertyName, classProperty, type, componentType, std::forward(callback)); } else if (isPropertyTypeMatN(type)) { - getMatNArrayPropertyViewImpl( + getMatNArrayPropertyViewImpl( propertyName, classProperty, type, @@ -606,14 +681,14 @@ class PropertyTableView { } else if (type == PropertyType::Boolean) { callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, false>( propertyName, classProperty)); } else if (type == PropertyType::String) { callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, false>( propertyName, classProperty)); } else { @@ -624,7 +699,7 @@ class PropertyTableView { } } - template + template void getVecNPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -635,68 +710,70 @@ class PropertyTableView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Int32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Int64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, - getPropertyViewImpl>(propertyName, classProperty)); + getPropertyViewImpl, false>( + propertyName, + classProperty)); break; case PropertyComponentType::Float64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, false>( propertyName, classProperty)); break; @@ -709,7 +786,7 @@ class PropertyTableView { } } - template + template void getVecNPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -719,21 +796,21 @@ class PropertyTableView { const glm::length_t N = getDimensionsFromPropertyType(type); switch (N) { case 2: - getVecNPropertyViewImpl( + getVecNPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); break; case 3: - getVecNPropertyViewImpl( + getVecNPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); break; case 4: - getVecNPropertyViewImpl( + getVecNPropertyViewImpl( propertyName, classProperty, componentType, @@ -748,7 +825,7 @@ class PropertyTableView { } } - template + template void getMatNPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -758,70 +835,70 @@ class PropertyTableView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Int32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Int64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, false>( propertyName, classProperty)); break; case PropertyComponentType::Float64: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, false>( propertyName, classProperty)); break; @@ -834,7 +911,7 @@ class PropertyTableView { } } - template + template void getMatNPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -844,21 +921,21 @@ class PropertyTableView { glm::length_t N = getDimensionsFromPropertyType(type); switch (N) { case 2: - getMatNPropertyViewImpl( + getMatNPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); break; case 3: - getMatNPropertyViewImpl( + getMatNPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); break; case 4: - getMatNPropertyViewImpl( + getMatNPropertyViewImpl( propertyName, classProperty, componentType, @@ -873,7 +950,7 @@ class PropertyTableView { } } - template + template void getScalarPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -883,52 +960,66 @@ class PropertyTableView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl(propertyName, classProperty)); return; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); return; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); return; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); break; case PropertyComponentType::Int32: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); break; case PropertyComponentType::Int64: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); break; case PropertyComponentType::Uint64: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl(propertyName, classProperty)); break; case PropertyComponentType::Float64: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl(propertyName, classProperty)); break; default: callback( @@ -939,14 +1030,14 @@ class PropertyTableView { } } - template - PropertyTablePropertyView getPropertyViewImpl( + template + PropertyTablePropertyView getPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty) const { auto propertyTablePropertyIter = _pPropertyTable->properties.find(propertyName); if (propertyTablePropertyIter == _pPropertyTable->properties.end()) { - return PropertyTablePropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorNonexistentProperty); } @@ -954,7 +1045,7 @@ class PropertyTableView { propertyTablePropertyIter->second; if constexpr (IsMetadataNumeric::value || IsMetadataBoolean::value) { - return getNumericOrBooleanPropertyValues( + return getNumericOrBooleanPropertyValues( classProperty, propertyTableProperty); } @@ -963,49 +1054,58 @@ class PropertyTableView { return getStringPropertyValues(classProperty, propertyTableProperty); } - if constexpr ( - IsMetadataNumericArray::value || IsMetadataBooleanArray::value) { - return getPrimitiveArrayPropertyValues< - typename MetadataArrayType::type>( + if constexpr (IsMetadataBooleanArray::value) { + return getBooleanArrayPropertyValues( classProperty, propertyTableProperty); } + if constexpr (IsMetadataNumericArray::value) { + return getNumericArrayPropertyValues< + typename MetadataArrayType::type, + Normalized>(classProperty, propertyTableProperty); + } + if constexpr (IsMetadataStringArray::value) { return getStringArrayPropertyValues(classProperty, propertyTableProperty); } } - template - PropertyTablePropertyView getNumericOrBooleanPropertyValues( + template + PropertyTablePropertyView getNumericOrBooleanPropertyValues( const ClassProperty& classProperty, const PropertyTableProperty& propertyTableProperty) const { if (classProperty.array) { - return PropertyTablePropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { - return PropertyTablePropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorTypeMismatch); } const PropertyComponentType componentType = convertStringToPropertyComponentType( classProperty.componentType.value_or("")); if (TypeToPropertyType::component != componentType) { - return PropertyTablePropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } + if (classProperty.normalized != Normalized) { + return PropertyTablePropertyView( + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + gsl::span values; const auto status = getBufferSafe(propertyTableProperty.values, values); if (status != PropertyTablePropertyViewStatus::Valid) { - return PropertyTablePropertyView(status); + return PropertyTablePropertyView(status); } if (values.size() % sizeof(T) != 0) { - return PropertyTablePropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize); } @@ -1019,12 +1119,12 @@ class PropertyTableView { } if (values.size() < maxRequiredBytes) { - return PropertyTablePropertyView( + return PropertyTablePropertyView( PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } - return PropertyTablePropertyView( + return PropertyTablePropertyView( propertyTableProperty, classProperty, _pPropertyTable->count, @@ -1035,19 +1135,24 @@ class PropertyTableView { const ClassProperty& classProperty, const PropertyTableProperty& propertyTableProperty) const; - template - PropertyTablePropertyView> - getPrimitiveArrayPropertyValues( + PropertyTablePropertyView> + getBooleanArrayPropertyValues( + const ClassProperty& classProperty, + const PropertyTableProperty& propertyTableProperty) const; + + template + PropertyTablePropertyView, Normalized> + getNumericArrayPropertyValues( const ClassProperty& classProperty, const PropertyTableProperty& propertyTableProperty) const { if (!classProperty.array) { - return PropertyTablePropertyView>( + return PropertyTablePropertyView, Normalized>( PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { - return PropertyTablePropertyView>( + return PropertyTablePropertyView, Normalized>( PropertyTablePropertyViewStatus::ErrorTypeMismatch); } @@ -1055,63 +1160,57 @@ class PropertyTableView { convertStringToPropertyComponentType( classProperty.componentType.value_or("")); if (TypeToPropertyType::component != componentType) { - return PropertyTablePropertyView>( + return PropertyTablePropertyView, Normalized>( PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } + if (classProperty.normalized != Normalized) { + return PropertyTablePropertyView, Normalized>( + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + gsl::span values; auto status = getBufferSafe(propertyTableProperty.values, values); if (status != PropertyTablePropertyViewStatus::Valid) { - return PropertyTablePropertyView>(status); + return PropertyTablePropertyView, Normalized>( + status); } if (values.size() % sizeof(T) != 0) { - return PropertyTablePropertyView>( + return PropertyTablePropertyView, Normalized>( PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize); } const int64_t fixedLengthArrayCount = classProperty.count.value_or(0); if (fixedLengthArrayCount > 0 && propertyTableProperty.arrayOffsets >= 0) { - return PropertyTablePropertyView>( + return PropertyTablePropertyView, Normalized>( PropertyTablePropertyViewStatus:: ErrorArrayCountAndOffsetBufferCoexist); } if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { - return PropertyTablePropertyView>( + return PropertyTablePropertyView, Normalized>( PropertyTablePropertyViewStatus:: ErrorArrayCountAndOffsetBufferDontExist); } // Handle fixed-length arrays if (fixedLengthArrayCount > 0) { - size_t maxRequiredBytes = 0; - if constexpr (IsMetadataBoolean::value) { - maxRequiredBytes = static_cast(glm::ceil( - static_cast( - _pPropertyTable->count * fixedLengthArrayCount) / - 8.0)); - } else { - maxRequiredBytes = static_cast( - _pPropertyTable->count * fixedLengthArrayCount * sizeof(T)); - } + size_t maxRequiredBytes = maxRequiredBytes = static_cast( + _pPropertyTable->count * fixedLengthArrayCount * sizeof(T)); if (values.size() < maxRequiredBytes) { - return PropertyTablePropertyView>( + return PropertyTablePropertyView, Normalized>( PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } - return PropertyTablePropertyView>( + return PropertyTablePropertyView, Normalized>( propertyTableProperty, classProperty, static_cast(_pPropertyTable->count), - values, - gsl::span(), - gsl::span(), - PropertyComponentType::None, - PropertyComponentType::None); + values); } // Handle variable-length arrays @@ -1119,11 +1218,11 @@ class PropertyTableView { convertArrayOffsetTypeStringToPropertyComponentType( propertyTableProperty.arrayOffsetType); if (arrayOffsetType == PropertyComponentType::None) { - return PropertyTablePropertyView>( + return PropertyTablePropertyView, Normalized>( PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); } - constexpr bool checkBitsSize = IsMetadataBoolean::value; + constexpr bool checkBitsSize = false; gsl::span arrayOffsets; status = getArrayOffsetsBufferSafe( propertyTableProperty.arrayOffsets, @@ -1133,18 +1232,29 @@ class PropertyTableView { checkBitsSize, arrayOffsets); if (status != PropertyTablePropertyViewStatus::Valid) { - return PropertyTablePropertyView>(status); + return PropertyTablePropertyView, Normalized>( + status); } - return PropertyTablePropertyView>( - propertyTableProperty, - classProperty, - static_cast(_pPropertyTable->count), - values, - arrayOffsets, - gsl::span(), - arrayOffsetType, - PropertyComponentType::None); + if constexpr (Normalized) { + return PropertyTablePropertyView, true>( + propertyTableProperty, + classProperty, + static_cast(_pPropertyTable->count), + values, + arrayOffsets, + arrayOffsetType); + } else { + return PropertyTablePropertyView, false>( + propertyTableProperty, + classProperty, + static_cast(_pPropertyTable->count), + values, + arrayOffsets, + gsl::span(), + arrayOffsetType, + PropertyComponentType::None); + } } PropertyTablePropertyView> diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index cf5c16aaa..731627a2d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -20,73 +20,45 @@ namespace CesiumGltf { * corresponding property texture property. This enumeration provides the * reason. */ -enum class PropertyTexturePropertyViewStatus { - /** - * @brief This property view is valid and ready to use. - */ - Valid, - +class PropertyTexturePropertyViewStatus : public PropertyViewStatus { +public: /** * @brief This property view was initialized from an invalid * {@link PropertyTexture}. */ - ErrorInvalidPropertyTexture, - - /** - * @brief This property view is trying to view a property that does not exist - * in the {@link PropertyTexture}. - */ - ErrorNonexistentProperty, + static const int ErrorInvalidPropertyTexture = 12; /** * @brief This property view is associated with a {@link ClassProperty} of an * unsupported type. */ - ErrorUnsupportedProperty, - - /** - * @brief This property view's type does not match what is - * specified in {@link ClassProperty::type}. - */ - ErrorTypeMismatch, - - /** - * @brief This property view's component type does not match what - * is specified in {@link ClassProperty::componentType}. - */ - ErrorComponentTypeMismatch, - - /** - * @brief This property view differs from what is specified in - * {@link ClassProperty::array}. - */ - ErrorArrayTypeMismatch, + static const int ErrorUnsupportedProperty = 13; /** * @brief This property view does not have a valid texture index. */ - ErrorInvalidTexture, + static const int ErrorInvalidTexture = 14; /** * @brief This property view does not have a valid sampler index. */ - ErrorInvalidSampler, + static const int ErrorInvalidSampler = 15; /** * @brief This property view does not have a valid image index. */ - ErrorInvalidImage, + static const int ErrorInvalidImage = 16; /** * @brief This property is viewing an empty image. */ - ErrorEmptyImage, + static const int ErrorEmptyImage = 17; /** * @brief This property uses an image with multi-byte channels. Only * single-byte channels are supported. */ - ErrorInvalidBytesPerChannel, + static const int ErrorInvalidBytesPerChannel = 18; /** * @brief The channels of this property texture property are invalid. @@ -95,15 +67,15 @@ enum class PropertyTexturePropertyViewStatus { * more than four channels can be defined for specialized texture * formats, this implementation only supports four channels max. */ - ErrorInvalidChannels, + static const int ErrorInvalidChannels = 19; /** - * @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. + * @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. */ - ErrorChannelsAndTypeMismatch, + static const int ErrorChannelsAndTypeMismatch = 20; }; /** @@ -129,9 +101,9 @@ template class PropertyTexturePropertyView { /** * @brief Constructs an invalid instance for an erroneous property. * - * @param status The {@link PropertyTexturePropertyViewStatus} indicating the error with the property. + * @param status The code from {@link PropertyTexturePropertyViewStatus} indicating the error with the property. */ - PropertyTexturePropertyView(PropertyTexturePropertyViewStatus status) noexcept + PropertyTexturePropertyView(PropertyViewStatusType status) noexcept : _status(status), _pSampler(nullptr), _pImage(nullptr), @@ -145,7 +117,7 @@ template class PropertyTexturePropertyView { } /** - * @brief Construct a valid view of the data specified by a {@link PropertyTextureProperty}. + * @brief Construct a view of the data specified by a {@link PropertyTextureProperty}. * * @param pSampler A pointer to the sampler used by the property. * @param pImage A pointer to the image used by the property. @@ -248,9 +220,7 @@ template class PropertyTexturePropertyView { * * If invalid, this view cannot be sampled. */ - PropertyTexturePropertyViewStatus status() const noexcept { - return this->_status; - } + PropertyViewStatusType status() const noexcept { return this->_status; } /** * @brief Get the texture coordinate set index for this property. @@ -445,7 +415,7 @@ template class PropertyTexturePropertyView { return std::clamp(v, 0.0, 1.0); } - PropertyTexturePropertyViewStatus _status; + PropertyViewStatusType _status; const Sampler* _pSampler; const ImageCesium* _pImage; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index eedde43e9..86f213af0 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -382,6 +382,7 @@ class PropertyTextureView { classProperty)); break; } + [[fallthrough]]; case PropertyComponentType::Uint16: if constexpr (N == 2) { callback( @@ -391,6 +392,7 @@ class PropertyTextureView { classProperty)); break; } + [[fallthrough]]; default: callback( propertyName, @@ -593,18 +595,17 @@ class PropertyTextureView { classProperty.normalized); } - PropertyTexturePropertyViewStatus getTextureSafe( + PropertyViewStatusType getTextureSafe( const int32_t textureIndex, int32_t& samplerIndex, int32_t& imageIndex) const noexcept; - PropertyTexturePropertyViewStatus + PropertyViewStatusType checkSampler(const int32_t samplerIndex) const noexcept; - PropertyTexturePropertyViewStatus - checkImage(const int32_t imageIndex) const noexcept; + PropertyViewStatusType checkImage(const int32_t imageIndex) const noexcept; - PropertyTexturePropertyViewStatus checkChannels( + PropertyViewStatusType checkChannels( const std::vector& channels, const ImageCesium& image) const noexcept; diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 4beb9aebf..804992f64 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -1196,7 +1196,7 @@ template <> class PropertyView { * property. */ template -class PropertyView> { +class PropertyView, false> { public: /** * @brief Constructs an empty property instance. diff --git a/CesiumGltf/src/PropertyTableView.cpp b/CesiumGltf/src/PropertyTableView.cpp index 5ba0af589..e26b53bc4 100644 --- a/CesiumGltf/src/PropertyTableView.cpp +++ b/CesiumGltf/src/PropertyTableView.cpp @@ -326,6 +326,90 @@ PropertyTableView::getStringPropertyValues( offsetType); } +PropertyTablePropertyView> +PropertyTableView::getBooleanArrayPropertyValues( + const ClassProperty& classProperty, + const PropertyTableProperty& propertyTableProperty) const { + if (!classProperty.array) { + return PropertyTablePropertyView>( + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + if (classProperty.type != ClassProperty::Type::BOOLEAN) { + return PropertyTablePropertyView>( + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + gsl::span values; + auto status = getBufferSafe(propertyTableProperty.values, values); + if (status != PropertyTablePropertyViewStatus::Valid) { + return PropertyTablePropertyView>(status); + } + + const int64_t fixedLengthArrayCount = classProperty.count.value_or(0); + if (fixedLengthArrayCount > 0 && propertyTableProperty.arrayOffsets >= 0) { + return PropertyTablePropertyView>( + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } + + if (fixedLengthArrayCount <= 0 && propertyTableProperty.arrayOffsets < 0) { + return PropertyTablePropertyView>( + PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } + + // Handle fixed-length arrays + if (fixedLengthArrayCount > 0) { + size_t maxRequiredBytes = maxRequiredBytes = static_cast(glm::ceil( + static_cast(_pPropertyTable->count * fixedLengthArrayCount) / + 8.0)); + + if (values.size() < maxRequiredBytes) { + return PropertyTablePropertyView>( + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } + + return PropertyTablePropertyView>( + propertyTableProperty, + classProperty, + static_cast(_pPropertyTable->count), + values); + } + + // Handle variable-length arrays + const PropertyComponentType arrayOffsetType = + convertArrayOffsetTypeStringToPropertyComponentType( + propertyTableProperty.arrayOffsetType); + if (arrayOffsetType == PropertyComponentType::None) { + return PropertyTablePropertyView>( + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + constexpr bool checkBitsSize = true; + gsl::span arrayOffsets; + status = getArrayOffsetsBufferSafe( + propertyTableProperty.arrayOffsets, + arrayOffsetType, + values.size(), + static_cast(_pPropertyTable->count), + checkBitsSize, + arrayOffsets); + if (status != PropertyTablePropertyViewStatus::Valid) { + return PropertyTablePropertyView>(status); + } + + return PropertyTablePropertyView>( + propertyTableProperty, + classProperty, + static_cast(_pPropertyTable->count), + values, + arrayOffsets, + gsl::span(), + arrayOffsetType, + PropertyComponentType::None); +} + PropertyTablePropertyView> PropertyTableView::getStringArrayPropertyValues( const ClassProperty& classProperty, diff --git a/CesiumGltf/src/PropertyTextureView.cpp b/CesiumGltf/src/PropertyTextureView.cpp index d92c00bc2..c81247318 100644 --- a/CesiumGltf/src/PropertyTextureView.cpp +++ b/CesiumGltf/src/PropertyTextureView.cpp @@ -45,7 +45,7 @@ PropertyTextureView::getClassProperty(const std::string& propertyName) const { return &propertyIter->second; } -PropertyTexturePropertyViewStatus PropertyTextureView::getTextureSafe( +PropertyViewStatusType PropertyTextureView::getTextureSafe( const int32_t textureIndex, int32_t& samplerIndex, int32_t& imageIndex) const noexcept { @@ -61,7 +61,7 @@ PropertyTexturePropertyViewStatus PropertyTextureView::getTextureSafe( return PropertyTexturePropertyViewStatus::Valid; } -PropertyTexturePropertyViewStatus +PropertyViewStatusType PropertyTextureView::checkSampler(const int32_t samplerIndex) const noexcept { if (samplerIndex < 0 || static_cast(samplerIndex) >= _pModel->samplers.size()) { @@ -73,7 +73,7 @@ PropertyTextureView::checkSampler(const int32_t samplerIndex) const noexcept { return PropertyTexturePropertyViewStatus::Valid; } -PropertyTexturePropertyViewStatus +PropertyViewStatusType PropertyTextureView::checkImage(const int32_t imageIndex) const noexcept { if (imageIndex < 0 || static_cast(imageIndex) >= _pModel->images.size()) { @@ -94,7 +94,7 @@ PropertyTextureView::checkImage(const int32_t imageIndex) const noexcept { return PropertyTexturePropertyViewStatus::Valid; } -PropertyTexturePropertyViewStatus PropertyTextureView::checkChannels( +PropertyViewStatusType PropertyTextureView::checkChannels( const std::vector& channels, const ImageCesium& image) const noexcept { if (channels.size() <= 0 || channels.size() > 4) { diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 016fd5bf5..065f0414a 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -3389,7 +3389,7 @@ TEST_CASE("Check fixed-length array of string") { auto values = *maybeValues; auto expectedValues = *expected[static_cast(i)]; for (int64_t j = 0; j < values.size(); ++j) { - REQUIRE(values[j] == expectedValues[j]); + REQUIRE(values[j] == expectedValues[static_cast(j)]); } } } @@ -3447,7 +3447,7 @@ TEST_CASE("Check fixed-length array of string") { auto values = *maybeValues; auto expectedValues = *expected[static_cast(i)]; for (int64_t j = 0; j < values.size(); ++j) { - REQUIRE(values[j] == expectedValues[j]); + REQUIRE(values[j] == expectedValues[static_cast(j)]); } } } @@ -3594,7 +3594,7 @@ TEST_CASE("Check variable-length string array PropertyTablePropertyView") { auto values = *maybeValues; auto expectedValues = *expected[static_cast(i)]; for (int64_t j = 0; j < values.size(); ++j) { - REQUIRE(values[j] == expectedValues[j]); + REQUIRE(values[j] == expectedValues[static_cast(j)]); } } } @@ -3655,7 +3655,7 @@ TEST_CASE("Check variable-length string array PropertyTablePropertyView") { auto values = *maybeValues; auto expectedValues = *expected[static_cast(i)]; for (int64_t j = 0; j < values.size(); ++j) { - REQUIRE(values[j] == expectedValues[j]); + REQUIRE(values[j] == expectedValues[static_cast(j)]); } } } diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index b79cf2e9e..b258becb2 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -1,3 +1,4 @@ +#include "CesiumGltf/PropertyTablePropertyViewType.h" #include "CesiumGltf/PropertyTableView.h" #include @@ -136,7 +137,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Access correct type") { PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE(uint32Property.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(uint32Property.size() > 0); @@ -147,25 +148,25 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Access wrong type") { PropertyTablePropertyView uvec3Invalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uvec3Invalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); PropertyTablePropertyView u32mat3x3Invalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( u32mat3x3Invalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); PropertyTablePropertyView boolInvalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( boolInvalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); PropertyTablePropertyView stringInvalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( stringInvalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); @@ -173,19 +174,19 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Access wrong component type") { PropertyTablePropertyView uint8Invalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint8Invalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); PropertyTablePropertyView int32Invalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( int32Invalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); PropertyTablePropertyView uint64Invalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint64Invalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); @@ -193,7 +194,8 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Access incorrectly as array") { PropertyTablePropertyView> uint32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); + view.getPropertyView, false>( + "TestClassProperty"); REQUIRE( uint32ArrayInvalid.status() == PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); @@ -202,7 +204,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Wrong buffer index") { model.bufferViews[valueBufferViewIndex].buffer = 2; PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); @@ -211,7 +213,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Wrong buffer view index") { propertyTableProperty.values = -1; PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); @@ -220,7 +222,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Buffer view points outside of the real buffer length") { model.buffers[valueBufferIndex].cesium.data.resize(12); PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); @@ -229,7 +231,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Buffer view length isn't multiple of sizeof(T)") { model.bufferViews[valueBufferViewIndex].byteLength = 13; PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == PropertyTablePropertyViewStatus:: @@ -239,7 +241,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Buffer view length doesn't match with propertyTableCount") { model.bufferViews[valueBufferViewIndex].byteLength = 12; PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == PropertyTablePropertyViewStatus:: @@ -2337,6 +2339,13 @@ TEST_CASE("Test variable-length arrays of strings") { } } +template +void testFunction(PropertyTablePropertyView view) { + REQUIRE( + propertyValue.status() == + PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); +} + TEST_CASE("Test callback on invalid property table view") { Model model; ExtensionModelExtStructuralMetadata& metadata = @@ -2361,17 +2370,17 @@ TEST_CASE("Test callback on invalid property table view") { REQUIRE(!classProperty); uint32_t invokedCallbackCount = 0; - view.getPropertyView( - "TestClassProperty", - [&invokedCallbackCount]( - const std::string& /*propertyName*/, - auto propertyValue) mutable { - invokedCallbackCount++; - REQUIRE( - propertyValue.status() == - PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); - REQUIRE(propertyValue.size() == 0); - }); + auto callback = [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto property) mutable { + invokedCallbackCount++; + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); + REQUIRE(property.size() == 0); + }; + + view.getPropertyView("TestClassProperty", callback); REQUIRE(invokedCallbackCount == 1); } @@ -2476,9 +2485,8 @@ TEST_CASE("Test callback for scalar PropertyTableProperty") { values[static_cast(i)]); } } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); } }); @@ -2545,9 +2553,8 @@ TEST_CASE("Test callback for vecN PropertyTableProperty") { values[static_cast(i)]); } } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); } }); @@ -2623,9 +2630,8 @@ TEST_CASE("Test callback for matN PropertyTableProperty") { values[static_cast(i)]); } } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrecttype for TestClassProperty."); } invokedCallbackCount++; }); @@ -2706,9 +2712,8 @@ TEST_CASE("Test callback for boolean PropertyTableProperty") { expected[static_cast(i)]); } } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); } }); @@ -2796,9 +2801,8 @@ TEST_CASE("Test callback for string PropertyTableProperty") { expected[static_cast(i)]); } } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); } }); @@ -2867,9 +2871,8 @@ TEST_CASE("Test callback for scalar array PropertyTableProperty") { } } } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); } }); @@ -2944,9 +2947,8 @@ TEST_CASE("Test callback for vecN array PropertyTableProperty") { } } } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); } }); @@ -3035,9 +3037,8 @@ TEST_CASE("Test callback for matN array PropertyTableProperty") { } } } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); } }); @@ -3126,9 +3127,8 @@ TEST_CASE("Test callback for boolean array PropertyTableProperty") { } } } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); } }); @@ -3237,9 +3237,8 @@ TEST_CASE("Test callback for string array PropertyTableProperty") { REQUIRE(v2[0] == "I love you, meat bags! ❤️"); REQUIRE(v2[1] == "Book in the freezer"); } else { - FAIL( - "getPropertyView returned PropertyTablePropertyView of incorrect " - "type for TestClassProperty."); + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); } }); From a00b819dcae2b5fcf23c9dcac46e0d8230954415 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 24 Aug 2023 14:35:45 -0400 Subject: [PATCH 091/121] Finish up PropertyTableView tests --- .../CesiumGltf/PropertyTablePropertyView.h | 1 - ...ype.h => PropertyTablePropertyViewTypes.h} | 231 +- .../test/TestPropertyTablePropertyView.cpp | 10 +- CesiumGltf/test/TestPropertyTableView.cpp | 3732 ++++++++++++++--- 4 files changed, 3215 insertions(+), 759 deletions(-) rename CesiumGltf/include/CesiumGltf/{PropertyTablePropertyViewType.h => PropertyTablePropertyViewTypes.h} (95%) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 4c1c42cae..fe73675e8 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -567,7 +567,6 @@ class PropertyTablePropertyView _arrayOffsetType{arrayOffsetType}, _arrayOffsetTypeSize{getOffsetTypeSize(arrayOffsetType)} {} - /** * @brief Get the value of an element of the {@link PropertyTable}, * with normalization and other value transforms applied. In other words, the diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewType.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewTypes.h similarity index 95% rename from CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewType.h rename to CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewTypes.h index e879c1973..257c99615 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewType.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewTypes.h @@ -6,9 +6,9 @@ #include #include -#include #include #include +#include namespace CesiumGltf { @@ -16,7 +16,7 @@ namespace CesiumGltf { /** * @brief An alias for all of the potential types of - * {@link PropertyTablePropertyView} possible, with and without normalization. + * {@link PropertyTablePropertyView} possible without normalization. * Can be useful for applications that want to implement abstract * representations of PropertyTablePropertyView, without the mess of templated * types. @@ -30,14 +30,6 @@ typedef std::variant< View, View, View, - View, - View, - View, - View, - View, - View, - View, - View, View, View, View, @@ -50,14 +42,6 @@ typedef std::variant< View, false>, View, false>, View, false>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, View>, View>, View, false>, @@ -68,14 +52,6 @@ typedef std::variant< View, false>, View, false>, View, false>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, View>, View>, View, false>, @@ -86,14 +62,6 @@ typedef std::variant< View, false>, View, false>, View, false>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, View>, View>, View, false>, @@ -104,14 +72,6 @@ typedef std::variant< View, false>, View, false>, View, false>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, View>, View>, View, false>, @@ -122,14 +82,6 @@ typedef std::variant< View, false>, View, false>, View, false>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, View>, View>, View, false>, @@ -140,14 +92,6 @@ typedef std::variant< View, false>, View, false>, View, false>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, View>, View>, View, false>, @@ -158,14 +102,6 @@ typedef std::variant< View, false>, View, false>, View, false>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, - View, true>, View>, View>, View>, @@ -178,14 +114,6 @@ typedef std::variant< View>, false>, View>, false>, View>, false>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, View>>, View>>, View>, false>, @@ -196,14 +124,6 @@ typedef std::variant< View>, false>, View>, false>, View>, false>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, View>>, View>>, View>, false>, @@ -214,14 +134,6 @@ typedef std::variant< View>, false>, View>, false>, View>, false>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, View>>, View>>, View>, false>, @@ -232,14 +144,6 @@ typedef std::variant< View>, false>, View>, false>, View>, false>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, View>>, View>>, View>, false>, @@ -250,14 +154,6 @@ typedef std::variant< View>, false>, View>, false>, View>, false>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, - View>, true>, View>>, View>>, View>, false>, @@ -268,6 +164,122 @@ typedef std::variant< View>, false>, View>, false>, View>, false>, + View>>, + View>>> + NonNormalizedPropertyTablePropertyView; + +/** + * @brief An alias for all of the potential types of + * {@link PropertyTablePropertyView} possible with normalization. + * Can be useful for applications that want to implement abstract + * representations of PropertyTablePropertyView, without the mess of templated + * types. + */ +typedef std::variant< + View, + View, + View, + View, + View, + View, + View, + View, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, + View>, true>, View>, true>, View>, true>, View>, true>, @@ -275,11 +287,8 @@ typedef std::variant< View>, true>, View>, true>, View>, true>, - View>, true>, - View>>, - View>>> - PropertyTablePropertyViewType; + View>, true>> + NormalizedPropertyTablePropertyView; #undef View - } // namespace CesiumGltf diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 065f0414a..5ed7f2444 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -782,8 +782,8 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { std::optional noData = -1; std::vector> expected{ std::nullopt, - 3, - 7, + static_cast(3), + static_cast(7), std::nullopt}; checkScalar( values, @@ -798,7 +798,11 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { std::vector values{-1, 3, 7, -1}; std::optional noData = -1; std::optional defaultValue = 0; - std::vector> expected{0, 3, 7, 0}; + std::vector> expected{ + static_cast(0), + static_cast(3), + static_cast(7), + static_cast(0)}; checkScalar( values, expected, diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index b258becb2..2e9f9cd69 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -1,4 +1,4 @@ -#include "CesiumGltf/PropertyTablePropertyViewType.h" +#include "CesiumGltf/PropertyTablePropertyView.h" #include "CesiumGltf/PropertyTableView.h" #include @@ -134,39 +134,42 @@ TEST_CASE("Test scalar PropertyTableProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); SECTION("Access correct type") { PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE(uint32Property.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(uint32Property.size() > 0); for (int64_t i = 0; i < uint32Property.size(); ++i) { REQUIRE(uint32Property.getRaw(i) == values[static_cast(i)]); + REQUIRE(uint32Property.get(i)); + REQUIRE(*uint32Property.get(i) == uint32Property.getRaw(i)); } } SECTION("Access wrong type") { PropertyTablePropertyView uvec3Invalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uvec3Invalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); PropertyTablePropertyView u32mat3x3Invalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( u32mat3x3Invalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); PropertyTablePropertyView boolInvalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( boolInvalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); PropertyTablePropertyView stringInvalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( stringInvalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); @@ -174,37 +177,36 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Access wrong component type") { PropertyTablePropertyView uint8Invalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint8Invalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); PropertyTablePropertyView int32Invalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( int32Invalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); PropertyTablePropertyView uint64Invalid = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint64Invalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } - SECTION("Access incorrectly as array") { - PropertyTablePropertyView> uint32ArrayInvalid = - view.getPropertyView, false>( - "TestClassProperty"); + SECTION("Access incorrectly as normalized") { + PropertyTablePropertyView uint32NormalizedInvalid = + view.getPropertyView("TestClassProperty"); REQUIRE( - uint32ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + uint32NormalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); } SECTION("Wrong buffer index") { model.bufferViews[valueBufferViewIndex].buffer = 2; PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); @@ -213,7 +215,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Wrong buffer view index") { propertyTableProperty.values = -1; PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); @@ -222,7 +224,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Buffer view points outside of the real buffer length") { model.buffers[valueBufferIndex].cesium.data.resize(12); PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); @@ -231,7 +233,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Buffer view length isn't multiple of sizeof(T)") { model.bufferViews[valueBufferViewIndex].byteLength = 13; PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == PropertyTablePropertyViewStatus:: @@ -241,7 +243,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { SECTION("Buffer view length doesn't match with propertyTableCount") { model.bufferViews[valueBufferViewIndex].byteLength = 12; PropertyTablePropertyView uint32Property = - view.getPropertyView("TestClassProperty"); + view.getPropertyView("TestClassProperty"); REQUIRE( uint32Property.status() == PropertyTablePropertyViewStatus:: @@ -249,6 +251,159 @@ TEST_CASE("Test scalar PropertyTableProperty") { } } +TEST_CASE("Test scalar PropertyTableProperty (normalized)") { + Model model; + std::vector values = {-128, 0, 32, 2340, -1234, 127}; + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + 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; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + 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->normalized); + REQUIRE(!classProperty->array); + + SECTION("Access correct type") { + PropertyTablePropertyView int16Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(int16Property.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(int16Property.size() > 0); + + for (int64_t i = 0; i < int16Property.size(); ++i) { + auto value = int16Property.getRaw(i); + REQUIRE(value == values[static_cast(i)]); + REQUIRE(int16Property.get(i)); + REQUIRE(*int16Property.get(i) == normalize(value)); + } + } + + SECTION("Access wrong type") { + PropertyTablePropertyView i16vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i16vec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView i16mat3x3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i16mat3x3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyTablePropertyView uint16Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint16Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTablePropertyView int32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + int32Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + PropertyTablePropertyView, true> arrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Access incorrectly as non-normalized") { + PropertyTablePropertyView nonNormalizedInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + nonNormalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Access incorrectly as double") { + PropertyTablePropertyView doubleInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + doubleInvalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Wrong buffer index") { + model.bufferViews[valueBufferViewIndex].buffer = 2; + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE( + propertyView.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); + } + + SECTION("Wrong buffer view index") { + propertyTableProperty.values = -1; + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE( + propertyView.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[valueBufferIndex].cesium.data.resize(4); + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE( + propertyView.status() == + PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Buffer view length isn't multiple of sizeof(T)") { + model.bufferViews[valueBufferViewIndex].byteLength = 7; + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE( + propertyView.status() == PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Buffer view length doesn't match with propertyTableCount") { + model.bufferViews[valueBufferViewIndex].byteLength = 2; + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE( + propertyView.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + TEST_CASE("Test vecN PropertyTableProperty") { Model model; std::vector values = { @@ -289,6 +444,7 @@ TEST_CASE("Test vecN PropertyTableProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); SECTION("Access correct type") { PropertyTablePropertyView ivec3Property = @@ -298,6 +454,8 @@ TEST_CASE("Test vecN PropertyTableProperty") { for (int64_t i = 0; i < ivec3Property.size(); ++i) { REQUIRE(ivec3Property.getRaw(i) == values[static_cast(i)]); + REQUIRE(ivec3Property.get(i)); + REQUIRE(*ivec3Property.get(i) == ivec3Property.getRaw(i)); } } @@ -362,6 +520,14 @@ TEST_CASE("Test vecN PropertyTableProperty") { PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } + SECTION("Access incorrectly as normalized") { + PropertyTablePropertyView normalizedInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + SECTION("Wrong buffer index") { model.bufferViews[valueBufferViewIndex].buffer = 2; PropertyTablePropertyView ivec3Property = @@ -410,6 +576,170 @@ TEST_CASE("Test vecN PropertyTableProperty") { } } +TEST_CASE("Test vecN PropertyTableProperty (normalized)") { + Model model; + std::vector values = { + glm::ivec3(-12, 34, 30), + glm::ivec3(11, 73, 0), + glm::ivec3(-2, 6, 12), + glm::ivec3(-4, 8, -13)}; + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + SECTION("Access correct type") { + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(ivec3Property.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(ivec3Property.size() > 0); + + for (int64_t i = 0; i < ivec3Property.size(); ++i) { + auto value = ivec3Property.getRaw(i); + REQUIRE(value == values[static_cast(i)]); + REQUIRE(ivec3Property.get(i)); + REQUIRE(*ivec3Property.get(i) == normalize(value)); + } + } + + SECTION("Access wrong type") { + PropertyTablePropertyView int32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + int32Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView ivec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView i32mat3x3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i32mat3x3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyTablePropertyView u8vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTablePropertyView i16vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i16vec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + PropertyTablePropertyView> ivec3ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + ivec3ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Access incorrectly as non-normalized") { + PropertyTablePropertyView nonNormalizedInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + nonNormalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Access incorrectly as dvec3") { + PropertyTablePropertyView dvec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + dvec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Wrong buffer index") { + model.bufferViews[valueBufferViewIndex].buffer = 2; + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); + } + + SECTION("Wrong buffer view index") { + propertyTableProperty.values = -1; + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[valueBufferIndex].cesium.data.resize(12); + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Buffer view length isn't multiple of sizeof(T)") { + model.bufferViews[valueBufferViewIndex].byteLength = 11; + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Buffer view length doesn't match with propertyTableCount") { + model.bufferViews[valueBufferViewIndex].byteLength = 12; + PropertyTablePropertyView ivec3Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Property.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + TEST_CASE("Test matN PropertyTableProperty") { Model model; // clang-format off @@ -460,6 +790,7 @@ TEST_CASE("Test matN PropertyTableProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); SECTION("Access correct type") { PropertyTablePropertyView u32mat2x2Property = @@ -470,6 +801,8 @@ TEST_CASE("Test matN PropertyTableProperty") { for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { REQUIRE(u32mat2x2Property.getRaw(i) == values[static_cast(i)]); + REQUIRE(u32mat2x2Property.get(i)); + REQUIRE(*u32mat2x2Property.get(i) == u32mat2x2Property.getRaw(i)); } } @@ -526,12 +859,21 @@ TEST_CASE("Test matN PropertyTableProperty") { } SECTION("Access incorrectly as array") { - PropertyTablePropertyView> - u32mat2x2ArrayInvalid = - view.getPropertyView>( + PropertyTablePropertyView> arrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Access incorrectly as normalized") { + PropertyTablePropertyView, true> + normalizedInvalid = + view.getPropertyView, true>( "TestClassProperty"); REQUIRE( - u32mat2x2ArrayInvalid.status() == + normalizedInvalid.status() == PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } @@ -585,16 +927,194 @@ TEST_CASE("Test matN PropertyTableProperty") { } } -TEST_CASE("Test boolean PropertyTableProperty") { +TEST_CASE("Test matN PropertyTableProperty (normalized)") { Model model; - - int64_t instanceCount = 21; - std::vector expected; - std::vector values; - values.resize(3); - for (int64_t i = 0; i < instanceCount; ++i) { - if (i % 2 == 0) { - expected.emplace_back(true); + // clang-format off + std::vector values = { + glm::u32mat2x2( + 12, 34, + 30, 1), + glm::u32mat2x2( + 11, 8, + 73, 102), + glm::u32mat2x2( + 1, 0, + 63, 2), + glm::u32mat2x2( + 4, 8, + 3, 23)}; + // clang-format on + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + SECTION("Access correct type") { + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(u32mat2x2Property.size() > 0); + + for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { + auto value = u32mat2x2Property.getRaw(i); + REQUIRE(value == values[static_cast(i)]); + REQUIRE(u32mat2x2Property.get(i)); + REQUIRE(*u32mat2x2Property.get(i) == normalize(value)); + } + } + + SECTION("Access wrong type") { + PropertyTablePropertyView uint32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView uvec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uvec2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView u32mat4x4Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat4x4Invalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyTablePropertyView u8mat2x2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8mat2x2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTablePropertyView i32mat2x2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + i32mat2x2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + PropertyTablePropertyView, true> + arrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Access incorrectly as non-normalized") { + PropertyTablePropertyView nonNormalizedInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + nonNormalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Access incorrectly as dmat2") { + PropertyTablePropertyView dmat2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + dmat2Invalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Wrong buffer index") { + model.bufferViews[valueBufferViewIndex].buffer = 2; + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); + } + + SECTION("Wrong buffer view index") { + propertyTableProperty.values = -1; + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[valueBufferIndex].cesium.data.resize(sizeof(glm::u32mat2x2)); + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Buffer view length isn't multiple of sizeof(T)") { + model.bufferViews[valueBufferViewIndex].byteLength = + sizeof(glm::u32mat2x2) * 4 - 1; + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Buffer view length doesn't match with propertyTableCount") { + model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::u32mat2x2); + + PropertyTablePropertyView u32mat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u32mat2x2Property.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test boolean PropertyTableProperty") { + Model model; + + int64_t instanceCount = 21; + std::vector expected; + std::vector values; + values.resize(3); + for (int64_t i = 0; i < instanceCount; ++i) { + if (i % 2 == 0) { + expected.emplace_back(true); } else { expected.emplace_back(false); } @@ -644,6 +1164,8 @@ TEST_CASE("Test boolean PropertyTableProperty") { for (int64_t i = 0; i < boolProperty.size(); ++i) { bool expectedValue = expected[static_cast(i)]; REQUIRE(boolProperty.getRaw(i) == expectedValue); + REQUIRE(boolProperty.get(i)); + REQUIRE(*boolProperty.get(i) == expectedValue); } } @@ -727,6 +1249,8 @@ TEST_CASE("Test string PropertyTableProperty") { REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { REQUIRE(stringProperty.getRaw(static_cast(i)) == expected[i]); + REQUIRE(stringProperty.get(i)); + REQUIRE(*stringProperty.get(i) == expected[i]); } } @@ -841,6 +1365,7 @@ TEST_CASE("Test fixed-length scalar array") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 3); + REQUIRE(!classProperty->normalized); SECTION("Access the right type") { PropertyTablePropertyView> arrayProperty = @@ -848,9 +1373,12 @@ TEST_CASE("Test fixed-length scalar array") { REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { - PropertyArrayView member = arrayProperty.getRaw(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 3 + j)]); + PropertyArrayView array = arrayProperty.getRaw(i); + auto maybeArray = arrayProperty.get(i); + REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == values[static_cast(i * 3 + j)]); + REQUIRE((*maybeArray)[j] == array[j]); } } } @@ -886,6 +1414,16 @@ TEST_CASE("Test fixed-length scalar array") { PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } + SECTION("Incorrectly normalized") { + PropertyTablePropertyView, true> + normalizedInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + SECTION("Buffer size is not a multiple of type size") { model.bufferViews[valueBufferViewIndex].byteLength = 13; PropertyTablePropertyView> arrayProperty = @@ -896,7 +1434,7 @@ TEST_CASE("Test fixed-length scalar array") { ErrorBufferViewSizeNotDivisibleByTypeSize); } - SECTION("Negative component count") { + SECTION("Negative count") { testClassProperty.count = -1; PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); @@ -916,6 +1454,137 @@ TEST_CASE("Test fixed-length scalar array") { } } +TEST_CASE("Test fixed-length scalar array (normalized)") { + Model model; + std::vector values = + {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.array = true; + testClassProperty.count = 3; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + REQUIRE(classProperty->normalized); + + SECTION("Access the right type") { + PropertyTablePropertyView, true> arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + + for (int64_t i = 0; i < arrayProperty.size(); ++i) { + PropertyArrayView array = arrayProperty.getRaw(i); + auto maybeArray = arrayProperty.get(i); + REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == values[static_cast(i * 3 + j)]); + REQUIRE((*maybeArray)[j] == normalize(array[j])); + } + } + } + + SECTION("Wrong type") { + PropertyTablePropertyView, true> + uvec2ArrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + uvec2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Wrong component type") { + PropertyTablePropertyView, true> + int32ArrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + int32ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Not an array type") { + PropertyTablePropertyView uint32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint32Invalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Incorrectly non-normalized") { + PropertyTablePropertyView> + nonNormalizedInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + nonNormalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Buffer size is not a multiple of type size") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + PropertyTablePropertyView, true> arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Negative count") { + testClassProperty.count = -1; + PropertyTablePropertyView, true> arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Value buffer doesn't fit into property table count") { + testClassProperty.count = 55; + PropertyTablePropertyView, true> arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + TEST_CASE("Test variable-length scalar array") { Model model; @@ -985,24 +1654,39 @@ TEST_CASE("Test variable-length scalar array") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT16); REQUIRE(classProperty->array); REQUIRE(!classProperty->count); + REQUIRE(!classProperty->normalized); SECTION("Access the correct type") { PropertyTablePropertyView> property = view.getPropertyView>("TestClassProperty"); REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { - PropertyArrayView valueMember = + PropertyArrayView array = property.getRaw(static_cast(i)); - REQUIRE(valueMember.size() == static_cast(expected[i].size())); + auto maybeArray = property.get(static_cast(i)); + REQUIRE(maybeArray); + REQUIRE(maybeArray->size() == array.size()); + REQUIRE(array.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(expected[i][j] == valueMember[static_cast(j)]); + REQUIRE(expected[i][j] == array[static_cast(j)]); + REQUIRE( + (*maybeArray)[static_cast(j)] == + array[static_cast(j)]); } } } - SECTION("Wrong offset type") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView> arrayProperty = + + SECTION("Incorrectly normalized") { + PropertyTablePropertyView> property = + view.getPropertyView>("TestClassProperty"); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); + } + + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT8; + PropertyTablePropertyView> arrayProperty = view.getPropertyView>("TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1070,159 +1754,32 @@ TEST_CASE("Test variable-length scalar array") { } } -TEST_CASE("Test fixed-length vecN array") { +TEST_CASE("Test variable-length scalar array (normalized)") { Model model; - std::vector values = { - glm::ivec3(12, 34, -30), - glm::ivec3(-2, 0, 1), - glm::ivec3(1, 2, 8), - glm::ivec3(-100, 84, 6), - glm::ivec3(2, -2, -2), - glm::ivec3(40, 61, 3), - }; - - addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::VEC3; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; - testClassProperty.array = true; - testClassProperty.count = 2; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - values.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::VEC3); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 2); - - SECTION("Access the right type") { - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); - - for (int64_t i = 0; i < arrayProperty.size(); ++i) { - PropertyArrayView member = arrayProperty.getRaw(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 2 + j)]); - } - } - } - - SECTION("Wrong type") { - PropertyTablePropertyView> int32ArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - int32ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - - PropertyTablePropertyView> ivec2ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - ivec2ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - } - - SECTION("Wrong component type") { - PropertyTablePropertyView> uvec3ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - uvec3ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); - } - - SECTION("Not an array type") { - PropertyTablePropertyView ivec3Invalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Invalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Buffer size is not a multiple of type size") { - model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Negative component count") { - testClassProperty.count = -1; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == PropertyTablePropertyViewStatus:: - ErrorArrayCountAndOffsetBufferDontExist); - } - - SECTION("Value buffer doesn't fit into property table count") { - testClassProperty.count = 55; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } -} -TEST_CASE("Test variable-length vecN array") { - Model model; - // clang-format off - std::vector> expected{ - { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1) }, - { glm::ivec3(1, 2, 8), }, + std::vector> expected{ + {12, 33, 11, 344, 112, 444, 1}, {}, - { glm::ivec3(-100, 84, 6), glm::ivec3(2, -2, -2), glm::ivec3(40, 61, 3) }, - { glm::ivec3(-1, 4, -7) }, - }; - // clang-format on - + {}, + {122, 23, 333, 12}, + {}, + {333, 311, 22, 34}, + {}, + {33, 1888, 233, 33019}}; size_t numOfElements = 0; for (const auto& expectedMember : expected) { numOfElements += expectedMember.size(); } - std::vector values(numOfElements * sizeof(glm::ivec3)); + std::vector values(numOfElements * sizeof(uint16_t)); std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); uint64_t* offsetValue = reinterpret_cast(offsets.data()); for (size_t i = 0; i < expected.size(); ++i) { std::memcpy( values.data() + offsetValue[i], expected[i].data(), - expected[i].size() * sizeof(glm::ivec3)); - offsetValue[i + 1] = - offsetValue[i] + expected[i].size() * sizeof(glm::ivec3); + expected[i].size() * sizeof(uint16_t)); + offsetValue[i + 1] = offsetValue[i] + expected[i].size() * sizeof(uint16_t); } addBufferToModel(model, values); @@ -1239,9 +1796,10 @@ TEST_CASE("Test variable-length vecN array") { Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::VEC3; - testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT16; testClassProperty.array = true; + testClassProperty.normalized = true; PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; @@ -1262,31 +1820,46 @@ TEST_CASE("Test variable-length vecN array") { const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::VEC3); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT16); REQUIRE(classProperty->array); REQUIRE(!classProperty->count); + REQUIRE(classProperty->normalized); SECTION("Access the correct type") { - PropertyTablePropertyView> property = - view.getPropertyView>( + PropertyTablePropertyView, true> property = + view.getPropertyView, true>( "TestClassProperty"); REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { - PropertyArrayView valueMember = + PropertyArrayView array = property.getRaw(static_cast(i)); - REQUIRE(valueMember.size() == static_cast(expected[i].size())); + auto maybeArray = property.get(static_cast(i)); + REQUIRE(maybeArray); + REQUIRE(maybeArray->size() == array.size()); + REQUIRE(array.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(expected[i][j] == valueMember[static_cast(j)]); + auto value = array[static_cast(j)]; + REQUIRE(expected[i][j] == value); + REQUIRE((*maybeArray)[static_cast(j)] == normalize(value)); } } } + SECTION("Incorrectly non-normalized") { + PropertyTablePropertyView> property = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + SECTION("Wrong offset type") { propertyTableProperty.arrayOffsetType = PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView, true> arrayProperty = + view.getPropertyView, true>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1295,7 +1868,7 @@ TEST_CASE("Test variable-length vecN array") { propertyTableProperty.arrayOffsetType = PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView, true>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1303,7 +1876,7 @@ TEST_CASE("Test variable-length vecN array") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView, true>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1312,7 +1885,7 @@ TEST_CASE("Test variable-length vecN array") { propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = PropertyTableProperty::StringOffsetType::UINT64; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView, true>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1325,8 +1898,8 @@ TEST_CASE("Test variable-length vecN array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView, true> arrayProperty = + view.getPropertyView, true>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1338,8 +1911,8 @@ TEST_CASE("Test variable-length vecN array") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView, true> arrayProperty = + view.getPropertyView, true>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1348,8 +1921,8 @@ TEST_CASE("Test variable-length vecN array") { SECTION("Count and offset buffer are both present") { testClassProperty.count = 3; - PropertyTablePropertyView> property = - view.getPropertyView>( + PropertyTablePropertyView, true> property = + view.getPropertyView, true>( "TestClassProperty"); REQUIRE( property.status() == @@ -1357,30 +1930,16 @@ TEST_CASE("Test variable-length vecN array") { } } -TEST_CASE("Test fixed-length matN array") { +TEST_CASE("Test fixed-length vecN array") { Model model; - // clang-format off - std::vector values = { - glm::i32mat2x2( - 12, 34, - -30, 20), - glm::i32mat2x2( - -2, -2, - 0, 1), - glm::i32mat2x2( - 1, 2, - 8, 5), - glm::i32mat2x2( - -100, 3, - 84, 6), - glm::i32mat2x2( - 2, 12, - -2, -2), - glm::i32mat2x2( - 40, 61, - 7, -3), + std::vector values = { + glm::ivec3(12, 34, -30), + glm::ivec3(-2, 0, 1), + glm::ivec3(1, 2, 8), + glm::ivec3(-100, 84, 6), + glm::ivec3(2, -2, -2), + glm::ivec3(40, 61, 3), }; - // clang-format on addBufferToModel(model, values); size_t valueBufferViewIndex = model.bufferViews.size() - 1; @@ -1391,7 +1950,7 @@ TEST_CASE("Test fixed-length matN array") { Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.type = ClassProperty::Type::VEC3; testClassProperty.componentType = ClassProperty::ComponentType::INT32; testClassProperty.array = true; testClassProperty.count = 2; @@ -1413,21 +1972,26 @@ TEST_CASE("Test fixed-length matN array") { const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); + REQUIRE(!classProperty->normalized); SECTION("Access the right type") { - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); for (int64_t i = 0; i < arrayProperty.size(); ++i) { - PropertyArrayView member = arrayProperty.getRaw(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + PropertyArrayView array = arrayProperty.getRaw(i); + auto maybeArray = arrayProperty.get(i); + REQUIRE(maybeArray); + + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == values[static_cast(i * 2 + j)]); + REQUIRE((*maybeArray)[j] == array[j]); } } } @@ -1448,27 +2012,36 @@ TEST_CASE("Test fixed-length matN array") { } SECTION("Wrong component type") { - PropertyTablePropertyView> - u32mat2x2ArrayInvalid = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> uvec3ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( - u32mat2x2ArrayInvalid.status() == + uvec3ArrayInvalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Not an array type") { - PropertyTablePropertyView ivec3Invalid = - view.getPropertyView("TestClassProperty"); + PropertyTablePropertyView ivec3Invalid = + view.getPropertyView("TestClassProperty"); REQUIRE( ivec3Invalid.status() == PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); } + SECTION("Incorrect normalization") { + PropertyTablePropertyView, true> + normalizedInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + SECTION("Buffer size is not a multiple of type size") { model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1476,10 +2049,10 @@ TEST_CASE("Test fixed-length matN array") { ErrorBufferViewSizeNotDivisibleByTypeSize); } - SECTION("Negative component count") { + SECTION("Negative count") { testClassProperty.count = -1; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -1488,9 +2061,9 @@ TEST_CASE("Test fixed-length matN array") { SECTION("Value buffer doesn't fit into property table count") { testClassProperty.count = 55; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( - "TestClassProperty"); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -1498,53 +2071,182 @@ TEST_CASE("Test fixed-length matN array") { } } -TEST_CASE("Test variable-length matN array") { +TEST_CASE("Test fixed-length vecN array (normalized)") { + Model model; + std::vector values = { + glm::ivec3(12, 34, -30), + glm::ivec3(-2, 0, 1), + glm::ivec3(1, 2, 8), + glm::ivec3(-100, 84, 6), + glm::ivec3(2, -2, -2), + glm::ivec3(40, 61, 3), + }; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + REQUIRE(classProperty->normalized); + + SECTION("Access the right type") { + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + + for (int64_t i = 0; i < arrayProperty.size(); ++i) { + PropertyArrayView array = arrayProperty.getRaw(i); + auto maybeArray = arrayProperty.get(i); + REQUIRE(maybeArray); + + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == values[static_cast(i * 2 + j)]); + REQUIRE((*maybeArray)[j] == normalize(array[j])); + } + } + } + + SECTION("Wrong type") { + PropertyTablePropertyView, true> + int32ArrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + int32ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView, true> + ivec2ArrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + ivec2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Wrong component type") { + PropertyTablePropertyView, true> + uvec3ArrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + uvec3ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Not an array type") { + PropertyTablePropertyView ivec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Incorrect non-normalization") { + PropertyTablePropertyView> normalizedInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Buffer size is not a multiple of type size") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Negative count") { + testClassProperty.count = -1; + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Value buffer doesn't fit into property table count") { + testClassProperty.count = 55; + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test variable-length vecN array") { Model model; // clang-format off - std::vector data0{ - glm::i32mat2x2( - 3, -2, - 1, 0), - glm::i32mat2x2( - 40, 3, - 8, -9) - }; - std::vector data1{ - glm::i32mat2x2( - 1, 10, - 7, 8), - }; - std::vector data2{ - glm::i32mat2x2( - 18, 0, - 1, 17), - glm::i32mat2x2( - -4, -2, - -9, 1), - glm::i32mat2x2( - 1, 8, - -99, 3), - }; + std::vector> expected{ + { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1) }, + { glm::ivec3(1, 2, 8), }, + {}, + { glm::ivec3(-100, 84, 6), glm::ivec3(2, -2, -2), glm::ivec3(40, 61, 3) }, + { glm::ivec3(-1, 4, -7) }, + }; // clang-format on - std::vector> - expected{data0, {}, data1, data2, {}}; - size_t numOfElements = 0; for (const auto& expectedMember : expected) { numOfElements += expectedMember.size(); } - std::vector values(numOfElements * sizeof(glm::i32mat2x2)); + std::vector values(numOfElements * sizeof(glm::ivec3)); std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); uint64_t* offsetValue = reinterpret_cast(offsets.data()); for (size_t i = 0; i < expected.size(); ++i) { std::memcpy( values.data() + offsetValue[i], expected[i].data(), - expected[i].size() * sizeof(glm::i32mat2x2)); + expected[i].size() * sizeof(glm::ivec3)); offsetValue[i + 1] = - offsetValue[i] + expected[i].size() * sizeof(glm::i32mat2x2); + offsetValue[i] + expected[i].size() * sizeof(glm::ivec3); } addBufferToModel(model, values); @@ -1561,7 +2263,7 @@ TEST_CASE("Test variable-length matN array") { Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.type = ClassProperty::Type::VEC3; testClassProperty.componentType = ClassProperty::ComponentType::INT32; testClassProperty.array = true; @@ -1584,31 +2286,45 @@ TEST_CASE("Test variable-length matN array") { const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(!classProperty->count); + REQUIRE(!classProperty->normalized); SECTION("Access the correct type") { - PropertyTablePropertyView> property = - view.getPropertyView>( + PropertyTablePropertyView> property = + view.getPropertyView>( "TestClassProperty"); REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { - PropertyArrayView valueMember = + PropertyArrayView array = property.getRaw(static_cast(i)); - REQUIRE(valueMember.size() == static_cast(expected[i].size())); + auto maybeArray = property.get(i); + REQUIRE(maybeArray); + REQUIRE(array.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(expected[i][j] == valueMember[static_cast(j)]); + auto value = array[static_cast(j)]; + REQUIRE(expected[i][j] == value); + REQUIRE((*maybeArray)[j] == value); } } } + SECTION("Incorrectly normalized") { + PropertyTablePropertyView, true> property = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + SECTION("Wrong offset type") { propertyTableProperty.arrayOffsetType = PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1617,7 +2333,7 @@ TEST_CASE("Test variable-length matN array") { propertyTableProperty.arrayOffsetType = PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1625,7 +2341,7 @@ TEST_CASE("Test variable-length matN array") { ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1634,7 +2350,7 @@ TEST_CASE("Test variable-length matN array") { propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = PropertyTableProperty::StringOffsetType::UINT64; - arrayProperty = view.getPropertyView>( + arrayProperty = view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1647,8 +2363,8 @@ TEST_CASE("Test variable-length matN array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1660,8 +2376,8 @@ TEST_CASE("Test variable-length matN array") { model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>( + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayProperty.status() == @@ -1670,8 +2386,8 @@ TEST_CASE("Test variable-length matN array") { SECTION("Count and offset buffer are both present") { testClassProperty.count = 3; - PropertyTablePropertyView> property = - view.getPropertyView>( + PropertyTablePropertyView> property = + view.getPropertyView>( "TestClassProperty"); REQUIRE( property.status() == @@ -1679,35 +2395,42 @@ TEST_CASE("Test variable-length matN array") { } } -TEST_CASE("Test fixed-length boolean array") { +TEST_CASE("Test variable-length vecN array (normalized)") { Model model; + // clang-format off + std::vector> expected{ + { glm::ivec3(12, 34, -30), glm::ivec3(-2, 0, 1) }, + { glm::ivec3(1, 2, 8), }, + {}, + { glm::ivec3(-100, 84, 6), glm::ivec3(2, -2, -2), glm::ivec3(40, 61, 3) }, + { glm::ivec3(-1, 4, -7) }, + }; + // clang-format on - std::vector expected = { - true, - false, - false, - true, - false, - false, - true, - true, - true, - false, - false, - true}; - std::vector values; - size_t requiredBytesSize = static_cast( - glm::ceil(static_cast(expected.size()) / 8.0)); - values.resize(requiredBytesSize); + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + std::vector values(numOfElements * sizeof(glm::ivec3)); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); for (size_t i = 0; i < expected.size(); ++i) { - uint8_t expectedValue = expected[i]; - size_t byteIndex = i / 8; - size_t bitIndex = i % 8; - values[byteIndex] = - static_cast((expectedValue << bitIndex) | values[byteIndex]); + std::memcpy( + values.data() + offsetValue[i], + expected[i].data(), + expected[i].size() * sizeof(glm::ivec3)); + offsetValue[i + 1] = + offsetValue[i] + expected[i].size() * sizeof(glm::ivec3); } addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -1715,138 +2438,14 @@ TEST_CASE("Test fixed-length boolean array") { Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::BOOLEAN; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; testClassProperty.array = true; - testClassProperty.count = 3; + testClassProperty.normalized = true; PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast( - expected.size() / static_cast(testClassProperty.count.value())); - - PropertyTableProperty& propertyTableProperty = - propertyTable.properties["TestClassProperty"]; - propertyTableProperty.values = - static_cast(model.bufferViews.size() - 1); - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 3); - - SECTION("Access correct type") { - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(boolArrayProperty.size() == propertyTable.count); - REQUIRE(boolArrayProperty.size() > 0); - for (int64_t i = 0; i < boolArrayProperty.size(); ++i) { - PropertyArrayView valueMember = boolArrayProperty.getRaw(i); - for (int64_t j = 0; j < valueMember.size(); ++j) { - REQUIRE(valueMember[j] == expected[static_cast(i * 3 + j)]); - } - } - } - - SECTION("Wrong type") { - PropertyTablePropertyView> uint8ArrayInvalid = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - uint8ArrayInvalid.status() == - PropertyTablePropertyViewStatus::ErrorTypeMismatch); - } - - SECTION("View is not array type") { - PropertyTablePropertyView boolInvalid = - view.getPropertyView("TestClassProperty"); - REQUIRE( - boolInvalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); - } - - SECTION("Value buffer doesn't have enough required bytes") { - testClassProperty.count = 11; - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } - - SECTION("Count is negative") { - testClassProperty.count = -1; - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorArrayCountAndOffsetBufferDontExist); - } -} - -TEST_CASE("Test variable-length boolean array") { - Model model; - - std::vector> expected{ - {true, false, true, true, false, true, true}, - {}, - {}, - {}, - {false, false, false, false}, - {true, false, true}, - {false}, - {true, true, true, true, true, false, false}}; - size_t numOfElements = 0; - for (const auto& expectedMember : expected) { - numOfElements += expectedMember.size(); - } - - size_t requiredBytesSize = - static_cast(glm::ceil(static_cast(numOfElements) / 8.0)); - std::vector values(requiredBytesSize); - std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); - uint64_t* offsetValue = reinterpret_cast(offsets.data()); - size_t indexSoFar = 0; - for (size_t i = 0; i < expected.size(); ++i) { - for (size_t j = 0; j < expected[i].size(); ++j) { - uint8_t expectedValue = expected[i][j]; - size_t byteIndex = indexSoFar / 8; - size_t bitIndex = indexSoFar % 8; - values[byteIndex] = static_cast( - (expectedValue << bitIndex) | static_cast(values[byteIndex])); - ++indexSoFar; - } - offsetValue[i + 1] = offsetValue[i] + expected[i].size(); - } - - addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; - size_t valueBufferViewIndex = model.bufferViews.size() - 1; - - addBufferToModel(model, offsets); - size_t offsetBufferIndex = model.buffers.size() - 1; - size_t offsetBufferViewIndex = model.bufferViews.size() - 1; - - ExtensionModelExtStructuralMetadata& metadata = - model.addExtension(); - - Schema& schema = metadata.schema.emplace(); - Class& testClass = schema.classes["TestClass"]; - ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::BOOLEAN; - testClassProperty.array = true; - - PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); - propertyTable.classProperty = "TestClass"; - propertyTable.count = static_cast(expected.size()); + propertyTable.count = static_cast(expected.size()); PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; @@ -1863,30 +2462,47 @@ TEST_CASE("Test variable-length boolean array") { const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(!classProperty->count); + REQUIRE(classProperty->normalized); - SECTION("Access correct type") { - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + SECTION("Access the correct type") { + PropertyTablePropertyView, true> property = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { - PropertyArrayView arrayMember = - boolArrayProperty.getRaw(static_cast(i)); - REQUIRE(arrayMember.size() == static_cast(expected[i].size())); + PropertyArrayView array = + property.getRaw(static_cast(i)); + auto maybeArray = property.get(i); + REQUIRE(maybeArray); + REQUIRE(array.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { - REQUIRE(expected[i][j] == arrayMember[static_cast(j)]); + auto value = array[static_cast(j)]; + REQUIRE(expected[i][j] == value); + REQUIRE((*maybeArray)[j] == normalize(value)); } } } + SECTION("Incorrectly non-normalized") { + PropertyTablePropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + SECTION("Wrong offset type") { propertyTableProperty.arrayOffsetType = PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: @@ -1894,16 +2510,16 @@ TEST_CASE("Test variable-length boolean array") { propertyTableProperty.arrayOffsetType = PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = - view.getPropertyView>("TestClassProperty"); + arrayProperty = view.getPropertyView, true>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = - view.getPropertyView>("TestClassProperty"); + arrayProperty = view.getPropertyView, true>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); @@ -1911,8 +2527,8 @@ TEST_CASE("Test variable-length boolean array") { propertyTableProperty.arrayOffsetType = ""; propertyTableProperty.stringOffsetType = PropertyTableProperty::StringOffsetType::UINT64; - arrayProperty = - view.getPropertyView>("TestClassProperty"); + arrayProperty = view.getPropertyView, true>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); @@ -1924,8 +2540,10 @@ TEST_CASE("Test variable-length boolean array") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); offset[propertyTable.count] = 0; - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); @@ -1934,82 +2552,76 @@ TEST_CASE("Test variable-length boolean array") { SECTION("Offset value points outside of value buffer") { uint64_t* offset = reinterpret_cast( model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = static_cast( - model.buffers[valueBufferIndex].byteLength * 8 + 20); - PropertyTablePropertyView> arrayProperty = - view.getPropertyView>("TestClassProperty"); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); REQUIRE( arrayProperty.status() == PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); } - SECTION("Count and offset buffer both present") { + SECTION("Count and offset buffer are both present") { testClassProperty.count = 3; - PropertyTablePropertyView> boolArrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTablePropertyView, true> property = + view.getPropertyView, true>( + "TestClassProperty"); REQUIRE( - boolArrayProperty.status() == + property.status() == PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); } } -TEST_CASE("Test fixed-length arrays of strings") { +TEST_CASE("Test fixed-length matN array") { Model model; - - std::vector expected{ - "What's up", - "Breaking news!!! Aliens no longer attacks the US first", - "But they still abduct my cows! Those milk thiefs! 👽 🐮", - "I'm not crazy. My mother had me tested 🤪", - "I love you, meat bags! ❤️", - "Book in the freezer"}; - - size_t totalBytes = 0; - for (const std::string& expectedValue : expected) { - totalBytes += expectedValue.size(); - } - - std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); - std::vector values(totalBytes); - uint32_t* offsetValue = reinterpret_cast(offsets.data()); - for (size_t i = 0; i < expected.size(); ++i) { - const std::string& expectedValue = expected[i]; - std::memcpy( - values.data() + offsetValue[i], - expectedValue.c_str(), - expectedValue.size()); - offsetValue[i + 1] = - offsetValue[i] + static_cast(expectedValue.size()); - } + // clang-format off + std::vector values = { + glm::i32mat2x2( + 12, 34, + -30, 20), + glm::i32mat2x2( + -2, -2, + 0, 1), + glm::i32mat2x2( + 1, 2, + 8, 5), + glm::i32mat2x2( + -100, 3, + 84, 6), + glm::i32mat2x2( + 2, 12, + -2, -2), + glm::i32mat2x2( + 40, 61, + 7, -3), + }; + // clang-format on addBufferToModel(model, values); size_t valueBufferViewIndex = model.bufferViews.size() - 1; - addBufferToModel(model, offsets); - size_t offsetBufferViewIndex = model.bufferViews.size() - 1; - ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::STRING; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; testClassProperty.array = true; testClassProperty.count = 2; PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; propertyTable.count = static_cast( - expected.size() / static_cast(testClassProperty.count.value())); + values.size() / static_cast(testClassProperty.count.value())); PropertyTableProperty& propertyTableProperty = propertyTable.properties["TestClassProperty"]; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT32; - propertyTableProperty.values = static_cast(valueBufferViewIndex); - propertyTableProperty.stringOffsets = - static_cast(offsetBufferViewIndex); + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); PropertyTableView view(model, propertyTable); REQUIRE(view.status() == PropertyTableViewStatus::Valid); @@ -2018,32 +2630,1048 @@ TEST_CASE("Test fixed-length arrays of strings") { const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::STRING); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); + REQUIRE(!classProperty->normalized); - SECTION("Access correct type") { - PropertyTablePropertyView> - stringProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(stringProperty.size() == 3); - - PropertyArrayView v0 = stringProperty.getRaw(0); - REQUIRE(v0.size() == 2); - REQUIRE(v0[0] == "What's up"); - REQUIRE(v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); + SECTION("Access the right type") { + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); - PropertyArrayView v1 = stringProperty.getRaw(1); - REQUIRE(v1.size() == 2); - REQUIRE(v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); + for (int64_t i = 0; i < arrayProperty.size(); ++i) { + PropertyArrayView member = arrayProperty.getRaw(i); + for (int64_t j = 0; j < member.size(); ++j) { + REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + } + } + } + + SECTION("Wrong type") { + PropertyTablePropertyView> int32ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + int32ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView> ivec2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + ivec2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Wrong component type") { + PropertyTablePropertyView> + u32mat2x2ArrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + u32mat2x2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Not an array type") { + PropertyTablePropertyView ivec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Incorrect normalization") { + PropertyTablePropertyView, true> + normalizedInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Buffer size is not a multiple of type size") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Negative count") { + testClassProperty.count = -1; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Value buffer doesn't fit into property table count") { + testClassProperty.count = 55; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test fixed-length matN array (normalized)") { + Model model; + // clang-format off + std::vector values = { + glm::i32mat2x2( + 12, 34, + -30, 20), + glm::i32mat2x2( + -2, -2, + 0, 1), + glm::i32mat2x2( + 1, 2, + 8, 5), + glm::i32mat2x2( + -100, 3, + 84, 6), + glm::i32mat2x2( + 2, 12, + -2, -2), + glm::i32mat2x2( + 40, 61, + 7, -3), + }; + // clang-format on + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + REQUIRE(classProperty->normalized); + + SECTION("Access the right type") { + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE(arrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + + for (int64_t i = 0; i < arrayProperty.size(); ++i) { + PropertyArrayView array = arrayProperty.getRaw(i); + auto maybeArray = arrayProperty.get(i); + REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == values[static_cast(i * 2 + j)]); + REQUIRE((*maybeArray)[j] == normalize(array[j])); + } + } + } + + SECTION("Wrong type") { + PropertyTablePropertyView, true> + int32ArrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + int32ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + + PropertyTablePropertyView, true> + ivec2ArrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + ivec2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Wrong component type") { + PropertyTablePropertyView, true> + u32mat2x2ArrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + u32mat2x2ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Not an array type") { + PropertyTablePropertyView ivec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + ivec3Invalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Incorrect non-normalization") { + PropertyTablePropertyView> + nonNormalizedInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + nonNormalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Buffer size is not a multiple of type size") { + model.bufferViews[valueBufferViewIndex].byteLength = 13; + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeNotDivisibleByTypeSize); + } + + SECTION("Negative count") { + testClassProperty.count = -1; + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } + + SECTION("Value buffer doesn't fit into property table count") { + testClassProperty.count = 55; + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } +} + +TEST_CASE("Test variable-length matN array") { + Model model; + // clang-format off + std::vector data0{ + glm::i32mat2x2( + 3, -2, + 1, 0), + glm::i32mat2x2( + 40, 3, + 8, -9) + }; + std::vector data1{ + glm::i32mat2x2( + 1, 10, + 7, 8), + }; + std::vector data2{ + glm::i32mat2x2( + 18, 0, + 1, 17), + glm::i32mat2x2( + -4, -2, + -9, 1), + glm::i32mat2x2( + 1, 8, + -99, 3), + }; + // clang-format on + + std::vector> + expected{data0, {}, data1, data2, {}}; + + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + std::vector values(numOfElements * sizeof(glm::i32mat2x2)); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + std::memcpy( + values.data() + offsetValue[i], + expected[i].data(), + expected[i].size() * sizeof(glm::i32mat2x2)); + offsetValue[i + 1] = + offsetValue[i] + expected[i].size() * sizeof(glm::i32mat2x2); + } + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + REQUIRE(!classProperty->normalized); + + SECTION("Access the correct type") { + PropertyTablePropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + PropertyArrayView array = + property.getRaw(static_cast(i)); + auto maybeArray = property.get(i); + REQUIRE(maybeArray); + REQUIRE(array.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + auto value = array[static_cast(j)]; + REQUIRE(expected[i][j] == value); + REQUIRE((*maybeArray)[j] == value); + } + } + } + + SECTION("Incorrectly normalized") { + PropertyTablePropertyView, true> + property = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT8; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT16; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT64; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer are both present") { + testClassProperty.count = 3; + PropertyTablePropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test variable-length matN array (normalized)") { + Model model; + // clang-format off + std::vector data0{ + glm::i32mat2x2( + 3, -2, + 1, 0), + glm::i32mat2x2( + 40, 3, + 8, -9) + }; + std::vector data1{ + glm::i32mat2x2( + 1, 10, + 7, 8), + }; + std::vector data2{ + glm::i32mat2x2( + 18, 0, + 1, 17), + glm::i32mat2x2( + -4, -2, + -9, 1), + glm::i32mat2x2( + 1, 8, + -99, 3), + }; + // clang-format on + + std::vector> + expected{data0, {}, data1, data2, {}}; + + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + std::vector values(numOfElements * sizeof(glm::i32mat2x2)); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + std::memcpy( + values.data() + offsetValue[i], + expected[i].data(), + expected[i].size() * sizeof(glm::i32mat2x2)); + offsetValue[i + 1] = + offsetValue[i] + expected[i].size() * sizeof(glm::i32mat2x2); + } + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + REQUIRE(classProperty->normalized); + + SECTION("Access the correct type") { + PropertyTablePropertyView, true> + property = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + PropertyArrayView array = + property.getRaw(static_cast(i)); + auto maybeArray = property.get(i); + REQUIRE(maybeArray); + REQUIRE(array.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + auto value = array[static_cast(j)]; + REQUIRE(expected[i][j] == value); + REQUIRE((*maybeArray)[j] == normalize(value)); + } + } + } + + SECTION("Incorrectly non-normalized") { + PropertyTablePropertyView> property = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT8; + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT16; + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT64; + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = + static_cast(model.buffers[valueBufferIndex].byteLength + 4); + PropertyTablePropertyView, true> + arrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer are both present") { + testClassProperty.count = 3; + PropertyTablePropertyView, true> + property = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test fixed-length boolean array") { + Model model; + + std::vector expected = { + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true}; + std::vector values; + size_t requiredBytesSize = static_cast( + glm::ceil(static_cast(expected.size()) / 8.0)); + values.resize(requiredBytesSize); + for (size_t i = 0; i < expected.size(); ++i) { + uint8_t expectedValue = expected[i]; + size_t byteIndex = i / 8; + size_t bitIndex = i % 8; + values[byteIndex] = + static_cast((expectedValue << bitIndex) | values[byteIndex]); + } + + addBufferToModel(model, values); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; + testClassProperty.array = true; + testClassProperty.count = 3; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + expected.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + + SECTION("Access correct type") { + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(boolArrayProperty.size() == propertyTable.count); + REQUIRE(boolArrayProperty.size() > 0); + for (int64_t i = 0; i < boolArrayProperty.size(); ++i) { + PropertyArrayView array = boolArrayProperty.getRaw(i); + auto maybeArray = boolArrayProperty.get(i); + REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == expected[static_cast(i * 3 + j)]); + REQUIRE((*maybeArray)[j] == array[j]); + } + } + } + + SECTION("Wrong type") { + PropertyTablePropertyView> uint8ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayInvalid.status() == + PropertyTablePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("View is not array type") { + PropertyTablePropertyView boolInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + boolInvalid.status() == + PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Value buffer doesn't have enough required bytes") { + testClassProperty.count = 11; + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + } + + SECTION("Count is negative") { + testClassProperty.count = -1; + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorArrayCountAndOffsetBufferDontExist); + } +} + +TEST_CASE("Test variable-length boolean array") { + Model model; + + std::vector> expected{ + {true, true, true, true, true}, + {}, + {}, + {}, + {false}, + {true, true}, + {false}, + {true, true, true, true, true}}; + size_t numOfElements = 0; + for (const auto& expectedMember : expected) { + numOfElements += expectedMember.size(); + } + + size_t requiredBytesSize = + static_cast(glm::ceil(static_cast(numOfElements) / 8.0)); + std::vector values(requiredBytesSize); + std::vector offsets((expected.size() + 1) * sizeof(uint64_t)); + uint64_t* offsetValue = reinterpret_cast(offsets.data()); + size_t indexSoFar = 0; + for (size_t i = 0; i < expected.size(); ++i) { + for (size_t j = 0; j < expected[i].size(); ++j) { + uint8_t expectedValue = expected[i][j]; + size_t byteIndex = indexSoFar / 8; + size_t bitIndex = indexSoFar % 8; + values[byteIndex] = static_cast( + (expectedValue << bitIndex) | static_cast(values[byteIndex])); + ++indexSoFar; + } + offsetValue[i + 1] = offsetValue[i] + expected[i].size(); + } + + addBufferToModel(model, values); + size_t valueBufferIndex = model.buffers.size() - 1; + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferIndex = model.buffers.size() - 1; + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::BOOLEAN; + testClassProperty.array = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(expected.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.arrayOffsets = + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::BOOLEAN); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + + SECTION("Access correct type") { + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + PropertyArrayView array = + boolArrayProperty.getRaw(static_cast(i)); + auto maybeArray = boolArrayProperty.get(i); + REQUIRE(maybeArray); + REQUIRE(array.size() == static_cast(expected[i].size())); + for (size_t j = 0; j < expected[i].size(); ++j) { + auto value = array[static_cast(j)]; + REQUIRE(expected[i][j] == value); + REQUIRE((*maybeArray)[j] == value); + } + } + } + + SECTION("Wrong offset type") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT8; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT16; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.arrayOffsetType = "NONSENSE"; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + + propertyTableProperty.arrayOffsetType = ""; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT64; + arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); + } + + SECTION("Offset values are not sorted ascending") { + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = 0; + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); + } + + SECTION("Offset value points outside of value buffer") { + uint64_t* offset = reinterpret_cast( + model.buffers[offsetBufferIndex].cesium.data.data()); + offset[propertyTable.count] = static_cast( + model.buffers[valueBufferIndex].byteLength * 8 + 20); + PropertyTablePropertyView> arrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); + } + + SECTION("Count and offset buffer both present") { + testClassProperty.count = 3; + PropertyTablePropertyView> boolArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test fixed-length arrays of strings") { + Model model; + + std::vector expected{ + "What's up", + "Breaking news!!! Aliens no longer attacks the US first", + "But they still abduct my cows! Those milk thiefs! 👽 🐮", + "I'm not crazy. My mother had me tested 🤪", + "I love you, meat bags! ❤️", + "Book in the freezer"}; + + size_t totalBytes = 0; + for (const std::string& expectedValue : expected) { + totalBytes += expectedValue.size(); + } + + std::vector offsets((expected.size() + 1) * sizeof(uint32_t)); + std::vector values(totalBytes); + uint32_t* offsetValue = reinterpret_cast(offsets.data()); + for (size_t i = 0; i < expected.size(); ++i) { + const std::string& expectedValue = expected[i]; + std::memcpy( + values.data() + offsetValue[i], + expectedValue.c_str(), + expectedValue.size()); + offsetValue[i + 1] = + offsetValue[i] + static_cast(expectedValue.size()); + } + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + addBufferToModel(model, offsets); + size_t offsetBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::STRING; + testClassProperty.array = true; + testClassProperty.count = 2; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + expected.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT32; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + propertyTableProperty.stringOffsets = + static_cast(offsetBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::STRING); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + SECTION("Access correct type") { + PropertyTablePropertyView> + stringProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(stringProperty.size() == 3); + + PropertyArrayView v0 = stringProperty.getRaw(0); + REQUIRE(v0.size() == 2); + REQUIRE(v0[0] == "What's up"); + REQUIRE(v0[1] == "Breaking news!!! Aliens no longer attacks the US first"); + + PropertyArrayView v1 = stringProperty.getRaw(1); + REQUIRE(v1.size() == 2); + REQUIRE(v1[0] == "But they still abduct my cows! Those milk thiefs! 👽 🐮"); REQUIRE(v1[1] == "I'm not crazy. My mother had me tested 🤪"); PropertyArrayView v2 = stringProperty.getRaw(2); REQUIRE(v2.size() == 2); REQUIRE(v2[0] == "I love you, meat bags! ❤️"); REQUIRE(v2[1] == "Book in the freezer"); + + for (int64_t i = 0; i < stringProperty.size(); i++) { + auto maybeValue = stringProperty.get(i); + REQUIRE(maybeValue); + + auto value = stringProperty.getRaw(i); + REQUIRE(maybeValue->size() == value.size()); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE((*maybeValue)[j] == value[j]); + } + } } SECTION("Array type mismatch") { @@ -2201,8 +3829,11 @@ TEST_CASE("Test variable-length arrays of strings") { for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView stringArray = stringProperty.getRaw(static_cast(i)); + auto maybeArray = stringProperty.get(static_cast(i)); + REQUIRE(maybeArray); for (size_t j = 0; j < expected[i].size(); ++j) { REQUIRE(stringArray[static_cast(j)] == expected[i][j]); + REQUIRE((*maybeArray)[static_cast(j)] == expected[i][j]); } } } @@ -2250,100 +3881,475 @@ TEST_CASE("Test variable-length arrays of strings") { PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT16; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT16; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus:: + ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + + propertyTableProperty.stringOffsetType = "NONSENSE"; + arrayProperty = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); + propertyTableProperty.stringOffsetType = + PropertyTableProperty::StringOffsetType::UINT32; + } + + SECTION("Array offset values are not sorted ascending") { + uint32_t* offset = reinterpret_cast( + model.buffers[arrayOffsetBuffer].cesium.data.data()); + offset[0] = static_cast(1000); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); + offset[0] = 0; + } + + SECTION("String offset values are not sorted ascending") { + uint32_t* offset = reinterpret_cast( + model.buffers[stringOffsetBuffer].cesium.data.data()); + offset[0] = static_cast(1000); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); + offset[0] = 0; + } + + SECTION("Array offset value points outside of value buffer") { + uint32_t* offset = reinterpret_cast( + model.buffers[arrayOffsetBuffer].cesium.data.data()); + uint32_t previousValue = offset[propertyTable.count]; + offset[propertyTable.count] = static_cast(100000); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); + offset[propertyTable.count] = previousValue; + } + + SECTION("String offset value points outside of value buffer") { + uint32_t* offset = reinterpret_cast( + model.buffers[stringOffsetBuffer].cesium.data.data()); + uint32_t previousValue = offset[6]; + offset[6] = static_cast(100000); + PropertyTablePropertyView> + arrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); + offset[6] = previousValue; + } + + SECTION("Count and offset buffer both present") { + testClassProperty.count = 3; + PropertyTablePropertyView> + boolArrayProperty = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + boolArrayProperty.status() == + PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + } +} + +TEST_CASE("Test with property offset, scale, min, max") { + Model model; + std::vector values = {1.0f, 2.0f, 3.0f, 4.0f}; + const float offset = 0.5f; + const float scale = 2.0f; + const float min = 3.5f; + const float max = 8.5f; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::FLOAT32; + testClassProperty.offset = offset; + testClassProperty.scale = scale; + testClassProperty.min = min; + testClassProperty.max = max; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE( + classProperty->componentType == ClassProperty::ComponentType::FLOAT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); + REQUIRE(classProperty->offset); + REQUIRE(classProperty->scale); + REQUIRE(classProperty->min); + REQUIRE(classProperty->max); + + SECTION("Use class property values") { + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyView.size() > 0); + REQUIRE(propertyView.offset()); + REQUIRE(*propertyView.offset() == offset); + REQUIRE(propertyView.scale()); + REQUIRE(*propertyView.scale() == scale); + REQUIRE(propertyView.min()); + REQUIRE(*propertyView.min() == min); + REQUIRE(propertyView.max()); + REQUIRE(*propertyView.max() == max); + + for (int64_t i = 0; i < propertyView.size(); ++i) { + REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); + REQUIRE(propertyView.get(i)); + REQUIRE(*propertyView.get(i) == propertyView.getRaw(i) * scale + offset); + } + } + + SECTION("Use own property values") { + const float newOffset = 1.0f; + const float newScale = -1.0f; + const float newMin = -3.0f; + const float newMax = 0.0f; + propertyTableProperty.offset = newOffset; + propertyTableProperty.scale = newScale; + propertyTableProperty.min = newMin; + propertyTableProperty.max = newMax; + + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyView.size() > 0); + REQUIRE(propertyView.offset()); + REQUIRE(*propertyView.offset() == newOffset); + REQUIRE(propertyView.scale()); + REQUIRE(*propertyView.scale() == newScale); + REQUIRE(propertyView.min()); + REQUIRE(*propertyView.min() == newMin); + REQUIRE(propertyView.max()); + REQUIRE(*propertyView.max() == newMax); + + for (int64_t i = 0; i < propertyView.size(); ++i) { + REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); + REQUIRE(propertyView.get(i)); + REQUIRE( + *propertyView.get(i) == + propertyView.getRaw(i) * newScale + newOffset); + } + } +} + +TEST_CASE("Test with property offset, scale, min, max (normalized)") { + Model model; + std::vector values = {-128, 0, 32, 127}; + const double offset = 0.5; + const double scale = 2.0; + const double min = 1.5; + const double max = 2.5; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::INT8; + testClassProperty.normalized = true; + testClassProperty.offset = offset; + testClassProperty.scale = scale; + testClassProperty.min = min; + testClassProperty.max = max; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + REQUIRE(classProperty->offset); + REQUIRE(classProperty->scale); + REQUIRE(classProperty->min); + REQUIRE(classProperty->max); + + SECTION("Use class property values") { + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyView.size() > 0); + REQUIRE(propertyView.offset()); + REQUIRE(*propertyView.offset() == offset); + REQUIRE(propertyView.scale()); + REQUIRE(*propertyView.scale() == scale); + REQUIRE(propertyView.min()); + REQUIRE(*propertyView.min() == min); + REQUIRE(propertyView.max()); + REQUIRE(*propertyView.max() == max); + + for (int64_t i = 0; i < propertyView.size(); ++i) { + REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); + REQUIRE(propertyView.get(i)); + REQUIRE( + *propertyView.get(i) == + normalize(propertyView.getRaw(i)) * scale + offset); + } + } + + SECTION("Use own property values") { + const double newOffset = -0.5; + const double newScale = 1.0; + const double newMin = -1.5; + const double newMax = 0.5; + propertyTableProperty.offset = newOffset; + propertyTableProperty.scale = newScale; + propertyTableProperty.min = newMin; + propertyTableProperty.max = newMax; + + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyView.size() > 0); + REQUIRE(propertyView.offset()); + REQUIRE(*propertyView.offset() == newOffset); + REQUIRE(propertyView.scale()); + REQUIRE(*propertyView.scale() == newScale); + REQUIRE(propertyView.min()); + REQUIRE(*propertyView.min() == newMin); + REQUIRE(propertyView.max()); + REQUIRE(*propertyView.max() == newMax); + + for (int64_t i = 0; i < propertyView.size(); ++i) { + REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); + REQUIRE(propertyView.get(i)); + REQUIRE( + *propertyView.get(i) == + normalize(propertyView.getRaw(i)) * newScale + newOffset); + } + } +} + +TEST_CASE("Test with property noData value") { + Model model; + std::vector values = {-128, 0, 32, -128, 127}; + const int8_t noData = -128; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::INT8; + testClassProperty.noData = noData; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); - propertyTableProperty.stringOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidStringOffsetType); - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT32; + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); + REQUIRE(classProperty->noData); + + SECTION("Without default value") { + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyView.size() > 0); + REQUIRE(propertyView.noData()); + REQUIRE(*propertyView.noData() == noData); + + for (int64_t i = 0; i < propertyView.size(); ++i) { + REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); + if (propertyView.getRaw(i) == noData) { + REQUIRE(!propertyView.get(i)); + } else { + REQUIRE(propertyView.get(i)); + REQUIRE(*propertyView.get(i) == propertyView.getRaw(i)); + } + } } - SECTION("Array offset values are not sorted ascending") { - uint32_t* offset = reinterpret_cast( - model.buffers[arrayOffsetBuffer].cesium.data.data()); - offset[0] = static_cast(1000); - PropertyTablePropertyView> - arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); - offset[0] = 0; + SECTION("With default value") { + const int8_t defaultValue = 100; + testClassProperty.defaultProperty = defaultValue; + classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty->defaultProperty); + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyView.size() > 0); + REQUIRE(propertyView.noData()); + REQUIRE(*propertyView.noData() == noData); + REQUIRE(propertyView.defaultValue()); + REQUIRE(*propertyView.defaultValue() == defaultValue); + + for (int64_t i = 0; i < propertyView.size(); ++i) { + REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); + REQUIRE(propertyView.get(i)); + if (propertyView.getRaw(i) == noData) { + REQUIRE(*propertyView.get(i) == defaultValue); + } else { + REQUIRE(*propertyView.get(i) == propertyView.getRaw(i)); + } + } } +} - SECTION("String offset values are not sorted ascending") { - uint32_t* offset = reinterpret_cast( - model.buffers[stringOffsetBuffer].cesium.data.data()); - offset[0] = static_cast(1000); - PropertyTablePropertyView> - arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorStringOffsetsNotSorted); - offset[0] = 0; - } +TEST_CASE("Test with property noData value (normalized)") { + Model model; + std::vector values = {-128, 0, 32, -128, 127}; + const int8_t noData = -128; - SECTION("Array offset value points outside of value buffer") { - uint32_t* offset = reinterpret_cast( - model.buffers[arrayOffsetBuffer].cesium.data.data()); - uint32_t previousValue = offset[propertyTable.count]; - offset[propertyTable.count] = static_cast(100000); - PropertyTablePropertyView> - arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); - offset[propertyTable.count] = previousValue; - } + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; - SECTION("String offset value points outside of value buffer") { - uint32_t* offset = reinterpret_cast( - model.buffers[stringOffsetBuffer].cesium.data.data()); - uint32_t previousValue = offset[6]; - offset[6] = static_cast(100000); - PropertyTablePropertyView> - arrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds); - offset[6] = previousValue; - } + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); - SECTION("Count and offset buffer both present") { - testClassProperty.count = 3; - PropertyTablePropertyView> - boolArrayProperty = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - boolArrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::INT8; + testClassProperty.normalized = true; + testClassProperty.noData = noData; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + REQUIRE(classProperty->noData); + + SECTION("Without default value") { + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyView.size() > 0); + REQUIRE(propertyView.noData()); + REQUIRE(*propertyView.noData() == noData); + + for (int64_t i = 0; i < propertyView.size(); ++i) { + REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); + if (propertyView.getRaw(i) == noData) { + REQUIRE(!propertyView.get(i)); + } else { + REQUIRE(propertyView.get(i)); + REQUIRE(*propertyView.get(i) == normalize(propertyView.getRaw(i))); + } + } } -} -template -void testFunction(PropertyTablePropertyView view) { - REQUIRE( - propertyValue.status() == - PropertyTablePropertyViewStatus::ErrorInvalidPropertyTable); + SECTION("With default value") { + const double defaultValue = 10.5; + testClassProperty.defaultProperty = defaultValue; + classProperty = view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty->defaultProperty); + + PropertyTablePropertyView propertyView = + view.getPropertyView("TestClassProperty"); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyView.size() > 0); + REQUIRE(propertyView.noData()); + REQUIRE(*propertyView.noData() == noData); + REQUIRE(propertyView.defaultValue()); + REQUIRE(*propertyView.defaultValue() == defaultValue); + + for (int64_t i = 0; i < propertyView.size(); ++i) { + REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); + REQUIRE(propertyView.get(i)); + if (propertyView.getRaw(i) == noData) { + REQUIRE(*propertyView.get(i) == defaultValue); + } else { + REQUIRE(*propertyView.get(i) == normalize(propertyView.getRaw(i))); + } + } + } } TEST_CASE("Test callback on invalid property table view") { @@ -2426,12 +4432,157 @@ TEST_CASE("Test callback for invalid PropertyTableProperty") { view.getPropertyView("InvalidProperty", testCallback); view.getPropertyView("NonexistentProperty", testCallback); - REQUIRE(invokedCallbackCount == 2); + REQUIRE(invokedCallbackCount == 2); +} + +TEST_CASE("Test callback for scalar PropertyTableProperty") { + Model model; + std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + if constexpr (std::is_same_v< + PropertyTablePropertyView, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + for (int64_t i = 0; i < propertyValue.size(); ++i) { + auto expectedValue = values[static_cast(i)]; + REQUIRE( + static_cast(propertyValue.getRaw(i)) == + expectedValue); + + auto maybeValue = propertyValue.get(i); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expectedValue); + } + } else { + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for scalar PropertyTableProperty (normalized)") { + Model model; + std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + if constexpr (std::is_same_v< + PropertyTablePropertyView, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + for (int64_t i = 0; i < propertyValue.size(); ++i) { + auto expectedValue = values[static_cast(i)]; + REQUIRE( + static_cast(propertyValue.getRaw(i)) == + expectedValue); + + auto maybeValue = propertyValue.get(i); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == normalize(expectedValue)); + } + } else { + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for scalar PropertyTableProperty") { +TEST_CASE("Test callback for vecN PropertyTableProperty") { Model model; - std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; + std::vector values = { + glm::ivec3(-12, 34, 30), + glm::ivec3(11, 73, 0), + glm::ivec3(-2, 6, 12), + glm::ivec3(-4, 8, -13)}; addBufferToModel(model, values); size_t valueBufferViewIndex = model.bufferViews.size() - 1; @@ -2442,8 +4593,8 @@ TEST_CASE("Test callback for scalar PropertyTableProperty") { Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; - testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; @@ -2460,10 +4611,11 @@ TEST_CASE("Test callback for scalar PropertyTableProperty") { const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); - REQUIRE(!classProperty->array); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); uint32_t invokedCallbackCount = 0; view.getPropertyView( @@ -2472,17 +4624,22 @@ TEST_CASE("Test callback for scalar PropertyTableProperty") { const std::string& /*propertyName*/, auto propertyValue) mutable { invokedCallbackCount++; + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + if constexpr (std::is_same_v< - PropertyTablePropertyView, + PropertyTablePropertyView, decltype(propertyValue)>) { - REQUIRE( - propertyValue.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(propertyValue.size() > 0); - for (int64_t i = 0; i < propertyValue.size(); ++i) { + auto expectedValue = values[static_cast(i)]; REQUIRE( - static_cast(propertyValue.getRaw(i)) == - values[static_cast(i)]); + static_cast(propertyValue.getRaw(i)) == + expectedValue); + + auto maybeValue = propertyValue.get(i); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expectedValue); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -2493,7 +4650,7 @@ TEST_CASE("Test callback for scalar PropertyTableProperty") { REQUIRE(invokedCallbackCount == 1); } -TEST_CASE("Test callback for vecN PropertyTableProperty") { +TEST_CASE("Test callback for vecN PropertyTableProperty (normalized)") { Model model; std::vector values = { glm::ivec3(-12, 34, 30), @@ -2512,6 +4669,7 @@ TEST_CASE("Test callback for vecN PropertyTableProperty") { ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; testClassProperty.type = ClassProperty::Type::VEC3; testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.normalized = true; PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); propertyTable.classProperty = "TestClass"; @@ -2532,6 +4690,7 @@ TEST_CASE("Test callback for vecN PropertyTableProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); uint32_t invokedCallbackCount = 0; view.getPropertyView( @@ -2545,12 +4704,17 @@ TEST_CASE("Test callback for vecN PropertyTableProperty") { REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - PropertyTablePropertyView, + PropertyTablePropertyView, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { + auto expectedValue = values[static_cast(i)]; REQUIRE( static_cast(propertyValue.getRaw(i)) == - values[static_cast(i)]); + expectedValue); + + auto maybeValue = propertyValue.get(i); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == normalize(expectedValue)); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -2610,6 +4774,7 @@ TEST_CASE("Test callback for matN PropertyTableProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); uint32_t invokedCallbackCount = 0; view.getPropertyView( @@ -2625,13 +4790,103 @@ TEST_CASE("Test callback for matN PropertyTableProperty") { PropertyTablePropertyView, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { + auto expectedValue = values[static_cast(i)]; + REQUIRE( + static_cast(propertyValue.getRaw(i)) == + expectedValue); + + auto maybeValue = propertyValue.get(i); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expectedValue); + } + } else { + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); + } + invokedCallbackCount++; + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for matN PropertyTableProperty (normalized)") { + Model model; + // clang-format off + std::vector values = { + glm::u32mat2x2( + 12, 34, + 30, 1), + glm::u32mat2x2( + 11, 8, + 73, 102), + glm::u32mat2x2( + 1, 0, + 63, 2), + glm::u32mat2x2( + 4, 8, + 3, 23)}; + // clang-format on + + addBufferToModel(model, values); + size_t valueBufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(values.size()); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = static_cast(valueBufferViewIndex); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr (std::is_same_v< + PropertyTablePropertyView, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + auto expectedValue = values[static_cast(i)]; REQUIRE( static_cast(propertyValue.getRaw(i)) == - values[static_cast(i)]); + expectedValue); + + auto maybeValue = propertyValue.get(i); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == normalize(expectedValue)); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " - "incorrecttype for TestClassProperty."); + "incorrect type for TestClassProperty."); } invokedCallbackCount++; }); @@ -2707,9 +4962,13 @@ TEST_CASE("Test callback for boolean PropertyTableProperty") { PropertyTablePropertyView, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { + auto expectedValue = expected[static_cast(i)]; REQUIRE( - static_cast(propertyValue.getRaw(i)) == - expected[static_cast(i)]); + static_cast(propertyValue.getRaw(i)) == expectedValue); + + auto maybeValue = propertyValue.get(i); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expectedValue); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -2796,9 +5055,14 @@ TEST_CASE("Test callback for string PropertyTableProperty") { PropertyTablePropertyView, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { + auto expectedValue = expected[static_cast(i)]; REQUIRE( static_cast(propertyValue.getRaw(i)) == - expected[static_cast(i)]); + expectedValue); + + auto maybeValue = propertyValue.get(i); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expectedValue); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -2848,6 +5112,7 @@ TEST_CASE("Test callback for scalar array PropertyTableProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 3); + REQUIRE(!classProperty->normalized); uint32_t invokedCallbackCount = 0; view.getPropertyView( @@ -2865,9 +5130,87 @@ TEST_CASE("Test callback for scalar array PropertyTableProperty") { PropertyArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.getRaw(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 3 + j)]); + PropertyArrayView array = propertyValue.getRaw(i); + auto maybeArray = propertyValue.get(i); + REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == values[static_cast(i * 3 + j)]); + REQUIRE((*maybeArray)[j] == array[j]); + } + } + } else { + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for scalar array PropertyTableProperty (normalized)") { + Model model; + std::vector values = + {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; + + addBufferToModel(model, values); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.array = true; + testClassProperty.count = 3; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + REQUIRE(classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr ( + std::is_same_v< + PropertyTablePropertyView, true>, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + PropertyArrayView array = propertyValue.getRaw(i); + auto maybeArray = propertyValue.get(i); + REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == values[static_cast(i * 3 + j)]); + REQUIRE((*maybeArray)[j] == normalize(array[j])); } } } else { @@ -2924,6 +5267,7 @@ TEST_CASE("Test callback for vecN array PropertyTableProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); + REQUIRE(!classProperty->normalized); uint32_t invokedCallbackCount = 0; view.getPropertyView( @@ -2941,9 +5285,95 @@ TEST_CASE("Test callback for vecN array PropertyTableProperty") { PropertyArrayView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.getRaw(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == values[static_cast(i * 2 + j)]); + PropertyArrayView array = propertyValue.getRaw(i); + auto maybeArray = propertyValue.get(i); + REQUIRE(maybeArray); + + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == values[static_cast(i * 2 + j)]); + REQUIRE((*maybeArray)[j] == array[j]); + } + } + } else { + FAIL("getPropertyView returned PropertyTablePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for vecN array PropertyTableProperty (normalized)") { + Model model; + std::vector values = { + glm::ivec3(12, 34, -30), + glm::ivec3(-2, 0, 1), + glm::ivec3(1, 2, 8), + glm::ivec3(-100, 84, 6), + glm::ivec3(2, -2, -2), + glm::ivec3(40, 61, 3), + }; + + addBufferToModel(model, values); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC3; + testClassProperty.componentType = ClassProperty::ComponentType::INT32; + testClassProperty.array = true; + testClassProperty.count = 2; + testClassProperty.normalized = true; + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast( + values.size() / static_cast(testClassProperty.count.value())); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = + static_cast(model.bufferViews.size() - 1); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + REQUIRE(classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&values, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyValue.size() > 0); + + if constexpr ( + std::is_same_v< + PropertyTablePropertyView, true>, + decltype(propertyValue)>) { + for (int64_t i = 0; i < propertyValue.size(); ++i) { + PropertyArrayView array = propertyValue.getRaw(i); + auto maybeArray = propertyValue.get(i); + REQUIRE(maybeArray); + + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == values[static_cast(i * 2 + j)]); + REQUIRE((*maybeArray)[j] == normalize(array[j])); } } } else { @@ -3121,9 +5551,12 @@ TEST_CASE("Test callback for boolean array PropertyTableProperty") { PropertyTablePropertyView>, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { - PropertyArrayView member = propertyValue.getRaw(i); - for (int64_t j = 0; j < member.size(); ++j) { - REQUIRE(member[j] == expected[static_cast(i * 3 + j)]); + PropertyArrayView array = propertyValue.getRaw(i); + auto maybeArray = propertyValue.get(i); + REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { + REQUIRE(array[j] == expected[static_cast(i * 3 + j)]); + REQUIRE((*maybeArray)[j] == array[j]); } } } else { @@ -3236,6 +5669,17 @@ TEST_CASE("Test callback for string array PropertyTableProperty") { REQUIRE(v2.size() == 2); REQUIRE(v2[0] == "I love you, meat bags! ❤️"); REQUIRE(v2[1] == "Book in the freezer"); + + for (int64_t i = 0; i < propertyValue.size(); i++) { + auto maybeValue = propertyValue.get(i); + REQUIRE(maybeValue); + + auto value = propertyValue.getRaw(i); + REQUIRE(maybeValue->size() == value.size()); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE((*maybeValue)[j] == value[j]); + } + } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " "incorrect type for TestClassProperty."); From 76427497ca3ae10eb8359654976b140341fe2bf4 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 24 Aug 2023 18:33:56 -0400 Subject: [PATCH 092/121] Rewrite property texture property tests --- .../include/CesiumGltf/PropertyTableView.h | 6 +- .../CesiumGltf/PropertyTexturePropertyView.h | 552 ++++- CesiumGltf/src/PropertyTableView.cpp | 4 +- .../test/TestPropertyTablePropertyView.cpp | 228 +- .../test/TestPropertyTexturePropertyView.cpp | 1902 +++++++++++------ 5 files changed, 1797 insertions(+), 895 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h index 4688b9e4d..c1aac5bf8 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -1209,7 +1209,7 @@ class PropertyTableView { return PropertyTablePropertyView, Normalized>( propertyTableProperty, classProperty, - static_cast(_pPropertyTable->count), + _pPropertyTable->count, values); } @@ -1240,7 +1240,7 @@ class PropertyTableView { return PropertyTablePropertyView, true>( propertyTableProperty, classProperty, - static_cast(_pPropertyTable->count), + _pPropertyTable->count, values, arrayOffsets, arrayOffsetType); @@ -1248,7 +1248,7 @@ class PropertyTableView { return PropertyTablePropertyView, false>( propertyTableProperty, classProperty, - static_cast(_pPropertyTable->count), + _pPropertyTable->count, values, arrayOffsets, gsl::span(), diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 731627a2d..f49b27baf 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -2,6 +2,7 @@ #include "CesiumGltf/ImageCesium.h" #include "CesiumGltf/PropertyTextureProperty.h" +#include "CesiumGltf/PropertyTransformations.h" #include "CesiumGltf/PropertyTypeTraits.h" #include "CesiumGltf/PropertyView.h" #include "CesiumGltf/Sampler.h" @@ -78,25 +79,101 @@ class PropertyTexturePropertyViewStatus : public PropertyViewStatus { static const int ErrorChannelsAndTypeMismatch = 20; }; +namespace { +template +ElementType assembleScalarValue(const std::vector& bytes) { + if constexpr (std::is_same_v) { + 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(bytes[i]) << i * 8; + } + + // Reinterpret the bits as a float. + return *reinterpret_cast(&resultAsUint); + } + + if constexpr (IsMetadataInteger::value) { + using UintType = std::make_unsigned_t; + UintType resultAsUint = 0; + for (size_t i = 0; i < bytes.size(); i++) { + resultAsUint |= static_cast(bytes[i]) << i * 8; + } + + // Reinterpret the bits with the correct signedness. + return *reinterpret_cast(&resultAsUint); + } +} + +double applySamplerWrapS(const double u, const int32_t wrapS) { + if (wrapS == Sampler::WrapS::REPEAT) { + double integral = 0; + double fraction = std::modf(u, &integral); + return fraction < 0 ? 1.0 - fraction : fraction; + } + + if (wrapS == Sampler::WrapS::MIRRORED_REPEAT) { + double integral = 0; + double fraction = std::abs(std::modf(u, &integral)); + int64_t integer = static_cast(std::abs(integral)); + // If the integer part is odd, the direction is reversed. + return integer % 2 == 1 ? 1.0 - fraction : fraction; + } + + return std::clamp(u, 0.0, 1.0); +} + +double applySamplerWrapT(const double v, const int32_t wrapT) { + if (wrapT == Sampler::WrapT::REPEAT) { + double integral = 0; + double fraction = std::modf(v, &integral); + return fraction < 0 ? 1.0 - fraction : fraction; + } + + if (wrapT == Sampler::WrapT::MIRRORED_REPEAT) { + double integral = 0; + double fraction = std::abs(std::modf(v, &integral)); + int64_t integer = static_cast(std::abs(integral)); + // If the integer part is odd, the direction is reversed. + return integer % 2 == 1 ? 1.0 - fraction : fraction; + } + + return std::clamp(v, 0.0, 1.0); +} +} // namespace + /** * @brief A view of the data specified by a {@link PropertyTextureProperty}. * * Provides utilities to sample the property texture property using texture * coordinates. */ -template class PropertyTexturePropertyView { +template +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. + */ +template +class PropertyTexturePropertyView + : public PropertyView { public: /** * @brief Constructs an invalid instance for a non-existent property. */ PropertyTexturePropertyView() noexcept - : _status(PropertyTexturePropertyViewStatus::ErrorNonexistentProperty), + : PropertyView(), _pSampler(nullptr), _pImage(nullptr), _texCoordSetIndex(0), _channels(), - _swizzle(""), - _normalized(false) {} + _swizzle("") {} /** * @brief Constructs an invalid instance for an erroneous property. @@ -104,13 +181,12 @@ template class PropertyTexturePropertyView { * @param status The code from {@link PropertyTexturePropertyViewStatus} indicating the error with the property. */ PropertyTexturePropertyView(PropertyViewStatusType status) noexcept - : _status(status), + : PropertyView(), _pSampler(nullptr), _pImage(nullptr), _texCoordSetIndex(0), _channels(), - _swizzle(""), - _normalized(false) { + _swizzle("") { assert( _status != PropertyTexturePropertyViewStatus::Valid && "An empty property view should not be constructed with a valid status"); @@ -119,6 +195,8 @@ template class PropertyTexturePropertyView { /** * @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 pSampler A pointer to the sampler used by the property. * @param pImage A pointer to the image used by the property. * @param texCoordSetIndex The value of {@link PropertyTextureProperty::texcoord}. @@ -126,18 +204,22 @@ template class PropertyTexturePropertyView { * @param normalized Whether this property has a normalized integer type. */ PropertyTexturePropertyView( + const PropertyTextureProperty& property, + const ClassProperty& classProperty, const Sampler& sampler, const ImageCesium& image, int64_t texCoordSetIndex, - const std::vector& channels, - bool normalized) noexcept - : _status(PropertyTexturePropertyViewStatus::Valid), + const std::vector& channels) noexcept + : PropertyView(classProperty, property), _pSampler(&sampler), _pImage(&image), _texCoordSetIndex(texCoordSetIndex), _channels(channels), - _swizzle(""), - _normalized(normalized) { + _swizzle("") { + if (this->_status != PropertyTexturePropertyViewStatus::Valid) { + return; + } + for (size_t i = 0; i < _channels.size(); ++i) { switch (_channels[i]) { case 0: @@ -159,8 +241,48 @@ template class PropertyTexturePropertyView { } /** - * @brief Gets the property value for the given texture coordinates. The - * sampler's wrapping mode will be used when sampling the texture. + * @brief Gets the raw 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 get(double u, double v) const noexcept { + ElementType value = getRaw(u, v); + + if (this->noData() && value == *(this->noData())) { + return this->defaultValue(); + } + + if constexpr (IsMetadataNumeric::value) { + value = transformValue(value, this->offset(), this->scale()); + } + + if constexpr (IsMetadataNumericArray::value) { + value = transformArray(value, this->offset(), this->scale()); + } + + 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. @@ -168,7 +290,7 @@ template class PropertyTexturePropertyView { * @return The value at the nearest pixel to the texture coordinates. */ - ElementType get(double u, double v) const noexcept { + ElementType getRaw(double u, double v) const noexcept { assert( _status == PropertyTexturePropertyViewStatus::Valid && "Check the status() first to make sure view is valid"); @@ -215,13 +337,6 @@ template class PropertyTexturePropertyView { return assembleValueFromChannels(channelValues); } - /** - * @brief Get the status of this view. - * - * If invalid, this view cannot be sampled. - */ - PropertyViewStatusType status() const noexcept { return this->_status; } - /** * @brief Get the texture coordinate set index for this property. */ @@ -229,11 +344,6 @@ template class PropertyTexturePropertyView { return this->_texCoordSetIndex; } - /** - * @brief Whether the component type for this property should be normalized. - */ - bool isNormalized() const noexcept { return this->_normalized; } - /** * @brief Get the image containing this property's data. * @@ -260,7 +370,7 @@ template class PropertyTexturePropertyView { assert(bytes.size() > 0 && "Channel input must have at least one value."); if constexpr (IsMetadataScalar::value) { - return assembleScalarValue(bytes); + return assembleScalarValue(bytes); } if constexpr (IsMetadataVecN::value) { @@ -273,33 +383,6 @@ template class PropertyTexturePropertyView { } } - ElementType - assembleScalarValue(const std::vector& bytes) const noexcept { - if constexpr (std::is_same_v) { - 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(bytes[i]) << i * 8; - } - - // Reinterpret the bits as a float. - return *reinterpret_cast(&resultAsUint); - } - - if constexpr (IsMetadataInteger::value) { - using UintType = std::make_unsigned_t; - UintType resultAsUint = 0; - for (size_t i = 0; i < bytes.size(); i++) { - resultAsUint |= static_cast(bytes[i]) << i * 8; - } - - // Reinterpret the bits with the correct signedness. - return *reinterpret_cast(&resultAsUint); - } - } - ElementType assembleVecNValue(const std::vector& bytes) const noexcept { const glm::length_t N = @@ -379,49 +462,356 @@ template class PropertyTexturePropertyView { return PropertyArrayView(std::move(result)); } - double applySamplerWrapS(const double u, const int32_t wrapS) const noexcept { - if (wrapS == Sampler::WrapS::REPEAT) { - double integral = 0; - double fraction = std::modf(u, &integral); - return fraction < 0 ? 1.0 - fraction : fraction; + const Sampler* _pSampler; + const ImageCesium* _pImage; + int64_t _texCoordSetIndex; + std::vector _channels; + std::string _swizzle; +}; + +/** + * @brief A view of the normalized data specified by a + * {@link PropertyTextureProperty}. + * + * Provides utilities to sample the property texture property using texture + * coordinates. + */ +template +class PropertyTexturePropertyView + : public PropertyView { +private: + using NormalizedType = typename TypeToNormalizedType::type; + +public: + /** + * @brief Constructs an invalid instance for a non-existent property. + */ + PropertyTexturePropertyView() noexcept + : PropertyView(), + _pSampler(nullptr), + _pImage(nullptr), + _texCoordSetIndex(0), + _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(), + _pSampler(nullptr), + _pImage(nullptr), + _texCoordSetIndex(0), + _channels(), + _swizzle("") { + assert( + _status != PropertyTexturePropertyViewStatus::Valid && + "An empty property view should not be constructed with a valid status"); + } + + /** + * @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 pSampler A pointer to the sampler used by the property. + * @param pImage A pointer to the image used by the property. + * @param texCoordSetIndex The value of {@link PropertyTextureProperty::texcoord}. + * @param channels The value of {@link PropertyTextureProperty::channels}. + * @param normalized Whether this property has a normalized integer type. + */ + PropertyTexturePropertyView( + const PropertyTextureProperty& property, + const ClassProperty& classProperty, + const Sampler& sampler, + const ImageCesium& image, + int64_t texCoordSetIndex, + const std::vector& channels) noexcept + : PropertyView(classProperty, property), + _pSampler(&sampler), + _pImage(&image), + _texCoordSetIndex(texCoordSetIndex), + _channels(channels), + _swizzle("") { + if (this->_status != PropertyTexturePropertyViewStatus::Valid) { + return; } - if (wrapS == Sampler::WrapS::MIRRORED_REPEAT) { - double integral = 0; - double fraction = std::abs(std::modf(u, &integral)); - int64_t integer = static_cast(std::abs(integral)); - // If the integer part is odd, the direction is reversed. - return integer % 2 == 1 ? 1.0 - fraction : fraction; + 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: + 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 get(double u, double v) const noexcept { + ElementType value = getRaw(u, v); - return std::clamp(u, 0.0, 1.0); + if (this->noData() && value == *(this->noData())) { + return this->defaultValue(); + } + + if constexpr (IsMetadataScalar::value) { + return transformValue( + normalize(value), + this->offset(), + this->scale()); + } + + if constexpr (IsMetadataVecN::value) { + constexpr glm::length_t N = ElementType::length(); + using T = typename ElementType::value_type; + using NormalizedT = typename NormalizedType::value_type; + return transformValue>( + normalize(value), + this->offset(), + this->scale()); + } + + if constexpr (IsMetadataArray::value) { + using ArrayElementType = typename MetadataArrayType::type; + if constexpr (IsMetadataScalar::value) { + return transformNormalizedArray( + value, + this->offset(), + this->scale()); + } + + if constexpr (IsMetadataVecN::value) { + constexpr glm::length_t N = ArrayElementType::length(); + using T = typename ArrayElementType::value_type; + return transformNormalizedVecNArray( + value, + this->offset(), + this->scale()); + } + } } - double applySamplerWrapT(const double v, const int32_t wrapT) const noexcept { - if (wrapT == Sampler::WrapT::REPEAT) { - double integral = 0; - double fraction = std::modf(v, &integral); - return fraction < 0 ? 1.0 - fraction : fraction; + /** + * @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. + */ + + ElementType getRaw(double u, double v) const noexcept { + assert( + _status == PropertyTexturePropertyViewStatus::Valid && + "Check the status() first to make sure view is valid"); + + double wrappedU = applySamplerWrapS(u, this->_pSampler->wrapS); + double wrappedV = applySamplerWrapT(v, this->_pSampler->wrapT); + + // TODO: account for sampler's filter (can be nearest or linear) + + // For nearest filtering, std::floor is used instead of std::round. + // This is because filtering is supposed to consider the pixel centers. But + // memory access here acts as sampling the beginning of the pixel. Example: + // 0.4 * 2 = 0.8. In a 2x1 pixel image, that should be closer to the left + // pixel's center. But it will round to 1.0 which corresponds to the right + // pixel. So the right pixel has a bigger range than the left one, which is + // incorrect. + double xCoord = std::floor(wrappedU * this->_pImage->width); + double yCoord = std::floor(wrappedV * this->_pImage->height); + + // Clamp to ensure no out-of-bounds data access + int64_t x = std::clamp( + static_cast(xCoord), + static_cast(0), + static_cast(this->_pImage->width) - 1); + int64_t y = std::clamp( + static_cast(yCoord), + static_cast(0), + static_cast(this->_pImage->height) - 1); + + int64_t pixelIndex = this->_pImage->bytesPerChannel * + this->_pImage->channels * + (y * this->_pImage->width + x); + + // TODO: Currently stb only outputs uint8 pixel types. If that + // changes this should account for additional pixel byte sizes. + const uint8_t* pValue = reinterpret_cast( + this->_pImage->pixelData.data() + pixelIndex); + + std::vector channelValues(this->_channels.size()); + for (size_t i = 0; i < this->_channels.size(); i++) { + channelValues[i] = *(pValue + this->_channels[i]); } - if (wrapT == Sampler::WrapT::MIRRORED_REPEAT) { - double integral = 0; - double fraction = std::abs(std::modf(v, &integral)); - int64_t integer = static_cast(std::abs(integral)); - // If the integer part is odd, the direction is reversed. - return integer % 2 == 1 ? 1.0 - fraction : fraction; + return assembleValueFromChannels(channelValues); + } + + /** + * @brief Get the texture coordinate set index for this property. + */ + int64_t getTexCoordSetIndex() const noexcept { + return this->_texCoordSetIndex; + } + + /** + * @brief Get the image containing this property's data. + * + * This will be nullptr if the property texture property view runs into + * problems during construction. + */ + const ImageCesium* getImage() const noexcept { return this->_pImage; } + + /** + * @brief Gets the channels of this property texture property. + */ + const std::vector& 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: + ElementType + assembleValueFromChannels(const std::vector& bytes) const noexcept { + assert(bytes.size() > 0 && "Channel input must have at least one value."); + + if constexpr (IsMetadataScalar::value) { + return assembleScalarValue(bytes); } - return std::clamp(v, 0.0, 1.0); + if constexpr (IsMetadataVecN::value) { + return assembleVecNValue(bytes); + } + + if constexpr (IsMetadataArray::value) { + return assembleArrayValue::type>( + bytes); + } + } + + ElementType + assembleVecNValue(const std::vector& bytes) const noexcept { + const glm::length_t N = + getDimensionsFromPropertyType(TypeToPropertyType::value); + switch (N) { + case 2: + return assembleVecNValueImpl<2, typename ElementType::value_type>(bytes); + case 3: + return assembleVecNValueImpl<3, typename ElementType::value_type>(bytes); + case 4: + return assembleVecNValueImpl<4, typename ElementType::value_type>(bytes); + default: + return ElementType(); + } + } + + template + ElementType + assembleVecNValueImpl(const std::vector& bytes) const noexcept { + ElementType result = ElementType(); + assert( + sizeof(T) <= 2 && + "Components cannot be larger than two bytes in size."); + + if constexpr (std::is_same_v) { + assert(N == 2 && "Only vec2s can contain two-byte integer components."); + uint16_t x = static_cast(bytes[0]) | + (static_cast(bytes[1]) << 8); + uint16_t y = static_cast(bytes[2]) | + (static_cast(bytes[3]) << 8); + + result[0] = *reinterpret_cast(&x); + result[1] = *reinterpret_cast(&y); + } + + if constexpr (std::is_same_v) { + assert(N == 2 && "Only vec2s can contain two-byte integer components."); + result[0] = static_cast(bytes[0]) | + (static_cast(bytes[1]) << 8); + result[1] = static_cast(bytes[2]) | + (static_cast(bytes[3]) << 8); + } + + if constexpr (std::is_same_v) { + for (size_t i = 0; i < bytes.size(); i++) { + result[i] = *reinterpret_cast(&bytes[i]); + } + } + + if constexpr (std::is_same_v) { + for (size_t i = 0; i < bytes.size(); i++) { + result[i] = bytes[i]; + } + } + + return result; } - PropertyViewStatusType _status; + template + PropertyArrayView + assembleArrayValue(const std::vector& bytes) const noexcept { + std::vector 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; + UintType resultAsUint = static_cast(bytes[b]) | + (static_cast(bytes[b + 1]) << 8); + result[i] = *reinterpret_cast(&resultAsUint); + } + } else { + for (size_t i = 0; i < bytes.size(); i++) { + result[i] = *reinterpret_cast(&bytes[i]); + } + } + + return PropertyArrayView(std::move(result)); + } const Sampler* _pSampler; const ImageCesium* _pImage; int64_t _texCoordSetIndex; std::vector _channels; std::string _swizzle; - bool _normalized; }; + } // namespace CesiumGltf diff --git a/CesiumGltf/src/PropertyTableView.cpp b/CesiumGltf/src/PropertyTableView.cpp index e26b53bc4..f2456cf77 100644 --- a/CesiumGltf/src/PropertyTableView.cpp +++ b/CesiumGltf/src/PropertyTableView.cpp @@ -373,7 +373,7 @@ PropertyTableView::getBooleanArrayPropertyValues( return PropertyTablePropertyView>( propertyTableProperty, classProperty, - static_cast(_pPropertyTable->count), + _pPropertyTable->count, values); } @@ -402,7 +402,7 @@ PropertyTableView::getBooleanArrayPropertyValues( return PropertyTablePropertyView>( propertyTableProperty, classProperty, - static_cast(_pPropertyTable->count), + _pPropertyTable->count, values, arrayOffsets, gsl::span(), diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 5ed7f2444..d6fb63878 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -53,7 +53,7 @@ template static void checkNumeric(const std::vector& expected) { } template -static void checkScalar( +static void checkNumeric( const std::vector& values, const std::vector>& expected, const std::optional offset = std::nullopt, @@ -85,6 +85,7 @@ static void checkScalar( gsl::span(data.data(), data.size())); REQUIRE(property.size() == static_cast(expected.size())); + REQUIRE(!property.normalized()); for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == values[static_cast(i)]); @@ -97,90 +98,10 @@ static void checkScalar( } } -template -static void checkVecN( - const std::vector>& values, - const std::vector>>& expected, - const std::optional offset = std::nullopt, - const std::optional scale = std::nullopt, - const std::optional noData = std::nullopt, - const std::optional defaultValue = std::nullopt) { - std::vector data; - data.resize(values.size() * sizeof(glm::vec)); - std::memcpy(data.data(), values.data(), data.size()); - - PropertyTableProperty propertyTableProperty; - ClassProperty classProperty; - classProperty.type = - convertPropertyTypeToString(TypeToPropertyType>::value); - - PropertyComponentType componentType = TypeToPropertyType::component; - classProperty.componentType = - convertPropertyComponentTypeToString(componentType); - - classProperty.offset = offset; - classProperty.scale = scale; - classProperty.noData = noData; - classProperty.defaultProperty = defaultValue; - - PropertyTablePropertyView> property( - propertyTableProperty, - classProperty, - static_cast(expected.size()), - gsl::span(data.data(), data.size())); - - REQUIRE(property.size() == static_cast(expected.size())); - - for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.getRaw(i) == values[static_cast(i)]); - REQUIRE(property.get(i) == expected[static_cast(i)]); - } -} - -template -static void checkMatN( - const std::vector>& values, - const std::vector>>& expected, - const std::optional offset = std::nullopt, - const std::optional scale = std::nullopt, - const std::optional noData = std::nullopt, - const std::optional defaultValue = std::nullopt) { - std::vector data; - data.resize(values.size() * sizeof(glm::mat)); - std::memcpy(data.data(), values.data(), data.size()); - - PropertyTableProperty propertyTableProperty; - ClassProperty classProperty; - classProperty.type = - convertPropertyTypeToString(TypeToPropertyType>::value); - - PropertyComponentType componentType = TypeToPropertyType::component; - classProperty.componentType = - convertPropertyComponentTypeToString(componentType); - - classProperty.offset = offset; - classProperty.scale = scale; - classProperty.noData = noData; - classProperty.defaultProperty = defaultValue; - - PropertyTablePropertyView> property( - propertyTableProperty, - classProperty, - static_cast(expected.size()), - gsl::span(data.data(), data.size())); - - REQUIRE(property.size() == static_cast(expected.size())); - - for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.getRaw(i) == values[static_cast(i)]); - REQUIRE(property.get(i) == expected[static_cast(i)]); - } -} - -template -static void checkNormalizedScalar( +template ::type> +static void checkNormalizedNumeric( const std::vector& values, - const std::vector>& expected, + const std::vector>& expected, const std::optional offset = std::nullopt, const std::optional scale = std::nullopt, const std::optional noData = std::nullopt, @@ -212,90 +133,7 @@ static void checkNormalizedScalar( gsl::span(data.data(), data.size())); REQUIRE(property.size() == static_cast(expected.size())); - - for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.getRaw(i) == values[static_cast(i)]); - REQUIRE(property.get(i) == expected[static_cast(i)]); - } -} - -template -static void checkNormalizedVecN( - const std::vector>& values, - const std::vector>>& expected, - const std::optional offset = std::nullopt, - const std::optional scale = std::nullopt, - const std::optional noData = std::nullopt, - const std::optional defaultValue = std::nullopt) { - std::vector data; - data.resize(values.size() * sizeof(glm::vec)); - std::memcpy(data.data(), values.data(), data.size()); - - PropertyTableProperty propertyTableProperty; - ClassProperty classProperty; - classProperty.type = - convertPropertyTypeToString(TypeToPropertyType>::value); - - PropertyComponentType componentType = TypeToPropertyType::component; - classProperty.componentType = - convertPropertyComponentTypeToString(componentType); - - classProperty.normalized = true; - - classProperty.offset = offset; - classProperty.scale = scale; - classProperty.noData = noData; - classProperty.defaultProperty = defaultValue; - - PropertyTablePropertyView, true> property( - propertyTableProperty, - classProperty, - static_cast(expected.size()), - gsl::span(data.data(), data.size())); - - REQUIRE(property.size() == static_cast(expected.size())); - - for (int64_t i = 0; i < property.size(); ++i) { - REQUIRE(property.getRaw(i) == values[static_cast(i)]); - REQUIRE(property.get(i) == expected[static_cast(i)]); - } -} - -template -static void checkNormalizedMatN( - const std::vector>& values, - const std::vector>>& expected, - const std::optional offset = std::nullopt, - const std::optional scale = std::nullopt, - const std::optional noData = std::nullopt, - const std::optional defaultValue = std::nullopt) { - std::vector data; - data.resize(values.size() * sizeof(glm::mat)); - std::memcpy(data.data(), values.data(), data.size()); - - PropertyTableProperty propertyTableProperty; - ClassProperty classProperty; - classProperty.type = - convertPropertyTypeToString(TypeToPropertyType>::value); - - PropertyComponentType componentType = TypeToPropertyType::component; - classProperty.componentType = - convertPropertyComponentTypeToString(componentType); - - classProperty.normalized = true; - - classProperty.offset = offset; - classProperty.scale = scale; - classProperty.noData = noData; - classProperty.defaultProperty = defaultValue; - - PropertyTablePropertyView, true> property( - propertyTableProperty, - classProperty, - static_cast(expected.size()), - gsl::span(data.data(), data.size())); - - REQUIRE(property.size() == static_cast(expected.size())); + REQUIRE(property.normalized()); for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == values[static_cast(i)]); @@ -744,7 +582,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { 64.0 / 255.0, 128.0 / 255.0, 1.0}; - checkNormalizedScalar(values, expected); + checkNormalizedNumeric(values, expected); } SECTION("Normalized Int16") { @@ -754,7 +592,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { 0.0, 16384.0 / 32767.0, 1.0}; - checkNormalizedScalar(values, expected); + checkNormalizedNumeric(values, expected); } SECTION("Float with Offset / Scale") { @@ -762,7 +600,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { std::optional offset = 1.0f; std::optional scale = 2.0f; std::vector> expected{26.0f, -24.0f, -9.0f, 14.5f}; - checkScalar(values, expected, offset, scale); + checkNumeric(values, expected, offset, scale); } SECTION("Normalized Uint8 with Offset and Scale") { @@ -774,7 +612,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { 1 + 2 * (64.0 / 255.0), 1 + 2 * (128.0 / 255.0), 3.0}; - checkNormalizedScalar(values, expected, offset, scale); + checkNormalizedNumeric(values, expected, offset, scale); } SECTION("Int16 with NoData") { @@ -785,7 +623,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { static_cast(3), static_cast(7), std::nullopt}; - checkScalar( + checkNumeric( values, expected, std::nullopt, @@ -803,7 +641,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { static_cast(3), static_cast(7), static_cast(0)}; - checkScalar( + checkNumeric( values, expected, std::nullopt, @@ -823,7 +661,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { 1 + 2 * (64.0 / 255.0), 1 + 2 * (128.0 / 255.0), 3.0}; - checkNormalizedScalar( + checkNormalizedNumeric( values, expected, offset, @@ -915,7 +753,7 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::dvec2(0.0, 64.0 / 255.0), glm::dvec2(128.0 / 255.0, 1.0), glm::dvec2(1.0, 0.0)}; - checkNormalizedVecN(values, expected); + checkNormalizedNumeric(values, expected); } SECTION("Normalized Int16 Vec2") { @@ -928,7 +766,7 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::dvec2(16384.0 / 32767.0, 1.0), glm::dvec2(1.0, -1.0), }; - checkNormalizedVecN(values, expected); + checkNormalizedNumeric(values, expected); } SECTION("Float Vec3 with Offset / Scale") { @@ -944,7 +782,7 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::vec3(14.0f, 4.0f, 11.0f), glm::vec3(17.0f, -1.0f, 5.0f), }; - checkVecN(values, expected, offset, scale); + checkNumeric(values, expected, offset, scale); } SECTION("Normalized Uint8 Vec2 with Offset and Scale") { @@ -958,7 +796,7 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::dvec2(0.0, 1 + (64.0 / 255.0)), glm::dvec2(2 * (128.0 / 255.0), 2.0), glm::dvec2(2.0, 1.0)}; - checkNormalizedVecN(values, expected, offset, scale); + checkNormalizedNumeric(values, expected, offset, scale); } SECTION("Int16 Vec2 with NoData") { @@ -971,7 +809,7 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::i16vec2(-1, 3), std::nullopt, glm::i16vec2(7, 0)}; - checkVecN<2, glm::i16>( + checkNumeric( values, expected, std::nullopt, @@ -991,7 +829,7 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::i16vec2(-1, 3), glm::i16vec2(0, 1), glm::i16vec2(7, 0)}; - checkVecN<2, glm::i16>( + checkNumeric( values, expected, std::nullopt, @@ -1015,7 +853,13 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::dvec2(2 * (128.0 / 255.0), 2.0), glm::dvec2(2.0, 1.0), glm::dvec2(5.0, 15.0)}; - checkNormalizedVecN(values, expected, offset, scale, noData, defaultValue); + checkNormalizedNumeric( + values, + expected, + offset, + scale, + noData, + defaultValue); } SECTION("Overrides class property values") { @@ -1148,7 +992,7 @@ TEST_CASE("Check matN PropertyTablePropertyView") { 1.0, 0.0, 128.0 / 255.0, 0.0)}; // clang-format on - checkNormalizedMatN(values, expected); + checkNormalizedNumeric(values, expected); } SECTION("Normalized Int16 Mat2") { @@ -1169,7 +1013,7 @@ TEST_CASE("Check matN PropertyTablePropertyView") { 1.0, -1.0), }; // clang-format on - checkNormalizedMatN(values, expected); + checkNormalizedNumeric(values, expected); } SECTION("Float Mat2 with Offset / Scale") { @@ -1203,7 +1047,7 @@ TEST_CASE("Check matN PropertyTablePropertyView") { 3.0f, 3.0f), }; // clang-format on - checkMatN(values, expected, offset, scale); + checkNumeric(values, expected, offset, scale); } SECTION("Normalized Uint8 Mat2 with Offset and Scale") { @@ -1229,7 +1073,7 @@ TEST_CASE("Check matN PropertyTablePropertyView") { 2.0, 1.0, 1.0, 0.0)}; // clang-format on - checkNormalizedMatN(values, expected, offset, scale); + checkNormalizedNumeric(values, expected, offset, scale); } SECTION("Int16 Mat3 with NoData") { @@ -1257,7 +1101,7 @@ TEST_CASE("Check matN PropertyTablePropertyView") { values[0], values[1], std::nullopt}; - checkMatN<3, glm::i16>( + checkNumeric( values, expected, std::nullopt, @@ -1294,7 +1138,7 @@ TEST_CASE("Check matN PropertyTablePropertyView") { values[0], values[1], glm::i16mat3x3(1)}; - checkMatN<3, glm::i16>( + checkNumeric( values, expected, std::nullopt, @@ -1335,7 +1179,13 @@ TEST_CASE("Check matN PropertyTablePropertyView") { 2.0, 1.0, 1.0, 0.0)}; // clang-format on - checkNormalizedMatN(values, expected, offset, scale, noData, defaultValue); + checkNormalizedNumeric( + values, + expected, + offset, + scale, + noData, + defaultValue); } SECTION("Overrides class property values") { diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index 7a329d00f..4cad0637f 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -10,75 +10,479 @@ #include using namespace CesiumGltf; +using namespace CesiumUtility; + +std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + +template +void checkTextureValues( + const std::vector& data, + const std::vector& expected) { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = static_cast(sizeof(T)); + image.bytesPerChannel = 1; + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels; + for (int32_t i = 0; i < image.channels; i++) { + channels.push_back(i); + } -TEST_CASE("Check scalar PropertyTexturePropertyView") { - SECTION("uint8_t") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 1; - image.bytesPerChannel = 1; + PropertyTexturePropertyView + view(property, classProperty, sampler, image, 0, channels); + switch (sizeof(T)) { + case 1: + CHECK(view.getSwizzle() == "r"); + break; + case 2: + CHECK(view.getSwizzle() == "rg"); + break; + case 3: + CHECK(view.getSwizzle() == "rgb"); + break; + case 4: + CHECK(view.getSwizzle() == "rgba"); + break; + default: + FAIL("Invalid property texture property view type"); + } - std::vector data{12, 33, 56, 67}; - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); + REQUIRE(!view.normalized()); - std::vector channels{0}; + for (size_t i = 0; i < texCoords.size(); i++) { + glm::dvec2 uv = texCoords[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == expected[i]); - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expected[i]); + } +} + +template +void checkTextureValues( + const std::vector& data, + const std::vector& expectedRaw, + const std::vector>& expectedTransformed, + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; + + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = static_cast(sizeof(T)); + image.bytesPerChannel = 1; + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels; + for (int32_t i = 0; i < image.channels; i++) { + channels.push_back(i); + } + + PropertyTexturePropertyView + view(property, classProperty, sampler, image, 0, channels); + switch (sizeof(T)) { + case 1: CHECK(view.getSwizzle() == "r"); + break; + case 2: + CHECK(view.getSwizzle() == "rg"); + break; + case 3: + CHECK(view.getSwizzle() == "rgb"); + break; + case 4: + CHECK(view.getSwizzle() == "rgba"); + break; + default: + FAIL("Invalid property texture property view type"); + } + + REQUIRE(!view.normalized()); + + for (size_t i = 0; i < texCoords.size(); i++) { + glm::dvec2 uv = texCoords[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == expectedRaw[i]); - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == data[i]); + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue == expectedTransformed[i]); + } +} + +template ::type> +void checkNormalizedTextureValues( + const std::vector& data, + const std::vector& expectedRaw, + const std::vector>& expectedTransformed, + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.normalized = true; + + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; + + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = static_cast(sizeof(T)); + image.bytesPerChannel = 1; + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels; + for (int32_t i = 0; i < image.channels; i++) { + channels.push_back(i); + } + + PropertyTexturePropertyView + view(property, classProperty, sampler, image, 0, channels); + switch (sizeof(T)) { + case 1: + CHECK(view.getSwizzle() == "r"); + break; + case 2: + CHECK(view.getSwizzle() == "rg"); + break; + case 3: + CHECK(view.getSwizzle() == "rgb"); + break; + case 4: + CHECK(view.getSwizzle() == "rgba"); + break; + default: + FAIL("Invalid property texture property view type"); + } + + REQUIRE(view.normalized()); + + for (size_t i = 0; i < texCoords.size(); i++) { + glm::dvec2 uv = texCoords[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == expectedRaw[i]); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue == expectedTransformed[i]); + } +} + +template +void checkTextureArrayValues( + const std::vector& data, + const int64_t count, + const std::vector>& expected) { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.array = true; + classProperty.count = count; + + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = + static_cast(count) * static_cast(sizeof(T)); + image.bytesPerChannel = 1; + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels; + for (int32_t i = 0; i < image.channels; i++) { + channels.push_back(i); + } + + PropertyTexturePropertyView> + view(property, classProperty, sampler, image, 0, channels); + switch (image.channels) { + case 1: + CHECK(view.getSwizzle() == "r"); + break; + case 2: + CHECK(view.getSwizzle() == "rg"); + break; + case 3: + CHECK(view.getSwizzle() == "rgb"); + break; + case 4: + CHECK(view.getSwizzle() == "rgba"); + break; + default: + FAIL("Unsupported count value"); + } + + REQUIRE(!view.normalized()); + + for (size_t i = 0; i < texCoords.size(); i++) { + const std::vector& expectedValue = expected[i]; + glm::dvec2 uv = texCoords[i]; + + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(static_cast(value.size()) == expectedValue.size()); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(maybeValue->size() == value.size()); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE(value[j] == expectedValue[static_cast(j)]); + REQUIRE((*maybeValue)[j] == value[j]); } } +} - SECTION("int8_t") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 1; - image.bytesPerChannel = 1; +template +void checkTextureArrayValues( + const std::vector& data, + const int64_t count, + const std::vector>& expectedRaw, + const std::vector>>& expectedTransformed, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.array = true; + classProperty.count = count; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; + + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = + static_cast(count) * static_cast(sizeof(T)); + image.bytesPerChannel = 1; + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels; + for (int32_t i = 0; i < image.channels; i++) { + channels.push_back(i); + } - std::vector data{255, 0, 223, 67}; - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); + PropertyTexturePropertyView> + view(property, classProperty, sampler, image, 0, channels); + switch (count) { + case 1: + CHECK(view.getSwizzle() == "r"); + break; + case 2: + CHECK(view.getSwizzle() == "rg"); + break; + case 3: + CHECK(view.getSwizzle() == "rgb"); + break; + case 4: + CHECK(view.getSwizzle() == "rgba"); + break; + default: + FAIL("Unsupported count value"); + } + + REQUIRE(!view.normalized()); + + for (size_t i = 0; i < texCoords.size(); i++) { + auto expectedRawValue = expectedRaw[i]; + glm::dvec2 uv = texCoords[i]; + + // Check raw values first + auto rawValue = view.getRaw(uv[0], uv[1]); + REQUIRE(static_cast(rawValue.size()) == expectedRawValue.size()); + for (int64_t j = 0; j < rawValue.size(); j++) { + REQUIRE(rawValue[j] == expectedRawValue[static_cast(j)]); + } + + // Check transformed values + auto maybeValue = view.get(uv[0], uv[1]); + if (!maybeValue) { + REQUIRE(!expectedTransformed[i]); + continue; + } - std::vector channels{0}; + auto expectedValue = *(expectedTransformed[i]); + REQUIRE(maybeValue->size() == static_cast(expectedValue.size())); + for (int64_t j = 0; j < maybeValue->size(); j++) { + REQUIRE((*maybeValue)[j] == expectedValue[static_cast(j)]); + } + } +} - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); +template ::type> +void checkNormalizedTextureArrayValues( + const std::vector& data, + const int64_t count, + const std::vector>& expectedRaw, + const std::vector>>& expectedTransformed, + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.array = true; + classProperty.count = count; + classProperty.normalized = true; + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; + + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = + static_cast(count) * static_cast(sizeof(T)); + image.bytesPerChannel = 1; + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels; + for (int32_t i = 0; i < image.channels; i++) { + channels.push_back(i); + } + + PropertyTexturePropertyView, true> + view(property, classProperty, sampler, image, 0, channels); + switch (image.channels) { + case 1: CHECK(view.getSwizzle() == "r"); + break; + case 2: + CHECK(view.getSwizzle() == "rg"); + break; + case 3: + CHECK(view.getSwizzle() == "rgb"); + break; + case 4: + CHECK(view.getSwizzle() == "rgba"); + break; + default: + FAIL("Unsupported count value"); + } - std::vector expected{-1, 0, -33, 67}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); + REQUIRE(view.normalized()); + + for (size_t i = 0; i < texCoords.size(); i++) { + auto expectedRawValue = expectedRaw[i]; + glm::dvec2 uv = texCoords[i]; + + // Check raw values first + auto rawValue = view.getRaw(uv[0], uv[1]); + REQUIRE(static_cast(rawValue.size()) == expectedRawValue.size()); + for (int64_t j = 0; j < rawValue.size(); j++) { + REQUIRE(rawValue[j] == expectedRawValue[static_cast(j)]); + } + + // Check transformed values + auto maybeValue = view.get(uv[0], uv[1]); + if (!maybeValue) { + REQUIRE(!expectedTransformed[i]); + continue; + } + + auto expectedValue = *(expectedTransformed[i]); + REQUIRE(maybeValue->size() == static_cast(expectedValue.size())); + for (int64_t j = 0; j < maybeValue->size(); j++) { + REQUIRE((*maybeValue)[j] == expectedValue[j]); } } +} - SECTION("uint16_t") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 2; - image.bytesPerChannel = 1; +TEST_CASE("Check scalar PropertyTexturePropertyView") { + SECTION("uint8_t") { + std::vector data{12, 33, 56, 67}; + checkTextureValues(data, data); + } + SECTION("int8_t") { + std::vector data{255, 0, 223, 67}; + std::vector expected{-1, 0, -33, 67}; + checkTextureValues(data, expected); + } + + SECTION("uint16_t") { // clang-format off std::vector data{ 28, 0, @@ -86,36 +490,11 @@ TEST_CASE("Check scalar PropertyTexturePropertyView") { 0, 3, 182, 1}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1}; - - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rg"); - std::vector expected{28, 257, 768, 438}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("int16_t") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 2; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 255, 255, @@ -123,36 +502,11 @@ TEST_CASE("Check scalar PropertyTexturePropertyView") { 0, 3, 182, 1}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1}; - - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rg"); - std::vector expected{-1, -32511, 768, 438}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("uint32_t") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 0, 0, 0, 1, @@ -160,36 +514,11 @@ TEST_CASE("Check scalar PropertyTexturePropertyView") { 20, 2, 2, 0, 8, 1, 0, 1}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2, 3}; - - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); - std::vector expected{16777216, 65545, 131604, 16777480}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("int32_t") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 255, 255, 255, 255, @@ -197,35 +526,11 @@ TEST_CASE("Check scalar PropertyTexturePropertyView") { 20, 2, 2, 255, 8, 1, 0, 1}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2, 3}; - - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); std::vector expected{-1, 65545, -16645612, 16777480}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("float") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 0, 0, 0, 1, @@ -234,15 +539,6 @@ TEST_CASE("Check scalar PropertyTexturePropertyView") { 8, 1, 0, 1}; // clang-format on - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2, 3}; - - PropertyTexturePropertyView view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); - std::vector expectedUint{16777216, 65545, 131604, 16777480}; std::vector expected(expectedUint.size()); for (size_t i = 0; i < expectedUint.size(); i++) { @@ -250,67 +546,177 @@ TEST_CASE("Check scalar PropertyTexturePropertyView") { expected[i] = value; } - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); + checkTextureValues(data, expected); + } + + SECTION("float with offset / scale") { + // clang-format off + std::vector data{ + 0, 0, 0, 1, + 9, 0, 1, 0, + 20, 2, 2, 0, + 8, 1, 0, 1}; + // clang-format on + + std::vector expectedUint{16777216, 65545, 131604, 16777480}; + std::vector expectedRaw(expectedUint.size()); + std::vector> expectedTransformed(expectedUint.size()); + + const float offset = 1.0f; + const float scale = 2.0f; + + for (size_t i = 0; i < expectedUint.size(); i++) { + float value = *reinterpret_cast(&expectedUint[i]); + expectedRaw[i] = value; + expectedTransformed[i] = value * scale + offset; } + + checkTextureValues(data, expectedRaw, expectedTransformed, offset, scale); + } + + SECTION("uint8_t with noData") { + std::vector data{12, 33, 0, 128, 0, 56, 67}; + const uint8_t noData = 0; + std::vector> expected{ + data[0], + data[1], + std::nullopt, + data[3], + std::nullopt, + data[5], + data[6]}; + checkTextureValues( + data, + data, + expected, + std::nullopt, + std::nullopt, + noData); + } + + SECTION("uint8_t with noData and defaultValue") { + std::vector data{12, 33, 0, 128, 0, 56, 67}; + const uint8_t noData = 0; + const uint8_t defaultValue = 255; + std::vector> expected{ + data[0], + data[1], + defaultValue, + data[3], + defaultValue, + data[5], + data[6]}; + checkTextureValues( + data, + data, + expected, + std::nullopt, + std::nullopt, + noData, + defaultValue); } } -TEST_CASE("Check vecN PropertyTexturePropertyView") { - SECTION("glm::u8vec2") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 2; - image.bytesPerChannel = 1; +TEST_CASE("Check scalar PropertyTexturePropertyView (normalized)") { + SECTION("uint8_t") { + std::vector data{12, 33, 56, 67}; + std::vector> expected{ + 12.0 / 255.0, + 33 / 255.0, + 56 / 255.0, + 67 / 255.0}; + checkNormalizedTextureValues(data, data, expected); + } + SECTION("int16_t") { // clang-format off std::vector data{ - 28, 0, - 1, 1, + 255, 255, + 1, 129, 0, 3, 182, 1}; // clang-format on + std::vector expectedRaw{-1, -32511, 768, 438}; + std::vector> expectedTransformed{ + normalize(expectedRaw[0]), + normalize(expectedRaw[1]), + normalize(expectedRaw[2]), + normalize(expectedRaw[3])}; + checkNormalizedTextureValues(data, expectedRaw, expectedTransformed); + } - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); + SECTION("uint32_t") { + // clang-format off + std::vector data{ + 0, 0, 0, 1, + 9, 0, 1, 0, + 20, 2, 2, 0, + 8, 1, 0, 1}; + // clang-format on + std::vector expectedRaw{16777216, 65545, 131604, 16777480}; + std::vector> expectedTransformed{ + normalize(expectedRaw[0]), + normalize(expectedRaw[1]), + normalize(expectedRaw[2]), + normalize(expectedRaw[3])}; + checkNormalizedTextureValues(data, expectedRaw, expectedTransformed); + } - std::vector channels{0, 1}; + SECTION("uint8_t with offset / scale") { + std::vector data{12, 33, 56, 67}; + const double offset = 1.0; + const double scale = 2.0; + std::vector> expected{ + normalize(data[0]) * scale + offset, + normalize(data[1]) * scale + offset, + normalize(data[2]) * scale + offset, + normalize(data[3]) * scale + offset, + }; + checkNormalizedTextureValues(data, data, expected, offset, scale); + } - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rg"); + SECTION("uint8_t with all properties") { + std::vector data{12, 33, 56, 0, 67}; + const double offset = 1.0; + const double scale = 2.0; + const uint8_t noData = 0; + const double defaultValue = 10.0; + std::vector> expected{ + normalize(data[0]) * scale + offset, + normalize(data[1]) * scale + offset, + normalize(data[2]) * scale + offset, + 10.0, + normalize(data[4]) * scale + offset, + }; + checkNormalizedTextureValues( + data, + data, + expected, + offset, + scale, + noData, + defaultValue); + } +} +TEST_CASE("Check vecN PropertyTexturePropertyView") { + SECTION("glm::u8vec2") { + // clang-format off + std::vector data{ + 28, 0, + 1, 1, + 0, 3, + 182, 1}; + // clang-format on std::vector expected{ glm::u8vec2(28, 0), glm::u8vec2(1, 1), glm::u8vec2(0, 3), glm::u8vec2(182, 1)}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("glm::i8vec2") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 2; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 28, 255, @@ -318,40 +724,15 @@ TEST_CASE("Check vecN PropertyTexturePropertyView") { 0, 3, 182, 1}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1}; - - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rg"); - std::vector expected{ glm::i8vec2(28, -1), glm::i8vec2(-2, 1), glm::i8vec2(0, 3), glm::i8vec2(-74, 1)}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("glm::u8vec3") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 3; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 1, 2, 3, @@ -359,40 +740,15 @@ TEST_CASE("Check vecN PropertyTexturePropertyView") { 7, 8, 9, 0, 5, 2}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2}; - - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgb"); - std::vector expected{ glm::u8vec3(1, 2, 3), glm::u8vec3(4, 5, 6), glm::u8vec3(7, 8, 9), glm::u8vec3(0, 5, 2)}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("glm::i8vec3") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 3; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 255, 2, 3, @@ -400,40 +756,15 @@ TEST_CASE("Check vecN PropertyTexturePropertyView") { 7, 8, 159, 0, 5, 2}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2}; - - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgb"); - std::vector expected{ glm::i8vec3(-1, 2, 3), glm::i8vec3(4, -2, 6), glm::i8vec3(7, 8, -97), glm::i8vec3(0, 5, 2)}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("glm::u8vec4") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 1, 2, 3, 0, @@ -441,40 +772,15 @@ TEST_CASE("Check vecN PropertyTexturePropertyView") { 7, 8, 9, 3, 0, 5, 2, 27}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2, 3}; - - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); - std::vector expected{ glm::u8vec4(1, 2, 3, 0), glm::u8vec4(4, 5, 6, 11), glm::u8vec4(7, 8, 9, 3), glm::u8vec4(0, 5, 2, 27)}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("glm::i8vec4") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 1, 200, 3, 0, @@ -482,40 +788,15 @@ TEST_CASE("Check vecN PropertyTexturePropertyView") { 129, 8, 9, 3, 0, 155, 2, 27}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2, 3}; - - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); - std::vector expected{ glm::i8vec4(1, -56, 3, 0), glm::i8vec4(4, 5, 6, -5), glm::i8vec4(-127, 8, 9, 3), glm::i8vec4(0, -101, 2, 27)}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("glm::u16vec2") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 0, 0, 0, 1, @@ -523,40 +804,160 @@ TEST_CASE("Check vecN PropertyTexturePropertyView") { 20, 2, 2, 0, 8, 1, 0, 1}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2, 3}; - - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); - std::vector expected{ glm::u16vec2(0, 256), glm::u16vec2(9, 1), glm::u16vec2(532, 2), glm::u16vec2(264, 256)}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + checkTextureValues(data, expected); } SECTION("glm::i16vec2") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; + // clang-format off + std::vector data{ + 255, 255, 0, 1, + 9, 0, 146, 195, + 20, 2, 2, 0, + 8, 1, 255, 1}; + // clang-format on + std::vector expected{ + glm::i16vec2(-1, 256), + glm::i16vec2(9, -15470), + glm::i16vec2(532, 2), + glm::i16vec2(264, 511)}; + checkTextureValues(data, expected); + } + SECTION("glm::i8vec2 with noData") { + // clang-format off + std::vector data{ + 28, 255, + 254, 1, + 0, 3, + 0, 0, + 182, 1}; + // clang-format on + std::optional noData = JsonValue::Array{0, 0}; + std::vector expectedRaw{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(0), + glm::i8vec2(-74, 1)}; + std::vector> expectedTransformed{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + std::nullopt, + glm::i8vec2(-74, 1)}; + checkTextureValues( + data, + expectedRaw, + expectedTransformed, + std::nullopt, + std::nullopt, + noData); + } + + SECTION("glm::i8vec2 with defaultValue") { + // clang-format off + std::vector data{ + 28, 255, + 254, 1, + 0, 3, + 0, 0, + 182, 1}; + // clang-format on + std::optional noData = JsonValue::Array{0, 0}; + std::optional defaultValue = JsonValue::Array{127, 127}; + std::vector expectedRaw{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(0, 0), + glm::i8vec2(-74, 1)}; + std::vector> expectedTransformed{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(127, 127), + glm::i8vec2(-74, 1)}; + checkTextureValues( + data, + expectedRaw, + expectedTransformed, + std::nullopt, + std::nullopt, + noData, + defaultValue); + } +} + +TEST_CASE("Check vecN PropertyTexturePropertyView (normalized)") { + SECTION("glm::i8vec2") { + // clang-format off + std::vector data{ + 28, 255, + 254, 1, + 0, 3, + 182, 1}; + // clang-format on + std::vector expectedRaw{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(-74, 1)}; + std::vector> expectedTransformed{ + normalize(expectedRaw[0]), + normalize(expectedRaw[1]), + normalize(expectedRaw[2]), + normalize(expectedRaw[3])}; + checkNormalizedTextureValues(data, expectedRaw, expectedTransformed); + } + + SECTION("glm::u8vec3") { + // clang-format off + std::vector data{ + 1, 2, 3, + 4, 5, 6, + 7, 8, 9, + 0, 5, 2}; + // clang-format on + std::vector expectedRaw{ + glm::u8vec3(1, 2, 3), + glm::u8vec3(4, 5, 6), + glm::u8vec3(7, 8, 9), + glm::u8vec3(0, 5, 2)}; + std::vector> expectedTransformed{ + normalize(expectedRaw[0]), + normalize(expectedRaw[1]), + normalize(expectedRaw[2]), + normalize(expectedRaw[3])}; + checkNormalizedTextureValues(data, expectedRaw, expectedTransformed); + } + + SECTION("glm::u8vec4") { + // clang-format off + std::vector data{ + 1, 2, 3, 0, + 4, 5, 6, 11, + 7, 8, 9, 3, + 0, 5, 2, 27}; + // clang-format on + std::vector expectedRaw{ + glm::u8vec4(1, 2, 3, 0), + glm::u8vec4(4, 5, 6, 11), + glm::u8vec4(7, 8, 9, 3), + glm::u8vec4(0, 5, 2, 27)}; + std::vector> expectedTransformed{ + normalize(expectedRaw[0]), + normalize(expectedRaw[1]), + normalize(expectedRaw[2]), + normalize(expectedRaw[3])}; + checkNormalizedTextureValues(data, expectedRaw, expectedTransformed); + } + + SECTION("glm::i16vec2") { // clang-format off std::vector data{ 255, 255, 0, 1, @@ -564,42 +965,92 @@ TEST_CASE("Check vecN PropertyTexturePropertyView") { 20, 2, 2, 0, 8, 1, 255, 1}; // clang-format on + std::vector expectedRaw{ + glm::i16vec2(-1, 256), + glm::i16vec2(9, -15470), + glm::i16vec2(532, 2), + glm::i16vec2(264, 511)}; + std::vector> expectedTransformed{ + normalize(expectedRaw[0]), + normalize(expectedRaw[1]), + normalize(expectedRaw[2]), + normalize(expectedRaw[3])}; + checkNormalizedTextureValues(data, expectedRaw, expectedTransformed); + } - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); + SECTION("glm::i8vec2 with offset / scale") { + // clang-format off + std::vector data{ + 28, 255, + 254, 1, + 0, 3, + 0, 0, + 182, 1}; + // clang-format on + const glm::dvec2 offset(-1.0, 4.0); + const glm::dvec2 scale(2.0, 1.0); - std::vector channels{0, 1, 2, 3}; + std::vector expectedRaw{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(0), + glm::i8vec2(-74, 1)}; + std::vector> expectedTransformed{ + normalize(expectedRaw[0]) * scale + offset, + normalize(expectedRaw[1]) * scale + offset, + normalize(expectedRaw[2]) * scale + offset, + normalize(expectedRaw[3]) * scale + offset, + normalize(expectedRaw[4]) * scale + offset, + }; + checkNormalizedTextureValues( + data, + expectedRaw, + expectedTransformed, + JsonValue::Array{offset[0], offset[1]}, + JsonValue::Array{scale[0], scale[1]}); + } - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); + SECTION("glm::i8vec2 with all properties") { + // clang-format off + std::vector data{ + 28, 255, + 254, 1, + 0, 3, + 0, 0, + 182, 1}; + // clang-format on + const glm::dvec2 offset(-1.0, 4.0); + const glm::dvec2 scale(2.0, 1.0); + const glm::i8vec2 noData(0); + const glm::dvec2 defaultValue(100.0, 5.5); - std::vector expected{ - glm::i16vec2(-1, 256), - glm::i16vec2(9, -15470), - glm::i16vec2(532, 2), - glm::i16vec2(264, 511)}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); - } + std::vector expectedRaw{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(0), + glm::i8vec2(-74, 1)}; + std::vector> expectedTransformed{ + normalize(expectedRaw[0]) * scale + offset, + normalize(expectedRaw[1]) * scale + offset, + normalize(expectedRaw[2]) * scale + offset, + defaultValue, + normalize(expectedRaw[4]) * scale + offset, + }; + checkNormalizedTextureValues( + data, + expectedRaw, + expectedTransformed, + JsonValue::Array{offset[0], offset[1]}, + JsonValue::Array{scale[0], scale[1]}, + JsonValue::Array{noData[0], noData[1]}, + JsonValue::Array{defaultValue[0], defaultValue[1]}); } } TEST_CASE("Check array PropertyTexturePropertyView") { SECTION("uint8_t array") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 1, 2, 3, 0, @@ -608,43 +1059,15 @@ TEST_CASE("Check array PropertyTexturePropertyView") { 0, 5, 2, 27}; // clang-format on - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2, 3}; - - PropertyTexturePropertyView> - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); - - std::vector> values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - - int64_t size = static_cast(values.size()); - for (int64_t i = 0; i < size; i++) { - auto dataStart = data.begin() + i * 4; - std::vector expected(dataStart, dataStart + 4); - - const PropertyArrayView& value = values[static_cast(i)]; - REQUIRE(static_cast(value.size()) == expected.size()); - for (int64_t j = 0; j < value.size(); j++) { - REQUIRE(value[j] == expected[static_cast(j)]); - } - } + std::vector> expected{ + {1, 2, 3, 0}, + {4, 5, 6, 11}, + {7, 8, 9, 3}, + {0, 5, 2, 27}}; + checkTextureArrayValues(data, 4, expected); } SECTION("int8_t array") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 1, 200, 3, 0, @@ -652,46 +1075,15 @@ TEST_CASE("Check array PropertyTexturePropertyView") { 129, 8, 9, 3, 0, 155, 2, 27}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2, 3}; - - PropertyTexturePropertyView> - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); - std::vector> expected{ {1, -56, 3, 0}, {4, 5, 6, -5}, {-127, 8, 9, 3}, {0, -101, 2, 27}}; - std::vector> values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - - for (size_t i = 0; i < values.size(); i++) { - std::vector& expectedValue = expected[i]; - const PropertyArrayView& value = values[i]; - REQUIRE(static_cast(value.size()) == expected.size()); - for (int64_t j = 0; j < value.size(); j++) { - REQUIRE(value[j] == expectedValue[static_cast(j)]); - } - } + checkTextureArrayValues(data, 4, expected); } SECTION("uint16_t array") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 0, 0, 0, 1, @@ -699,47 +1091,15 @@ TEST_CASE("Check array PropertyTexturePropertyView") { 20, 2, 2, 0, 8, 1, 0, 1}; // clang-format on - - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0, 1, 2, 3}; - - PropertyTexturePropertyView> - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); - - std::vector> values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - std::vector> expected{ {0, 256}, {9, 1}, {532, 2}, {264, 256}}; - - for (size_t i = 0; i < expected.size(); i++) { - std::vector& expectedValue = expected[i]; - const PropertyArrayView& value = values[i]; - REQUIRE(static_cast(value.size()) == expectedValue.size()); - for (int64_t j = 0; j < value.size(); j++) { - REQUIRE(value[j] == expectedValue[static_cast(j)]); - } - } + checkTextureArrayValues(data, 2, expected); } SECTION("int16_t array") { - Sampler sampler; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 4; - image.bytesPerChannel = 1; - // clang-format off std::vector data{ 255, 255, 0, 1, @@ -747,40 +1107,332 @@ TEST_CASE("Check array PropertyTexturePropertyView") { 20, 2, 2, 0, 8, 255, 0, 1}; // clang-format on + std::vector> expected{ + {-1, 256}, + {9, -15470}, + {532, 2}, + {-248, 256}}; + checkTextureArrayValues(data, 2, expected); + } + + SECTION("uint8_t array with noData") { + // clang-format off + std::vector data{ + 1, 2, 3, 0, + 4, 5, 6, 11, + 7, 8, 9, 3, + 0, 0, 0, 0,}; + // clang-format on - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); + std::optional noData = JsonValue::Array{0, 0, 0, 0}; + std::vector> expectedRaw{ + {1, 2, 3, 0}, + {4, 5, 6, 11}, + {7, 8, 9, 3}, + {0, 0, 0, 0}}; + std::vector>> expectedTransformed{ + std::vector{1, 2, 3, 0}, + std::vector{4, 5, 6, 11}, + std::vector{7, 8, 9, 3}, + std::nullopt}; + checkTextureArrayValues(data, 4, expectedRaw, expectedTransformed, noData); + } - std::vector channels{0, 1, 2, 3}; + SECTION("uint8_t array with noData and defaultValue") { + // clang-format off + std::vector data{ + 1, 2, 3, 0, + 4, 5, 6, 11, + 7, 8, 9, 3, + 0, 0, 0, 0,}; + // clang-format on - PropertyTexturePropertyView> - view(sampler, image, 0, channels, false); - CHECK(view.getSwizzle() == "rgba"); + std::optional noData = JsonValue::Array{0, 0, 0, 0}; + std::optional defaultValue = JsonValue::Array{255, 8, 12, 5}; + std::vector> expectedRaw{ + {1, 2, 3, 0}, + {4, 5, 6, 11}, + {7, 8, 9, 3}, + {0, 0, 0, 0}}; + std::vector>> expectedTransformed{ + std::vector{1, 2, 3, 0}, + std::vector{4, 5, 6, 11}, + std::vector{7, 8, 9, 3}, + std::vector{255, 8, 12, 5}}; + checkTextureArrayValues( + data, + 4, + expectedRaw, + expectedTransformed, + noData, + defaultValue); + } +} - std::vector> expected{ +TEST_CASE("Check array PropertyTexturePropertyView (normalized)") { + SECTION("uint8_t array") { + // clang-format off + std::vector data{ + 1, 2, 3, 0, + 4, 5, 6, 11, + 7, 8, 9, 3, + 0, 5, 2, 27}; + // clang-format on + std::vector> expectedRaw{ + {1, 2, 3, 0}, + {4, 5, 6, 11}, + {7, 8, 9, 3}, + {0, 5, 2, 27}}; + std::vector>> expectedTransformed( + expectedRaw.size()); + + for (size_t i = 0; i < expectedRaw.size(); i++) { + auto rawValues = expectedRaw[i]; + std::vector transformedValues(rawValues.size()); + for (size_t j = 0; j < rawValues.size(); j++) { + transformedValues[j] = normalize(rawValues[j]); + } + expectedTransformed[i] = transformedValues; + } + checkNormalizedTextureArrayValues( + data, + 4, + expectedRaw, + expectedTransformed); + } + + SECTION("int16_t array") { + // clang-format off + std::vector data{ + 255, 255, 0, 1, + 9, 0, 146, 195, + 20, 2, 2, 0, + 8, 255, 0, 1}; + // clang-format on + std::vector> expectedRaw{ {-1, 256}, {9, -15470}, {532, 2}, {-248, 256}}; - std::vector> values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - std::vector& expectedValue = expected[i]; - const PropertyArrayView& value = values[i]; - REQUIRE(static_cast(value.size()) == expectedValue.size()); - for (int64_t j = 0; j < value.size(); j++) { - REQUIRE(value[j] == expectedValue[static_cast(j)]); + std::vector>> expectedTransformed( + expectedRaw.size()); + + for (size_t i = 0; i < expectedRaw.size(); i++) { + auto rawValues = expectedRaw[i]; + std::vector transformedValues(rawValues.size()); + for (size_t j = 0; j < rawValues.size(); j++) { + transformedValues[j] = normalize(rawValues[j]); + } + expectedTransformed[i] = transformedValues; + } + + checkNormalizedTextureArrayValues( + data, + 2, + expectedRaw, + expectedTransformed); + } + + SECTION("uint8_t array with offset / scale") { + // clang-format off + std::vector data{ + 1, 2, 3, 0, + 4, 5, 6, 11, + 7, 8, 9, 3, + 0, 0, 0, 0,}; + // clang-format on + + const std::vector offset{1, 2, 0, 4}; + const std::vector scale{1, -1, 3, -2}; + std::vector> expectedRaw{ + {1, 2, 3, 0}, + {4, 5, 6, 11}, + {7, 8, 9, 3}, + {0, 0, 0, 0}}; + std::vector>> expectedTransformed( + expectedRaw.size()); + + for (size_t i = 0; i < expectedRaw.size(); i++) { + auto rawValues = expectedRaw[i]; + std::vector transformedValues(rawValues.size()); + for (size_t j = 0; j < rawValues.size(); j++) { + transformedValues[j] = normalize(rawValues[j]) * scale[j] + offset[j]; + } + expectedTransformed[i] = transformedValues; + } + + checkNormalizedTextureArrayValues( + data, + 4, + expectedRaw, + expectedTransformed, + JsonValue::Array{offset[0], offset[1], offset[2], offset[3]}, + JsonValue::Array{scale[0], scale[1], scale[2], scale[3]}); + } + + SECTION("uint8_t array with noData") { + // clang-format off + std::vector data{ + 1, 2, 3, 0, + 4, 5, 6, 11, + 7, 8, 9, 3, + 0, 0, 0, 0,}; + // clang-format on + + std::optional noData = JsonValue::Array{0, 0, 0, 0}; + std::vector> expectedRaw{ + {1, 2, 3, 0}, + {4, 5, 6, 11}, + {7, 8, 9, 3}, + {0, 0, 0, 0}}; + std::vector>> expectedTransformed( + expectedRaw.size()); + + for (size_t i = 0; i < expectedRaw.size() - 1; i++) { + auto rawValues = expectedRaw[i]; + std::vector transformedValues(rawValues.size()); + for (size_t j = 0; j < rawValues.size(); j++) { + transformedValues[j] = normalize(rawValues[j]); + } + expectedTransformed[i] = transformedValues; + } + + expectedTransformed[3] = std::nullopt; + + checkNormalizedTextureArrayValues( + data, + 4, + expectedRaw, + expectedTransformed, + std::nullopt, + std::nullopt, + noData); + } + + SECTION("uint8_t array with all properties") { + // clang-format off + std::vector data{ + 1, 2, 3, 0, + 4, 5, 6, 11, + 7, 8, 9, 3, + 0, 0, 0, 0,}; + // clang-format on + + const std::vector offset{1, 2, 0, 4}; + const std::vector scale{1, -1, 3, -2}; + std::optional noData = JsonValue::Array{0, 0, 0, 0}; + std::optional defaultValue = + JsonValue::Array{1.0, 2.0, 3.0, 4.0}; + + std::vector> expectedRaw{ + {1, 2, 3, 0}, + {4, 5, 6, 11}, + {7, 8, 9, 3}, + {0, 0, 0, 0}}; + std::vector>> expectedTransformed( + expectedRaw.size()); + + for (size_t i = 0; i < expectedRaw.size() - 1; i++) { + auto rawValues = expectedRaw[i]; + std::vector transformedValues(rawValues.size()); + for (size_t j = 0; j < rawValues.size(); j++) { + transformedValues[j] = normalize(rawValues[j]) * scale[j] + offset[j]; } + expectedTransformed[i] = transformedValues; } + + expectedTransformed[3] = std::vector{1.0, 2.0, 3.0, 4.0}; + + checkNormalizedTextureArrayValues( + data, + 4, + expectedRaw, + expectedTransformed, + JsonValue::Array{offset[0], offset[1], offset[2], offset[3]}, + JsonValue::Array{scale[0], scale[1], scale[2], scale[3]}, + noData, + defaultValue); + } +} + +TEST_CASE("Check that property values override class property values") { + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + + classProperty.offset = 0.0f; + classProperty.scale = 1.0f; + classProperty.min = -10.0f; + classProperty.max = 10.0f; + + Sampler sampler; + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 4; + image.bytesPerChannel = 1; + + // clang-format off + std::vector data{ + 0, 0, 0, 1, + 9, 0, 1, 0, + 20, 2, 2, 0, + 8, 1, 0, 1}; + // clang-format on + + const float offset = 1.0f; + const float scale = 2.0f; + std::vector expectedUint{16777216, 65545, 131604, 16777480}; + std::vector expectedRaw(expectedUint.size()); + std::vector> expectedTransformed(expectedUint.size()); + for (size_t i = 0; i < expectedUint.size(); i++) { + float value = *reinterpret_cast(&expectedUint[i]); + expectedRaw[i] = value; + expectedTransformed[i] = value * scale + offset; + } + + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0, 1, 2, 3}; + + PropertyTextureProperty property; + property.offset = offset; + property.scale = scale; + property.min = std::numeric_limits::lowest(); + property.max = std::numeric_limits::max(); + + PropertyTexturePropertyView + view(property, classProperty, sampler, image, 0, channels); + CHECK(view.getSwizzle() == "rgba"); + + REQUIRE(view.offset()); + REQUIRE(*view.offset() == offset); + REQUIRE(view.scale()); + REQUIRE(*view.scale() == scale); + REQUIRE(view.min()); + REQUIRE(*view.min() == std::numeric_limits::lowest()); + REQUIRE(view.max()); + REQUIRE(*view.max() == std::numeric_limits::max()); + + for (size_t i = 0; i < texCoords.size(); i++) { + glm::dvec2 uv = texCoords[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == expectedRaw[i]); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue == expectedTransformed[i]); } } TEST_CASE("Check that non-adjacent channels resolve to expected output") { SECTION("single-byte scalar") { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + Sampler sampler; ImageCesium image; image.width = 2; @@ -802,22 +1454,28 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector channels{3}; - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); + PropertyTexturePropertyView + view(property, classProperty, sampler, image, 0, channels); CHECK(view.getSwizzle() == "a"); - std::vector expected{3, 4, 0, 1}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); + std::vector expected{3, 4, 0, 1}; + for (size_t i = 0; i < expected.size(); i++) { + glm::dvec2 uv = texCoords[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == expected[i]); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expected[i]); } } SECTION("multi-byte scalar") { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT16; + Sampler sampler; ImageCesium image; image.width = 2; @@ -839,21 +1497,27 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector channels{2, 0}; PropertyTexturePropertyView - view(sampler, image, 0, channels, false); + view(property, classProperty, sampler, image, 0, channels); CHECK(view.getSwizzle() == "br"); std::vector expected{2, 259, 257, 520}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); + for (size_t i = 0; i < expected.size(); i++) { + glm::dvec2 uv = texCoords[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == expected[i]); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expected[i]); } } SECTION("vecN") { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC3; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + Sampler sampler; ImageCesium image; image.width = 2; @@ -875,7 +1539,7 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector channels{3, 2, 1}; PropertyTexturePropertyView - view(sampler, image, 0, channels, false); + view(property, classProperty, sampler, image, 0, channels); CHECK(view.getSwizzle() == "abg"); std::vector expected{ @@ -883,17 +1547,24 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { glm::u8vec3(4, 3, 2), glm::u8vec3(0, 1, 0), glm::u8vec3(1, 8, 3)}; - std::vector values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == expected[i]); + for (size_t i = 0; i < expected.size(); i++) { + glm::dvec2 uv = texCoords[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == expected[i]); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expected[i]); } } SECTION("array") { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + classProperty.array = true; + Sampler sampler; ImageCesium image; image.width = 2; @@ -916,15 +1587,9 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector channels{1, 0, 3, 2}; PropertyTexturePropertyView> - view(sampler, image, 0, channels, false); + view(property, classProperty, sampler, image, 0, channels); CHECK(view.getSwizzle() == "grab"); - std::vector> values{ - view.get(0, 0), - view.get(0.5, 0), - view.get(0, 0.5), - view.get(0.5, 0.5)}; - std::vector> expected{ {2, 1, 0, 3}, {5, 4, 11, 6}, @@ -933,45 +1598,63 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { for (size_t i = 0; i < expected.size(); i++) { std::vector& expectedValue = expected[i]; - const PropertyArrayView& value = values[i]; + glm::dvec2 uv = texCoords[i]; + + auto value = view.getRaw(uv[0], uv[1]); REQUIRE(static_cast(value.size()) == expectedValue.size()); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(maybeValue->size() == value.size()); for (int64_t j = 0; j < value.size(); j++) { REQUIRE(value[j] == expectedValue[static_cast(j)]); + REQUIRE((*maybeValue)[j] == value[j]); } } } } TEST_CASE("Check sampling with different sampler values") { + PropertyTextureProperty property; + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::UINT8; + + ImageCesium image; + image.width = 2; + image.height = 2; + image.channels = 1; + image.bytesPerChannel = 1; + + std::vector data{12, 33, 56, 67}; + std::vector& imageData = image.pixelData; + imageData.resize(data.size()); + std::memcpy(imageData.data(), data.data(), data.size()); + + std::vector channels{0}; + SECTION("REPEAT") { Sampler sampler; sampler.wrapS = Sampler::WrapS::REPEAT; sampler.wrapT = Sampler::WrapT::REPEAT; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 1; - image.bytesPerChannel = 1; - - std::vector data{12, 33, 56, 67}; - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0}; - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); + view(property, classProperty, sampler, image, 0, channels); CHECK(view.getSwizzle() == "r"); - std::vector values{ - view.get(1.0, 0), - view.get(-1.5, 0), - view.get(0, -0.5), - view.get(1.5, -0.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == data[i]); + std::vector uvs{ + glm::dvec2(1.0, 0), + glm::dvec2(-1.5, 0), + glm::dvec2(0, -0.5), + glm::dvec2(1.5, -0.5)}; + for (size_t i = 0; i < uvs.size(); i++) { + glm::dvec2 uv = uvs[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == data[i]); } } @@ -983,30 +1666,23 @@ TEST_CASE("Check sampling with different sampler values") { // MIRRORED: | 1 2 3 | 3 2 1 | // Sampling 0.6 is equal to sampling 1.4 or -0.6. - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 1; - image.bytesPerChannel = 1; - - std::vector data{12, 33, 56, 67}; - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0}; - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); + view(property, classProperty, sampler, image, 0, channels); CHECK(view.getSwizzle() == "r"); - std::vector values{ - view.get(2.0, 0), - view.get(-0.75, 0), - view.get(0, 1.25), - view.get(-1.25, 2.75)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == data[i]); + std::vector uvs{ + glm::dvec2(2.0, 0), + glm::dvec2(-0.75, 0), + glm::dvec2(0, 1.25), + glm::dvec2(-1.25, 2.75)}; + for (size_t i = 0; i < uvs.size(); i++) { + glm::dvec2 uv = uvs[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == data[i]); } } @@ -1015,30 +1691,23 @@ TEST_CASE("Check sampling with different sampler values") { sampler.wrapS = Sampler::WrapS::CLAMP_TO_EDGE; sampler.wrapT = Sampler::WrapT::CLAMP_TO_EDGE; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 1; - image.bytesPerChannel = 1; - - std::vector data{12, 33, 56, 67}; - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0}; - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); + view(property, classProperty, sampler, image, 0, channels); CHECK(view.getSwizzle() == "r"); - std::vector values{ - view.get(-1.0, 0), - view.get(1.4, 0), - view.get(0, 2.0), - view.get(1.5, 1.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == data[i]); + std::vector uvs{ + glm::dvec2(-1.0, 0), + glm::dvec2(1.4, 0), + glm::dvec2(0, 2.0), + glm::dvec2(1.5, 1.5)}; + for (size_t i = 0; i < uvs.size(); i++) { + glm::dvec2 uv = uvs[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == data[i]); } } @@ -1047,30 +1716,23 @@ TEST_CASE("Check sampling with different sampler values") { sampler.wrapS = Sampler::WrapS::REPEAT; sampler.wrapT = Sampler::WrapT::CLAMP_TO_EDGE; - ImageCesium image; - image.width = 2; - image.height = 2; - image.channels = 1; - image.bytesPerChannel = 1; - - std::vector data{12, 33, 56, 67}; - std::vector& imageData = image.pixelData; - imageData.resize(data.size()); - std::memcpy(imageData.data(), data.data(), data.size()); - - std::vector channels{0}; - PropertyTexturePropertyView - view(sampler, image, 0, channels, false); + view(property, classProperty, sampler, image, 0, channels); CHECK(view.getSwizzle() == "r"); - std::vector values{ - view.get(1.0, 0), - view.get(-1.5, -1.0), - view.get(0, 1.5), - view.get(1.5, 1.5)}; - for (size_t i = 0; i < values.size(); i++) { - REQUIRE(values[i] == data[i]); + std::vector uvs{ + glm::dvec2(1.0, 0), + glm::dvec2(-1.5, -1.0), + glm::dvec2(0, 1.5), + glm::dvec2(1.5, 1.5)}; + for (size_t i = 0; i < uvs.size(); i++) { + glm::dvec2 uv = uvs[i]; + auto value = view.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = view.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == data[i]); } } } From ed2bdbd55319dc6b5e40edc086b70fd26efe6029 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 24 Aug 2023 20:52:45 -0400 Subject: [PATCH 093/121] Update PropertyTextureView --- CHANGES.md | 6 +- .../CesiumGltf/PropertyTexturePropertyView.h | 10 +- .../include/CesiumGltf/PropertyTextureView.h | 251 ++- CesiumGltf/test/TestPropertyTableView.cpp | 8 +- .../test/TestPropertyTexturePropertyView.cpp | 84 +- CesiumGltf/test/TestPropertyTextureView.cpp | 1547 +++++++++++++++-- 6 files changed, 1679 insertions(+), 227 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 178e949bf..e21ada456 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,20 +12,20 @@ - 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`. -- Replaced `MetadataPropertyView` with `PropertyTablePropertyView`, which is a templated view of a `PropertyTableProperty` in `EXT_structural_metadata`. This takes two template parameters: a typename `T` , and a `bool` indicating whether or not the values are normalized. +- Replaced `MetadataPropertyView` with `PropertyTablePropertyView`, which is a view of a `PropertyTableProperty` in `EXT_structural_metadata`. This takes two template parameters: a typename `T` , and a `bool` indicating whether or not the values are normalized. - 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 is a templated view of a `PropertyTextureProperty` in `EXT_structural_metadata`. +- Replaced `FeatureTexturePropertyView` with `PropertyTexturePropertyView`, which is a view of a `PropertyTextureProperty` in `EXT_structural_metadata`. This takes two template parameters: a typename `T` , and a `bool` indicating whether or not the values are normalized. - 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`. ##### Additions :tada: +- Added `PropertyView`, which acts as a base class for all metadata property views. This takes two template parameters: a type `T` , and a `bool` indicating whether or not the values are normalized. - Added `PropertyTableViewStatus` to indicate whether a `PropertyTableView` is valid. - Added `PropertyComponentType` to reflect the values of `componentType` in a `ClassProperty` from `EXT_structural_metadata`. -- Added `PropertyView`, which acts as a base class for all metadata property views. This takes two template parameters: a typename `T` , and a `bool` indicating whether or not the values are normalized. ### v0.25.0 - 2023-06-01 diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index f49b27baf..e71dc1976 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -181,7 +181,7 @@ class PropertyTexturePropertyView * @param status The code from {@link PropertyTexturePropertyViewStatus} indicating the error with the property. */ PropertyTexturePropertyView(PropertyViewStatusType status) noexcept - : PropertyView(), + : PropertyView(status), _pSampler(nullptr), _pImage(nullptr), _texCoordSetIndex(0), @@ -208,12 +208,11 @@ class PropertyTexturePropertyView const ClassProperty& classProperty, const Sampler& sampler, const ImageCesium& image, - int64_t texCoordSetIndex, const std::vector& channels) noexcept : PropertyView(classProperty, property), _pSampler(&sampler), _pImage(&image), - _texCoordSetIndex(texCoordSetIndex), + _texCoordSetIndex(property.texCoord), _channels(channels), _swizzle("") { if (this->_status != PropertyTexturePropertyViewStatus::Valid) { @@ -500,7 +499,7 @@ class PropertyTexturePropertyView * @param status The code from {@link PropertyTexturePropertyViewStatus} indicating the error with the property. */ PropertyTexturePropertyView(PropertyViewStatusType status) noexcept - : PropertyView(), + : PropertyView(status), _pSampler(nullptr), _pImage(nullptr), _texCoordSetIndex(0), @@ -527,12 +526,11 @@ class PropertyTexturePropertyView const ClassProperty& classProperty, const Sampler& sampler, const ImageCesium& image, - int64_t texCoordSetIndex, const std::vector& channels) noexcept : PropertyView(classProperty, property), _pSampler(&sampler), _pImage(&image), - _texCoordSetIndex(texCoordSetIndex), + _texCoordSetIndex(property.texCoord), _channels(channels), _swizzle("") { if (this->_status != PropertyTexturePropertyViewStatus::Valid) { diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 86f213af0..1a56fa2ec 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -91,21 +91,21 @@ class PropertyTextureView { * @return A {@link PropertyTexturePropertyView} of the property. If no valid property is * found, the property view will be invalid. */ - template - PropertyTexturePropertyView + template + PropertyTexturePropertyView getPropertyView(const std::string& propertyName) const { if (this->_status != PropertyTextureViewStatus::Valid) { - return PropertyTexturePropertyView( + return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorInvalidPropertyTexture); } const ClassProperty* pClassProperty = getClassProperty(propertyName); if (!pClassProperty) { - return PropertyTexturePropertyView( + return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorNonexistentProperty); } - return getPropertyViewImpl(propertyName, *pClassProperty); + return getPropertyViewImpl(propertyName, *pClassProperty); } /** @@ -152,34 +152,68 @@ class PropertyTextureView { componentType = convertStringToPropertyComponentType(*pClassProperty->componentType); } + bool normalized = pClassProperty->normalized; if (pClassProperty->array) { - getArrayPropertyViewImpl( - propertyName, - *pClassProperty, - type, - componentType, - std::forward(callback)); - } else if (type == PropertyType::Scalar) { - getScalarPropertyViewImpl( - propertyName, - *pClassProperty, - componentType, - std::forward(callback)); - } else if (isPropertyTypeVecN(type)) { - getVecNPropertyViewImpl( - propertyName, - *pClassProperty, - type, - componentType, - std::forward(callback)); - } else { - callback( - propertyName, - PropertyTexturePropertyView( - PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + if (normalized) { + getArrayPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } else { + getArrayPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } + return; + } + + if (type == PropertyType::Scalar) { + if (normalized) { + getScalarPropertyViewImpl( + propertyName, + *pClassProperty, + componentType, + std::forward(callback)); + } else { + getScalarPropertyViewImpl( + propertyName, + *pClassProperty, + componentType, + std::forward(callback)); + } + return; + } + + if (isPropertyTypeVecN(type)) { + if (normalized) { + getVecNPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } else { + getVecNPropertyViewImpl( + propertyName, + *pClassProperty, + type, + componentType, + std::forward(callback)); + } return; } + + callback( + propertyName, + PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty)); + return; } /** @@ -207,14 +241,14 @@ class PropertyTextureView { } private: - template - PropertyTexturePropertyView getPropertyViewImpl( + template + PropertyTexturePropertyView getPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty) const { auto propertyTexturePropertyIter = _pPropertyTexture->properties.find(propertyName); if (propertyTexturePropertyIter == _pPropertyTexture->properties.end()) { - return PropertyTexturePropertyView( + return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorNonexistentProperty); } @@ -222,23 +256,25 @@ class PropertyTextureView { propertyTexturePropertyIter->second; if constexpr (IsMetadataScalar::value) { - return createScalarPropertyView( + return createScalarPropertyView( classProperty, propertyTextureProperty); } if constexpr (IsMetadataVecN::value) { - return createVecNPropertyView(classProperty, propertyTextureProperty); + return createVecNPropertyView( + classProperty, + propertyTextureProperty); } if constexpr (IsMetadataArray::value) { - return createArrayPropertyView::type>( - classProperty, - propertyTextureProperty); + return createArrayPropertyView< + typename MetadataArrayType::type, + Normalized>(classProperty, propertyTextureProperty); } } - template + template void getArrayPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -267,28 +303,28 @@ class PropertyTextureView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; @@ -301,7 +337,7 @@ class PropertyTextureView { } } - template + template void getScalarPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -311,37 +347,47 @@ class PropertyTextureView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl(propertyName, classProperty)); return; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); return; case PropertyComponentType::Int16: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); return; case PropertyComponentType::Uint16: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); break; case PropertyComponentType::Int32: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl( + propertyName, + classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, - getPropertyViewImpl(propertyName, classProperty)); + getPropertyViewImpl(propertyName, classProperty)); break; default: callback( @@ -352,7 +398,7 @@ class PropertyTextureView { } } - template + template void getVecNPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -362,14 +408,14 @@ class PropertyTextureView { case PropertyComponentType::Int8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; @@ -377,7 +423,7 @@ class PropertyTextureView { if constexpr (N == 2) { callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; @@ -387,7 +433,7 @@ class PropertyTextureView { if constexpr (N == 2) { callback( propertyName, - getPropertyViewImpl>( + getPropertyViewImpl, Normalized>( propertyName, classProperty)); break; @@ -402,7 +448,7 @@ class PropertyTextureView { } } - template + template void getVecNPropertyViewImpl( const std::string& propertyName, const ClassProperty& classProperty, @@ -412,21 +458,21 @@ class PropertyTextureView { const glm::length_t N = getDimensionsFromPropertyType(type); switch (N) { case 2: - getVecNPropertyViewImpl( + getVecNPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); break; case 3: - getVecNPropertyViewImpl( + getVecNPropertyViewImpl( propertyName, classProperty, componentType, std::forward(callback)); break; case 4: - getVecNPropertyViewImpl( + getVecNPropertyViewImpl( propertyName, classProperty, componentType, @@ -441,18 +487,18 @@ class PropertyTextureView { } } - template - PropertyTexturePropertyView createScalarPropertyView( + template + PropertyTexturePropertyView createScalarPropertyView( const ClassProperty& classProperty, const PropertyTextureProperty& propertyTextureProperty) const { if (classProperty.array) { - return PropertyTexturePropertyView( + return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); } const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { - return PropertyTexturePropertyView( + return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorTypeMismatch); } @@ -460,31 +506,39 @@ class PropertyTextureView { convertStringToPropertyComponentType( classProperty.componentType.value_or("")); if (TypeToPropertyType::component != componentType) { - return PropertyTexturePropertyView( + return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } + if (classProperty.normalized != Normalized) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + } + // Only up to four bytes of image data are supported. if constexpr (sizeof(T) <= 4) { - return createPropertyViewImpl( + return createPropertyViewImpl( classProperty, propertyTextureProperty, sizeof(T)); + } else { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); } } - template - PropertyTexturePropertyView createVecNPropertyView( + template + PropertyTexturePropertyView createVecNPropertyView( const ClassProperty& classProperty, const PropertyTextureProperty& propertyTextureProperty) const { if (classProperty.array) { - return PropertyTexturePropertyView( + return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); } const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { - return PropertyTexturePropertyView( + return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorTypeMismatch); } @@ -492,31 +546,40 @@ class PropertyTextureView { convertStringToPropertyComponentType( classProperty.componentType.value_or("")); if (TypeToPropertyType::component != componentType) { - return PropertyTexturePropertyView( + return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } + if (classProperty.normalized != Normalized) { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + } + // Only up to four bytes of image data are supported. if constexpr (sizeof(T) <= 4) { - return createPropertyViewImpl( + return createPropertyViewImpl( classProperty, propertyTextureProperty, sizeof(T)); + } else { + return PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); } } - template - PropertyTexturePropertyView> createArrayPropertyView( + template + PropertyTexturePropertyView, Normalized> + createArrayPropertyView( const ClassProperty& classProperty, const PropertyTextureProperty& propertyTextureProperty) const { if (!classProperty.array) { - return PropertyTexturePropertyView>( + return PropertyTexturePropertyView, Normalized>( PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); } const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { - return PropertyTexturePropertyView>( + return PropertyTexturePropertyView, Normalized>( PropertyTexturePropertyViewStatus::ErrorTypeMismatch); } @@ -524,34 +587,42 @@ class PropertyTextureView { convertStringToPropertyComponentType( classProperty.componentType.value_or("")); if (TypeToPropertyType::component != componentType) { - return PropertyTexturePropertyView>( + return PropertyTexturePropertyView, Normalized>( PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } + if (classProperty.normalized != Normalized) { + return PropertyTexturePropertyView, Normalized>( + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + } + // Only scalar arrays are supported. The scalar component type must not // exceed two bytes. if constexpr (IsMetadataScalar::value && sizeof(T) <= 4) { // Only up to four elements are supported. int64_t count = classProperty.count.value_or(0); if (count <= 0 || count > 4) { - return PropertyTexturePropertyView>( + return PropertyTexturePropertyView, Normalized>( PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); } if (count * sizeof(T) > 4) { - return PropertyTexturePropertyView>( + return PropertyTexturePropertyView, Normalized>( PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); } - return createPropertyViewImpl>( + return createPropertyViewImpl, Normalized>( classProperty, propertyTextureProperty, count * sizeof(T)); + } else { + return PropertyTexturePropertyView, Normalized>( + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty); } } - template - PropertyTexturePropertyView createPropertyViewImpl( + template + PropertyTexturePropertyView createPropertyViewImpl( const ClassProperty& classProperty, const PropertyTextureProperty& propertyTextureProperty, size_t elementSize) const { @@ -562,17 +633,17 @@ class PropertyTextureView { getTextureSafe(propertyTextureProperty.index, samplerIndex, imageIndex); if (status != PropertyTexturePropertyViewStatus::Valid) { - return PropertyTexturePropertyView(status); + return PropertyTexturePropertyView(status); } status = checkSampler(samplerIndex); if (status != PropertyTexturePropertyViewStatus::Valid) { - return PropertyTexturePropertyView(status); + return PropertyTexturePropertyView(status); } status = checkImage(imageIndex); if (status != PropertyTexturePropertyViewStatus::Valid) { - return PropertyTexturePropertyView(status); + return PropertyTexturePropertyView(status); } const ImageCesium& image = _pModel->images[imageIndex].cesium; @@ -580,19 +651,19 @@ class PropertyTextureView { status = checkChannels(channels, image); if (status != PropertyTexturePropertyViewStatus::Valid) { - return PropertyTexturePropertyView(status); + return PropertyTexturePropertyView(status); } if (channels.size() * image.bytesPerChannel != elementSize) { return PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch; } - return PropertyTexturePropertyView( + return PropertyTexturePropertyView( + propertyTextureProperty, + classProperty, _pModel->samplers[samplerIndex], image, - propertyTextureProperty.texCoord, - channels, - classProperty.normalized); + channels); } PropertyViewStatusType getTextureSafe( @@ -614,5 +685,5 @@ class PropertyTextureView { const Class* _pClass; PropertyTextureViewStatus _status; -}; +}; // namespace CesiumGltf } // namespace CesiumGltf diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index 2e9f9cd69..3bb8ca0e8 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -3970,7 +3970,7 @@ TEST_CASE("Test variable-length arrays of strings") { } } -TEST_CASE("Test with property offset, scale, min, max") { +TEST_CASE("Test with PropertyTableProperty offset, scale, min, max") { Model model; std::vector values = {1.0f, 2.0f, 3.0f, 4.0f}; const float offset = 0.5f; @@ -4074,7 +4074,7 @@ TEST_CASE("Test with property offset, scale, min, max") { } } -TEST_CASE("Test with property offset, scale, min, max (normalized)") { +TEST_CASE("Test with PropertyTableProperty offset, scale, min, max (normalized)") { Model model; std::vector values = {-128, 0, 32, 127}; const double offset = 0.5; @@ -4180,7 +4180,7 @@ TEST_CASE("Test with property offset, scale, min, max (normalized)") { } } -TEST_CASE("Test with property noData value") { +TEST_CASE("Test with PropertyTableProperty noData value") { Model model; std::vector values = {-128, 0, 32, -128, 127}; const int8_t noData = -128; @@ -4265,7 +4265,7 @@ TEST_CASE("Test with property noData value") { } } -TEST_CASE("Test with property noData value (normalized)") { +TEST_CASE("Test with PropertyTableProperty noData value (normalized)") { Model model; std::vector values = {-128, 0, 32, -128, 127}; const int8_t noData = -128; diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index 4cad0637f..2b1889a64 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -12,12 +12,6 @@ using namespace CesiumGltf; using namespace CesiumUtility; -std::vector texCoords{ - glm::dvec2(0, 0), - glm::dvec2(0.5, 0), - glm::dvec2(0, 0.5), - glm::dvec2(0.5, 0.5)}; - template void checkTextureValues( const std::vector& data, @@ -48,7 +42,7 @@ void checkTextureValues( } PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); switch (sizeof(T)) { case 1: CHECK(view.getSwizzle() == "r"); @@ -68,6 +62,12 @@ void checkTextureValues( REQUIRE(!view.normalized()); + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + for (size_t i = 0; i < texCoords.size(); i++) { glm::dvec2 uv = texCoords[i]; auto value = view.getRaw(uv[0], uv[1]); @@ -119,7 +119,7 @@ void checkTextureValues( } PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); switch (sizeof(T)) { case 1: CHECK(view.getSwizzle() == "r"); @@ -139,6 +139,12 @@ void checkTextureValues( REQUIRE(!view.normalized()); + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + for (size_t i = 0; i < texCoords.size(); i++) { glm::dvec2 uv = texCoords[i]; auto value = view.getRaw(uv[0], uv[1]); @@ -191,7 +197,7 @@ void checkNormalizedTextureValues( } PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); switch (sizeof(T)) { case 1: CHECK(view.getSwizzle() == "r"); @@ -211,6 +217,12 @@ void checkNormalizedTextureValues( REQUIRE(view.normalized()); + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + for (size_t i = 0; i < texCoords.size(); i++) { glm::dvec2 uv = texCoords[i]; auto value = view.getRaw(uv[0], uv[1]); @@ -256,7 +268,7 @@ void checkTextureArrayValues( } PropertyTexturePropertyView> - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); switch (image.channels) { case 1: CHECK(view.getSwizzle() == "r"); @@ -276,6 +288,12 @@ void checkTextureArrayValues( REQUIRE(!view.normalized()); + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + for (size_t i = 0; i < texCoords.size(); i++) { const std::vector& expectedValue = expected[i]; glm::dvec2 uv = texCoords[i]; @@ -333,7 +351,7 @@ void checkTextureArrayValues( } PropertyTexturePropertyView> - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); switch (count) { case 1: CHECK(view.getSwizzle() == "r"); @@ -353,6 +371,12 @@ void checkTextureArrayValues( REQUIRE(!view.normalized()); + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + for (size_t i = 0; i < texCoords.size(); i++) { auto expectedRawValue = expectedRaw[i]; glm::dvec2 uv = texCoords[i]; @@ -424,7 +448,7 @@ void checkNormalizedTextureArrayValues( } PropertyTexturePropertyView, true> - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); switch (image.channels) { case 1: CHECK(view.getSwizzle() == "r"); @@ -444,6 +468,12 @@ void checkNormalizedTextureArrayValues( REQUIRE(view.normalized()); + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + for (size_t i = 0; i < texCoords.size(); i++) { auto expectedRawValue = expectedRaw[i]; glm::dvec2 uv = texCoords[i]; @@ -1404,7 +1434,7 @@ TEST_CASE("Check that property values override class property values") { property.max = std::numeric_limits::max(); PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); CHECK(view.getSwizzle() == "rgba"); REQUIRE(view.offset()); @@ -1416,6 +1446,12 @@ TEST_CASE("Check that property values override class property values") { REQUIRE(view.max()); REQUIRE(*view.max() == std::numeric_limits::max()); + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + for (size_t i = 0; i < texCoords.size(); i++) { glm::dvec2 uv = texCoords[i]; auto value = view.getRaw(uv[0], uv[1]); @@ -1427,6 +1463,12 @@ TEST_CASE("Check that property values override class property values") { } TEST_CASE("Check that non-adjacent channels resolve to expected output") { + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + SECTION("single-byte scalar") { PropertyTextureProperty property; ClassProperty classProperty; @@ -1455,7 +1497,7 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector channels{3}; PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); CHECK(view.getSwizzle() == "a"); std::vector expected{3, 4, 0, 1}; @@ -1497,7 +1539,7 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector channels{2, 0}; PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); CHECK(view.getSwizzle() == "br"); std::vector expected{2, 259, 257, 520}; @@ -1539,7 +1581,7 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector channels{3, 2, 1}; PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); CHECK(view.getSwizzle() == "abg"); std::vector expected{ @@ -1587,7 +1629,7 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector channels{1, 0, 3, 2}; PropertyTexturePropertyView> - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); CHECK(view.getSwizzle() == "grab"); std::vector> expected{ @@ -1639,7 +1681,7 @@ TEST_CASE("Check sampling with different sampler values") { sampler.wrapT = Sampler::WrapT::REPEAT; PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); CHECK(view.getSwizzle() == "r"); std::vector uvs{ @@ -1667,7 +1709,7 @@ TEST_CASE("Check sampling with different sampler values") { // Sampling 0.6 is equal to sampling 1.4 or -0.6. PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); CHECK(view.getSwizzle() == "r"); std::vector uvs{ @@ -1692,7 +1734,7 @@ TEST_CASE("Check sampling with different sampler values") { sampler.wrapT = Sampler::WrapT::CLAMP_TO_EDGE; PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); CHECK(view.getSwizzle() == "r"); std::vector uvs{ @@ -1717,7 +1759,7 @@ TEST_CASE("Check sampling with different sampler values") { sampler.wrapT = Sampler::WrapT::CLAMP_TO_EDGE; PropertyTexturePropertyView - view(property, classProperty, sampler, image, 0, channels); + view(property, classProperty, sampler, image, channels); CHECK(view.getSwizzle() == "r"); std::vector uvs{ diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index d442ee364..af6e61e13 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -159,21 +159,27 @@ TEST_CASE("Test scalar PropertyTextureProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); SECTION("Access correct type") { PropertyTexturePropertyView uint8Property = view.getPropertyView("TestClassProperty"); REQUIRE(uint8Property.status() == PropertyTexturePropertyViewStatus::Valid); - std::vector values{ - uint8Property.get(0.0, 0.0), - uint8Property.get(0.5, 0.0), - uint8Property.get(0.0, 0.5), - uint8Property.get(0.5, 0.5), - }; + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; - for (size_t i = 0; i < values.size(); ++i) { - REQUIRE(values[i] == data[i]); + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = uint8Property.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = uint8Property.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == data[i]); } } @@ -213,6 +219,14 @@ TEST_CASE("Test scalar PropertyTextureProperty") { PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); } + SECTION("Access incorrectly as normalized") { + PropertyTexturePropertyView normalizedInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + } + SECTION("Channel and type mismatch") { model.images[imageIndex].cesium.channels = 2; propertyTextureProperty.channels = {0, 1}; @@ -287,6 +301,195 @@ TEST_CASE("Test scalar PropertyTextureProperty") { } } +TEST_CASE("Test scalar PropertyTextureProperty (normalized)") { + Model model; + std::vector data = {12, 34, 30, 11}; + + addTextureToModel( + model, + Sampler::WrapS::CLAMP_TO_EDGE, + Sampler::WrapS::CLAMP_TO_EDGE, + 2, + 2, + 1, + data); + size_t textureIndex = model.textures.size() - 1; + size_t imageIndex = model.images.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.normalized = true; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(textureIndex); + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + 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::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + SECTION("Access correct type") { + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(uint8Property.status() == PropertyTexturePropertyViewStatus::Valid); + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = uint8Property.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = uint8Property.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == normalize(data[i])); + } + } + + SECTION("Access wrong type") { + PropertyTexturePropertyView u8vec2Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec2Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyTexturePropertyView uint16Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint16Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTexturePropertyView int32Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + int32Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as array") { + PropertyTexturePropertyView, true> arrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + arrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Access incorrectly as non-normalized") { + PropertyTexturePropertyView normalizedInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Access incorrectly as double") { + PropertyTexturePropertyView doubleInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + doubleInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Channel and type mismatch") { + model.images[imageIndex].cesium.channels = 2; + propertyTextureProperty.channels = {0, 1}; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch); + } + + SECTION("Invalid channel values") { + propertyTextureProperty.channels = {5}; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidChannels); + } + + SECTION("Zero channel values") { + propertyTextureProperty.channels.clear(); + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidChannels); + } + + SECTION("Invalid bytes per channel") { + model.images[imageIndex].cesium.bytesPerChannel = 2; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); + } + + SECTION("Empty image") { + model.images[imageIndex].cesium.width = 0; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorEmptyImage); + } + + SECTION("Wrong image index") { + model.textures[textureIndex].source = 1; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidImage); + } + + SECTION("Wrong sampler index") { + model.textures[textureIndex].sampler = 1; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidSampler); + } + + SECTION("Wrong texture index") { + propertyTextureProperty.index = 1; + PropertyTexturePropertyView uint8Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidTexture); + } +} + TEST_CASE("Test vecN PropertyTextureProperty") { Model model; std::vector data = {12, 34, 10, 3, 40, 0, 30, 11}; @@ -330,6 +533,7 @@ TEST_CASE("Test vecN PropertyTextureProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); SECTION("Access correct type") { PropertyTexturePropertyView u8vec2Property = @@ -337,19 +541,25 @@ TEST_CASE("Test vecN PropertyTextureProperty") { REQUIRE( u8vec2Property.status() == PropertyTexturePropertyViewStatus::Valid); + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + std::vector expected{ glm::u8vec2(12, 34), glm::u8vec2(10, 3), glm::u8vec2(40, 0), glm::u8vec2(30, 11)}; - std::vector values{ - u8vec2Property.get(0.0, 0.0), - u8vec2Property.get(0.5, 0.0), - u8vec2Property.get(0.0, 0.5), - u8vec2Property.get(0.5, 0.5), - }; - for (size_t i = 0; i < values.size(); ++i) { - REQUIRE(values[i] == expected[i]); + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = u8vec2Property.getRaw(uv[0], uv[1]); + REQUIRE(value == expected[i]); + + auto maybeValue = u8vec2Property.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expected[i]); } } @@ -381,6 +591,23 @@ TEST_CASE("Test vecN PropertyTextureProperty") { PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } + SECTION("Access incorrectly as array") { + PropertyTexturePropertyView> arrayInvalid = + view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + arrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Access incorrectly as normalized") { + PropertyTexturePropertyView normalizedInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + } + SECTION("Channel and type mismatch") { model.images[imageIndex].cesium.channels = 4; propertyTextureProperty.channels = {0, 1, 2, 3}; @@ -410,16 +637,9 @@ TEST_CASE("Test vecN PropertyTextureProperty") { } } -TEST_CASE("Test array PropertyTextureProperty") { +TEST_CASE("Test vecN PropertyTextureProperty (normalized)") { Model model; - // clang-format off - std::vector data = { - 12, 34, 10, - 40, 0, 30, - 80, 4, 2, - 6, 3, 4, - }; - // clang-format on + std::vector data = {12, 34, 10, 3, 40, 0, 30, 11}; addTextureToModel( model, @@ -427,7 +647,7 @@ TEST_CASE("Test array PropertyTextureProperty") { Sampler::WrapS::CLAMP_TO_EDGE, 2, 2, - 3, + 2, data); size_t textureIndex = model.textures.size() - 1; size_t imageIndex = model.images.size() - 1; @@ -438,10 +658,9 @@ TEST_CASE("Test array PropertyTextureProperty") { Schema& schema = metadata.schema.emplace(); Class& testClass = schema.classes["TestClass"]; ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; - testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.type = ClassProperty::Type::VEC2; testClassProperty.componentType = ClassProperty::ComponentType::UINT8; - testClassProperty.array = true; - testClassProperty.count = 3; + testClassProperty.normalized = true; PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); propertyTexture.classProperty = "TestClass"; @@ -450,7 +669,7 @@ TEST_CASE("Test array PropertyTextureProperty") { propertyTexture.properties["TestClassProperty"]; propertyTextureProperty.index = static_cast(textureIndex); propertyTextureProperty.texCoord = 0; - propertyTextureProperty.channels = {0, 1, 2}; + propertyTextureProperty.channels = {0, 1}; PropertyTextureView view(model, propertyTexture); REQUIRE(view.status() == PropertyTextureViewStatus::Valid); @@ -458,92 +677,900 @@ TEST_CASE("Test array PropertyTextureProperty") { const ClassProperty* classProperty = view.getClassProperty("TestClassProperty"); REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->type == ClassProperty::Type::VEC2); REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); - REQUIRE(classProperty->array); - REQUIRE(classProperty->count == 3); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); SECTION("Access correct type") { - PropertyTexturePropertyView> uint8ArrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTexturePropertyView u8vec2Property = + view.getPropertyView("TestClassProperty"); REQUIRE( - uint8ArrayProperty.status() == - PropertyTexturePropertyViewStatus::Valid); + u8vec2Property.status() == PropertyTexturePropertyViewStatus::Valid); - std::vector> values{ - uint8ArrayProperty.get(0.0, 0.0), - uint8ArrayProperty.get(0.5, 0.0), - uint8ArrayProperty.get(0.0, 0.5), - uint8ArrayProperty.get(0.5, 0.5), - }; + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; - int64_t size = static_cast(values.size()); - for (int64_t i = 0; i < size; ++i) { - auto dataStart = data.begin() + i * 3; - std::vector expected(dataStart, dataStart + 3); - const PropertyArrayView& value = values[static_cast(i)]; - REQUIRE(static_cast(value.size()) == expected.size()); - for (int64_t j = 0; j < value.size(); j++) { - REQUIRE(value[j] == expected[static_cast(j)]); - } + std::vector expected{ + glm::u8vec2(12, 34), + glm::u8vec2(10, 3), + glm::u8vec2(40, 0), + glm::u8vec2(30, 11)}; + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = u8vec2Property.getRaw(uv[0], uv[1]); + REQUIRE(value == expected[i]); + + auto maybeValue = u8vec2Property.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == normalize(expected[i])); } } + SECTION("Access wrong type") { + PropertyTexturePropertyView uint8Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorTypeMismatch); + + PropertyTexturePropertyView u8vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec3Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorTypeMismatch); + } + SECTION("Access wrong component type") { - PropertyTexturePropertyView> int8ArrayInvalid = - view.getPropertyView>("TestClassProperty"); + PropertyTexturePropertyView u16vec2Invalid = + view.getPropertyView("TestClassProperty"); REQUIRE( - int8ArrayInvalid.status() == + u16vec2Invalid.status() == PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); - PropertyTexturePropertyView> - uint16ArrayInvalid = view.getPropertyView>( - "TestClassProperty"); + PropertyTexturePropertyView i8vec2Invalid = + view.getPropertyView("TestClassProperty"); REQUIRE( - uint16ArrayInvalid.status() == + i8vec2Invalid.status() == PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } - SECTION("Access incorrectly as non-array") { - PropertyTexturePropertyView uint8Invalid = - view.getPropertyView("TestClassProperty"); + SECTION("Access incorrectly as array") { + PropertyTexturePropertyView, true> + arrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); REQUIRE( - uint8Invalid.status() == + arrayInvalid.status() == PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } - PropertyTexturePropertyView u8vec3Invalid = - view.getPropertyView("TestClassProperty"); + SECTION("Access incorrectly as non-normalized") { + PropertyTexturePropertyView normalizedInvalid = + view.getPropertyView("TestClassProperty"); REQUIRE( - u8vec3Invalid.status() == - PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + normalizedInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Access incorrectly as dvec2") { + PropertyTexturePropertyView normalizedInvalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } SECTION("Channel and type mismatch") { model.images[imageIndex].cesium.channels = 4; propertyTextureProperty.channels = {0, 1, 2, 3}; - PropertyTexturePropertyView> uint8ArrayProperty = - view.getPropertyView>("TestClassProperty"); + PropertyTexturePropertyView u8vec2Property = + view.getPropertyView("TestClassProperty"); REQUIRE( - uint8ArrayProperty.status() == + u8vec2Property.status() == PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch); } SECTION("Invalid channel values") { - propertyTextureProperty.channels = {0, 4, 1}; - PropertyTexturePropertyView> uint8ArrayProperty = - view.getPropertyView>("TestClassProperty"); + propertyTextureProperty.channels = {0, 4}; + PropertyTexturePropertyView u8vec2Property = + view.getPropertyView("TestClassProperty"); REQUIRE( - uint8ArrayProperty.status() == + u8vec2Property.status() == PropertyTexturePropertyViewStatus::ErrorInvalidChannels); } - SECTION("Invalid bytes per channel") { - model.images[imageIndex].cesium.bytesPerChannel = 2; - PropertyTexturePropertyView> uint8ArrayProperty = - view.getPropertyView>("TestClassProperty"); - REQUIRE( - uint8ArrayProperty.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); + SECTION("Invalid bytes per channel") { + model.images[imageIndex].cesium.bytesPerChannel = 2; + PropertyTexturePropertyView u8vec2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec2Property.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); + } +} + +TEST_CASE("Test array PropertyTextureProperty") { + Model model; + // clang-format off + std::vector data = { + 12, 34, 10, + 40, 0, 30, + 80, 4, 2, + 6, 3, 4, + }; + // clang-format on + + addTextureToModel( + model, + Sampler::WrapS::CLAMP_TO_EDGE, + Sampler::WrapS::CLAMP_TO_EDGE, + 2, + 2, + 3, + data); + size_t textureIndex = model.textures.size() - 1; + size_t imageIndex = model.images.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.array = true; + testClassProperty.count = 3; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(textureIndex); + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0, 1, 2}; + + 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::UINT8); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + REQUIRE(!classProperty->normalized); + + SECTION("Access correct type") { + PropertyTexturePropertyView> uint8ArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::Valid); + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + + int64_t size = static_cast(texCoords.size()); + for (int64_t i = 0; i < size; ++i) { + glm::dvec2 uv = texCoords[static_cast(i)]; + + auto dataStart = data.begin() + i * 3; + std::vector expected(dataStart, dataStart + 3); + + const PropertyArrayView& value = + uint8ArrayProperty.getRaw(uv[0], uv[1]); + REQUIRE(static_cast(value.size()) == expected.size()); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE(value[j] == expected[static_cast(j)]); + } + + auto maybeValue = uint8ArrayProperty.get(uv[0], uv[1]); + REQUIRE(maybeValue); + for (int64_t j = 0; j < maybeValue->size(); j++) { + REQUIRE((*maybeValue)[j] == value[j]); + } + } + } + + SECTION("Access wrong component type") { + PropertyTexturePropertyView> int8ArrayInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + int8ArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTexturePropertyView> + uint16ArrayInvalid = view.getPropertyView>( + "TestClassProperty"); + REQUIRE( + uint16ArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as non-array") { + PropertyTexturePropertyView uint8Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + + PropertyTexturePropertyView u8vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec3Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Access incorrectly as normalized") { + PropertyTexturePropertyView, true> + normalizedInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Channel and type mismatch") { + model.images[imageIndex].cesium.channels = 4; + propertyTextureProperty.channels = {0, 1, 2, 3}; + PropertyTexturePropertyView> uint8ArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch); + } + + SECTION("Invalid channel values") { + propertyTextureProperty.channels = {0, 4, 1}; + PropertyTexturePropertyView> uint8ArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidChannels); + } + + SECTION("Invalid bytes per channel") { + model.images[imageIndex].cesium.bytesPerChannel = 2; + PropertyTexturePropertyView> uint8ArrayProperty = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); + } +} + +TEST_CASE("Test array PropertyTextureProperty (normalized)") { + Model model; + // clang-format off + std::vector data = { + 12, 34, 10, + 40, 0, 30, + 80, 4, 2, + 6, 3, 4, + }; + // clang-format on + + addTextureToModel( + model, + Sampler::WrapS::CLAMP_TO_EDGE, + Sampler::WrapS::CLAMP_TO_EDGE, + 2, + 2, + 3, + data); + size_t textureIndex = model.textures.size() - 1; + size_t imageIndex = model.images.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.array = true; + testClassProperty.count = 3; + testClassProperty.normalized = true; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(textureIndex); + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0, 1, 2}; + + 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::UINT8); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 3); + REQUIRE(classProperty->normalized); + + SECTION("Access correct type") { + PropertyTexturePropertyView, true> + uint8ArrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::Valid); + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + + int64_t size = static_cast(texCoords.size()); + for (int64_t i = 0; i < size; ++i) { + glm::dvec2 uv = texCoords[static_cast(i)]; + + auto dataStart = data.begin() + i * 3; + std::vector expected(dataStart, dataStart + 3); + + const PropertyArrayView& value = + uint8ArrayProperty.getRaw(uv[0], uv[1]); + REQUIRE(static_cast(value.size()) == expected.size()); + for (int64_t j = 0; j < value.size(); j++) { + REQUIRE(value[j] == expected[static_cast(j)]); + } + + auto maybeValue = uint8ArrayProperty.get(uv[0], uv[1]); + REQUIRE(maybeValue); + for (int64_t j = 0; j < maybeValue->size(); j++) { + REQUIRE((*maybeValue)[j] == normalize(value[j])); + } + } + } + + SECTION("Access wrong component type") { + PropertyTexturePropertyView, true> + int8ArrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + int8ArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyTexturePropertyView, true> + uint16ArrayInvalid = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + uint16ArrayInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as non-array") { + PropertyTexturePropertyView uint8Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + uint8Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + + PropertyTexturePropertyView u8vec3Invalid = + view.getPropertyView("TestClassProperty"); + REQUIRE( + u8vec3Invalid.status() == + PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); + } + + SECTION("Access incorrectly as normalized") { + PropertyTexturePropertyView> normalizedInvalid = + view.getPropertyView>("TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + } + + SECTION("Channel and type mismatch") { + model.images[imageIndex].cesium.channels = 4; + propertyTextureProperty.channels = {0, 1, 2, 3}; + PropertyTexturePropertyView, true> + uint8ArrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch); + } + + SECTION("Invalid channel values") { + propertyTextureProperty.channels = {0, 4, 1}; + PropertyTexturePropertyView, true> + uint8ArrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidChannels); + } + + SECTION("Invalid bytes per channel") { + model.images[imageIndex].cesium.bytesPerChannel = 2; + PropertyTexturePropertyView, true> + uint8ArrayProperty = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + uint8ArrayProperty.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); + } +} + +TEST_CASE("Test with PropertyTextureProperty offset, scale, min, max") { + Model model; + // clang-format off + std::vector data{ + 0, 0, 0, 1, + 9, 0, 1, 0, + 20, 2, 2, 0, + 8, 1, 0, 1}; + // clang-format on + + std::vector expectedUint{16777216, 65545, 131604, 16777480}; + + const float offset = 1.0f; + const float scale = 2.0f; + const float min = -10.0f; + const float max = 10.0f; + + 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(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::FLOAT32; + testClassProperty.offset = offset; + testClassProperty.scale = scale; + testClassProperty.min = min; + testClassProperty.max = max; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(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::FLOAT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); + REQUIRE(classProperty->offset); + REQUIRE(classProperty->scale); + REQUIRE(classProperty->min); + REQUIRE(classProperty->max); + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + + SECTION("Use class property values") { + PropertyTexturePropertyView property = + view.getPropertyView("TestClassProperty"); + REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); + REQUIRE(property.offset()); + REQUIRE(*property.offset() == offset); + REQUIRE(property.scale()); + REQUIRE(*property.scale() == scale); + REQUIRE(property.min()); + REQUIRE(*property.min() == min); + REQUIRE(property.max()); + REQUIRE(*property.max() == max); + + std::vector expectedRaw(expectedUint.size()); + std::vector> expectedTransformed(expectedUint.size()); + for (size_t i = 0; i < expectedUint.size(); i++) { + float value = *reinterpret_cast(&expectedUint[i]); + expectedRaw[i] = value; + expectedTransformed[i] = value * scale + offset; + } + + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = property.getRaw(uv[0], uv[1]); + REQUIRE(value == expectedRaw[i]); + + auto maybeValue = property.get(uv[0], uv[1]); + REQUIRE(maybeValue == expectedTransformed[i]); + } + } + + SECTION("Use own property values") { + const float newOffset = 1.0f; + const float newScale = -1.0f; + const float newMin = -3.0f; + const float newMax = 0.0f; + propertyTextureProperty.offset = newOffset; + propertyTextureProperty.scale = newScale; + propertyTextureProperty.min = newMin; + propertyTextureProperty.max = newMax; + + PropertyTexturePropertyView property = + view.getPropertyView("TestClassProperty"); + REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); + REQUIRE(property.offset()); + REQUIRE(*property.offset() == newOffset); + REQUIRE(property.scale()); + REQUIRE(*property.scale() == newScale); + REQUIRE(property.min()); + REQUIRE(*property.min() == newMin); + REQUIRE(property.max()); + REQUIRE(*property.max() == newMax); + + std::vector expectedRaw(expectedUint.size()); + std::vector> expectedTransformed(expectedUint.size()); + for (size_t i = 0; i < expectedUint.size(); i++) { + float value = *reinterpret_cast(&expectedUint[i]); + expectedRaw[i] = value; + expectedTransformed[i] = value * newScale + newOffset; + } + + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = property.getRaw(uv[0], uv[1]); + REQUIRE(value == expectedRaw[i]); + + auto maybeValue = property.get(uv[0], uv[1]); + REQUIRE(maybeValue == expectedTransformed[i]); + } + } +} + +TEST_CASE( + "Test with PropertyTextureProperty offset, scale, min, max (normalized)") { + Model model; + std::vector data = {12, 34, 30, 11}; + + const double offset = 1.0; + const double scale = 2.0; + const double min = 1.0; + const double max = 3.0; + + addTextureToModel( + model, + Sampler::WrapS::CLAMP_TO_EDGE, + Sampler::WrapS::CLAMP_TO_EDGE, + 2, + 2, + 1, + data); + size_t textureIndex = model.textures.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.normalized = true; + testClassProperty.offset = offset; + testClassProperty.scale = scale; + testClassProperty.min = min; + testClassProperty.max = max; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(textureIndex); + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + 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::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + + SECTION("Use class property values") { + PropertyTexturePropertyView property = + view.getPropertyView("TestClassProperty"); + REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); + REQUIRE(property.offset()); + REQUIRE(*property.offset() == offset); + REQUIRE(property.scale()); + REQUIRE(*property.scale() == scale); + REQUIRE(property.min()); + REQUIRE(*property.min() == min); + REQUIRE(property.max()); + REQUIRE(*property.max() == max); + + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = property.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = property.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == normalize(data[i]) * scale + offset); + } + } + + SECTION("Use own property values") { + const double newOffset = 2.0; + const double newScale = 5.0; + const double newMin = 10.0; + const double newMax = 11.0; + propertyTextureProperty.offset = newOffset; + propertyTextureProperty.scale = newScale; + propertyTextureProperty.min = newMin; + propertyTextureProperty.max = newMax; + + PropertyTexturePropertyView property = + view.getPropertyView("TestClassProperty"); + REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); + REQUIRE(property.offset()); + REQUIRE(*property.offset() == newOffset); + REQUIRE(property.scale()); + REQUIRE(*property.scale() == newScale); + REQUIRE(property.min()); + REQUIRE(*property.min() == newMin); + REQUIRE(property.max()); + REQUIRE(*property.max() == newMax); + + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = property.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = property.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == normalize(data[i]) * newScale + newOffset); + } + } +} + +TEST_CASE("Test with PropertyTextureProperty noData") { + Model model; + std::vector data = {12, 34, 30, 11}; + const uint8_t noData = 34; + + addTextureToModel( + model, + Sampler::WrapS::CLAMP_TO_EDGE, + Sampler::WrapS::CLAMP_TO_EDGE, + 2, + 2, + 1, + data); + size_t textureIndex = model.textures.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.noData = noData; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(textureIndex); + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + 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::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + + SECTION("Without default value") { + PropertyTexturePropertyView property = + view.getPropertyView("TestClassProperty"); + REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); + + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = property.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = property.get(uv[0], uv[1]); + if (value == noData) { + REQUIRE(!maybeValue); + } else { + REQUIRE(maybeValue); + REQUIRE(*maybeValue == data[i]); + } + } + } + + SECTION("With default value") { + const uint8_t defaultValue = 255; + testClassProperty.defaultProperty = defaultValue; + + PropertyTexturePropertyView property = + view.getPropertyView("TestClassProperty"); + REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); + + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = property.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = property.get(uv[0], uv[1]); + REQUIRE(maybeValue); + if (value == noData) { + REQUIRE(*maybeValue == defaultValue); + } else { + REQUIRE(*maybeValue == data[i]); + } + } + } +} + +TEST_CASE("Test with PropertyTextureProperty noData (normalized)") { + Model model; + std::vector data = {12, 34, 30, 11}; + const uint8_t noData = 34; + + addTextureToModel( + model, + Sampler::WrapS::CLAMP_TO_EDGE, + Sampler::WrapS::CLAMP_TO_EDGE, + 2, + 2, + 1, + data); + size_t textureIndex = model.textures.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.normalized = true; + testClassProperty.noData = noData; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(textureIndex); + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0}; + + 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::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + + SECTION("Without default value") { + PropertyTexturePropertyView property = + view.getPropertyView("TestClassProperty"); + REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); + + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = property.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = property.get(uv[0], uv[1]); + if (value == noData) { + REQUIRE(!maybeValue); + } else { + REQUIRE(maybeValue); + REQUIRE(*maybeValue == normalize(data[i])); + } + } + } + + SECTION("With default value") { + const double defaultValue = -1.0; + testClassProperty.defaultProperty = defaultValue; + + PropertyTexturePropertyView property = + view.getPropertyView("TestClassProperty"); + REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); + + for (size_t i = 0; i < texCoords.size(); ++i) { + glm::dvec2 uv = texCoords[i]; + auto value = property.getRaw(uv[0], uv[1]); + REQUIRE(value == data[i]); + + auto maybeValue = property.get(uv[0], uv[1]); + REQUIRE(maybeValue); + if (value == noData) { + REQUIRE(*maybeValue == defaultValue); + } else { + REQUIRE(*maybeValue == normalize(data[i])); + } + } } } @@ -666,14 +1693,15 @@ TEST_CASE("Test callback for scalar PropertyTextureProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT16); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); - std::vector expected{-1, 268, 542, -256}; - std::vector texCoords{ - glm::vec2(0, 0), - glm::vec2(0.5, 0), - glm::vec2(0, 0.5), - glm::vec2(0.5, 0.5)}; + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + std::vector expected{-1, 268, 542, -256}; uint32_t invokedCallbackCount = 0; view.getPropertyView( "TestClassProperty", @@ -689,8 +1717,97 @@ TEST_CASE("Test callback for scalar PropertyTextureProperty") { 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]); + glm::dvec2& uv = texCoords[i]; + auto value = propertyValue.getRaw(uv[0], uv[1]); + REQUIRE(value == expected[i]); + + auto maybeValue = propertyValue.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expected[i]); + } + } else { + FAIL("getPropertyView returned PropertyTexturePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for scalar PropertyTextureProperty (normalized)") { + Model model; + std::vector 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(); + + 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; + testClassProperty.normalized = true; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(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); + REQUIRE(classProperty->normalized); + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + + std::vector expected{-1, 268, 542, -256}; + 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, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == + PropertyTexturePropertyViewStatus::Valid); + + for (size_t i = 0; i < expected.size(); ++i) { + glm::dvec2& uv = texCoords[i]; + auto value = propertyValue.getRaw(uv[0], uv[1]); + REQUIRE(value == expected[i]); + + auto maybeValue = propertyValue.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == normalize(expected[i])); } } else { FAIL("getPropertyView returned PropertyTexturePropertyView of " @@ -749,17 +1866,19 @@ TEST_CASE("Test callback for vecN PropertyTextureProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT8); REQUIRE(classProperty->count == std::nullopt); REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); std::vector expected{ glm::i8vec2(-1, -1), glm::i8vec2(12, 1), glm::i8vec2(30, 2), glm::i8vec2(0, -1)}; - std::vector texCoords{ - glm::vec2(0, 0), - glm::vec2(0.5, 0), - glm::vec2(0, 0.5), - glm::vec2(0.5, 0.5)}; + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; uint32_t invokedCallbackCount = 0; view.getPropertyView( @@ -776,8 +1895,108 @@ TEST_CASE("Test callback for vecN PropertyTextureProperty") { 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]); + glm::dvec2& uv = texCoords[i]; + auto value = propertyValue.getRaw(uv[0], uv[1]); + REQUIRE(value == expected[i]); + + auto maybeValue = propertyValue.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == expected[i]); + } + } else { + FAIL("getPropertyView returned PropertyTexturePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for vecN PropertyTextureProperty (normalized)") { + Model model; + // clang-format off + std::vector 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(); + + 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; + testClassProperty.normalized = true; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(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); + REQUIRE(classProperty->normalized); + + std::vector expected{ + glm::i8vec2(-1, -1), + glm::i8vec2(12, 1), + glm::i8vec2(30, 2), + glm::i8vec2(0, -1)}; + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(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, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == + PropertyTexturePropertyViewStatus::Valid); + + for (size_t i = 0; i < expected.size(); ++i) { + glm::dvec2& uv = texCoords[i]; + auto value = propertyValue.getRaw(uv[0], uv[1]); + REQUIRE(value == expected[i]); + + auto maybeValue = propertyValue.get(uv[0], uv[1]); + REQUIRE(maybeValue); + REQUIRE(*maybeValue == normalize(expected[i])); } } else { FAIL("getPropertyView returned PropertyTexturePropertyView of " @@ -838,17 +2057,19 @@ TEST_CASE("Test callback for array PropertyTextureProperty") { REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT16); REQUIRE(classProperty->array); REQUIRE(classProperty->count == 2); + REQUIRE(!classProperty->normalized); std::vector> expected{ {254, 509}, {522, 808}, {30, 512}, {522, 1279}}; - std::vector texCoords{ - glm::vec2(0, 0), - glm::vec2(0.5, 0), - glm::vec2(0, 0.5), - glm::vec2(0.5, 0.5)}; + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; uint32_t invokedCallbackCount = 0; view.getPropertyView( @@ -867,14 +2088,134 @@ TEST_CASE("Test callback for array PropertyTextureProperty") { for (size_t i = 0; i < expected.size(); ++i) { std::vector& expectedArray = expected[i]; - glm::vec2& texCoord = texCoords[i]; + glm::dvec2& uv = texCoords[i]; + PropertyArrayView array = + propertyValue.getRaw(uv[0], uv[1]); + + REQUIRE(static_cast(array.size()) == expectedArray.size()); + for (int64_t j = 0; j < array.size(); j++) { + REQUIRE(array[j] == expectedArray[static_cast(j)]); + } + + auto maybeArray = propertyValue.get(uv[0], uv[1]); + REQUIRE(maybeArray); + REQUIRE( + static_cast(maybeArray->size()) == + expectedArray.size()); + for (int64_t j = 0; j < array.size(); j++) { + REQUIRE( + (*maybeArray)[j] == expectedArray[static_cast(j)]); + } + } + } else { + FAIL("getPropertyView returned PropertyTexturePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for array PropertyTextureProperty (normalized)") { + Model model; + // clang-format off + std::vector 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(); + + 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; + testClassProperty.normalized = true; + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(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); + REQUIRE(classProperty->normalized); + + std::vector> expected{ + {254, 509}, + {522, 808}, + {30, 512}, + {522, 1279}}; + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(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, true>, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == + PropertyTexturePropertyViewStatus::Valid); + + for (size_t i = 0; i < expected.size(); ++i) { + std::vector& expectedArray = expected[i]; + glm::dvec2& uv = texCoords[i]; PropertyArrayView array = - propertyValue.get(texCoord[0], texCoord[1]); + propertyValue.getRaw(uv[0], uv[1]); REQUIRE(static_cast(array.size()) == expectedArray.size()); for (int64_t j = 0; j < array.size(); j++) { REQUIRE(array[j] == expectedArray[static_cast(j)]); } + + auto maybeArray = propertyValue.get(uv[0], uv[1]); + REQUIRE(maybeArray); + REQUIRE( + static_cast(maybeArray->size()) == + expectedArray.size()); + for (int64_t j = 0; j < array.size(); j++) { + auto rawValue = expectedArray[static_cast(j)]; + REQUIRE((*maybeArray)[j] == normalize(rawValue)); + } } } else { FAIL("getPropertyView returned PropertyTexturePropertyView of " From d5f6944580366a7a59dfe91ba6fa573524cf3d9a Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Fri, 25 Aug 2023 15:30:32 +1000 Subject: [PATCH 094/121] Formatting. --- CesiumGltf/test/TestPropertyTableView.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index 3bb8ca0e8..747256fe1 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -4074,7 +4074,8 @@ TEST_CASE("Test with PropertyTableProperty offset, scale, min, max") { } } -TEST_CASE("Test with PropertyTableProperty offset, scale, min, max (normalized)") { +TEST_CASE( + "Test with PropertyTableProperty offset, scale, min, max (normalized)") { Model model; std::vector values = {-128, 0, 32, 127}; const double offset = 0.5; From 3e5d630a1fa043ed28a732e8f7be0c6302747d5c Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 25 Aug 2023 16:17:11 -0400 Subject: [PATCH 095/121] First round of cleanup / PR feedback --- .../include/CesiumGltf/PropertyArrayView.h | 8 +- .../CesiumGltf/PropertyTablePropertyView.h | 48 +- .../include/CesiumGltf/PropertyTableView.h | 32 +- .../CesiumGltf/PropertyTexturePropertyView.h | 376 +++----- .../include/CesiumGltf/PropertyTextureView.h | 74 +- CesiumGltf/include/CesiumGltf/PropertyView.h | 20 +- CesiumGltf/src/FeatureIdTextureView.cpp | 4 +- CesiumGltf/src/PropertyTableView.cpp | 2 +- .../src/PropertyTexturePropertyView.cpp | 23 + CesiumGltf/test/TestPropertyTableView.cpp | 832 ++++-------------- CesiumGltf/test/TestPropertyTextureView.cpp | 326 +++---- 11 files changed, 550 insertions(+), 1195 deletions(-) create mode 100644 CesiumGltf/src/PropertyTexturePropertyView.cpp diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index 80d8bbc61..bc58d0160 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -81,7 +81,7 @@ template <> class PropertyArrayView { /** * @brief Constructs an empty array view. */ - PropertyArrayView() : _values{} {} + PropertyArrayView() : _values{}, _bitOffset{0}, _size{0} {} /** * @brief Constructs an array view from a buffer. @@ -123,8 +123,8 @@ template <> class PropertyArrayView { private: gsl::span _values; - int64_t _bitOffset = 0; - int64_t _size = 0; + int64_t _bitOffset; + int64_t _size; }; template <> class PropertyArrayView { @@ -154,7 +154,7 @@ template <> class PropertyArrayView { : _values{values}, _stringOffsets{stringOffsets}, _stringOffsetType{stringOffsetType}, - _size(size) {} + _size{size} {} std::string_view operator[](int64_t index) const noexcept { const size_t currentOffset = diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index fe73675e8..1a86d0972 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -18,112 +18,114 @@ namespace CesiumGltf { * @brief Indicates the status of a property table property view. * * The {@link PropertyTablePropertyView} constructor always completes successfully. - * However, it may not always reflect the actual content of the {@link PropertyTableProperty}, - * but instead indicate that its {@link PropertyTablePropertyView::size} is 0. + * However, it may not always reflect the actual content of the + * {@link PropertyTableProperty}, but instead indicate that its + * {@link PropertyTablePropertyView::size} is 0. * This enumeration provides the reason. */ class PropertyTablePropertyViewStatus : public PropertyViewStatus { public: /** - * @brief This property view was initialized from an invalid {@link PropertyTable}. + * @brief This property view was initialized from an invalid + * {@link PropertyTable}. */ - static const PropertyViewStatusType ErrorInvalidPropertyTable = 12; + static const PropertyViewStatusType ErrorInvalidPropertyTable = 13; /** * @brief This property view does not have a valid value buffer view index. */ - static const PropertyViewStatusType ErrorInvalidValueBufferView = 13; + static const PropertyViewStatusType ErrorInvalidValueBufferView = 14; /** * @brief This array property view does not have a valid array offset buffer * view index. */ - static const PropertyViewStatusType ErrorInvalidArrayOffsetBufferView = 14; + static const PropertyViewStatusType ErrorInvalidArrayOffsetBufferView = 15; /** * @brief This string property view does not have a valid string offset buffer * view index. */ - static const PropertyViewStatusType ErrorInvalidStringOffsetBufferView = 15; + static const PropertyViewStatusType ErrorInvalidStringOffsetBufferView = 16; /** * @brief This property view has a valid value buffer view, but the buffer * view specifies an invalid buffer index. */ - static const PropertyViewStatusType ErrorInvalidValueBuffer = 16; + static const PropertyViewStatusType ErrorInvalidValueBuffer = 17; /** * @brief This property view has a valid array string buffer view, but the * buffer view specifies an invalid buffer index. */ - static const PropertyViewStatusType ErrorInvalidArrayOffsetBuffer = 17; + static const PropertyViewStatusType ErrorInvalidArrayOffsetBuffer = 18; /** * @brief This property view has a valid string offset buffer view, but the * buffer view specifies an invalid buffer index. */ - static const PropertyViewStatusType ErrorInvalidStringOffsetBuffer = 18; + static const PropertyViewStatusType ErrorInvalidStringOffsetBuffer = 19; /** * @brief This property view has a buffer view that points outside the bounds * of its target buffer. */ - static const PropertyViewStatusType ErrorBufferViewOutOfBounds = 19; + static const PropertyViewStatusType ErrorBufferViewOutOfBounds = 20; /** * @brief This property view has an invalid buffer view; its length is not * a multiple of the size of its type / offset type. */ static const PropertyViewStatusType - ErrorBufferViewSizeNotDivisibleByTypeSize = 20; + ErrorBufferViewSizeNotDivisibleByTypeSize = 21; /** * @brief This property view has an invalid buffer view; its length does not * match the size of the property table. */ static const PropertyViewStatusType - ErrorBufferViewSizeDoesNotMatchPropertyTableCount = 21; + ErrorBufferViewSizeDoesNotMatchPropertyTableCount = 22; /** * @brief This array property view has both a fixed length and an offset * buffer view defined. */ static const PropertyViewStatusType ErrorArrayCountAndOffsetBufferCoexist = - 22; + 23; /** * @brief This array property view has neither a fixed length nor an offset * buffer view defined. */ static const PropertyViewStatusType ErrorArrayCountAndOffsetBufferDontExist = - 23; + 24; /** * @brief This property view has an unknown array offset type. */ - static const PropertyViewStatusType ErrorInvalidArrayOffsetType = 24; + static const PropertyViewStatusType ErrorInvalidArrayOffsetType = 25; /** * @brief This property view has an unknown string offset type. */ - static const PropertyViewStatusType ErrorInvalidStringOffsetType = 25; + static const PropertyViewStatusType ErrorInvalidStringOffsetType = 26; /** * @brief This property view's array offset values are not sorted in ascending * order. */ - static const PropertyViewStatusType ErrorArrayOffsetsNotSorted = 26; + static const PropertyViewStatusType ErrorArrayOffsetsNotSorted = 27; /** * @brief This property view's string offset values are not sorted in * ascending order. */ - static const PropertyViewStatusType ErrorStringOffsetsNotSorted = 27; + static const PropertyViewStatusType ErrorStringOffsetsNotSorted = 28; /** * @brief This property view has an array offset that is out of bounds. */ - static const PropertyViewStatusType ErrorArrayOffsetOutOfBounds = 28; + static const PropertyViewStatusType ErrorArrayOffsetOutOfBounds = 29; /** * @brief This property view has a string offset that is out of bounds. @@ -131,8 +133,7 @@ class PropertyTablePropertyViewStatus : public PropertyViewStatus { static const PropertyViewStatusType ErrorStringOffsetOutOfBounds = 29; }; -namespace { -int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { +inline int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { switch (offsetType) { case PropertyComponentType::Uint8: return sizeof(uint8_t); @@ -146,7 +147,6 @@ int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { return 0; } } -} // namespace /** * @brief A view on the data of the {@link PropertyTableProperty} that is created @@ -282,7 +282,7 @@ class PropertyTablePropertyView std::optional get(int64_t index) const noexcept { ElementType value = getRaw(index); - if (this->noData() && value == *(this->noData())) { + if (value == this->noData()) { return this->defaultValue(); } diff --git a/CesiumGltf/include/CesiumGltf/PropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h index c1aac5bf8..bd18c705e 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -104,6 +104,16 @@ class PropertyTableView { * std::string_view, or {@link PropertyArrayView} with T as one of the * aforementioned types. * + * If T does not match the type specified by the class property, this returns + * an invalid PropertyTexturePropertyView. Likewise, if the value of + * Normalized + * does not match the value of {@ClassProperty::normalized} for that class property, + * this returns an invalid property view. Only types with integer components + * may be normalized. + * + * @tparam T The C++ type corresponding to the type of the data retrieved. + * @tparam Normalized Whether the property is normalized. Only applicable to + * types with integer components. * @param propertyName The name of the property to retrieve data from * @return A {@link PropertyTablePropertyView} of the property. If no valid property is * found, the property view will be invalid. @@ -136,9 +146,11 @@ class PropertyTableView { * uint64_t, int64_t, float, double), a glm vecN composed of one of the scalar * types, a glm matN composed of one of the scalar types, bool, * std::string_view, or {@link PropertyArrayView} with T as one of the - * aforementioned types. If the property is invalid, an empty - * {@link PropertyTablePropertyView} with an error status will be passed to the - * callback. Otherwise, a valid property view will be passed to the callback. + * aforementioned types. + * + * If the property is invalid, an empty {@link PropertyTablePropertyView} 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 @@ -184,6 +196,7 @@ class PropertyTableView { case PropertyComponentType::Uint64: break; default: + // Only integer components may be normalized. callback( propertyName, PropertyTablePropertyView( @@ -299,10 +312,11 @@ class PropertyTableView { * int32_t, uint64_t, int64_t, float, double), a glm vecN composed of one of * the scalar types, a glm matN composed of one of the scalar types, bool, * std::string_view, or {@link PropertyArrayView} with T as one of the - * aforementioned types. If the property is invalid, an empty - * {@link PropertyTablePropertyView} with an error status code will be passed to the - * callback. Otherwise, a valid property view will be passed to - * the callback. + * aforementioned types. + * + * If the property is invalid, an empty {@link PropertyTablePropertyView} with + * an error status code 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 @@ -1095,7 +1109,7 @@ class PropertyTableView { if (classProperty.normalized != Normalized) { return PropertyTablePropertyView( - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } gsl::span values; @@ -1166,7 +1180,7 @@ class PropertyTableView { if (classProperty.normalized != Normalized) { return PropertyTablePropertyView, Normalized>( - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } gsl::span values; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index e71dc1976..6b191caff 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -27,39 +27,39 @@ class PropertyTexturePropertyViewStatus : public PropertyViewStatus { * @brief This property view was initialized from an invalid * {@link PropertyTexture}. */ - static const int ErrorInvalidPropertyTexture = 12; + static const int ErrorInvalidPropertyTexture = 13; /** * @brief This property view is associated with a {@link ClassProperty} of an * unsupported type. */ - static const int ErrorUnsupportedProperty = 13; + static const int ErrorUnsupportedProperty = 14; /** * @brief This property view does not have a valid texture index. */ - static const int ErrorInvalidTexture = 14; + static const int ErrorInvalidTexture = 15; /** * @brief This property view does not have a valid sampler index. */ - static const int ErrorInvalidSampler = 15; + static const int ErrorInvalidSampler = 16; /** * @brief This property view does not have a valid image index. */ - static const int ErrorInvalidImage = 16; + static const int ErrorInvalidImage = 17; /** * @brief This property is viewing an empty image. */ - static const int ErrorEmptyImage = 17; + static const int ErrorEmptyImage = 18; /** * @brief This property uses an image with multi-byte channels. Only * single-byte channels are supported. */ - static const int ErrorInvalidBytesPerChannel = 18; + static const int ErrorInvalidBytesPerChannel = 19; /** * @brief The channels of this property texture property are invalid. @@ -68,7 +68,7 @@ class PropertyTexturePropertyViewStatus : public PropertyViewStatus { * more than four channels can be defined for specialized texture * formats, this implementation only supports four channels max. */ - static const int ErrorInvalidChannels = 19; + static const int ErrorInvalidChannels = 20; /** * @brief The channels of this property texture property do not provide @@ -76,12 +76,30 @@ class PropertyTexturePropertyViewStatus : public PropertyViewStatus { * 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 = 20; + static const int ErrorChannelsAndTypeMismatch = 21; }; -namespace { template -ElementType assembleScalarValue(const std::vector& bytes) { +ElementType +assembleValueFromChannels(const std::vector& bytes) noexcept { + assert(bytes.size() > 0 && "Channel input must have at least one value."); + + if constexpr (IsMetadataScalar::value) { + return assembleScalarValue(bytes); + } + + if constexpr (IsMetadataVecN::value) { + return assembleVecNValue(bytes); + } + + if constexpr (IsMetadataArray::value) { + return assembleArrayValue::type>( + bytes); + } +} + +template +ElementType assembleScalarValue(const std::vector& bytes) noexcept { if constexpr (std::is_same_v) { assert( bytes.size() == sizeof(float) && @@ -107,7 +125,73 @@ ElementType assembleScalarValue(const std::vector& bytes) { } } -double applySamplerWrapS(const double u, const int32_t wrapS) { +template +ElementType assembleVecNValue(const std::vector& bytes) noexcept { + ElementType result = ElementType(); + + const glm::length_t N = + getDimensionsFromPropertyType(TypeToPropertyType::value); + using typename T = ElementType::value_type; + + assert( + sizeof(T) <= 2 && "Components cannot be larger than two bytes in size."); + + if constexpr (std::is_same_v) { + assert(N == 2 && "Only vec2s can contain two-byte integer components."); + uint16_t x = static_cast(bytes[0]) | + (static_cast(bytes[1]) << 8); + uint16_t y = static_cast(bytes[2]) | + (static_cast(bytes[3]) << 8); + + result[0] = *reinterpret_cast(&x); + result[1] = *reinterpret_cast(&y); + } + + if constexpr (std::is_same_v) { + assert(N == 2 && "Only vec2s can contain two-byte integer components."); + result[0] = static_cast(bytes[0]) | + (static_cast(bytes[1]) << 8); + result[1] = static_cast(bytes[2]) | + (static_cast(bytes[3]) << 8); + } + + if constexpr (std::is_same_v) { + for (size_t i = 0; i < bytes.size(); i++) { + result[i] = *reinterpret_cast(&bytes[i]); + } + } + + if constexpr (std::is_same_v) { + for (size_t i = 0; i < bytes.size(); i++) { + result[i] = bytes[i]; + } + } + + return result; +} + +template +PropertyArrayView +assembleArrayValue(const std::vector& bytes) noexcept { + std::vector 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; + UintType resultAsUint = static_cast(bytes[b]) | + (static_cast(bytes[b + 1]) << 8); + result[i] = *reinterpret_cast(&resultAsUint); + } + } else { + for (size_t i = 0; i < bytes.size(); i++) { + result[i] = *reinterpret_cast(&bytes[i]); + } + } + + return PropertyArrayView(std::move(result)); +} + +inline double applySamplerWrapS(const double u, const int32_t wrapS) { if (wrapS == Sampler::WrapS::REPEAT) { double integral = 0; double fraction = std::modf(u, &integral); @@ -122,10 +206,10 @@ double applySamplerWrapS(const double u, const int32_t wrapS) { return integer % 2 == 1 ? 1.0 - fraction : fraction; } - return std::clamp(u, 0.0, 1.0); + return glm::clamp(u, 0.0, 1.0); } -double applySamplerWrapT(const double v, const int32_t wrapT) { +inline double applySamplerWrapT(const double v, const int32_t wrapT) { if (wrapT == Sampler::WrapT::REPEAT) { double integral = 0; double fraction = std::modf(v, &integral); @@ -140,15 +224,19 @@ double applySamplerWrapT(const double v, const int32_t wrapT) { return integer % 2 == 1 ? 1.0 - fraction : fraction; } - return std::clamp(v, 0.0, 1.0); + return glm::clamp(v, 0.0, 1.0); } -} // namespace /** - * @brief A view of the data specified by a {@link PropertyTextureProperty}. + * @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 + * @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 class PropertyTexturePropertyView; @@ -159,6 +247,8 @@ class PropertyTexturePropertyView; * * Provides utilities to sample the property texture property using texture * coordinates. + * + * @tparam ElementType The type of the elements represented in the property view */ template class PropertyTexturePropertyView @@ -173,7 +263,7 @@ class PropertyTexturePropertyView _pImage(nullptr), _texCoordSetIndex(0), _channels(), - _swizzle("") {} + _swizzle() {} /** * @brief Constructs an invalid instance for an erroneous property. @@ -186,7 +276,7 @@ class PropertyTexturePropertyView _pImage(nullptr), _texCoordSetIndex(0), _channels(), - _swizzle("") { + _swizzle() { assert( _status != PropertyTexturePropertyViewStatus::Valid && "An empty property view should not be constructed with a valid status"); @@ -197,11 +287,9 @@ class PropertyTexturePropertyView * * @param property The {@link PropertyTextureProperty} * @param classProperty The {@link ClassProperty} this property conforms to. - * @param pSampler A pointer to the sampler used by the property. - * @param pImage A pointer to the image used by the property. - * @param texCoordSetIndex The value of {@link PropertyTextureProperty::texcoord}. + * @param sampler The {@link Sampler} used by the property. + * @param image The {@link ImageCesium} used by the property. * @param channels The value of {@link PropertyTextureProperty::channels}. - * @param normalized Whether this property has a normalized integer type. */ PropertyTexturePropertyView( const PropertyTextureProperty& property, @@ -214,11 +302,13 @@ class PropertyTexturePropertyView _pImage(&image), _texCoordSetIndex(property.texCoord), _channels(channels), - _swizzle("") { + _swizzle() { if (this->_status != PropertyTexturePropertyViewStatus::Valid) { return; } + _swizzle.reserve(_channels.size()); + for (size_t i = 0; i < _channels.size(); ++i) { switch (_channels[i]) { case 0: @@ -240,16 +330,15 @@ class PropertyTexturePropertyView } /** - * @brief Gets the raw 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. + * @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. + * 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. @@ -260,7 +349,7 @@ class PropertyTexturePropertyView std::optional get(double u, double v) const noexcept { ElementType value = getRaw(u, v); - if (this->noData() && value == *(this->noData())) { + if (value == this->noData()) { return this->defaultValue(); } @@ -310,11 +399,11 @@ class PropertyTexturePropertyView double yCoord = std::floor(wrappedV * this->_pImage->height); // Clamp to ensure no out-of-bounds data access - int64_t x = std::clamp( + int64_t x = glm::clamp( static_cast(xCoord), static_cast(0), static_cast(this->_pImage->width) - 1); - int64_t y = std::clamp( + int64_t y = glm::clamp( static_cast(yCoord), static_cast(0), static_cast(this->_pImage->height) - 1); @@ -333,7 +422,7 @@ class PropertyTexturePropertyView channelValues[i] = *(pValue + this->_channels[i]); } - return assembleValueFromChannels(channelValues); + return assembleValueFromChannels(channelValues); } /** @@ -364,103 +453,6 @@ class PropertyTexturePropertyView const std::string& getSwizzle() const noexcept { return this->_swizzle; } private: - ElementType - assembleValueFromChannels(const std::vector& bytes) const noexcept { - assert(bytes.size() > 0 && "Channel input must have at least one value."); - - if constexpr (IsMetadataScalar::value) { - return assembleScalarValue(bytes); - } - - if constexpr (IsMetadataVecN::value) { - return assembleVecNValue(bytes); - } - - if constexpr (IsMetadataArray::value) { - return assembleArrayValue::type>( - bytes); - } - } - - ElementType - assembleVecNValue(const std::vector& bytes) const noexcept { - const glm::length_t N = - getDimensionsFromPropertyType(TypeToPropertyType::value); - switch (N) { - case 2: - return assembleVecNValueImpl<2, typename ElementType::value_type>(bytes); - case 3: - return assembleVecNValueImpl<3, typename ElementType::value_type>(bytes); - case 4: - return assembleVecNValueImpl<4, typename ElementType::value_type>(bytes); - default: - return ElementType(); - } - } - - template - ElementType - assembleVecNValueImpl(const std::vector& bytes) const noexcept { - ElementType result = ElementType(); - assert( - sizeof(T) <= 2 && - "Components cannot be larger than two bytes in size."); - - if constexpr (std::is_same_v) { - assert(N == 2 && "Only vec2s can contain two-byte integer components."); - uint16_t x = static_cast(bytes[0]) | - (static_cast(bytes[1]) << 8); - uint16_t y = static_cast(bytes[2]) | - (static_cast(bytes[3]) << 8); - - result[0] = *reinterpret_cast(&x); - result[1] = *reinterpret_cast(&y); - } - - if constexpr (std::is_same_v) { - assert(N == 2 && "Only vec2s can contain two-byte integer components."); - result[0] = static_cast(bytes[0]) | - (static_cast(bytes[1]) << 8); - result[1] = static_cast(bytes[2]) | - (static_cast(bytes[3]) << 8); - } - - if constexpr (std::is_same_v) { - for (size_t i = 0; i < bytes.size(); i++) { - result[i] = *reinterpret_cast(&bytes[i]); - } - } - - if constexpr (std::is_same_v) { - for (size_t i = 0; i < bytes.size(); i++) { - result[i] = bytes[i]; - } - } - - return result; - } - - template - PropertyArrayView - assembleArrayValue(const std::vector& bytes) const noexcept { - std::vector 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; - UintType resultAsUint = static_cast(bytes[b]) | - (static_cast(bytes[b + 1]) << 8); - result[i] = *reinterpret_cast(&resultAsUint); - } - } else { - for (size_t i = 0; i < bytes.size(); i++) { - result[i] = *reinterpret_cast(&bytes[i]); - } - } - - return PropertyArrayView(std::move(result)); - } - const Sampler* _pSampler; const ImageCesium* _pImage; int64_t _texCoordSetIndex; @@ -491,7 +483,7 @@ class PropertyTexturePropertyView _pImage(nullptr), _texCoordSetIndex(0), _channels(), - _swizzle("") {} + _swizzle() {} /** * @brief Constructs an invalid instance for an erroneous property. @@ -504,7 +496,7 @@ class PropertyTexturePropertyView _pImage(nullptr), _texCoordSetIndex(0), _channels(), - _swizzle("") { + _swizzle() { assert( _status != PropertyTexturePropertyViewStatus::Valid && "An empty property view should not be constructed with a valid status"); @@ -515,11 +507,9 @@ class PropertyTexturePropertyView * * @param property The {@link PropertyTextureProperty} * @param classProperty The {@link ClassProperty} this property conforms to. - * @param pSampler A pointer to the sampler used by the property. - * @param pImage A pointer to the image used by the property. - * @param texCoordSetIndex The value of {@link PropertyTextureProperty::texcoord}. + * @param sampler The {@link Sampler} used by the property. + * @param image The {@link ImageCesium} used by the property. * @param channels The value of {@link PropertyTextureProperty::channels}. - * @param normalized Whether this property has a normalized integer type. */ PropertyTexturePropertyView( const PropertyTextureProperty& property, @@ -532,11 +522,12 @@ class PropertyTexturePropertyView _pImage(&image), _texCoordSetIndex(property.texCoord), _channels(channels), - _swizzle("") { + _swizzle() { if (this->_status != PropertyTexturePropertyViewStatus::Valid) { return; } + _swizzle.reserve(_channels.size()); for (size_t i = 0; i < _channels.size(); ++i) { switch (_channels[i]) { case 0: @@ -654,11 +645,11 @@ class PropertyTexturePropertyView double yCoord = std::floor(wrappedV * this->_pImage->height); // Clamp to ensure no out-of-bounds data access - int64_t x = std::clamp( + int64_t x = glm::clamp( static_cast(xCoord), static_cast(0), static_cast(this->_pImage->width) - 1); - int64_t y = std::clamp( + int64_t y = glm::clamp( static_cast(yCoord), static_cast(0), static_cast(this->_pImage->height) - 1); @@ -677,7 +668,7 @@ class PropertyTexturePropertyView channelValues[i] = *(pValue + this->_channels[i]); } - return assembleValueFromChannels(channelValues); + return assembleValueFromChannels(channelValues); } /** @@ -708,103 +699,6 @@ class PropertyTexturePropertyView const std::string& getSwizzle() const noexcept { return this->_swizzle; } private: - ElementType - assembleValueFromChannels(const std::vector& bytes) const noexcept { - assert(bytes.size() > 0 && "Channel input must have at least one value."); - - if constexpr (IsMetadataScalar::value) { - return assembleScalarValue(bytes); - } - - if constexpr (IsMetadataVecN::value) { - return assembleVecNValue(bytes); - } - - if constexpr (IsMetadataArray::value) { - return assembleArrayValue::type>( - bytes); - } - } - - ElementType - assembleVecNValue(const std::vector& bytes) const noexcept { - const glm::length_t N = - getDimensionsFromPropertyType(TypeToPropertyType::value); - switch (N) { - case 2: - return assembleVecNValueImpl<2, typename ElementType::value_type>(bytes); - case 3: - return assembleVecNValueImpl<3, typename ElementType::value_type>(bytes); - case 4: - return assembleVecNValueImpl<4, typename ElementType::value_type>(bytes); - default: - return ElementType(); - } - } - - template - ElementType - assembleVecNValueImpl(const std::vector& bytes) const noexcept { - ElementType result = ElementType(); - assert( - sizeof(T) <= 2 && - "Components cannot be larger than two bytes in size."); - - if constexpr (std::is_same_v) { - assert(N == 2 && "Only vec2s can contain two-byte integer components."); - uint16_t x = static_cast(bytes[0]) | - (static_cast(bytes[1]) << 8); - uint16_t y = static_cast(bytes[2]) | - (static_cast(bytes[3]) << 8); - - result[0] = *reinterpret_cast(&x); - result[1] = *reinterpret_cast(&y); - } - - if constexpr (std::is_same_v) { - assert(N == 2 && "Only vec2s can contain two-byte integer components."); - result[0] = static_cast(bytes[0]) | - (static_cast(bytes[1]) << 8); - result[1] = static_cast(bytes[2]) | - (static_cast(bytes[3]) << 8); - } - - if constexpr (std::is_same_v) { - for (size_t i = 0; i < bytes.size(); i++) { - result[i] = *reinterpret_cast(&bytes[i]); - } - } - - if constexpr (std::is_same_v) { - for (size_t i = 0; i < bytes.size(); i++) { - result[i] = bytes[i]; - } - } - - return result; - } - - template - PropertyArrayView - assembleArrayValue(const std::vector& bytes) const noexcept { - std::vector 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; - UintType resultAsUint = static_cast(bytes[b]) | - (static_cast(bytes[b + 1]) << 8); - result[i] = *reinterpret_cast(&resultAsUint); - } - } else { - for (size_t i = 0; i < bytes.size(); i++) { - result[i] = *reinterpret_cast(&bytes[i]); - } - } - - return PropertyArrayView(std::move(result)); - } - const Sampler* _pSampler; const ImageCesium* _pImage; int64_t _texCoordSetIndex; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 1a56fa2ec..5f2d4e98d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -42,9 +42,10 @@ enum class PropertyTextureViewStatus { /** * @brief A view on a {@link PropertyTexture}. * - * This should be used to get a {@link PropertyTexturePropertyView} of a property in the property texture. - * It will validate the EXT_structural_metadata format and ensure {@link PropertyTexturePropertyView} - * does not access out of bounds. + * This should be used to get a {@link PropertyTexturePropertyView} of a property + * in the property texture. It will validate the EXT_structural_metadata format + * and + * ensure {@link PropertyTexturePropertyView} does not access data out of bounds. */ class PropertyTextureView { public: @@ -82,14 +83,24 @@ class PropertyTextureView { * property stored in the {@link PropertyTexture}. * * 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, + * {@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 + * PropertyArrayView containing one of the scalar types. + * + * If T does not match the type specified by the class property, this returns + * an invalid PropertyTexturePropertyView. Likewise, if the value of + * Normalized + * does not match the value of {@ClassProperty::normalized} for that class property, + * this returns an invalid property view. Only types with integer components + * may be normalized. * + * @tparam T The C++ type corresponding to the type of the data retrieved. + * @tparam Normalized Whether the property is normalized. Only applicable to + * types with integer components. * @param propertyName The name of the property to retrieve data from - * @return A {@link PropertyTexturePropertyView} of the property. If no valid property is - * found, the property view will be invalid. + * @return A {@link PropertyTexturePropertyView} of the property. If no valid + * property is found, the property view will be invalid. */ template PropertyTexturePropertyView @@ -117,10 +128,11 @@ class PropertyTextureView { * {@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. + * PropertyArrayView containing one of the scalar types. + * + * If the property is somehow 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 @@ -152,7 +164,28 @@ class PropertyTextureView { componentType = convertStringToPropertyComponentType(*pClassProperty->componentType); } + bool normalized = pClassProperty->normalized; + if (normalized) { + switch (componentType) { + case PropertyComponentType::Int8: + case PropertyComponentType::Uint8: + case PropertyComponentType::Int16: + case PropertyComponentType::Uint16: + case PropertyComponentType::Int32: + case PropertyComponentType::Uint32: + case PropertyComponentType::Int64: + case PropertyComponentType::Uint64: + break; + default: + // Only integer components may be normalized. + callback( + propertyName, + PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization)); + return; + } + } if (pClassProperty->array) { if (normalized) { @@ -225,10 +258,11 @@ class PropertyTextureView { * {@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. + * 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 @@ -512,7 +546,7 @@ class PropertyTextureView { if (classProperty.normalized != Normalized) { return PropertyTexturePropertyView( - PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + PropertyTexturePropertyViewStatus::ErrorNormalizationMismatch); } // Only up to four bytes of image data are supported. @@ -552,7 +586,7 @@ class PropertyTextureView { if (classProperty.normalized != Normalized) { return PropertyTexturePropertyView( - PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + PropertyTexturePropertyViewStatus::ErrorNormalizationMismatch); } // Only up to four bytes of image data are supported. @@ -593,7 +627,7 @@ class PropertyTextureView { if (classProperty.normalized != Normalized) { return PropertyTexturePropertyView, Normalized>( - PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + PropertyTexturePropertyViewStatus::ErrorNormalizationMismatch); } // Only scalar arrays are supported. The scalar component type must not @@ -685,5 +719,5 @@ class PropertyTextureView { const Class* _pClass; PropertyTextureViewStatus _status; -}; // namespace CesiumGltf +}; } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 804992f64..8a283fa58 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -59,38 +59,43 @@ class PropertyViewStatus { */ static const PropertyViewStatusType ErrorInvalidNormalization = 5; + /** + * @brief This property view's normalization differs from what + * is specified in {@link ClassProperty::normalized} + */ + static const PropertyViewStatusType ErrorNormalizationMismatch = 6; + /** * @brief The property provided an invalid offset value. */ - static const PropertyViewStatusType ErrorInvalidOffset = 6; + static const PropertyViewStatusType ErrorInvalidOffset = 7; /** * @brief The property provided an invalid scale value. */ - static const PropertyViewStatusType ErrorInvalidScale = 7; + static const PropertyViewStatusType ErrorInvalidScale = 8; /** * @brief The property provided an invalid maximum value. */ - static const PropertyViewStatusType ErrorInvalidMax = 8; + static const PropertyViewStatusType ErrorInvalidMax = 9; /** * @brief The property provided an invalid minimum value. */ - static const PropertyViewStatusType ErrorInvalidMin = 9; + static const PropertyViewStatusType ErrorInvalidMin = 10; /** * @brief The property provided an invalid "no data" value. */ - static const PropertyViewStatusType ErrorInvalidNoDataValue = 10; + static const PropertyViewStatusType ErrorInvalidNoDataValue = 11; /** * @brief The property provided an invalid default value. */ - static const PropertyViewStatusType ErrorInvalidDefaultValue = 11; + static const PropertyViewStatusType ErrorInvalidDefaultValue = 12; }; -namespace { template PropertyViewStatusType validatePropertyType(const ClassProperty& classProperty) { @@ -228,7 +233,6 @@ int64_t getCount(std::optional>& buffer) { return static_cast(buffer->size() / sizeof(ElementType)); } -} // namespace /** * @brief Represents a metadata property in EXT_structural_metadata. diff --git a/CesiumGltf/src/FeatureIdTextureView.cpp b/CesiumGltf/src/FeatureIdTextureView.cpp index 22553e8d5..cf1ecb811 100644 --- a/CesiumGltf/src/FeatureIdTextureView.cpp +++ b/CesiumGltf/src/FeatureIdTextureView.cpp @@ -79,11 +79,11 @@ int64_t FeatureIdTextureView::getFeatureID(double u, double v) const noexcept { double yCoord = std::floor(v * this->_pImage->height); // Clamp to ensure no out-of-bounds data access - int64_t x = std::clamp( + int64_t x = glm::clamp( static_cast(xCoord), static_cast(0), static_cast(this->_pImage->width - 1)); - int64_t y = std::clamp( + int64_t y = glm::clamp( static_cast(yCoord), static_cast(0), static_cast(this->_pImage->height - 1)); diff --git a/CesiumGltf/src/PropertyTableView.cpp b/CesiumGltf/src/PropertyTableView.cpp index f2456cf77..3ba261999 100644 --- a/CesiumGltf/src/PropertyTableView.cpp +++ b/CesiumGltf/src/PropertyTableView.cpp @@ -360,7 +360,7 @@ PropertyTableView::getBooleanArrayPropertyValues( // Handle fixed-length arrays if (fixedLengthArrayCount > 0) { - size_t maxRequiredBytes = maxRequiredBytes = static_cast(glm::ceil( + size_t maxRequiredBytes = static_cast(glm::ceil( static_cast(_pPropertyTable->count * fixedLengthArrayCount) / 8.0)); diff --git a/CesiumGltf/src/PropertyTexturePropertyView.cpp b/CesiumGltf/src/PropertyTexturePropertyView.cpp new file mode 100644 index 000000000..f5bd80aed --- /dev/null +++ b/CesiumGltf/src/PropertyTexturePropertyView.cpp @@ -0,0 +1,23 @@ +#include "CesiumGltf/PropertyTexturePropertyView.h" + +using namespace CesiumGltf; + +// Re-initialize consts here to avoid "undefined reference" errors with GCC / +// Clang. +const PropertyViewStatusType + PropertyTexturePropertyViewStatus::ErrorInvalidPropertyTexture; +const PropertyViewStatusType + PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty; +const PropertyViewStatusType + PropertyTexturePropertyViewStatus::ErrorInvalidTexture; +const PropertyViewStatusType + PropertyTexturePropertyViewStatus::ErrorInvalidSampler; +const PropertyViewStatusType + PropertyTexturePropertyViewStatus::ErrorInvalidImage; +const PropertyViewStatusType PropertyTexturePropertyViewStatus::ErrorEmptyImage; +const PropertyViewStatusType + PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel; +const PropertyViewStatusType + PropertyTexturePropertyViewStatus::ErrorInvalidChannels; +const PropertyViewStatusType + PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch; diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index 3bb8ca0e8..378915c13 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -144,8 +144,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { for (int64_t i = 0; i < uint32Property.size(); ++i) { REQUIRE(uint32Property.getRaw(i) == values[static_cast(i)]); - REQUIRE(uint32Property.get(i)); - REQUIRE(*uint32Property.get(i) == uint32Property.getRaw(i)); + REQUIRE(uint32Property.get(i) == uint32Property.getRaw(i)); } } @@ -200,7 +199,7 @@ TEST_CASE("Test scalar PropertyTableProperty") { view.getPropertyView("TestClassProperty"); REQUIRE( uint32NormalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Wrong buffer index") { @@ -256,7 +255,6 @@ TEST_CASE("Test scalar PropertyTableProperty (normalized)") { std::vector values = {-128, 0, 32, 2340, -1234, 127}; addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = @@ -299,8 +297,7 @@ TEST_CASE("Test scalar PropertyTableProperty (normalized)") { for (int64_t i = 0; i < int16Property.size(); ++i) { auto value = int16Property.getRaw(i); REQUIRE(value == values[static_cast(i)]); - REQUIRE(int16Property.get(i)); - REQUIRE(*int16Property.get(i) == normalize(value)); + REQUIRE(int16Property.get(i) == normalize(value)); } } @@ -346,7 +343,7 @@ TEST_CASE("Test scalar PropertyTableProperty (normalized)") { view.getPropertyView("TestClassProperty"); REQUIRE( nonNormalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Access incorrectly as double") { @@ -356,52 +353,6 @@ TEST_CASE("Test scalar PropertyTableProperty (normalized)") { doubleInvalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } - - SECTION("Wrong buffer index") { - model.bufferViews[valueBufferViewIndex].buffer = 2; - PropertyTablePropertyView propertyView = - view.getPropertyView("TestClassProperty"); - REQUIRE( - propertyView.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); - } - - SECTION("Wrong buffer view index") { - propertyTableProperty.values = -1; - PropertyTablePropertyView propertyView = - view.getPropertyView("TestClassProperty"); - REQUIRE( - propertyView.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); - } - - SECTION("Buffer view points outside of the real buffer length") { - model.buffers[valueBufferIndex].cesium.data.resize(4); - PropertyTablePropertyView propertyView = - view.getPropertyView("TestClassProperty"); - REQUIRE( - propertyView.status() == - PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); - } - - SECTION("Buffer view length isn't multiple of sizeof(T)") { - model.bufferViews[valueBufferViewIndex].byteLength = 7; - PropertyTablePropertyView propertyView = - view.getPropertyView("TestClassProperty"); - REQUIRE( - propertyView.status() == PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Buffer view length doesn't match with propertyTableCount") { - model.bufferViews[valueBufferViewIndex].byteLength = 2; - PropertyTablePropertyView propertyView = - view.getPropertyView("TestClassProperty"); - REQUIRE( - propertyView.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } } TEST_CASE("Test vecN PropertyTableProperty") { @@ -525,7 +476,7 @@ TEST_CASE("Test vecN PropertyTableProperty") { view.getPropertyView("TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Wrong buffer index") { @@ -585,7 +536,6 @@ TEST_CASE("Test vecN PropertyTableProperty (normalized)") { glm::ivec3(-4, 8, -13)}; addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = @@ -628,8 +578,7 @@ TEST_CASE("Test vecN PropertyTableProperty (normalized)") { for (int64_t i = 0; i < ivec3Property.size(); ++i) { auto value = ivec3Property.getRaw(i); REQUIRE(value == values[static_cast(i)]); - REQUIRE(ivec3Property.get(i)); - REQUIRE(*ivec3Property.get(i) == normalize(value)); + REQUIRE(ivec3Property.get(i) == normalize(value)); } } @@ -681,7 +630,7 @@ TEST_CASE("Test vecN PropertyTableProperty (normalized)") { view.getPropertyView("TestClassProperty"); REQUIRE( nonNormalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Access incorrectly as dvec3") { @@ -691,53 +640,6 @@ TEST_CASE("Test vecN PropertyTableProperty (normalized)") { dvec3Invalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } - - SECTION("Wrong buffer index") { - model.bufferViews[valueBufferViewIndex].buffer = 2; - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); - } - - SECTION("Wrong buffer view index") { - propertyTableProperty.values = -1; - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); - } - - SECTION("Buffer view points outside of the real buffer length") { - model.buffers[valueBufferIndex].cesium.data.resize(12); - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Property.status() == - PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); - } - - SECTION("Buffer view length isn't multiple of sizeof(T)") { - model.bufferViews[valueBufferViewIndex].byteLength = 11; - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Property.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Buffer view length doesn't match with propertyTableCount") { - model.bufferViews[valueBufferViewIndex].byteLength = 12; - PropertyTablePropertyView ivec3Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - ivec3Property.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } } TEST_CASE("Test matN PropertyTableProperty") { @@ -801,8 +703,7 @@ TEST_CASE("Test matN PropertyTableProperty") { for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { REQUIRE(u32mat2x2Property.getRaw(i) == values[static_cast(i)]); - REQUIRE(u32mat2x2Property.get(i)); - REQUIRE(*u32mat2x2Property.get(i) == u32mat2x2Property.getRaw(i)); + REQUIRE(u32mat2x2Property.get(i) == u32mat2x2Property.getRaw(i)); } } @@ -868,13 +769,11 @@ TEST_CASE("Test matN PropertyTableProperty") { } SECTION("Access incorrectly as normalized") { - PropertyTablePropertyView, true> - normalizedInvalid = - view.getPropertyView, true>( - "TestClassProperty"); + PropertyTablePropertyView normalizedInvalid = + view.getPropertyView("TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorArrayTypeMismatch); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Wrong buffer index") { @@ -946,7 +845,6 @@ TEST_CASE("Test matN PropertyTableProperty (normalized)") { // clang-format on addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = @@ -990,8 +888,7 @@ TEST_CASE("Test matN PropertyTableProperty (normalized)") { for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { auto value = u32mat2x2Property.getRaw(i); REQUIRE(value == values[static_cast(i)]); - REQUIRE(u32mat2x2Property.get(i)); - REQUIRE(*u32mat2x2Property.get(i) == normalize(value)); + REQUIRE(u32mat2x2Property.get(i) == normalize(value)); } } @@ -1044,7 +941,7 @@ TEST_CASE("Test matN PropertyTableProperty (normalized)") { view.getPropertyView("TestClassProperty"); REQUIRE( nonNormalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Access incorrectly as dmat2") { @@ -1054,55 +951,6 @@ TEST_CASE("Test matN PropertyTableProperty (normalized)") { dmat2Invalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } - - SECTION("Wrong buffer index") { - model.bufferViews[valueBufferViewIndex].buffer = 2; - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); - } - - SECTION("Wrong buffer view index") { - propertyTableProperty.values = -1; - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); - } - - SECTION("Buffer view points outside of the real buffer length") { - model.buffers[valueBufferIndex].cesium.data.resize(sizeof(glm::u32mat2x2)); - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == - PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); - } - - SECTION("Buffer view length isn't multiple of sizeof(T)") { - model.bufferViews[valueBufferViewIndex].byteLength = - sizeof(glm::u32mat2x2) * 4 - 1; - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Buffer view length doesn't match with propertyTableCount") { - model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::u32mat2x2); - - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - } } TEST_CASE("Test boolean PropertyTableProperty") { @@ -1421,7 +1269,7 @@ TEST_CASE("Test fixed-length scalar array") { "TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Buffer size is not a multiple of type size") { @@ -1460,7 +1308,6 @@ TEST_CASE("Test fixed-length scalar array (normalized)") { {12, 34, 30, 11, 34, 34, 11, 33, 122, 33, 223, 11}; addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -1549,39 +1396,7 @@ TEST_CASE("Test fixed-length scalar array (normalized)") { "TestClassProperty"); REQUIRE( nonNormalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); - } - - SECTION("Buffer size is not a multiple of type size") { - model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView, true> arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Negative count") { - testClassProperty.count = -1; - PropertyTablePropertyView, true> arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == PropertyTablePropertyViewStatus:: - ErrorArrayCountAndOffsetBufferDontExist); - } - - SECTION("Value buffer doesn't fit into property table count") { - testClassProperty.count = 55; - PropertyTablePropertyView, true> arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } } @@ -1663,10 +1478,11 @@ TEST_CASE("Test variable-length scalar array") { for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView array = property.getRaw(static_cast(i)); + REQUIRE(array.size() == static_cast(expected[i].size())); + auto maybeArray = property.get(static_cast(i)); REQUIRE(maybeArray); REQUIRE(maybeArray->size() == array.size()); - REQUIRE(array.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { REQUIRE(expected[i][j] == array[static_cast(j)]); @@ -1678,9 +1494,12 @@ TEST_CASE("Test variable-length scalar array") { } SECTION("Incorrectly normalized") { - PropertyTablePropertyView> property = - view.getPropertyView>("TestClassProperty"); - REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); + PropertyTablePropertyView, true> property = + view.getPropertyView, true>( + "TestClassProperty"); + REQUIRE( + property.status() == + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Wrong offset type") { @@ -1783,11 +1602,9 @@ TEST_CASE("Test variable-length scalar array (normalized)") { } addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; size_t valueBufferViewIndex = model.bufferViews.size() - 1; addBufferToModel(model, offsets); - size_t offsetBufferIndex = model.buffers.size() - 1; size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = @@ -1834,10 +1651,11 @@ TEST_CASE("Test variable-length scalar array (normalized)") { for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView array = property.getRaw(static_cast(i)); + REQUIRE(array.size() == static_cast(expected[i].size())); + auto maybeArray = property.get(static_cast(i)); REQUIRE(maybeArray); REQUIRE(maybeArray->size() == array.size()); - REQUIRE(array.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { auto value = array[static_cast(j)]; @@ -1852,81 +1670,7 @@ TEST_CASE("Test variable-length scalar array (normalized)") { view.getPropertyView>("TestClassProperty"); REQUIRE( property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); - } - - SECTION("Wrong offset type") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView, true> arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - - propertyTableProperty.arrayOffsetType = ""; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT64; - arrayProperty = view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - } - - SECTION("Offset values are not sorted ascending") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = 0; - PropertyTablePropertyView, true> arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); - } - - SECTION("Offset value points outside of value buffer") { - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = - static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView, true> arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); - } - - SECTION("Count and offset buffer are both present") { - testClassProperty.count = 3; - PropertyTablePropertyView, true> property = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - property.status() == - PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } } @@ -2035,7 +1779,7 @@ TEST_CASE("Test fixed-length vecN array") { "TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Buffer size is not a multiple of type size") { @@ -2083,7 +1827,6 @@ TEST_CASE("Test fixed-length vecN array (normalized)") { }; addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2176,47 +1919,13 @@ TEST_CASE("Test fixed-length vecN array (normalized)") { } SECTION("Incorrect non-normalization") { - PropertyTablePropertyView> normalizedInvalid = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - normalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); - } - - SECTION("Buffer size is not a multiple of type size") { - model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Negative count") { - testClassProperty.count = -1; - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == PropertyTablePropertyViewStatus:: - ErrorArrayCountAndOffsetBufferDontExist); - } - - SECTION("Value buffer doesn't fit into property table count") { - testClassProperty.count = 55; - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( + PropertyTablePropertyView> + nonNormalizedInvalid = + view.getPropertyView>( "TestClassProperty"); REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + nonNormalizedInvalid.status() == + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } } @@ -2300,9 +2009,10 @@ TEST_CASE("Test variable-length vecN array") { for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView array = property.getRaw(static_cast(i)); + REQUIRE(array.size() == static_cast(expected[i].size())); + auto maybeArray = property.get(i); REQUIRE(maybeArray); - REQUIRE(array.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { auto value = array[static_cast(j)]; REQUIRE(expected[i][j] == value); @@ -2317,7 +2027,7 @@ TEST_CASE("Test variable-length vecN array") { "TestClassProperty"); REQUIRE( property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Wrong offset type") { @@ -2425,11 +2135,9 @@ TEST_CASE("Test variable-length vecN array (normalized)") { } addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; size_t valueBufferViewIndex = model.bufferViews.size() - 1; addBufferToModel(model, offsets); - size_t offsetBufferIndex = model.buffers.size() - 1; size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = @@ -2451,126 +2159,50 @@ TEST_CASE("Test variable-length vecN array (normalized)") { propertyTable.properties["TestClassProperty"]; propertyTableProperty.values = static_cast(valueBufferViewIndex); propertyTableProperty.arrayOffsets = - static_cast(offsetBufferViewIndex); - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - - PropertyTableView view(model, propertyTable); - REQUIRE(view.status() == PropertyTableViewStatus::Valid); - REQUIRE(view.size() == propertyTable.count); - - const ClassProperty* classProperty = - view.getClassProperty("TestClassProperty"); - REQUIRE(classProperty); - REQUIRE(classProperty->type == ClassProperty::Type::VEC3); - REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); - REQUIRE(classProperty->array); - REQUIRE(!classProperty->count); - REQUIRE(classProperty->normalized); - - SECTION("Access the correct type") { - PropertyTablePropertyView, true> property = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); - for (size_t i = 0; i < expected.size(); ++i) { - PropertyArrayView array = - property.getRaw(static_cast(i)); - auto maybeArray = property.get(i); - REQUIRE(maybeArray); - REQUIRE(array.size() == static_cast(expected[i].size())); - for (size_t j = 0; j < expected[i].size(); ++j) { - auto value = array[static_cast(j)]; - REQUIRE(expected[i][j] == value); - REQUIRE((*maybeArray)[j] == normalize(value)); - } - } - } - - SECTION("Incorrectly non-normalized") { - PropertyTablePropertyView> property = - view.getPropertyView>( - "TestClassProperty"); - REQUIRE( - property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); - } - - SECTION("Wrong offset type") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - - propertyTableProperty.arrayOffsetType = ""; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT64; - arrayProperty = view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - } + static_cast(offsetBufferViewIndex); + propertyTableProperty.arrayOffsetType = + PropertyTableProperty::ArrayOffsetType::UINT64; - SECTION("Offset values are not sorted ascending") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = 0; - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); - } + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); - SECTION("Offset value points outside of value buffer") { - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = - static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); - } + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC3); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT32); + REQUIRE(classProperty->array); + REQUIRE(!classProperty->count); + REQUIRE(classProperty->normalized); - SECTION("Count and offset buffer are both present") { - testClassProperty.count = 3; + SECTION("Access the correct type") { PropertyTablePropertyView, true> property = view.getPropertyView, true>( "TestClassProperty"); + REQUIRE(property.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { + PropertyArrayView array = + property.getRaw(static_cast(i)); + REQUIRE(array.size() == static_cast(expected[i].size())); + + auto maybeArray = property.get(i); + REQUIRE(maybeArray); + for (size_t j = 0; j < expected[i].size(); ++j) { + auto value = array[static_cast(j)]; + REQUIRE(expected[i][j] == value); + REQUIRE((*maybeArray)[j] == normalize(value)); + } + } + } + + SECTION("Incorrectly non-normalized") { + PropertyTablePropertyView> property = + view.getPropertyView>( + "TestClassProperty"); REQUIRE( property.status() == - PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } } @@ -2690,7 +2322,7 @@ TEST_CASE("Test fixed-length matN array") { "TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Buffer size is not a multiple of type size") { @@ -2752,7 +2384,6 @@ TEST_CASE("Test fixed-length matN array (normalized)") { // clang-format on addBufferToModel(model, values); - size_t valueBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = model.addExtension(); @@ -2850,42 +2481,7 @@ TEST_CASE("Test fixed-length matN array (normalized)") { "TestClassProperty"); REQUIRE( nonNormalizedInvalid.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); - } - - SECTION("Buffer size is not a multiple of type size") { - model.bufferViews[valueBufferViewIndex].byteLength = 13; - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeNotDivisibleByTypeSize); - } - - SECTION("Negative count") { - testClassProperty.count = -1; - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == PropertyTablePropertyViewStatus:: - ErrorArrayCountAndOffsetBufferDontExist); - } - - SECTION("Value buffer doesn't fit into property table count") { - testClassProperty.count = 55; - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } } @@ -2989,9 +2585,10 @@ TEST_CASE("Test variable-length matN array") { for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView array = property.getRaw(static_cast(i)); + REQUIRE(array.size() == static_cast(expected[i].size())); + auto maybeArray = property.get(i); REQUIRE(maybeArray); - REQUIRE(array.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { auto value = array[static_cast(j)]; REQUIRE(expected[i][j] == value); @@ -3007,7 +2604,7 @@ TEST_CASE("Test variable-length matN array") { "TestClassProperty"); REQUIRE( property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Wrong offset type") { @@ -3135,11 +2732,9 @@ TEST_CASE("Test variable-length matN array (normalized)") { } addBufferToModel(model, values); - size_t valueBufferIndex = model.buffers.size() - 1; size_t valueBufferViewIndex = model.bufferViews.size() - 1; addBufferToModel(model, offsets); - size_t offsetBufferIndex = model.buffers.size() - 1; size_t offsetBufferViewIndex = model.bufferViews.size() - 1; ExtensionModelExtStructuralMetadata& metadata = @@ -3204,88 +2799,7 @@ TEST_CASE("Test variable-length matN array (normalized)") { "TestClassProperty"); REQUIRE( property.status() == - PropertyTablePropertyViewStatus::ErrorInvalidNormalization); - } - - SECTION("Wrong offset type") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT8; - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT16; - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus:: - ErrorBufferViewSizeDoesNotMatchPropertyTableCount); - - propertyTableProperty.arrayOffsetType = "NONSENSE"; - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - - propertyTableProperty.arrayOffsetType = ""; - propertyTableProperty.stringOffsetType = - PropertyTableProperty::StringOffsetType::UINT64; - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorInvalidArrayOffsetType); - } - - SECTION("Offset values are not sorted ascending") { - propertyTableProperty.arrayOffsetType = - PropertyTableProperty::ArrayOffsetType::UINT64; - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = 0; - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetsNotSorted); - } - - SECTION("Offset value points outside of value buffer") { - uint64_t* offset = reinterpret_cast( - model.buffers[offsetBufferIndex].cesium.data.data()); - offset[propertyTable.count] = - static_cast(model.buffers[valueBufferIndex].byteLength + 4); - PropertyTablePropertyView, true> - arrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - arrayProperty.status() == - PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds); - } - - SECTION("Count and offset buffer are both present") { - testClassProperty.count = 3; - PropertyTablePropertyView, true> - property = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - property.status() == - PropertyTablePropertyViewStatus::ErrorArrayCountAndOffsetBufferCoexist); + PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); } } @@ -3488,9 +3002,10 @@ TEST_CASE("Test variable-length boolean array") { for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView array = boolArrayProperty.getRaw(static_cast(i)); + REQUIRE(array.size() == static_cast(expected[i].size())); + auto maybeArray = boolArrayProperty.get(i); REQUIRE(maybeArray); - REQUIRE(array.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { auto value = array[static_cast(j)]; REQUIRE(expected[i][j] == value); @@ -3826,6 +3341,7 @@ TEST_CASE("Test variable-length arrays of strings") { view.getPropertyView>( "TestClassProperty"); REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); + for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView stringArray = stringProperty.getRaw(static_cast(i)); @@ -4025,19 +3541,14 @@ TEST_CASE("Test with PropertyTableProperty offset, scale, min, max") { view.getPropertyView("TestClassProperty"); REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() > 0); - REQUIRE(propertyView.offset()); - REQUIRE(*propertyView.offset() == offset); - REQUIRE(propertyView.scale()); - REQUIRE(*propertyView.scale() == scale); - REQUIRE(propertyView.min()); - REQUIRE(*propertyView.min() == min); - REQUIRE(propertyView.max()); - REQUIRE(*propertyView.max() == max); + REQUIRE(propertyView.offset() == offset); + REQUIRE(propertyView.scale() == scale); + REQUIRE(propertyView.min() == min); + REQUIRE(propertyView.max() == max); for (int64_t i = 0; i < propertyView.size(); ++i) { REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); - REQUIRE(propertyView.get(i)); - REQUIRE(*propertyView.get(i) == propertyView.getRaw(i) * scale + offset); + REQUIRE(propertyView.get(i) == propertyView.getRaw(i) * scale + offset); } } @@ -4055,26 +3566,21 @@ TEST_CASE("Test with PropertyTableProperty offset, scale, min, max") { view.getPropertyView("TestClassProperty"); REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() > 0); - REQUIRE(propertyView.offset()); - REQUIRE(*propertyView.offset() == newOffset); - REQUIRE(propertyView.scale()); - REQUIRE(*propertyView.scale() == newScale); - REQUIRE(propertyView.min()); - REQUIRE(*propertyView.min() == newMin); - REQUIRE(propertyView.max()); - REQUIRE(*propertyView.max() == newMax); + REQUIRE(propertyView.offset() == newOffset); + REQUIRE(propertyView.scale() == newScale); + REQUIRE(propertyView.min() == newMin); + REQUIRE(propertyView.max() == newMax); for (int64_t i = 0; i < propertyView.size(); ++i) { REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); - REQUIRE(propertyView.get(i)); REQUIRE( - *propertyView.get(i) == - propertyView.getRaw(i) * newScale + newOffset); + propertyView.get(i) == propertyView.getRaw(i) * newScale + newOffset); } } } -TEST_CASE("Test with PropertyTableProperty offset, scale, min, max (normalized)") { +TEST_CASE( + "Test with PropertyTableProperty offset, scale, min, max (normalized)") { Model model; std::vector values = {-128, 0, 32, 127}; const double offset = 0.5; @@ -4129,20 +3635,15 @@ TEST_CASE("Test with PropertyTableProperty offset, scale, min, max (normalized)" view.getPropertyView("TestClassProperty"); REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() > 0); - REQUIRE(propertyView.offset()); - REQUIRE(*propertyView.offset() == offset); - REQUIRE(propertyView.scale()); - REQUIRE(*propertyView.scale() == scale); - REQUIRE(propertyView.min()); - REQUIRE(*propertyView.min() == min); - REQUIRE(propertyView.max()); - REQUIRE(*propertyView.max() == max); + REQUIRE(propertyView.offset() == offset); + REQUIRE(propertyView.scale() == scale); + REQUIRE(propertyView.min() == min); + REQUIRE(propertyView.max() == max); for (int64_t i = 0; i < propertyView.size(); ++i) { REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); - REQUIRE(propertyView.get(i)); REQUIRE( - *propertyView.get(i) == + propertyView.get(i) == normalize(propertyView.getRaw(i)) * scale + offset); } } @@ -4161,20 +3662,15 @@ TEST_CASE("Test with PropertyTableProperty offset, scale, min, max (normalized)" view.getPropertyView("TestClassProperty"); REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() > 0); - REQUIRE(propertyView.offset()); - REQUIRE(*propertyView.offset() == newOffset); - REQUIRE(propertyView.scale()); - REQUIRE(*propertyView.scale() == newScale); - REQUIRE(propertyView.min()); - REQUIRE(*propertyView.min() == newMin); - REQUIRE(propertyView.max()); - REQUIRE(*propertyView.max() == newMax); + REQUIRE(propertyView.offset() == newOffset); + REQUIRE(propertyView.scale() == newScale); + REQUIRE(propertyView.min() == newMin); + REQUIRE(propertyView.max() == newMax); for (int64_t i = 0; i < propertyView.size(); ++i) { REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); - REQUIRE(propertyView.get(i)); REQUIRE( - *propertyView.get(i) == + propertyView.get(i) == normalize(propertyView.getRaw(i)) * newScale + newOffset); } } @@ -4225,16 +3721,14 @@ TEST_CASE("Test with PropertyTableProperty noData value") { view.getPropertyView("TestClassProperty"); REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() > 0); - REQUIRE(propertyView.noData()); - REQUIRE(*propertyView.noData() == noData); + REQUIRE(propertyView.noData() == noData); for (int64_t i = 0; i < propertyView.size(); ++i) { REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); if (propertyView.getRaw(i) == noData) { REQUIRE(!propertyView.get(i)); } else { - REQUIRE(propertyView.get(i)); - REQUIRE(*propertyView.get(i) == propertyView.getRaw(i)); + REQUIRE(propertyView.get(i) == propertyView.getRaw(i)); } } } @@ -4248,18 +3742,15 @@ TEST_CASE("Test with PropertyTableProperty noData value") { view.getPropertyView("TestClassProperty"); REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() > 0); - REQUIRE(propertyView.noData()); - REQUIRE(*propertyView.noData() == noData); - REQUIRE(propertyView.defaultValue()); - REQUIRE(*propertyView.defaultValue() == defaultValue); + REQUIRE(propertyView.noData() == noData); + REQUIRE(propertyView.defaultValue() == defaultValue); for (int64_t i = 0; i < propertyView.size(); ++i) { REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); - REQUIRE(propertyView.get(i)); if (propertyView.getRaw(i) == noData) { - REQUIRE(*propertyView.get(i) == defaultValue); + REQUIRE(propertyView.get(i) == defaultValue); } else { - REQUIRE(*propertyView.get(i) == propertyView.getRaw(i)); + REQUIRE(propertyView.get(i) == propertyView.getRaw(i)); } } } @@ -4311,16 +3802,14 @@ TEST_CASE("Test with PropertyTableProperty noData value (normalized)") { view.getPropertyView("TestClassProperty"); REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() > 0); - REQUIRE(propertyView.noData()); - REQUIRE(*propertyView.noData() == noData); + REQUIRE(propertyView.noData() == noData); for (int64_t i = 0; i < propertyView.size(); ++i) { REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); if (propertyView.getRaw(i) == noData) { REQUIRE(!propertyView.get(i)); } else { - REQUIRE(propertyView.get(i)); - REQUIRE(*propertyView.get(i) == normalize(propertyView.getRaw(i))); + REQUIRE(propertyView.get(i) == normalize(propertyView.getRaw(i))); } } } @@ -4335,18 +3824,15 @@ TEST_CASE("Test with PropertyTableProperty noData value (normalized)") { view.getPropertyView("TestClassProperty"); REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); REQUIRE(propertyView.size() > 0); - REQUIRE(propertyView.noData()); - REQUIRE(*propertyView.noData() == noData); - REQUIRE(propertyView.defaultValue()); - REQUIRE(*propertyView.defaultValue() == defaultValue); + REQUIRE(propertyView.noData() == noData); + REQUIRE(propertyView.defaultValue() == defaultValue); for (int64_t i = 0; i < propertyView.size(); ++i) { REQUIRE(propertyView.getRaw(i) == values[static_cast(i)]); - REQUIRE(propertyView.get(i)); if (propertyView.getRaw(i) == noData) { - REQUIRE(*propertyView.get(i) == defaultValue); + REQUIRE(propertyView.get(i) == defaultValue); } else { - REQUIRE(*propertyView.get(i) == normalize(propertyView.getRaw(i))); + REQUIRE(propertyView.get(i) == normalize(propertyView.getRaw(i))); } } } @@ -4435,6 +3921,56 @@ TEST_CASE("Test callback for invalid PropertyTableProperty") { REQUIRE(invokedCallbackCount == 2); } +TEST_CASE("Test callback for invalid normalized PropertyTableProperty") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::FLOAT32; + testClassProperty.normalized = true; // This is erroneous. + + PropertyTable& propertyTable = metadata.propertyTables.emplace_back(); + propertyTable.classProperty = "TestClass"; + propertyTable.count = static_cast(5); + + PropertyTableProperty& propertyTableProperty = + propertyTable.properties["TestClassProperty"]; + propertyTableProperty.values = 0; + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE( + classProperty->componentType == ClassProperty::ComponentType::FLOAT32); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + "TestClassProperty", + [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == + PropertyTablePropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(propertyValue.size() == 0); + }); + + REQUIRE(invokedCallbackCount == 1); +} + TEST_CASE("Test callback for scalar PropertyTableProperty") { Model model; std::vector values = {12, 34, 30, 11, 34, 34, 11, 33, 122, 33}; @@ -4491,10 +4027,7 @@ TEST_CASE("Test callback for scalar PropertyTableProperty") { REQUIRE( static_cast(propertyValue.getRaw(i)) == expectedValue); - - auto maybeValue = propertyValue.get(i); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expectedValue); + REQUIRE(propertyValue.get(i) == expectedValue); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -4562,10 +4095,7 @@ TEST_CASE("Test callback for scalar PropertyTableProperty (normalized)") { REQUIRE( static_cast(propertyValue.getRaw(i)) == expectedValue); - - auto maybeValue = propertyValue.get(i); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == normalize(expectedValue)); + REQUIRE(propertyValue.get(i) == normalize(expectedValue)); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -4636,10 +4166,7 @@ TEST_CASE("Test callback for vecN PropertyTableProperty") { REQUIRE( static_cast(propertyValue.getRaw(i)) == expectedValue); - - auto maybeValue = propertyValue.get(i); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expectedValue); + REQUIRE(propertyValue.get(i) == expectedValue); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -4711,10 +4238,7 @@ TEST_CASE("Test callback for vecN PropertyTableProperty (normalized)") { REQUIRE( static_cast(propertyValue.getRaw(i)) == expectedValue); - - auto maybeValue = propertyValue.get(i); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == normalize(expectedValue)); + REQUIRE(propertyValue.get(i) == normalize(expectedValue)); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -4794,10 +4318,7 @@ TEST_CASE("Test callback for matN PropertyTableProperty") { REQUIRE( static_cast(propertyValue.getRaw(i)) == expectedValue); - - auto maybeValue = propertyValue.get(i); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expectedValue); + REQUIRE(propertyValue.get(i) == expectedValue); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -4879,10 +4400,7 @@ TEST_CASE("Test callback for matN PropertyTableProperty (normalized)") { REQUIRE( static_cast(propertyValue.getRaw(i)) == expectedValue); - - auto maybeValue = propertyValue.get(i); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == normalize(expectedValue)); + REQUIRE(propertyValue.get(i) == normalize(expectedValue)); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -4965,10 +4483,7 @@ TEST_CASE("Test callback for boolean PropertyTableProperty") { auto expectedValue = expected[static_cast(i)]; REQUIRE( static_cast(propertyValue.getRaw(i)) == expectedValue); - - auto maybeValue = propertyValue.get(i); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expectedValue); + REQUIRE(propertyValue.get(i) == expectedValue); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " @@ -5059,10 +4574,7 @@ TEST_CASE("Test callback for string PropertyTableProperty") { REQUIRE( static_cast(propertyValue.getRaw(i)) == expectedValue); - - auto maybeValue = propertyValue.get(i); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expectedValue); + REQUIRE(propertyValue.get(i) == expectedValue); } } else { FAIL("getPropertyView returned PropertyTablePropertyView of " diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index af6e61e13..626dd3891 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -3,10 +3,7 @@ #include #include -#include -#include #include -#include #include using namespace CesiumGltf; @@ -174,12 +171,8 @@ TEST_CASE("Test scalar PropertyTextureProperty") { for (size_t i = 0; i < texCoords.size(); ++i) { glm::dvec2 uv = texCoords[i]; - auto value = uint8Property.getRaw(uv[0], uv[1]); - REQUIRE(value == data[i]); - - auto maybeValue = uint8Property.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == data[i]); + REQUIRE(uint8Property.getRaw(uv[0], uv[1]) == data[i]); + REQUIRE(uint8Property.get(uv[0], uv[1]) == data[i]); } } @@ -224,7 +217,7 @@ TEST_CASE("Test scalar PropertyTextureProperty") { view.getPropertyView("TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + PropertyTexturePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Channel and type mismatch") { @@ -360,12 +353,8 @@ TEST_CASE("Test scalar PropertyTextureProperty (normalized)") { for (size_t i = 0; i < texCoords.size(); ++i) { glm::dvec2 uv = texCoords[i]; - auto value = uint8Property.getRaw(uv[0], uv[1]); - REQUIRE(value == data[i]); - - auto maybeValue = uint8Property.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == normalize(data[i])); + REQUIRE(uint8Property.getRaw(uv[0], uv[1]) == data[i]); + REQUIRE(uint8Property.get(uv[0], uv[1]) == normalize(data[i])); } } @@ -405,7 +394,7 @@ TEST_CASE("Test scalar PropertyTextureProperty (normalized)") { view.getPropertyView("TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + PropertyTexturePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Access incorrectly as double") { @@ -425,69 +414,6 @@ TEST_CASE("Test scalar PropertyTextureProperty (normalized)") { uint8Property.status() == PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch); } - - SECTION("Invalid channel values") { - propertyTextureProperty.channels = {5}; - PropertyTexturePropertyView uint8Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint8Property.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidChannels); - } - - SECTION("Zero channel values") { - propertyTextureProperty.channels.clear(); - PropertyTexturePropertyView uint8Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint8Property.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidChannels); - } - - SECTION("Invalid bytes per channel") { - model.images[imageIndex].cesium.bytesPerChannel = 2; - PropertyTexturePropertyView uint8Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint8Property.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); - } - - SECTION("Empty image") { - model.images[imageIndex].cesium.width = 0; - PropertyTexturePropertyView uint8Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint8Property.status() == - PropertyTexturePropertyViewStatus::ErrorEmptyImage); - } - - SECTION("Wrong image index") { - model.textures[textureIndex].source = 1; - PropertyTexturePropertyView uint8Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint8Property.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidImage); - } - - SECTION("Wrong sampler index") { - model.textures[textureIndex].sampler = 1; - PropertyTexturePropertyView uint8Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint8Property.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidSampler); - } - - SECTION("Wrong texture index") { - propertyTextureProperty.index = 1; - PropertyTexturePropertyView uint8Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - uint8Property.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidTexture); - } } TEST_CASE("Test vecN PropertyTextureProperty") { @@ -554,12 +480,8 @@ TEST_CASE("Test vecN PropertyTextureProperty") { glm::u8vec2(30, 11)}; for (size_t i = 0; i < texCoords.size(); ++i) { glm::dvec2 uv = texCoords[i]; - auto value = u8vec2Property.getRaw(uv[0], uv[1]); - REQUIRE(value == expected[i]); - - auto maybeValue = u8vec2Property.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expected[i]); + REQUIRE(u8vec2Property.getRaw(uv[0], uv[1]) == expected[i]); + REQUIRE(u8vec2Property.get(uv[0], uv[1]) == expected[i]); } } @@ -605,7 +527,7 @@ TEST_CASE("Test vecN PropertyTextureProperty") { view.getPropertyView("TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + PropertyTexturePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Channel and type mismatch") { @@ -702,12 +624,8 @@ TEST_CASE("Test vecN PropertyTextureProperty (normalized)") { glm::u8vec2(30, 11)}; for (size_t i = 0; i < texCoords.size(); ++i) { glm::dvec2 uv = texCoords[i]; - auto value = u8vec2Property.getRaw(uv[0], uv[1]); - REQUIRE(value == expected[i]); - - auto maybeValue = u8vec2Property.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == normalize(expected[i])); + REQUIRE(u8vec2Property.getRaw(uv[0], uv[1]) == expected[i]); + REQUIRE(u8vec2Property.get(uv[0], uv[1]) == normalize(expected[i])); } } @@ -754,7 +672,7 @@ TEST_CASE("Test vecN PropertyTextureProperty (normalized)") { view.getPropertyView("TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + PropertyTexturePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Access incorrectly as dvec2") { @@ -774,24 +692,6 @@ TEST_CASE("Test vecN PropertyTextureProperty (normalized)") { u8vec2Property.status() == PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch); } - - SECTION("Invalid channel values") { - propertyTextureProperty.channels = {0, 4}; - PropertyTexturePropertyView u8vec2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u8vec2Property.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidChannels); - } - - SECTION("Invalid bytes per channel") { - model.images[imageIndex].cesium.bytesPerChannel = 2; - PropertyTexturePropertyView u8vec2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u8vec2Property.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); - } } TEST_CASE("Test array PropertyTextureProperty") { @@ -919,7 +819,7 @@ TEST_CASE("Test array PropertyTextureProperty") { "TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + PropertyTexturePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Channel and type mismatch") { @@ -1080,7 +980,7 @@ TEST_CASE("Test array PropertyTextureProperty (normalized)") { view.getPropertyView>("TestClassProperty"); REQUIRE( normalizedInvalid.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + PropertyTexturePropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Channel and type mismatch") { @@ -1094,28 +994,6 @@ TEST_CASE("Test array PropertyTextureProperty (normalized)") { uint8ArrayProperty.status() == PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch); } - - SECTION("Invalid channel values") { - propertyTextureProperty.channels = {0, 4, 1}; - PropertyTexturePropertyView, true> - uint8ArrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - uint8ArrayProperty.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidChannels); - } - - SECTION("Invalid bytes per channel") { - model.images[imageIndex].cesium.bytesPerChannel = 2; - PropertyTexturePropertyView, true> - uint8ArrayProperty = - view.getPropertyView, true>( - "TestClassProperty"); - REQUIRE( - uint8ArrayProperty.status() == - PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel); - } } TEST_CASE("Test with PropertyTextureProperty offset, scale, min, max") { @@ -1194,17 +1072,13 @@ TEST_CASE("Test with PropertyTextureProperty offset, scale, min, max") { PropertyTexturePropertyView property = view.getPropertyView("TestClassProperty"); REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); - REQUIRE(property.offset()); - REQUIRE(*property.offset() == offset); - REQUIRE(property.scale()); - REQUIRE(*property.scale() == scale); - REQUIRE(property.min()); - REQUIRE(*property.min() == min); - REQUIRE(property.max()); - REQUIRE(*property.max() == max); + REQUIRE(property.offset() == offset); + REQUIRE(property.scale() == scale); + REQUIRE(property.min() == min); + REQUIRE(property.max() == max); std::vector expectedRaw(expectedUint.size()); - std::vector> expectedTransformed(expectedUint.size()); + std::vector expectedTransformed(expectedUint.size()); for (size_t i = 0; i < expectedUint.size(); i++) { float value = *reinterpret_cast(&expectedUint[i]); expectedRaw[i] = value; @@ -1213,11 +1087,8 @@ TEST_CASE("Test with PropertyTextureProperty offset, scale, min, max") { for (size_t i = 0; i < texCoords.size(); ++i) { glm::dvec2 uv = texCoords[i]; - auto value = property.getRaw(uv[0], uv[1]); - REQUIRE(value == expectedRaw[i]); - - auto maybeValue = property.get(uv[0], uv[1]); - REQUIRE(maybeValue == expectedTransformed[i]); + REQUIRE(property.getRaw(uv[0], uv[1]) == expectedRaw[i]); + REQUIRE(property.get(uv[0], uv[1]) == expectedTransformed[i]); } } @@ -1234,17 +1105,13 @@ TEST_CASE("Test with PropertyTextureProperty offset, scale, min, max") { PropertyTexturePropertyView property = view.getPropertyView("TestClassProperty"); REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); - REQUIRE(property.offset()); - REQUIRE(*property.offset() == newOffset); - REQUIRE(property.scale()); - REQUIRE(*property.scale() == newScale); - REQUIRE(property.min()); - REQUIRE(*property.min() == newMin); - REQUIRE(property.max()); - REQUIRE(*property.max() == newMax); + REQUIRE(property.offset() == newOffset); + REQUIRE(property.scale() == newScale); + REQUIRE(property.min() == newMin); + REQUIRE(property.max() == newMax); std::vector expectedRaw(expectedUint.size()); - std::vector> expectedTransformed(expectedUint.size()); + std::vector expectedTransformed(expectedUint.size()); for (size_t i = 0; i < expectedUint.size(); i++) { float value = *reinterpret_cast(&expectedUint[i]); expectedRaw[i] = value; @@ -1253,11 +1120,8 @@ TEST_CASE("Test with PropertyTextureProperty offset, scale, min, max") { for (size_t i = 0; i < texCoords.size(); ++i) { glm::dvec2 uv = texCoords[i]; - auto value = property.getRaw(uv[0], uv[1]); - REQUIRE(value == expectedRaw[i]); - - auto maybeValue = property.get(uv[0], uv[1]); - REQUIRE(maybeValue == expectedTransformed[i]); + REQUIRE(property.getRaw(uv[0], uv[1]) == expectedRaw[i]); + REQUIRE(property.get(uv[0], uv[1]) == expectedTransformed[i]); } } } @@ -1327,23 +1191,16 @@ TEST_CASE( PropertyTexturePropertyView property = view.getPropertyView("TestClassProperty"); REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); - REQUIRE(property.offset()); - REQUIRE(*property.offset() == offset); - REQUIRE(property.scale()); - REQUIRE(*property.scale() == scale); - REQUIRE(property.min()); - REQUIRE(*property.min() == min); - REQUIRE(property.max()); - REQUIRE(*property.max() == max); + REQUIRE(property.offset() == offset); + REQUIRE(property.scale() == scale); + REQUIRE(property.min() == min); + REQUIRE(property.max() == max); for (size_t i = 0; i < texCoords.size(); ++i) { glm::dvec2 uv = texCoords[i]; - auto value = property.getRaw(uv[0], uv[1]); - REQUIRE(value == data[i]); - - auto maybeValue = property.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == normalize(data[i]) * scale + offset); + REQUIRE(property.getRaw(uv[0], uv[1]) == data[i]); + REQUIRE( + property.get(uv[0], uv[1]) == normalize(data[i]) * scale + offset); } } @@ -1360,23 +1217,17 @@ TEST_CASE( PropertyTexturePropertyView property = view.getPropertyView("TestClassProperty"); REQUIRE(property.status() == PropertyTexturePropertyViewStatus::Valid); - REQUIRE(property.offset()); - REQUIRE(*property.offset() == newOffset); - REQUIRE(property.scale()); - REQUIRE(*property.scale() == newScale); - REQUIRE(property.min()); - REQUIRE(*property.min() == newMin); - REQUIRE(property.max()); - REQUIRE(*property.max() == newMax); + REQUIRE(property.offset() == newOffset); + REQUIRE(property.scale() == newScale); + REQUIRE(property.min() == newMin); + REQUIRE(property.max() == newMax); for (size_t i = 0; i < texCoords.size(); ++i) { glm::dvec2 uv = texCoords[i]; - auto value = property.getRaw(uv[0], uv[1]); - REQUIRE(value == data[i]); - - auto maybeValue = property.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == normalize(data[i]) * newScale + newOffset); + REQUIRE(property.getRaw(uv[0], uv[1]) == data[i]); + REQUIRE( + property.get(uv[0], uv[1]) == + normalize(data[i]) * newScale + newOffset); } } } @@ -1447,8 +1298,7 @@ TEST_CASE("Test with PropertyTextureProperty noData") { if (value == noData) { REQUIRE(!maybeValue); } else { - REQUIRE(maybeValue); - REQUIRE(*maybeValue == data[i]); + REQUIRE(maybeValue == data[i]); } } } @@ -1467,11 +1317,10 @@ TEST_CASE("Test with PropertyTextureProperty noData") { REQUIRE(value == data[i]); auto maybeValue = property.get(uv[0], uv[1]); - REQUIRE(maybeValue); if (value == noData) { - REQUIRE(*maybeValue == defaultValue); + REQUIRE(maybeValue == defaultValue); } else { - REQUIRE(*maybeValue == data[i]); + REQUIRE(maybeValue == data[i]); } } } @@ -1544,8 +1393,7 @@ TEST_CASE("Test with PropertyTextureProperty noData (normalized)") { if (value == noData) { REQUIRE(!maybeValue); } else { - REQUIRE(maybeValue); - REQUIRE(*maybeValue == normalize(data[i])); + REQUIRE(maybeValue == normalize(data[i])); } } } @@ -1564,11 +1412,10 @@ TEST_CASE("Test with PropertyTextureProperty noData (normalized)") { REQUIRE(value == data[i]); auto maybeValue = property.get(uv[0], uv[1]); - REQUIRE(maybeValue); if (value == noData) { - REQUIRE(*maybeValue == defaultValue); + REQUIRE(maybeValue == defaultValue); } else { - REQUIRE(*maybeValue == normalize(data[i])); + REQUIRE(maybeValue == normalize(data[i])); } } } @@ -1651,6 +1498,49 @@ TEST_CASE("Test callback on invalid PropertyTextureProperty") { REQUIRE(invokedCallbackCount == 2); } +TEST_CASE("Test callback on invalid normalized PropertyTextureProperty") { + Model model; + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::FLOAT32; + testClassProperty.normalized = true; // This is erroneous. + + PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back(); + propertyTexture.classProperty = "TestClass"; + + PropertyTextureProperty& propertyTextureProperty = + propertyTexture.properties["TestClassProperty"]; + propertyTextureProperty.index = static_cast(0); + propertyTextureProperty.texCoord = 0; + propertyTextureProperty.channels = {0, 1}; + + PropertyTextureView view(model, propertyTexture); + REQUIRE(view.status() == PropertyTextureViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + + uint32_t invokedCallbackCount = 0; + auto testCallback = [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization); + }; + + view.getPropertyView("TestClassProperty", testCallback); + + REQUIRE(invokedCallbackCount == 1); +} + TEST_CASE("Test callback for scalar PropertyTextureProperty") { Model model; std::vector data = {255, 255, 12, 1, 30, 2, 0, 255}; @@ -1718,12 +1608,8 @@ TEST_CASE("Test callback for scalar PropertyTextureProperty") { for (size_t i = 0; i < expected.size(); ++i) { glm::dvec2& uv = texCoords[i]; - auto value = propertyValue.getRaw(uv[0], uv[1]); - REQUIRE(value == expected[i]); - - auto maybeValue = propertyValue.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expected[i]); + REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); + REQUIRE(propertyValue.get(uv[0], uv[1]) == expected[i]); } } else { FAIL("getPropertyView returned PropertyTexturePropertyView of " @@ -1802,12 +1688,8 @@ TEST_CASE("Test callback for scalar PropertyTextureProperty (normalized)") { for (size_t i = 0; i < expected.size(); ++i) { glm::dvec2& uv = texCoords[i]; - auto value = propertyValue.getRaw(uv[0], uv[1]); - REQUIRE(value == expected[i]); - - auto maybeValue = propertyValue.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == normalize(expected[i])); + REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); + REQUIRE(propertyValue.get(uv[0], uv[1]) == normalize(expected[i])); } } else { FAIL("getPropertyView returned PropertyTexturePropertyView of " @@ -1896,12 +1778,8 @@ TEST_CASE("Test callback for vecN PropertyTextureProperty") { for (size_t i = 0; i < expected.size(); ++i) { glm::dvec2& uv = texCoords[i]; - auto value = propertyValue.getRaw(uv[0], uv[1]); - REQUIRE(value == expected[i]); - - auto maybeValue = propertyValue.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expected[i]); + REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); + REQUIRE(propertyValue.get(uv[0], uv[1]) == expected[i]); } } else { FAIL("getPropertyView returned PropertyTexturePropertyView of " @@ -1991,12 +1869,8 @@ TEST_CASE("Test callback for vecN PropertyTextureProperty (normalized)") { for (size_t i = 0; i < expected.size(); ++i) { glm::dvec2& uv = texCoords[i]; - auto value = propertyValue.getRaw(uv[0], uv[1]); - REQUIRE(value == expected[i]); - - auto maybeValue = propertyValue.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == normalize(expected[i])); + REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); + REQUIRE(propertyValue.get(uv[0], uv[1]) == normalize(expected[i])); } } else { FAIL("getPropertyView returned PropertyTexturePropertyView of " From 2c97ce24bad5af49a56f5167720afb06d4091cd5 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 25 Aug 2023 17:15:26 -0400 Subject: [PATCH 096/121] Second unit test / cleanup sweep --- CHANGES.md | 10 +- .../CesiumGltf/PropertyTexturePropertyView.h | 12 +- .../include/CesiumGltf/PropertyTextureView.h | 9 +- .../test/TestPropertyTablePropertyView.cpp | 379 +++++++++--------- .../test/TestPropertyTexturePropertyView.cpp | 89 ++-- 5 files changed, 240 insertions(+), 259 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index e21ada456..e4b438c46 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,20 +10,22 @@ - 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`. - Replaced `MetadataPropertyView` with `PropertyTablePropertyView`, which is a view of a `PropertyTableProperty` in `EXT_structural_metadata`. This takes two template parameters: a typename `T` , and a `bool` indicating whether or not the values are normalized. -- Renamed `MetadataArrayView` to `PropertyArrayView`. +- Replaced `MetadataPropertyViewStatus` with `PropertyTablePropertyViewStatus`. `PropertyTablePropertyViewStatus` is a class that inherits from `PropertyViewStatus`, defining additional error codes in the form of `static const` values. - Replaced `FeatureTextureView` with `PropertyTextureView`, which views a `PropertyTexture` in `EXT_structural_metadata`. -- Renamed `FeatureTextureViewStatus` to `PropertyTextureViewStatus`. - Replaced `FeatureTexturePropertyView` with `PropertyTexturePropertyView`, which is a view of a `PropertyTextureProperty` in `EXT_structural_metadata`. This takes two template parameters: a typename `T` , and a `bool` indicating whether or not the values are normalized. - Removed `FeatureTexturePropertyComponentType`, `FeatureTexturePropertyChannelOffsets`, and `FeatureTexturePropertyValue`. `PropertyTextureProperty` retrieves the values with the type indicated by its class property. -- Renamed `FeatureTexturePropertyViewStatus` to `PropertyTexturePropertyViewStatus`. +- Replaced `FeatureTexturePropertyViewStatus` with `PropertyTexturePropertyViewStatus`. `PropertyTexturePropertyViewStatus` is a class that inherits from `PropertyViewStatus`, defining additional error codes in the form of `static const` values. +- Renamed `FeatureIDTextureViewStatus` to `FeatureIdTextureViewStatus` for consistency. +- Renamed `MetadataArrayView` to `PropertyArrayView`. +- Renamed `FeatureTextureViewStatus` to `PropertyTextureViewStatus`. - Refactored `PropertyType` to reflect the values of `type` in a `ClassProperty` from `EXT_structural_metadata`. ##### Additions :tada: - Added `PropertyView`, which acts as a base class for all metadata property views. This takes two template parameters: a type `T` , and a `bool` indicating whether or not the values are normalized. +- Added `PropertyViewStatus`, which defines public `static const` values for various property errors. - Added `PropertyTableViewStatus` to indicate whether a `PropertyTableView` is valid. - Added `PropertyComponentType` to reflect the values of `componentType` in a `ClassProperty` from `EXT_structural_metadata`. diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 6b191caff..8d4933068 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -131,7 +131,7 @@ ElementType assembleVecNValue(const std::vector& bytes) noexcept { const glm::length_t N = getDimensionsFromPropertyType(TypeToPropertyType::value); - using typename T = ElementType::value_type; + using T = typename ElementType::value_type; assert( sizeof(T) <= 2 && "Components cannot be larger than two bytes in size."); @@ -278,7 +278,7 @@ class PropertyTexturePropertyView _channels(), _swizzle() { assert( - _status != PropertyTexturePropertyViewStatus::Valid && + this->_status != PropertyTexturePropertyViewStatus::Valid && "An empty property view should not be constructed with a valid status"); } @@ -380,7 +380,7 @@ class PropertyTexturePropertyView ElementType getRaw(double u, double v) const noexcept { assert( - _status == PropertyTexturePropertyViewStatus::Valid && + this->_status == PropertyTexturePropertyViewStatus::Valid && "Check the status() first to make sure view is valid"); double wrappedU = applySamplerWrapS(u, this->_pSampler->wrapS); @@ -498,7 +498,7 @@ class PropertyTexturePropertyView _channels(), _swizzle() { assert( - _status != PropertyTexturePropertyViewStatus::Valid && + this->_status != PropertyTexturePropertyViewStatus::Valid && "An empty property view should not be constructed with a valid status"); } @@ -569,7 +569,7 @@ class PropertyTexturePropertyView std::optional get(double u, double v) const noexcept { ElementType value = getRaw(u, v); - if (this->noData() && value == *(this->noData())) { + if (value == this->noData()) { return this->defaultValue(); } @@ -626,7 +626,7 @@ class PropertyTexturePropertyView ElementType getRaw(double u, double v) const noexcept { assert( - _status == PropertyTexturePropertyViewStatus::Valid && + this->_status == PropertyTexturePropertyViewStatus::Valid && "Check the status() first to make sure view is valid"); double wrappedU = applySamplerWrapS(u, this->_pSampler->wrapS); diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 5f2d4e98d..8b13e84b2 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -524,7 +524,8 @@ class PropertyTextureView { template PropertyTexturePropertyView createScalarPropertyView( const ClassProperty& classProperty, - const PropertyTextureProperty& propertyTextureProperty) const { + [[maybe_unused]] const PropertyTextureProperty& propertyTextureProperty) + const { if (classProperty.array) { return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); @@ -564,7 +565,8 @@ class PropertyTextureView { template PropertyTexturePropertyView createVecNPropertyView( const ClassProperty& classProperty, - const PropertyTextureProperty& propertyTextureProperty) const { + [[maybe_unused]] const PropertyTextureProperty& propertyTextureProperty) + const { if (classProperty.array) { return PropertyTexturePropertyView( PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); @@ -605,7 +607,8 @@ class PropertyTextureView { PropertyTexturePropertyView, Normalized> createArrayPropertyView( const ClassProperty& classProperty, - const PropertyTextureProperty& propertyTextureProperty) const { + [[maybe_unused]] const PropertyTextureProperty& propertyTextureProperty) + const { if (!classProperty.array) { return PropertyTexturePropertyView, Normalized>( PropertyTexturePropertyViewStatus::ErrorArrayTypeMismatch); diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index d6fb63878..5149eb536 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -47,8 +47,7 @@ template static void checkNumeric(const std::vector& expected) { for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == expected[static_cast(i)]); - REQUIRE(property.get(i)); - REQUIRE(*property.get(i) == property.getRaw(i)); + REQUIRE(property.get(i) == property.getRaw(i)); } } @@ -90,8 +89,7 @@ static void checkNumeric( for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == values[static_cast(i)]); if constexpr (IsMetadataFloating::value) { - REQUIRE(property.get(i)); - REQUIRE(*property.get(i) == Approx(*expected[static_cast(i)])); + REQUIRE(property.get(i) == Approx(*expected[static_cast(i)])); } else { REQUIRE(property.get(i) == expected[static_cast(i)]); } @@ -192,6 +190,12 @@ static void checkVariableLengthArray( REQUIRE(values[j] == data[expectedIdx]); ++expectedIdx; } + + auto maybeValues = property.get(i); + REQUIRE(maybeValues); + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE((*maybeValues)[j] == values[j]); + } } REQUIRE(expectedIdx == data.size()); @@ -398,10 +402,17 @@ static void checkFixedLengthArray( REQUIRE(values[j] == data[expectedIdx]); ++expectedIdx; } + + auto maybeValues = property.get(i); + REQUIRE(maybeValues); + for (int64_t j = 0; j < values.size(); ++j) { + REQUIRE((*maybeValues)[j] == values[j]); + } } REQUIRE(expectedIdx == data.size()); } + template static void checkFixedLengthArrayWithProperties( const std::vector& data, @@ -597,16 +608,16 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Float with Offset / Scale") { std::vector values{12.5f, -12.5f, -5.0f, 6.75f}; - std::optional offset = 1.0f; - std::optional scale = 2.0f; + const float offset = 1.0f; + const float scale = 2.0f; std::vector> expected{26.0f, -24.0f, -9.0f, 14.5f}; checkNumeric(values, expected, offset, scale); } SECTION("Normalized Uint8 with Offset and Scale") { std::vector values{0, 64, 128, 255}; - std::optional offset = 1.0; - std::optional scale = 2.0; + const double offset = 1.0; + const double scale = 2.0; std::vector> expected{ 1.0, 1 + 2 * (64.0 / 255.0), @@ -617,7 +628,7 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Int16 with NoData") { std::vector values{-1, 3, 7, -1}; - std::optional noData = -1; + const int16_t noData = -1; std::vector> expected{ std::nullopt, static_cast(3), @@ -634,8 +645,8 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Int16 with NoData and Default") { std::vector values{-1, 3, 7, -1}; - std::optional noData = -1; - std::optional defaultValue = 0; + const int16_t noData = -1; + const int16_t defaultValue = 0; std::vector> expected{ static_cast(0), static_cast(3), @@ -652,10 +663,10 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Normalized Uint8 with all properties") { std::vector values{0, 64, 128, 255}; - std::optional offset = 1.0; - std::optional scale = 2.0; - std::optional noData = 0; - std::optional defaultValue = 10.0; + const double offset = 1.0; + const double scale = 2.0; + const uint8_t noData = 0; + const double defaultValue = 10.0; std::vector> expected{ 10.0, 1 + 2 * (64.0 / 255.0), @@ -696,22 +707,15 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { static_cast(values.size()), gsl::span(data.data(), data.size())); - REQUIRE(property.offset()); - REQUIRE(*property.offset() == 1.0f); - REQUIRE(property.scale()); - REQUIRE(*property.scale() == 2.0f); - REQUIRE(property.min()); - REQUIRE(*property.min() == 3.0f); - REQUIRE(property.max()); - REQUIRE(*property.max() == 9.0f); + REQUIRE(property.offset() == 1.0f); + REQUIRE(property.scale() == 2.0f); + REQUIRE(property.min() == 3.0f); + REQUIRE(property.max() == 9.0f); std::vector expected{3.0, 7.0f, 5.0f, 9.0f}; for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == values[static_cast(i)]); - - std::optional transformedValue = property.get(i); - REQUIRE(transformedValue); - REQUIRE(*transformedValue == Approx(expected[static_cast(i)])); + REQUIRE(property.get(i) == Approx(expected[static_cast(i)])); } } } @@ -775,8 +779,8 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::vec3(6.5f, 2.0f, 4.0f), glm::vec3(8.0f, -3.0f, 1.0f), }; - std::optional offset = JsonValue::Array{1.0f, 2.0f, 3.0f}; - std::optional scale = JsonValue::Array{2.0f, 1.0f, 2.0f}; + JsonValue::Array offset{1.0f, 2.0f, 3.0f}; + JsonValue::Array scale{2.0f, 1.0f, 2.0f}; std::vector> expected{ glm::vec3(1.0f, 0.5f, -7.0f), glm::vec3(14.0f, 4.0f, 11.0f), @@ -790,8 +794,8 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::u8vec2(0, 64), glm::u8vec2(128, 255), glm::u8vec2(255, 0)}; - std::optional offset = JsonValue::Array{0.0, 1.0}; - std::optional scale = JsonValue::Array{2.0, 1.0}; + JsonValue::Array offset{0.0, 1.0}; + JsonValue::Array scale{2.0, 1.0}; std::vector> expected{ glm::dvec2(0.0, 1 + (64.0 / 255.0)), glm::dvec2(2 * (128.0 / 255.0), 2.0), @@ -804,7 +808,7 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::i16vec2(-1, 3), glm::i16vec2(-1, -1), glm::i16vec2(7, 0)}; - std::optional noData = JsonValue::Array{-1, -1}; + JsonValue::Array noData{-1, -1}; std::vector> expected{ glm::i16vec2(-1, 3), std::nullopt, @@ -823,8 +827,8 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::i16vec2(-1, 3), glm::i16vec2(-1, -1), glm::i16vec2(7, 0)}; - std::optional noData = JsonValue::Array{-1, -1}; - std::optional defaultValue = JsonValue::Array{0, 1}; + JsonValue::Array noData{-1, -1}; + JsonValue::Array defaultValue{0, 1}; std::vector> expected{ glm::i16vec2(-1, 3), glm::i16vec2(0, 1), @@ -844,10 +848,10 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::u8vec2(128, 255), glm::u8vec2(255, 0), glm::u8vec2(0, 0)}; - std::optional offset = JsonValue::Array{0.0, 1.0}; - std::optional scale = JsonValue::Array{2.0, 1.0}; - std::optional noData = JsonValue::Array{0, 0}; - std::optional defaultValue = JsonValue::Array{5.0, 15.0}; + JsonValue::Array offset{0.0, 1.0}; + JsonValue::Array scale{2.0, 1.0}; + JsonValue::Array noData{0, 0}; + JsonValue::Array defaultValue{5.0, 15.0}; std::vector> expected{ glm::dvec2(0.0, 1 + (64.0 / 255.0)), glm::dvec2(2 * (128.0 / 255.0), 2.0), @@ -891,14 +895,10 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { static_cast(values.size()), gsl::span(data.data(), data.size())); - REQUIRE(property.offset()); - REQUIRE(*property.offset() == glm::vec2(1.0f, 0.5f)); - REQUIRE(property.scale()); - REQUIRE(*property.scale() == glm::vec2(2.0f, 1.0f)); - REQUIRE(property.min()); - REQUIRE(*property.min() == glm::vec2(3.0f, 3.0f)); - REQUIRE(property.max()); - REQUIRE(*property.max() == glm::vec2(6.0f, 4.5f)); + REQUIRE(property.offset() == glm::vec2(1.0f, 0.5f)); + REQUIRE(property.scale() == glm::vec2(2.0f, 1.0f)); + REQUIRE(property.min() == glm::vec2(3.0f, 3.0f)); + REQUIRE(property.max() == glm::vec2(6.0f, 4.5f)); std::vector expected{ glm::vec2(3.0f, 3.5f), @@ -906,10 +906,7 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { glm::vec2(5.0f, 4.5f)}; for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == values[static_cast(i)]); - - std::optional transformedValue = property.get(i); - REQUIRE(transformedValue); - REQUIRE(*transformedValue == expected[static_cast(i)]); + REQUIRE(property.get(i) == expected[static_cast(i)]); } } } @@ -1029,10 +1026,10 @@ TEST_CASE("Check matN PropertyTablePropertyView") { 8.0f, -1.0f, -3.0f, 1.0f), }; - std::optional offset = JsonValue::Array{ + JsonValue::Array offset{ 1.0f, 2.0f, 3.0f, 1.0f}; - std::optional scale = JsonValue::Array{ + JsonValue::Array scale { 2.0f, 0.0f, 0.0f, 2.0f}; std::vector> expected{ @@ -1059,10 +1056,10 @@ TEST_CASE("Check matN PropertyTablePropertyView") { glm::u8mat2x2( 255, 0, 128, 0)}; - std::optional offset = JsonValue::Array{ + JsonValue::Array offset{ 0.0, 1.0, 1.0, 0.0}; - std::optional scale = JsonValue::Array{ + JsonValue::Array scale{ 2.0, 1.0, 0.0, 2.0}; std::vector> expected{ @@ -1091,8 +1088,7 @@ TEST_CASE("Check matN PropertyTablePropertyView") { -1, -1, -1, 0, 0, 0, 1, 1, 1)}; - std::optional noData = - JsonValue::Array{ + JsonValue::Array noData{ -1, -1, -1, 0, 0, 0, 1, 1, 1}; @@ -1125,11 +1121,11 @@ TEST_CASE("Check matN PropertyTablePropertyView") { -1, -1, -1, 0, 0, 0, 1, 1, 1)}; - std::optional noData = JsonValue::Array{ + JsonValue::Array noData{ -1, -1, -1, 0, 0, 0, 1, 1, 1}; - std::optional defaultValue = JsonValue::Array{ + JsonValue::Array defaultValue{ 1, 0, 0, 0, 1, 0, 0, 0, 1}; @@ -1157,16 +1153,16 @@ TEST_CASE("Check matN PropertyTablePropertyView") { glm::u8mat2x2( 255, 0, 128, 0)}; - std::optional offset = JsonValue::Array{ + JsonValue::Array offset{ 0.0, 1.0, 1.0, 0.0}; - std::optional scale = JsonValue::Array{ + JsonValue::Array scale{ 2.0, 1.0, 0.0, 2.0}; - std::optional noData = JsonValue::Array{ + JsonValue::Array noData{ 0, 0, 0, 0}; - std::optional defaultValue = JsonValue::Array{ + JsonValue::Array defaultValue{ 1.0, 0.0, 0.0, 1.0}; @@ -1202,20 +1198,36 @@ TEST_CASE("Check matN PropertyTablePropertyView") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::MAT2; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; - // clang-fomrat off - classProperty.offset = {0.0f, 0.0f, 0.0f, 0.0f}; - classProperty.scale = {1.0f, 1.0f, 1.0f, 1.0f}; - classProperty.min = {1.0f, 0.0f, 0.0f, 1.0f}; - classProperty.max = {3.0f, 0.0f, 0.0f, 3.0f}; - // clang-fomrat on + // clang-format off + classProperty.offset = { + 0.0f, 0.0f, + 0.0f, 0.0f}; + classProperty.scale = { + 1.0f, 1.0f, + 1.0f, 1.0f}; + classProperty.min = { + 1.0f, 0.0f, + 0.0f, 1.0f}; + classProperty.max = { + 3.0f, 0.0f, + 0.0f, 3.0f}; + // clang-format on PropertyTableProperty propertyTableProperty; - // clang-fomrat off - propertyTableProperty.offset = {1.0f, 0.5f, 0.5f, 1.0f}; - propertyTableProperty.scale = {2.0f, 1.0f, 0.0f, 1.0f}; - propertyTableProperty.min = {3.0f, 0.5f, 0.5f, 2.0f}; - propertyTableProperty.max = {7.0f, 1.5f, 0.5f, 4.0f}; - // clang-fomrat on + // clang-format off + propertyTableProperty.offset = { + 1.0f, 0.5f, + 0.5f, 1.0f}; + propertyTableProperty.scale = { + 2.0f, 1.0f, + 0.0f, 1.0f}; + propertyTableProperty.min = { + 3.0f, 0.5f, + 0.5f, 2.0f}; + propertyTableProperty.max = { + 7.0f, 1.5f, + 0.5f, 4.0f}; + // clang-format on PropertyTablePropertyView property( propertyTableProperty, @@ -1224,20 +1236,16 @@ TEST_CASE("Check matN PropertyTablePropertyView") { gsl::span(data.data(), data.size())); // clang-format off - REQUIRE(property.offset()); - REQUIRE(*property.offset() == glm::mat2( + REQUIRE(property.offset() == glm::mat2( 1.0f, 0.5f, 0.5f, 1.0f)); - REQUIRE(property.scale()); - REQUIRE(*property.scale() == glm::mat2( + REQUIRE(property.scale() == glm::mat2( 2.0f, 1.0f, 0.0f, 1.0f)); - REQUIRE(property.min()); - REQUIRE(*property.min() == glm::mat2( + REQUIRE(property.min() == glm::mat2( 3.0f, 0.5f, 0.5f, 2.0f)); - REQUIRE(property.max()); - REQUIRE(*property.max() == glm::mat2( + REQUIRE(property.max() == glm::mat2( 7.0f, 1.5f, 0.5f, 4.0f)); @@ -1254,10 +1262,7 @@ TEST_CASE("Check matN PropertyTablePropertyView") { // clang-format on for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == values[static_cast(i)]); - - std::optional transformedValue = property.get(i); - REQUIRE(transformedValue); - REQUIRE(*transformedValue == expected[static_cast(i)]); + REQUIRE(property.get(i) == expected[static_cast(i)]); } } } @@ -1281,6 +1286,7 @@ TEST_CASE("Check boolean PropertyTablePropertyView") { for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == bits[static_cast(i)]); + REQUIRE(property.get(i) == property.getRaw(i)); } } @@ -1338,8 +1344,7 @@ TEST_CASE("Check string PropertyTablePropertyView") { for (int64_t i = 0; i < property.size(); ++i) { REQUIRE(property.getRaw(i) == strings[static_cast(i)]); - REQUIRE(property.get(i)); - REQUIRE(*property.get(i) == strings[static_cast(i)]); + REQUIRE(property.get(i) == strings[static_cast(i)]); } } @@ -1516,10 +1521,8 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { }; // clang-format on - std::optional offset = - JsonValue::Array{1.0f, 0.0f, -1.0f, 0.0f}; - std::optional scale = - JsonValue::Array{1.0f, 2.0f, 1.0f, 2.0f}; + JsonValue::Array offset{1.0f, 0.0f, -1.0f, 0.0f}; + JsonValue::Array scale{1.0f, 2.0f, 1.0f, 2.0f}; std::vector>> expected{ std::vector{2.0f, 4.0f, 2.0f, 8.0f}, @@ -1534,7 +1537,7 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { -1, -1, -3, 44}; // clang-format on - std::optional noData = JsonValue::Array{-1, -1}; + JsonValue::Array noData{-1, -1}; std::vector>> expected{ std::vector{122, 12}, std::nullopt, @@ -1556,8 +1559,8 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { -1, -1, -3, 44}; // clang-format on - std::optional noData = JsonValue::Array{-1, -1}; - std::optional defaultValue = JsonValue::Array{0, 1}; + JsonValue::Array noData{-1, -1}; + JsonValue::Array defaultValue{0, 1}; std::vector>> expected{ std::vector{122, 12}, std::vector{0, 1}, @@ -1579,10 +1582,10 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { -64, 127, -128, 0, 0, 0}; // clang-format on - std::optional offset = JsonValue::Array{0, 1, 1}; - std::optional scale = JsonValue::Array{1, -1, 2}; - std::optional noData = JsonValue::Array{0, 0, 0}; - std::optional defaultValue = JsonValue::Array{10, 8, 2}; + JsonValue::Array offset{0, 1, 1}; + JsonValue::Array scale{1, -1, 2}; + JsonValue::Array noData{0, 0, 0}; + JsonValue::Array defaultValue{10, 8, 2}; std::vector>> expected{ std::vector{-1.0, 1.0, 1 + 2 * (64.0 / 127.0)}, @@ -1733,10 +1736,8 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { }; // clang-format on - std::optional offset = - JsonValue::Array{{1.0f, 0.0f}, {-1.0f, 0.0f}}; - std::optional scale = - JsonValue::Array{{1.0f, 2.0f}, {1.0f, 2.0f}}; + JsonValue::Array offset{{1.0f, 0.0f}, {-1.0f, 0.0f}}; + JsonValue::Array scale{{1.0f, 2.0f}, {1.0f, 2.0f}}; std::vector>> expected{ std::vector{glm::vec2(2.0f, 4.0f), glm::vec2(2.0f, 8.0f)}, @@ -1751,7 +1752,7 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { glm::ivec2( -3, 44), glm::ivec2(0, 7), glm::ivec2(-1, -1), glm::ivec2(0, 0)}; // clang-format on - std::optional noData = JsonValue::Array{{-1, -1}, {0, 0}}; + JsonValue::Array noData{{-1, -1}, {0, 0}}; std::vector>> expected{ std::vector{glm::ivec2(122, 12), glm::ivec2(-1, -1)}, std::vector{glm::ivec2(-3, 44), glm::ivec2(0, 7)}, @@ -1773,9 +1774,8 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { glm::ivec2( -3, 44), glm::ivec2(0, 7), glm::ivec2(-1, -1), glm::ivec2(0, 0)}; // clang-format on - std::optional noData = JsonValue::Array{{-1, -1}, {0, 0}}; - std::optional defaultValue = - JsonValue::Array{{1, 1}, {1, 2}}; + JsonValue::Array noData{{-1, -1}, {0, 0}}; + JsonValue::Array defaultValue{{1, 1}, {1, 2}}; std::vector>> expected{ std::vector{glm::ivec2(122, 12), glm::ivec2(-1, -1)}, std::vector{glm::ivec2(-3, 44), glm::ivec2(0, 7)}, @@ -1797,11 +1797,10 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { glm::i8vec2(127, -128), glm::i8vec2(0, 0), glm::i8vec2(0), glm::i8vec2(0)}; // clang-format on - std::optional offset = JsonValue::Array{{0, 1}, {1, 2}}; - std::optional scale = JsonValue::Array{{1, -1}, {2, 1}}; - std::optional noData = JsonValue::Array{{0, 0}, {0, 0}}; - std::optional defaultValue = - JsonValue::Array{{10, 2}, {4, 8}}; + JsonValue::Array offset{{0, 1}, {1, 2}}; + JsonValue::Array scale{{1, -1}, {2, 1}}; + JsonValue::Array noData{{0, 0}, {0, 0}}; + JsonValue::Array defaultValue{{10, 2}, {4, 8}}; std::vector>> expected{ std::vector{ @@ -2039,47 +2038,45 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { SECTION("Array of 2 mat2s with offset / scale") { // clang-format off std::vector data{ + glm::mat2( + 1.0f, 2.0f, + 3.0f, 4.0f), + glm::mat2( + 5.0f, -1.0f, + 0.0f, 2.0f), + glm::mat2( + -1.0f, -1.0f, + 0.0f, -2.0f), + glm::mat2( + 0.0f, -2.0f, + 4.0f, 3.0f)}; + + JsonValue::Array offset{ + {1.0f, 0.0f, + 2.0f, 3.0f}, + {-1.0f, 0.0f, + 0.0f, 2.0f}}; + JsonValue::Array scale{ + {1.0f, 2.0f, + 1.0f, 0.0f}, + {1.0f, -1.0f, + -1.0f, 2.0f}}; + + std::vector>> expected{ + std::vector{ glm::mat2( - 1.0f, 2.0f, - 3.0f, 4.0f), - glm::mat2( - 5.0f, -1.0f, - 0.0f, 2.0f), + 2.0f, 4.0f, + 5.0f, 3.0f), glm::mat2( - -1.0f, -1.0f, - 0.0f, -2.0f), + 4.0f, 1.0f, + 0.0f, 6.0f)}, + std::vector{ glm::mat2( 0.0f, -2.0f, - 4.0f, 3.0f)}; - - std::optional offset = - JsonValue::Array{ - {1.0f, 0.0f, - 2.0f, 3.0f}, - {-1.0f, 0.0f, - 0.0f, 2.0f}}; - std::optional scale = - JsonValue::Array{ - {1.0f, 2.0f, - 1.0f, 0.0f}, - {1.0f, -1.0f, - -1.0f, 2.0f}}; - - std::vector>> expected{ - std::vector{ - glm::mat2( - 2.0f, 4.0f, - 5.0f, 3.0f), - glm::mat2( - 4.0f, 1.0f, - 0.0f, 6.0f)}, - std::vector{ - glm::mat2( - 0.0f, -2.0f, - 2.0f, 3.0f), - glm::mat2( - -1.0f, 2.0f, - -4.0f, 8.0f)}}; + 2.0f, 3.0f), + glm::mat2( + -1.0f, 2.0f, + -4.0f, 8.0f)}}; // clang-format on checkFixedLengthArrayWithProperties(data, 2, expected, offset, scale); } @@ -2099,7 +2096,7 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { -1, 0), glm::imat2x2(-1), glm::imat2x2(0)}; - std::optional noData = JsonValue::Array{ + JsonValue::Array noData{ {-1, 0, 0, -1}, {0, 0, @@ -2144,12 +2141,12 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { -1, 0), glm::imat2x2(-1), glm::imat2x2(0)}; - std::optional noData = JsonValue::Array{ + JsonValue::Array noData{ {-1, 0, 0, -1}, {0, 0, 0, 0}}; - std::optional defaultValue = JsonValue::Array{ + JsonValue::Array defaultValue{ {2, 0, 0, 2}, {1, 0, @@ -2198,22 +2195,22 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { glm::i8mat2x2( -128, -128, -128, -128)}; - std::optional offset = JsonValue::Array{ + JsonValue::Array offset{ {0, 1, 2, 3}, {1, 2, 0, -2}}; - std::optional scale = JsonValue::Array{ + JsonValue::Array scale{ {1, -1, 0, 1}, {2, 1, -1, 0}}; - std::optional noData = JsonValue::Array{ + JsonValue::Array noData{ {0, 0, 0, 0}, {-128, -128, -128, -128}}; - std::optional defaultValue = JsonValue::Array{ + JsonValue::Array defaultValue{ {1, 0, 0, 1}, {2, 0, @@ -2491,7 +2488,7 @@ TEST_CASE("Check variable-length scalar array PropertyTablePropertyView") { 11 * sizeof(int32_t), 15 * sizeof(int32_t)}; - std::optional noData = JsonValue::Array{0}; + JsonValue::Array noData{0}; std::vector>> expected{ std::vector{3, 200}, @@ -2526,8 +2523,8 @@ TEST_CASE("Check variable-length scalar array PropertyTablePropertyView") { 11 * sizeof(int32_t), 15 * sizeof(int32_t)}; - std::optional noData = JsonValue::Array{0}; - std::optional defaultValue = JsonValue::Array{1}; + JsonValue::Array noData{0}; + JsonValue::Array defaultValue{1}; std::vector>> expected{ std::vector{3, 200}, @@ -2558,8 +2555,8 @@ TEST_CASE("Check variable-length scalar array PropertyTablePropertyView") { }; // clang-format on - std::optional noData = JsonValue::Array{255, 255}; - std::optional defaultValue = JsonValue::Array{-1.0}; + JsonValue::Array noData{255, 255}; + JsonValue::Array defaultValue{-1.0}; std::vector>> expected{ std::vector{1.0, 0.0}, @@ -2692,8 +2689,8 @@ TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { 7 * sizeof(glm::ivec3), 9 * sizeof(glm::ivec3)}; - std::optional noData = JsonValue::Array{}; - noData->push_back(JsonValue::Array{-1, -1, -1}); + JsonValue::Array noData{}; + noData.push_back(JsonValue::Array{-1, -1, -1}); std::vector>> expected{ std::vector{glm::ivec3(3, 200, 1), glm::ivec3(2, 4, 6)}, @@ -2731,10 +2728,10 @@ TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { 7 * sizeof(glm::ivec3), 9 * sizeof(glm::ivec3)}; - std::optional noData = JsonValue::Array{}; - noData->push_back(JsonValue::Array{-1, -1, -1}); - std::optional defaultValue = JsonValue::Array{}; - defaultValue->push_back(JsonValue::Array{0, 0, 0}); + JsonValue::Array noData{}; + noData.push_back(JsonValue::Array{-1, -1, -1}); + JsonValue::Array defaultValue{}; + defaultValue.push_back(JsonValue::Array{0, 0, 0}); std::vector>> expected{ std::vector{glm::ivec3(3, 200, 1), glm::ivec3(2, 4, 6)}, @@ -2769,10 +2766,10 @@ TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { 3 * sizeof(glm::u8vec2), 6 * sizeof(glm::u8vec2)}; - std::optional noData = JsonValue::Array{}; - noData->push_back(JsonValue::Array{0, 0}); - std::optional defaultValue = JsonValue::Array{}; - defaultValue->push_back(JsonValue::Array{-1.0, -1.0}); + JsonValue::Array noData{}; + noData.push_back(JsonValue::Array{0, 0}); + JsonValue::Array defaultValue{}; + defaultValue.push_back(JsonValue::Array{-1.0, -1.0}); std::vector>> expected{ std::vector{ @@ -2993,8 +2990,8 @@ TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { 9 * sizeof(glm::imat3x3)}; // clang-format off - std::optional noData = JsonValue::Array{}; - noData->push_back(JsonValue::Array{ + JsonValue::Array noData{}; + noData.push_back(JsonValue::Array{ -1, 0, 0, 0, -1, 0, 0, 0, -1}); @@ -3037,13 +3034,13 @@ TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { 9 * sizeof(glm::imat3x3)}; // clang-format off - std::optional noData = JsonValue::Array{}; - noData->push_back(JsonValue::Array{ + JsonValue::Array noData{}; + noData.push_back(JsonValue::Array{ -1, 0, 0, 0, -1, 0, 0, 0, -1}); - std::optional defaultValue = JsonValue::Array{}; - defaultValue->push_back(JsonValue::Array{ + JsonValue::Array defaultValue{}; + defaultValue.push_back(JsonValue::Array{ 99, 0, 0, 0, 99, 0, 0, 0, 99}); @@ -3083,12 +3080,12 @@ TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { 6 * sizeof(glm::u8mat2x2)}; // clang-format off - std::optional noData = JsonValue::Array{}; - noData->push_back(JsonValue::Array{ + JsonValue::Array noData{}; + noData.push_back(JsonValue::Array{ 0, 0, 0, 0}); - std::optional defaultValue = JsonValue::Array{}; - defaultValue->push_back(JsonValue::Array{ + JsonValue::Array defaultValue{}; + defaultValue.push_back(JsonValue::Array{ -1.0, 0.0, 0.0, -1.0}); // clang-format on @@ -3568,6 +3565,16 @@ TEST_CASE("Check fixed-length boolean array PropertyTablePropertyView") { REQUIRE(static_cast(val1[9]) == 1); REQUIRE(static_cast(val1[10]) == 1); REQUIRE(static_cast(val1[11]) == 1); + + for (int64_t i = 0; i < property.size(); i++) { + auto value = property.getRaw(i); + auto maybeValue = property.get(i); + REQUIRE(maybeValue); + REQUIRE(maybeValue->size() == value.size()); + for (int64_t j = 0; j < maybeValue->size(); j++) { + REQUIRE((*maybeValue)[j] == value[j]); + } + } } TEST_CASE("Check variable-length boolean array PropertyTablePropertyView") { @@ -3635,4 +3642,14 @@ TEST_CASE("Check variable-length boolean array PropertyTablePropertyView") { REQUIRE(static_cast(val2[13]) == 1); REQUIRE(static_cast(val2[14]) == 1); REQUIRE(static_cast(val2[15]) == 0); + + for (int64_t i = 0; i < property.size(); i++) { + auto value = property.getRaw(i); + auto maybeValue = property.get(i); + REQUIRE(maybeValue); + REQUIRE(maybeValue->size() == value.size()); + for (int64_t j = 0; j < maybeValue->size(); j++) { + REQUIRE((*maybeValue)[j] == value[j]); + } + } } diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index 2b1889a64..2450c926f 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -70,12 +70,8 @@ void checkTextureValues( for (size_t i = 0; i < texCoords.size(); i++) { glm::dvec2 uv = texCoords[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == expected[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expected[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == expected[i]); + REQUIRE(view.get(uv[0], uv[1]) == expected[i]); } } @@ -147,11 +143,8 @@ void checkTextureValues( for (size_t i = 0; i < texCoords.size(); i++) { glm::dvec2 uv = texCoords[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == expectedRaw[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue == expectedTransformed[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == expectedRaw[i]); + REQUIRE(view.get(uv[0], uv[1]) == expectedTransformed[i]); } } @@ -225,11 +218,8 @@ void checkNormalizedTextureValues( for (size_t i = 0; i < texCoords.size(); i++) { glm::dvec2 uv = texCoords[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == expectedRaw[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue == expectedTransformed[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == expectedRaw[i]); + REQUIRE(view.get(uv[0], uv[1]) == expectedTransformed[i]); } } @@ -898,8 +888,8 @@ TEST_CASE("Check vecN PropertyTexturePropertyView") { 0, 0, 182, 1}; // clang-format on - std::optional noData = JsonValue::Array{0, 0}; - std::optional defaultValue = JsonValue::Array{127, 127}; + JsonValue::Array noData{0, 0}; + JsonValue::Array defaultValue{127, 127}; std::vector expectedRaw{ glm::i8vec2(28, -1), glm::i8vec2(-2, 1), @@ -1454,11 +1444,8 @@ TEST_CASE("Check that property values override class property values") { for (size_t i = 0; i < texCoords.size(); i++) { glm::dvec2 uv = texCoords[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == expectedRaw[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue == expectedTransformed[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == expectedRaw[i]); + REQUIRE(view.get(uv[0], uv[1]) == expectedTransformed[i]); } } @@ -1503,12 +1490,8 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector expected{3, 4, 0, 1}; for (size_t i = 0; i < expected.size(); i++) { glm::dvec2 uv = texCoords[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == expected[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expected[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == expected[i]); + REQUIRE(view.get(uv[0], uv[1]) == expected[i]); } } @@ -1545,12 +1528,8 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { std::vector expected{2, 259, 257, 520}; for (size_t i = 0; i < expected.size(); i++) { glm::dvec2 uv = texCoords[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == expected[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expected[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == expected[i]); + REQUIRE(view.get(uv[0], uv[1]) == expected[i]); } } @@ -1591,12 +1570,8 @@ TEST_CASE("Check that non-adjacent channels resolve to expected output") { glm::u8vec3(1, 8, 3)}; for (size_t i = 0; i < expected.size(); i++) { glm::dvec2 uv = texCoords[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == expected[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == expected[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == expected[i]); + REQUIRE(view.get(uv[0], uv[1]) == expected[i]); } } @@ -1691,12 +1666,8 @@ TEST_CASE("Check sampling with different sampler values") { glm::dvec2(1.5, -0.5)}; for (size_t i = 0; i < uvs.size(); i++) { glm::dvec2 uv = uvs[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == data[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == data[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == data[i]); + REQUIRE(view.get(uv[0], uv[1]) == data[i]); } } @@ -1719,12 +1690,8 @@ TEST_CASE("Check sampling with different sampler values") { glm::dvec2(-1.25, 2.75)}; for (size_t i = 0; i < uvs.size(); i++) { glm::dvec2 uv = uvs[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == data[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == data[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == data[i]); + REQUIRE(view.get(uv[0], uv[1]) == data[i]); } } @@ -1744,12 +1711,8 @@ TEST_CASE("Check sampling with different sampler values") { glm::dvec2(1.5, 1.5)}; for (size_t i = 0; i < uvs.size(); i++) { glm::dvec2 uv = uvs[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == data[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == data[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == data[i]); + REQUIRE(view.get(uv[0], uv[1]) == data[i]); } } @@ -1769,12 +1732,8 @@ TEST_CASE("Check sampling with different sampler values") { glm::dvec2(1.5, 1.5)}; for (size_t i = 0; i < uvs.size(); i++) { glm::dvec2 uv = uvs[i]; - auto value = view.getRaw(uv[0], uv[1]); - REQUIRE(value == data[i]); - - auto maybeValue = view.get(uv[0], uv[1]); - REQUIRE(maybeValue); - REQUIRE(*maybeValue == data[i]); + REQUIRE(view.getRaw(uv[0], uv[1]) == data[i]); + REQUIRE(view.get(uv[0], uv[1]) == data[i]); } } } From 79eaa3e6877926b4838db2669347f62884f856e6 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 25 Aug 2023 17:46:16 -0400 Subject: [PATCH 097/121] Final sweep (hopefully) --- .../CesiumGltf/PropertyTexturePropertyView.h | 38 +-- CesiumGltf/include/CesiumGltf/PropertyView.h | 280 +++++++----------- CesiumGltf/test/TestPropertyView.cpp | 152 ++++------ 3 files changed, 184 insertions(+), 286 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 8d4933068..70ff28ce6 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -79,25 +79,6 @@ class PropertyTexturePropertyViewStatus : public PropertyViewStatus { static const int ErrorChannelsAndTypeMismatch = 21; }; -template -ElementType -assembleValueFromChannels(const std::vector& bytes) noexcept { - assert(bytes.size() > 0 && "Channel input must have at least one value."); - - if constexpr (IsMetadataScalar::value) { - return assembleScalarValue(bytes); - } - - if constexpr (IsMetadataVecN::value) { - return assembleVecNValue(bytes); - } - - if constexpr (IsMetadataArray::value) { - return assembleArrayValue::type>( - bytes); - } -} - template ElementType assembleScalarValue(const std::vector& bytes) noexcept { if constexpr (std::is_same_v) { @@ -191,6 +172,25 @@ assembleArrayValue(const std::vector& bytes) noexcept { return PropertyArrayView(std::move(result)); } +template +ElementType +assembleValueFromChannels(const std::vector& bytes) noexcept { + assert(bytes.size() > 0 && "Channel input must have at least one value."); + + if constexpr (IsMetadataScalar::value) { + return assembleScalarValue(bytes); + } + + if constexpr (IsMetadataVecN::value) { + return assembleVecNValue(bytes); + } + + if constexpr (IsMetadataArray::value) { + return assembleArrayValue::type>( + bytes); + } +} + inline double applySamplerWrapS(const double u, const int32_t wrapS) { if (wrapS == Sampler::WrapS::REPEAT) { double integral = 0; diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 8a283fa58..4bc809cf4 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -3,7 +3,6 @@ #include "CesiumGltf/PropertyTextureProperty.h" #include "CesiumGltf/PropertyTypeTraits.h" -#include #include #include @@ -54,7 +53,7 @@ class PropertyViewStatus { static const PropertyViewStatusType ErrorArrayTypeMismatch = 4; /** - * @brief This property says it is normalized, but is not of an integer + * @brief This property says it is normalized, but it does not have an integer * component type. */ static const PropertyViewStatusType ErrorInvalidNormalization = 5; @@ -283,7 +282,7 @@ template class PropertyView { } if (classProperty.normalized) { - _status = PropertyViewStatus::ErrorInvalidNormalization; + _status = PropertyViewStatus::ErrorNormalizationMismatch; return; } @@ -294,7 +293,7 @@ template class PropertyView { if (classProperty.noData) { if (!_required) { - // "noData" can only be defined if the property is required. + // "noData" can only be defined if the property is not required. _noData = getValue(*classProperty.noData); } @@ -307,7 +306,7 @@ template class PropertyView { if (classProperty.defaultProperty) { if (!_required) { - // "default" can only be defined if the property is required. + // "default" can only be defined if the property is not required. _defaultValue = getValue(*classProperty.defaultProperty); } @@ -323,7 +322,8 @@ template class PropertyView { /** * @brief Constructs an invalid instance for an erroneous property. * - * @param status The value of {@link PropertyViewStatus} indicating the error with the property. + * @param status The value of {@link PropertyViewStatus} indicating the error + * with the property. */ PropertyView(PropertyViewStatusType status) : _status(status), @@ -458,8 +458,49 @@ template class PropertyView { protected: PropertyViewStatusType _status; +private: + bool _required; + + std::optional _offset; + std::optional _scale; + std::optional _max; + std::optional _min; + + std::optional _noData; + std::optional _defaultValue; + + /** + * @brief Attempts to parse an ElementType from the given json value. + * + * If ElementType is a type with multiple components, e.g. a VECN or MATN + * type, this will return std::nullopt if one or more components could not be + * parsed. + * + * @return The value as an instance of ElementType, or std::nullopt if it + * could not be parsed. + */ + static std::optional + getValue(const CesiumUtility::JsonValue& jsonValue) { + if constexpr (IsMetadataScalar::value) { + return getScalar(jsonValue); + } + + if constexpr (IsMetadataVecN::value) { + return getVecN(jsonValue); + } + + if constexpr (IsMetadataMatN::value) { + return getMatN(jsonValue); + } + } + using PropertyDefinitionType = std:: variant; + + /** + * @brief Attempts to parse offset, scale, min, and max properties from the + * given property type. + */ void getNumericPropertyValues(const PropertyDefinitionType& inProperty) { std::visit( [this](auto property) { @@ -517,42 +558,6 @@ template class PropertyView { }, inProperty); } - -private: - bool _required; - - std::optional _offset; - std::optional _scale; - std::optional _max; - std::optional _min; - - std::optional _noData; - std::optional _defaultValue; - - /** - * @brief Attempts to parse an ElementType from the given json value. - * - * If ElementType is a type with multiple components, e.g. a VECN or MATN - * type, this will return std::nullopt if one or more components could not be - * parsed. - * - * @return The value as an instance of ElementType, or std::nullopt if it - * could not be parsed. - */ - static std::optional - getValue(const CesiumUtility::JsonValue& jsonValue) { - if constexpr (IsMetadataScalar::value) { - return getScalar(jsonValue); - } - - if constexpr (IsMetadataVecN::value) { - return getVecN(jsonValue); - } - - if constexpr (IsMetadataMatN::value) { - return getMatN(jsonValue); - } - } }; /** @@ -603,61 +608,19 @@ template class PropertyView { } if (!classProperty.normalized) { - _status = PropertyViewStatus::ErrorInvalidNormalization; - } - - if (classProperty.offset) { - _offset = getValue(*classProperty.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (classProperty.scale) { - _scale = getValue(*classProperty.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (classProperty.max) { - _max = getValue(*classProperty.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } + _status = PropertyViewStatus::ErrorNormalizationMismatch; } - if (classProperty.min) { - _min = getValue(*classProperty.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } - } - - if (_required) { - // "noData" should not be defined if the property is required. - if (classProperty.noData) { - _status = PropertyViewStatus::ErrorInvalidNoDataValue; - return; - } - - // default value should not be defined if the property is required. - if (classProperty.defaultProperty) { - _status = PropertyViewStatus::ErrorInvalidDefaultValue; - return; - } + getNumericPropertyValues(classProperty); + if (_status != PropertyViewStatus::Valid) { + return; } if (classProperty.noData) { - _noData = getValue(*classProperty.noData); + if (!_required) { + // "noData" should not be defined if the property is required. + _noData = getValue(*classProperty.noData); + } if (!_noData) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidNoDataValue; @@ -666,7 +629,11 @@ template class PropertyView { } if (classProperty.defaultProperty) { - _defaultValue = getValue(*classProperty.defaultProperty); + // default value should not be defined if the property is required. + if (!_required) { + _defaultValue = + getValue(*classProperty.defaultProperty); + } if (!_defaultValue) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidDefaultValue; @@ -704,42 +671,7 @@ template class PropertyView { } // If the property has its own values, override the class-provided values. - - if (property.offset) { - _offset = getValue(*property.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (property.scale) { - _scale = getValue(*property.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (property.max) { - _max = getValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (property.min) { - _min = getValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } - } + getNumericPropertyValues(property); } /** @@ -755,42 +687,7 @@ template class PropertyView { } // If the property has its own values, override the class-provided values. - - if (property.offset) { - _offset = getValue(*property.offset); - if (!_offset) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidOffset; - return; - } - } - - if (property.scale) { - _scale = getValue(*property.scale); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidScale; - return; - } - } - - if (property.max) { - _max = getValue(*property.max); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMax; - return; - } - } - - if (property.min) { - _min = getValue(*property.min); - if (!_scale) { - // The value was specified but something went wrong. - _status = PropertyViewStatus::ErrorInvalidMin; - return; - } - } + getNumericPropertyValues(property); } public: @@ -886,6 +783,55 @@ template class PropertyView { return getMatN(jsonValue); } } + + using PropertyDefinitionType = std:: + variant; + + /** + * @brief Attempts to parse offset, scale, min, and max properties from the + * given property type. + */ + void getNumericPropertyValues(const PropertyDefinitionType& inProperty) { + std::visit( + [this](auto property) { + if (property.offset) { + _offset = getValue(*property.offset); + if (!_offset) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidOffset; + return; + } + } + + if (property.scale) { + _scale = getValue(*property.scale); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidScale; + return; + } + } + + if (property.max) { + _max = getValue(*property.max); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMax; + return; + } + } + + if (property.min) { + _min = getValue(*property.min); + if (!_scale) { + // The value was specified but something went wrong. + _status = PropertyViewStatus::ErrorInvalidMin; + return; + } + } + }, + inProperty); + } }; /** @@ -1235,7 +1181,7 @@ class PropertyView, false> { } if (classProperty.normalized) { - _status = PropertyViewStatus::ErrorInvalidNormalization; + _status = PropertyViewStatus::ErrorNormalizationMismatch; return; } @@ -1599,7 +1545,7 @@ class PropertyView, true> { } if (!classProperty.normalized) { - _status = PropertyViewStatus::ErrorInvalidNormalization; + _status = PropertyViewStatus::ErrorNormalizationMismatch; return; } diff --git a/CesiumGltf/test/TestPropertyView.cpp b/CesiumGltf/test/TestPropertyView.cpp index 8aa81a9a9..833902790 100644 --- a/CesiumGltf/test/TestPropertyView.cpp +++ b/CesiumGltf/test/TestPropertyView.cpp @@ -46,8 +46,8 @@ TEST_CASE("Boolean PropertyView") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); - REQUIRE(view.defaultValue()); - REQUIRE(!*view.defaultValue()); + REQUIRE(view.defaultValue() == false); + ; } SECTION("Reports errors for incorrectly defined properties") { @@ -119,7 +119,7 @@ TEST_CASE("Scalar PropertyView") { classProperty.normalized = true; PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with offset, scale, max, and min") { @@ -133,15 +133,10 @@ TEST_CASE("Scalar PropertyView") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.offset()); - REQUIRE(view.scale()); - REQUIRE(view.max()); - REQUIRE(view.min()); - - REQUIRE(*view.offset() == 5.04f); - REQUIRE(*view.scale() == 2.2f); - REQUIRE(*view.max() == 10.5f); - REQUIRE(*view.min() == -10.5f); + REQUIRE(view.offset() == 5.04f); + REQUIRE(view.scale() == 2.2f); + REQUIRE(view.max() == 10.5f); + REQUIRE(view.min() == -10.5f); } SECTION("Constructs with noData and defaultProperty") { @@ -155,11 +150,8 @@ TEST_CASE("Scalar PropertyView") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); - REQUIRE(view.noData()); - REQUIRE(view.defaultValue()); - - REQUIRE(*view.noData() == 0); - REQUIRE(*view.defaultValue() == 1); + REQUIRE(view.noData() == 0); + REQUIRE(view.defaultValue() == 1); } SECTION("Reports errors for incorrectly defined properties") { @@ -279,7 +271,7 @@ TEST_CASE("Scalar PropertyView (normalized)") { classProperty.normalized = false; PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with offset, scale, max, and min") { @@ -294,15 +286,10 @@ TEST_CASE("Scalar PropertyView (normalized)") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.offset()); - REQUIRE(view.scale()); - REQUIRE(view.max()); - REQUIRE(view.min()); - - REQUIRE(*view.offset() == 5.04f); - REQUIRE(*view.scale() == 2.2f); - REQUIRE(*view.max() == 10.5f); - REQUIRE(*view.min() == -10.5f); + REQUIRE(view.offset() == 5.04f); + REQUIRE(view.scale() == 2.2f); + REQUIRE(view.max() == 10.5f); + REQUIRE(view.min() == -10.5f); } SECTION("Constructs with noData and defaultProperty") { @@ -317,11 +304,8 @@ TEST_CASE("Scalar PropertyView (normalized)") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); - REQUIRE(view.noData()); - REQUIRE(view.defaultValue()); - - REQUIRE(*view.noData() == 0); - REQUIRE(*view.defaultValue() == 1.5); + REQUIRE(view.noData() == 0); + REQUIRE(view.defaultValue() == 1.5); } SECTION("Reports errors for incorrectly defined properties") { @@ -424,7 +408,7 @@ TEST_CASE("VecN PropertyView") { classProperty.normalized = true; PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with offset, scale, max, and min") { @@ -438,15 +422,10 @@ TEST_CASE("VecN PropertyView") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.offset()); - REQUIRE(view.scale()); - REQUIRE(view.max()); - REQUIRE(view.min()); - - REQUIRE(*view.offset() == glm::vec3(-1, 1, 2)); - REQUIRE(*view.scale() == glm::vec3(2, 1, 3)); - REQUIRE(*view.max() == glm::vec3(10, 5, 6)); - REQUIRE(*view.min() == glm::vec3(-11, -12, -13)); + REQUIRE(view.offset() == glm::vec3(-1, 1, 2)); + REQUIRE(view.scale() == glm::vec3(2, 1, 3)); + REQUIRE(view.max() == glm::vec3(10, 5, 6)); + REQUIRE(view.min() == glm::vec3(-11, -12, -13)); } SECTION("Constructs with noData and defaultProperty") { @@ -459,12 +438,8 @@ TEST_CASE("VecN PropertyView") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(!view.required()); - REQUIRE(view.noData()); - REQUIRE(view.defaultValue()); - - REQUIRE(*view.noData() == glm::vec4(0.0f)); - REQUIRE(*view.defaultValue() == glm::vec4(1.0f, 2.0f, 3.0f, 4.0f)); + REQUIRE(view.noData() == glm::vec4(0.0f)); + REQUIRE(view.defaultValue() == glm::vec4(1.0f, 2.0f, 3.0f, 4.0f)); } SECTION("Reports errors for incorrectly defined properties") { @@ -592,7 +567,7 @@ TEST_CASE("VecN PropertyView (normalized)") { classProperty.normalized = false; PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with offset, scale, max, and min") { @@ -607,15 +582,10 @@ TEST_CASE("VecN PropertyView (normalized)") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.offset()); - REQUIRE(view.scale()); - REQUIRE(view.max()); - REQUIRE(view.min()); - - REQUIRE(*view.offset() == glm::dvec3(-1, 1, 2)); - REQUIRE(*view.scale() == glm::dvec3(2, 1, 3)); - REQUIRE(*view.max() == glm::dvec3(10, 5, 6)); - REQUIRE(*view.min() == glm::dvec3(-11, -12, -13)); + REQUIRE(view.offset() == glm::dvec3(-1, 1, 2)); + REQUIRE(view.scale() == glm::dvec3(2, 1, 3)); + REQUIRE(view.max() == glm::dvec3(10, 5, 6)); + REQUIRE(view.min() == glm::dvec3(-11, -12, -13)); } SECTION("Constructs with noData and defaultProperty") { @@ -630,11 +600,8 @@ TEST_CASE("VecN PropertyView (normalized)") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); - REQUIRE(view.noData()); - REQUIRE(view.defaultValue()); - - REQUIRE(*view.noData() == glm::i8vec4(0, 0, -1, -1)); - REQUIRE(*view.defaultValue() == glm::dvec4(1.0, 2.0, 3.0, 4.5)); + REQUIRE(view.noData() == glm::i8vec4(0, 0, -1, -1)); + REQUIRE(view.defaultValue() == glm::dvec4(1.0, 2.0, 3.0, 4.5)); } SECTION("Reports errors for incorrectly defined properties") { @@ -746,7 +713,7 @@ TEST_CASE("MatN PropertyView") { classProperty.normalized = true; PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with offset, scale, max, and min") { @@ -774,35 +741,31 @@ TEST_CASE("MatN PropertyView") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.offset()); - REQUIRE(view.scale()); - REQUIRE(view.max()); - REQUIRE(view.min()); // clang-format off glm::mat3 expectedOffset( -1, 1, 2, 3, -1, 4, -5, -5, 0); - REQUIRE(*view.offset() == expectedOffset); + REQUIRE(view.offset() == expectedOffset); glm::mat3 expectedScale( 1, 1, 1, 2, 2, 3, 3, 4, 5); - REQUIRE(*view.scale() == expectedScale); + REQUIRE(view.scale() == expectedScale); glm::mat3 expectedMax( 20, 5, 20, 30, 22, 43, 37, 1, 8); - REQUIRE(*view.max() == expectedMax); + REQUIRE(view.max() == expectedMax); glm::mat3 expectedMin( -10, -2, -3, 0, 20, 4, 9, 4, 5); - REQUIRE(*view.min() == expectedMin); + REQUIRE(view.min() == expectedMin); // clang-format on } @@ -823,19 +786,17 @@ TEST_CASE("MatN PropertyView") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); - REQUIRE(view.noData()); - REQUIRE(view.defaultValue()); // clang-format off glm::mat2 expectedNoData( 0.0f, 0.0f, 0.0f, 0.0f); - REQUIRE(*view.noData() == expectedNoData); + REQUIRE(view.noData() == expectedNoData); glm::mat2 expectedDefaultValue( 1.0f, 2.0f, 3.0f, 4.5f); - REQUIRE(*view.defaultValue() == expectedDefaultValue); + REQUIRE(view.defaultValue() == expectedDefaultValue); } SECTION("Reports errors for incorrectly defined properties") { @@ -1018,7 +979,7 @@ TEST_CASE("MatN PropertyView (normalized)") { classProperty.normalized = false; PropertyView view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with offset, scale, max, and min") { @@ -1047,35 +1008,30 @@ TEST_CASE("MatN PropertyView (normalized)") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); - REQUIRE(view.offset()); - REQUIRE(view.scale()); - REQUIRE(view.max()); - REQUIRE(view.min()); - // clang-format off glm::dmat3 expectedOffset( -1, 1, 2, 3, -1, 4, -5, -5, 0); - REQUIRE(*view.offset() == expectedOffset); + REQUIRE(view.offset() == expectedOffset); glm::dmat3 expectedScale( 1, 1, 1, 2, 2, 3, 3, 4, 5); - REQUIRE(*view.scale() == expectedScale); + REQUIRE(view.scale() == expectedScale); glm::dmat3 expectedMax( 20, 5, 20, 30, 22, 43, 37, 1, 8); - REQUIRE(*view.max() == expectedMax); + REQUIRE(view.max() == expectedMax); glm::dmat3 expectedMin( -10, -2, -3, 0, 20, 4, 9, 4, 5); - REQUIRE(*view.min() == expectedMin); + REQUIRE(view.min() == expectedMin); // clang-format on } @@ -1097,17 +1053,15 @@ TEST_CASE("MatN PropertyView (normalized)") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); - REQUIRE(view.noData()); - REQUIRE(view.defaultValue()); glm::imat2x2 expectedNoData(0); - REQUIRE(*view.noData() == expectedNoData); + REQUIRE(view.noData() == expectedNoData); // clang-format off glm::dmat2 expectedDefaultValue( 1.0, 2.0, 3.0, 4.5); - REQUIRE(*view.defaultValue() == expectedDefaultValue); + REQUIRE(view.defaultValue() == expectedDefaultValue); } SECTION("Reports errors for incorrectly defined properties") { @@ -1233,11 +1187,9 @@ TEST_CASE("String PropertyView") { PropertyView view(classProperty); REQUIRE(view.status() == PropertyViewStatus::Valid); REQUIRE(!view.required()); - REQUIRE(view.noData()); - REQUIRE(view.defaultValue()); - REQUIRE(*view.noData() == "null"); - REQUIRE(*view.defaultValue() == "default"); + REQUIRE(view.noData() == "null"); + REQUIRE(view.defaultValue() == "default"); } SECTION("Reports errors for incorrectly defined properties") { @@ -1404,7 +1356,7 @@ TEST_CASE("Scalar Array PropertyView") { classProperty.normalized = true; PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with count") { @@ -1651,7 +1603,7 @@ TEST_CASE("Scalar Array PropertyView (normalized)") { classProperty.normalized = false; PropertyView, true> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with count") { @@ -1878,7 +1830,7 @@ TEST_CASE("VecN Array PropertyView") { classProperty.normalized = true; PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with count") { @@ -2121,7 +2073,7 @@ TEST_CASE("VecN Array PropertyView (normalized)") { classProperty.normalized = false; PropertyView, true> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with count") { @@ -2344,7 +2296,7 @@ TEST_CASE("MatN Array PropertyView") { classProperty.normalized = true; PropertyView> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with count") { @@ -2725,7 +2677,7 @@ TEST_CASE("MatN Array PropertyView (normalized)") { classProperty.normalized = false; PropertyView, true> view(classProperty); - REQUIRE(view.status() == PropertyViewStatus::ErrorInvalidNormalization); + REQUIRE(view.status() == PropertyViewStatus::ErrorNormalizationMismatch); } SECTION("Constructs with count") { From 5b33dd72ad7d43a7a128d0c13c6f6d21f0233356 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 28 Aug 2023 10:07:08 -0400 Subject: [PATCH 098/121] Fix signed conversions --- CesiumGltf/test/TestPropertyTableView.cpp | 35 +++++++++++++---------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index 378915c13..00ed7f48b 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -405,8 +405,7 @@ TEST_CASE("Test vecN PropertyTableProperty") { for (int64_t i = 0; i < ivec3Property.size(); ++i) { REQUIRE(ivec3Property.getRaw(i) == values[static_cast(i)]); - REQUIRE(ivec3Property.get(i)); - REQUIRE(*ivec3Property.get(i) == ivec3Property.getRaw(i)); + REQUIRE(ivec3Property.get(i) == ivec3Property.getRaw(i)); } } @@ -1012,8 +1011,7 @@ TEST_CASE("Test boolean PropertyTableProperty") { for (int64_t i = 0; i < boolProperty.size(); ++i) { bool expectedValue = expected[static_cast(i)]; REQUIRE(boolProperty.getRaw(i) == expectedValue); - REQUIRE(boolProperty.get(i)); - REQUIRE(*boolProperty.get(i) == expectedValue); + REQUIRE(boolProperty.get(i) == expectedValue); } } @@ -1097,8 +1095,7 @@ TEST_CASE("Test string PropertyTableProperty") { REQUIRE(stringProperty.status() == PropertyTablePropertyViewStatus::Valid); for (size_t i = 0; i < expected.size(); ++i) { REQUIRE(stringProperty.getRaw(static_cast(i)) == expected[i]); - REQUIRE(stringProperty.get(i)); - REQUIRE(*stringProperty.get(i) == expected[i]); + REQUIRE(stringProperty.get(static_cast(i)) == expected[i]); } } @@ -1224,6 +1221,7 @@ TEST_CASE("Test fixed-length scalar array") { PropertyArrayView array = arrayProperty.getRaw(i); auto maybeArray = arrayProperty.get(i); REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { REQUIRE(array[j] == values[static_cast(i * 3 + j)]); REQUIRE((*maybeArray)[j] == array[j]); @@ -1354,6 +1352,7 @@ TEST_CASE("Test fixed-length scalar array (normalized)") { PropertyArrayView array = arrayProperty.getRaw(i); auto maybeArray = arrayProperty.get(i); REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { REQUIRE(array[j] == values[static_cast(i * 3 + j)]); REQUIRE((*maybeArray)[j] == normalize(array[j])); @@ -2011,12 +2010,12 @@ TEST_CASE("Test variable-length vecN array") { property.getRaw(static_cast(i)); REQUIRE(array.size() == static_cast(expected[i].size())); - auto maybeArray = property.get(i); + auto maybeArray = property.get(static_cast(i)); REQUIRE(maybeArray); for (size_t j = 0; j < expected[i].size(); ++j) { auto value = array[static_cast(j)]; REQUIRE(expected[i][j] == value); - REQUIRE((*maybeArray)[j] == value); + REQUIRE((*maybeArray)[static_cast(j)] == value); } } } @@ -2186,12 +2185,12 @@ TEST_CASE("Test variable-length vecN array (normalized)") { property.getRaw(static_cast(i)); REQUIRE(array.size() == static_cast(expected[i].size())); - auto maybeArray = property.get(i); + auto maybeArray = property.get(static_cast(i)); REQUIRE(maybeArray); for (size_t j = 0; j < expected[i].size(); ++j) { auto value = array[static_cast(j)]; REQUIRE(expected[i][j] == value); - REQUIRE((*maybeArray)[j] == normalize(value)); + REQUIRE((*maybeArray)[static_cast(j)] == normalize(value)); } } } @@ -2431,6 +2430,7 @@ TEST_CASE("Test fixed-length matN array (normalized)") { PropertyArrayView array = arrayProperty.getRaw(i); auto maybeArray = arrayProperty.get(i); REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { REQUIRE(array[j] == values[static_cast(i * 2 + j)]); REQUIRE((*maybeArray)[j] == normalize(array[j])); @@ -2587,12 +2587,12 @@ TEST_CASE("Test variable-length matN array") { property.getRaw(static_cast(i)); REQUIRE(array.size() == static_cast(expected[i].size())); - auto maybeArray = property.get(i); + auto maybeArray = property.get(static_cast(i)); REQUIRE(maybeArray); for (size_t j = 0; j < expected[i].size(); ++j) { auto value = array[static_cast(j)]; REQUIRE(expected[i][j] == value); - REQUIRE((*maybeArray)[j] == value); + REQUIRE((*maybeArray)[static_cast(j)] == value); } } } @@ -2782,9 +2782,10 @@ TEST_CASE("Test variable-length matN array (normalized)") { for (size_t i = 0; i < expected.size(); ++i) { PropertyArrayView array = property.getRaw(static_cast(i)); + REQUIRE(array.size() == static_cast(expected[i].size())); + auto maybeArray = property.get(i); REQUIRE(maybeArray); - REQUIRE(array.size() == static_cast(expected[i].size())); for (size_t j = 0; j < expected[i].size(); ++j) { auto value = array[static_cast(j)]; REQUIRE(expected[i][j] == value); @@ -2875,6 +2876,7 @@ TEST_CASE("Test fixed-length boolean array") { PropertyArrayView array = boolArrayProperty.getRaw(i); auto maybeArray = boolArrayProperty.get(i); REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { REQUIRE(array[j] == expected[static_cast(i * 3 + j)]); REQUIRE((*maybeArray)[j] == array[j]); @@ -3004,12 +3006,12 @@ TEST_CASE("Test variable-length boolean array") { boolArrayProperty.getRaw(static_cast(i)); REQUIRE(array.size() == static_cast(expected[i].size())); - auto maybeArray = boolArrayProperty.get(i); + auto maybeArray = boolArrayProperty.get(static_cast(i)); REQUIRE(maybeArray); for (size_t j = 0; j < expected[i].size(); ++j) { auto value = array[static_cast(j)]; REQUIRE(expected[i][j] == value); - REQUIRE((*maybeArray)[j] == value); + REQUIRE((*maybeArray)[static_cast(j)] == value); } } } @@ -4645,6 +4647,7 @@ TEST_CASE("Test callback for scalar array PropertyTableProperty") { PropertyArrayView array = propertyValue.getRaw(i); auto maybeArray = propertyValue.get(i); REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { REQUIRE(array[j] == values[static_cast(i * 3 + j)]); REQUIRE((*maybeArray)[j] == array[j]); @@ -4720,6 +4723,7 @@ TEST_CASE("Test callback for scalar array PropertyTableProperty (normalized)") { PropertyArrayView array = propertyValue.getRaw(i); auto maybeArray = propertyValue.get(i); REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { REQUIRE(array[j] == values[static_cast(i * 3 + j)]); REQUIRE((*maybeArray)[j] == normalize(array[j])); @@ -5066,6 +5070,7 @@ TEST_CASE("Test callback for boolean array PropertyTableProperty") { PropertyArrayView array = propertyValue.getRaw(i); auto maybeArray = propertyValue.get(i); REQUIRE(maybeArray); + for (int64_t j = 0; j < array.size(); ++j) { REQUIRE(array[j] == expected[static_cast(i * 3 + j)]); REQUIRE((*maybeArray)[j] == array[j]); From 36337303b1d7d60b490a4ff78ebe20ef48246596 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 28 Aug 2023 10:49:18 -0400 Subject: [PATCH 099/121] Fix sign conversion --- CesiumGltf/test/TestPropertyTableView.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index 00ed7f48b..b3c4e33ef 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -2784,12 +2784,12 @@ TEST_CASE("Test variable-length matN array (normalized)") { property.getRaw(static_cast(i)); REQUIRE(array.size() == static_cast(expected[i].size())); - auto maybeArray = property.get(i); + auto maybeArray = property.get(static_cast(i)); REQUIRE(maybeArray); for (size_t j = 0; j < expected[i].size(); ++j) { auto value = array[static_cast(j)]; REQUIRE(expected[i][j] == value); - REQUIRE((*maybeArray)[j] == normalize(value)); + REQUIRE((*maybeArray)[static_cast(j)] == normalize(value)); } } } From 7f13e1c3f4f1adae84fbd5d7e827cb810edd47cf Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 28 Aug 2023 11:21:10 -0400 Subject: [PATCH 100/121] Another CI fix --- CesiumGltf/test/TestPropertyTexturePropertyView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index 2450c926f..87dea27b2 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -485,7 +485,7 @@ void checkNormalizedTextureArrayValues( auto expectedValue = *(expectedTransformed[i]); REQUIRE(maybeValue->size() == static_cast(expectedValue.size())); for (int64_t j = 0; j < maybeValue->size(); j++) { - REQUIRE((*maybeValue)[j] == expectedValue[j]); + REQUIRE((*maybeValue)[j] == expectedValue[static_cast(j)]); } } } From f51012e6023be5b54421412c73bf2f18b9ebe95f Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 28 Aug 2023 13:18:51 -0400 Subject: [PATCH 101/121] Fix documentation and test --- .../CesiumGltf/PropertyTexturePropertyView.h | 3 +-- .../include/CesiumGltf/PropertyTextureView.h | 21 +++++++++---------- .../test/TestPropertyTexturePropertyView.cpp | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 70ff28ce6..821e3932d 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -7,7 +7,6 @@ #include "CesiumGltf/PropertyView.h" #include "CesiumGltf/Sampler.h" -#include #include #include #include @@ -228,7 +227,7 @@ inline double applySamplerWrapT(const double v, const int32_t wrapT) { } /** - * @brief A view of the non-normalized data specified by a {@link PropertyTextureProperty}. + * @brief A view of the data specified by a {@link PropertyTextureProperty}. * * Provides utilities to sample the property texture property using texture * coordinates. diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 8b13e84b2..39e65b077 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -84,16 +84,15 @@ class PropertyTextureView { * * 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. + * be a scalar with a supported component type (int8_t, uint8_t, int16_t, + * uint16_t, int32_t, uint32_t, float), a glm vecN composed of one of the + * scalar types, or a PropertyArrayView containing one of the scalar types. * * If T does not match the type specified by the class property, this returns * an invalid PropertyTexturePropertyView. Likewise, if the value of - * Normalized - * does not match the value of {@ClassProperty::normalized} for that class property, - * this returns an invalid property view. Only types with integer components - * may be normalized. + * Normalized does not match the value of {@ClassProperty::normalized} for that + * class property, this returns an invalid property view. Only types with + * integer components may be normalized. * * @tparam T The C++ type corresponding to the type of the data retrieved. * @tparam Normalized Whether the property is normalized. Only applicable to @@ -125,10 +124,10 @@ class PropertyTextureView { * 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. + * {@link PropertyTexturePropertyView} retrieves the correct data. . T must + * be a scalar with a supported component type (int8_t, uint8_t, int16_t, + * uint16_t, int32_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 somehow invalid, an empty {@link PropertyTexturePropertyView} * with an error status will be passed to the callback. Otherwise, a valid diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index 87dea27b2..638c721a4 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -485,7 +485,7 @@ void checkNormalizedTextureArrayValues( auto expectedValue = *(expectedTransformed[i]); REQUIRE(maybeValue->size() == static_cast(expectedValue.size())); for (int64_t j = 0; j < maybeValue->size(); j++) { - REQUIRE((*maybeValue)[j] == expectedValue[static_cast(j)]); + REQUIRE((*maybeValue)[j] == expectedValue[static_cast(j)]); } } } From 763271ac7468c749383399c07a1842022d6305a0 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 28 Aug 2023 13:55:55 -0400 Subject: [PATCH 102/121] Add missing const int to source file --- CesiumGltf/src/PropertyView.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/CesiumGltf/src/PropertyView.cpp b/CesiumGltf/src/PropertyView.cpp index 030469450..0f62eeed7 100644 --- a/CesiumGltf/src/PropertyView.cpp +++ b/CesiumGltf/src/PropertyView.cpp @@ -10,6 +10,7 @@ const PropertyViewStatusType PropertyViewStatus::ErrorTypeMismatch; const PropertyViewStatusType PropertyViewStatus::ErrorComponentTypeMismatch; const PropertyViewStatusType PropertyViewStatus::ErrorArrayTypeMismatch; const PropertyViewStatusType PropertyViewStatus::ErrorInvalidNormalization; +const PropertyViewStatusType PropertyViewStatus::ErrorNormalizationMismatch; const PropertyViewStatusType PropertyViewStatus::ErrorInvalidOffset; const PropertyViewStatusType PropertyViewStatus::ErrorInvalidScale; const PropertyViewStatusType PropertyViewStatus::ErrorInvalidMax; From a8f46ab0c5cb630227a457af5400130391d612fc Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 28 Aug 2023 17:49:51 -0400 Subject: [PATCH 103/121] Add PropertyAttributeView and PropertyAttributePropertyView --- CesiumGltf/include/CesiumGltf/AccessorView.h | 2 +- .../PropertyAttributePropertyView.h | 364 ++++++++++ .../CesiumGltf/PropertyAttributeView.h | 686 ++++++++++++++++++ .../include/CesiumGltf/PropertyTableView.h | 26 +- .../CesiumGltf/PropertyTexturePropertyView.h | 4 +- .../include/CesiumGltf/PropertyTextureView.h | 26 +- CesiumGltf/include/CesiumGltf/PropertyType.h | 2 + CesiumGltf/include/CesiumGltf/PropertyView.h | 84 +-- CesiumGltf/src/PropertyAttributeView.cpp | 94 +++ CesiumGltf/src/PropertyType.cpp | 11 + CesiumGltf/test/TestPropertyType.cpp | 44 ++ 11 files changed, 1261 insertions(+), 82 deletions(-) create mode 100644 CesiumGltf/include/CesiumGltf/PropertyAttributePropertyView.h create mode 100644 CesiumGltf/include/CesiumGltf/PropertyAttributeView.h create mode 100644 CesiumGltf/src/PropertyAttributeView.cpp diff --git a/CesiumGltf/include/CesiumGltf/AccessorView.h b/CesiumGltf/include/CesiumGltf/AccessorView.h index b693a4df4..3d73bf2e7 100644 --- a/CesiumGltf/include/CesiumGltf/AccessorView.h +++ b/CesiumGltf/include/CesiumGltf/AccessorView.h @@ -403,7 +403,7 @@ createAccessorView( } // TODO Print a warning here??? return callback(AccessorView>( - AccessorViewStatus::InvalidComponentType)); + AccessorViewStatus::InvalidType)); } } // namespace CesiumImpl diff --git a/CesiumGltf/include/CesiumGltf/PropertyAttributePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyAttributePropertyView.h new file mode 100644 index 000000000..7439758da --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/PropertyAttributePropertyView.h @@ -0,0 +1,364 @@ +#pragma once + +#include "CesiumGltf/AccessorView.h" +#include "CesiumGltf/PropertyAttributeProperty.h" +#include "CesiumGltf/PropertyTransformations.h" +#include "CesiumGltf/PropertyTypeTraits.h" +#include "CesiumGltf/PropertyView.h" + +#include +#include +#include + +namespace CesiumGltf { +/** + * @brief Indicates the status of a property attribute property view. + * + * The {@link PropertyAttributePropertyView} 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 PropertyAttributePropertyViewStatus : public PropertyViewStatus { +public: + /** + * @brief This property view was initialized from an invalid + * {@link PropertyAttribute}. + */ + static const int ErrorInvalidPropertyAttribute = 13; + + /** + * @brief This property view is associated with a {@link ClassProperty} of an + * unsupported type. + */ + static const int ErrorUnsupportedProperty = 14; + + /** + * @brief This property view was initialized with a primitive that does not + * contain the specified attribute. + */ + static const int ErrorMissingAttribute = 15; + + /** + * @brief This property view's attribute does not have a valid accessor index. + */ + static const int ErrorInvalidAccessor = 16; + + /** + * @brief This property view's type does not match the type of the accessor it + * uses. + */ + static const int ErrorAccessorTypeMismatch = 17; + + /** + * @brief This property view's component type does not match the type of the + * accessor it uses. + */ + static const int ErrorAccessorComponentTypeMismatch = 18; + + /** + * @brief This property view's normalization does not match the normalization + * of the accessor it uses. + */ + static const int ErrorAccessorNormalizationMismatch = 19; + + /** + * @brief This property view uses an accessor that does not have a valid + * buffer view index. + */ + static const int ErrorInvalidBufferView = 20; + + /** + * @brief This property view uses a buffer view that does not have a valid + * buffer index. + */ + static const int ErrorInvalidBuffer = 21; + + /** + * @brief This property view uses an accessor that points outside the bounds + * of its target buffer view. + */ + static const PropertyViewStatusType ErrorAccessorOutOfBounds = 22; + + /** + * @brief This property view uses a buffer view that points outside the bounds + * of its target buffer. + */ + static const PropertyViewStatusType ErrorBufferViewOutOfBounds = 23; +}; + +/** + * @brief A view of the data specified by a {@link PropertyAttributeProperty}. + * + * Ideally, property attribute properties can be initialized as vertex + * attributes in the target rendering context. However, some runtime engines do + * not allow custom vertex attributes. To compensate, this view can be used to + * sample the property attributes property via vertex index. + * + * @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 +class PropertyAttributePropertyView; + +/** + * @brief A view of the non-normalized data specified by a + * {@link PropertyAttributeProperty}. + * + * Ideally, property attribute properties can be initialized as vertex + * attributes in the target rendering context. However, some runtime engines do + * not allow custom vertex attributes. This view can be used instead to sample + * the property attributes property via vertex index. + * + * @tparam ElementType The type of the elements represented in the property view + */ +template +class PropertyAttributePropertyView + : public PropertyView { +public: + /** + * @brief Constructs an invalid instance for a non-existent property. + */ + PropertyAttributePropertyView() noexcept + : PropertyView(), _accessor{} {} + + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The code from {@link PropertyAttributePropertyViewStatus} indicating the error with the property. + */ + PropertyAttributePropertyView(PropertyViewStatusType status) noexcept + : PropertyView(status), _accessor{} { + assert( + this->_status != PropertyAttributePropertyViewStatus::Valid && + "An empty property view should not be constructed with a valid status"); + } + + /** + * @brief Construct a view of the data specified by a {@link PropertyAttributeProperty}. + * + * @param property The {@link PropertyAttributeProperty} + * @param classProperty The {@link ClassProperty} this property conforms to. + * @param accsesorView The {@link AccessorView} for the data that this property is + * associated with. + */ + PropertyAttributePropertyView( + const PropertyAttributeProperty& property, + const ClassProperty& classProperty, + const AccessorView& accessorView) noexcept + : PropertyView(classProperty, property), + _accessor{accessorView} {} + + /** + * @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. + * + * 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 index The vertex index. + * + * @return The value of the property for the given vertex, or std::nullopt if + * it matches the "no data" value + */ + std::optional get(int64_t index) const noexcept { + ElementType value = getRaw(index); + + if (value == this->noData()) { + return this->defaultValue(); + } + + return transformValue(value, this->offset(), this->scale()); + } + + /** + * @brief Gets the raw value of the property for the given vertex index. + * + * 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 index The vertex index. + * + * @return The value of the property for the given vertex. + */ + ElementType getRaw(int64_t index) const noexcept { + assert( + this->_status == PropertyAttributePropertyViewStatus::Valid && + "Check the status() first to make sure view is valid"); + assert( + size() > 0 && + "Check the size() of the view to make sure it's not empty"); + assert(index >= 0 && "index must be non-negative"); + assert(index < size() && "index must be less than size"); + + return _accessor[index]; + } + + /** + * @brief Get the number of elements in this PropertyAttributePropertyView. + * If the view is valid, this returns the count of the elements in the + * attribute's accessor. Otherwise, this returns 0. + * + * @return The number of elements in this PropertyAttributePropertyView. + */ + int64_t size() const noexcept { + if (this->_status != PropertyAttributePropertyViewStatus::Valid) { + return 0; + } + + return _accessor.size(); + } + +private: + AccessorView _accessor; +}; + +/** + * @brief A view of the normalized data specified by a + * {@link PropertyAttributeProperty}. + * + * Ideally, property attribute properties can be initialized as vertex + * attributes in the target rendering context. However, some runtime engines do + * not allow custom vertex attributes. This view can be used instead to sample + * the property attributes property via vertex index. + * + * @tparam ElementType The type of the elements represented in the property view + */ +template +class PropertyAttributePropertyView + : public PropertyView { +private: + using NormalizedType = typename TypeToNormalizedType::type; + +public: + /** + * @brief Constructs an invalid instance for a non-existent property. + */ + PropertyAttributePropertyView() noexcept + : PropertyView(), _accessor{} {} + + /** + * @brief Constructs an invalid instance for an erroneous property. + * + * @param status The code from {@link PropertyAttributePropertyViewStatus} indicating the error with the property. + */ + PropertyAttributePropertyView(PropertyViewStatusType status) noexcept + : PropertyView(status), _accessor{} { + assert( + this->_status != PropertyAttributePropertyViewStatus::Valid && + "An empty property view should not be constructed with a valid status"); + } + + /** + * @brief Construct a view of the data specified by a {@link PropertyAttributeProperty}. + * + * @param property The {@link PropertyAttributeProperty} + * @param classProperty The {@link ClassProperty} this property conforms to. + * @param accsesorView The {@link AccessorView} for the data that this property is + * associated with. + */ + PropertyAttributePropertyView( + const PropertyAttributeProperty& property, + const ClassProperty& classProperty, + const AccessorView& accessorView) noexcept + : PropertyView(classProperty, property), + _accessor{accessorView} {} + + /** + * @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. + * + * 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 index The vertex index. + * + * @return The value of the property for the given vertex, or std::nullopt if + * it matches the "no data" value + */ + std::optional get(int64_t index) const noexcept { + ElementType value = getRaw(index); + + if (value == this->noData()) { + return this->defaultValue(); + } + + if constexpr (IsMetadataScalar::value) { + return transformValue( + normalize(value), + this->offset(), + this->scale()); + } + + if constexpr (IsMetadataVecN::value) { + constexpr glm::length_t N = ElementType::length(); + using T = typename ElementType::value_type; + using NormalizedT = typename NormalizedType::value_type; + return transformValue>( + normalize(value), + this->offset(), + this->scale()); + } + + if constexpr (IsMetadataMatN::value) { + constexpr glm::length_t N = ElementType::length(); + using T = typename ElementType::value_type; + using NormalizedT = typename NormalizedType::value_type; + return transformValue>( + normalize(value), + this->offset(), + this->scale()); + } + } + + /** + * @brief Gets the raw value of the property for the given vertex index. + * + * 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 index The vertex index. + * + * @return The value of the property for the given vertex. + */ + ElementType getRaw(int64_t index) const noexcept { + assert( + this->_status == PropertyAttributePropertyViewStatus::Valid && + "Check the status() first to make sure view is valid"); + assert( + size() > 0 && + "Check the size() of the view to make sure it's not empty"); + assert(index >= 0 && "index must be non-negative"); + assert(index < size() && "index must be less than size"); + + return _accessor[index]; + } + + /** + * @brief Get the number of elements in this PropertyAttributePropertyView. + * If the view is valid, this returns the count of the elements in the + * attribute's accessor. Otherwise, this returns 0. + * + * @return The number of elements in this PropertyAttributePropertyView. + */ + int64_t size() const noexcept { + if (this->_status != PropertyAttributePropertyViewStatus::Valid) { + return 0; + } + + return _accessor.size(); + } + +private: + AccessorView _accessor; +}; + +} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h b/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h new file mode 100644 index 000000000..eb76620c5 --- /dev/null +++ b/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h @@ -0,0 +1,686 @@ +#pragma once + +#include "CesiumGltf/Class.h" +#include "CesiumGltf/ClassProperty.h" +#include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" +#include "CesiumGltf/PropertyAttribute.h" +#include "CesiumGltf/PropertyAttributePropertyView.h" +#include "Model.h" + +namespace CesiumGltf { +/** + * @brief Indicates the status of a property attribute view. + * + * The {@link PropertyAttributeView} constructor always completes successfully. + * However it may not always reflect the actual content of the + * {@link PropertyAttribute}. This enumeration provides the reason. + */ +enum class PropertyAttributeViewStatus { + /** + * @brief This property attribute view is valid and ready to use. + */ + Valid, + + /** + * @brief The glTF is missing the EXT_structural_metadata extension. + */ + ErrorMissingMetadataExtension, + + /** + * @brief The glTF EXT_structural_metadata extension doesn't contain a schema. + */ + ErrorMissingSchema, + + /** + * @brief The property attribute's specified class could not be found in the + * extension. + */ + ErrorClassNotFound +}; + +PropertyType getAccessorTypeAsPropertyType(const Accessor& accessor); + +PropertyComponentType +getAccessorComponentTypeAsPropertyComponentType(const Accessor& accessor); + +/** + * @brief A view on a {@link PropertyAttribute}. + * + * This should be used to get a {@link PropertyAttributePropertyView} of a property + * in the property attribute. It will validate the EXT_structural_metadata + * format and ensure {@link PropertyAttributePropertyView} does not access data out + * of bounds. + */ +class PropertyAttributeView { +public: + /** + * @brief Construct a PropertyAttributeView. + * + * @param model The glTF that contains the property attribute's data. + * @param propertyAttribute The {@link PropertyAttribute} from which + * the view will retrieve data. + */ + PropertyAttributeView( + const Model& model, + const PropertyAttribute& propertyAttribute) noexcept; + + /** + * @brief Gets the status of this property attribute view. + * + * Indicates whether the view accurately reflects the property attribute's + * data, or whether an error occurred. + */ + PropertyAttributeViewStatus status() const noexcept { return this->_status; } + + /** + * @brief Finds the {@link ClassProperty} that + * describes the type information of the property with the specified name. + * @param propertyName The name of the property to retrieve the class for. + * @return A pointer to the {@link ClassProperty}. + * Return nullptr if the PropertyAttributeView is invalid or if no class + * property was found. + */ + const ClassProperty* getClassProperty(const std::string& propertyName) const; + + /** + * @brief Gets a {@link PropertyAttributePropertyView} that views the data of a + * property stored in the {@link PropertyAttribute}. + * + * This method will validate the EXT_structural_metadata format to ensure + * {@link PropertyAttributePropertyView} retrieves the correct data. T must + * be a scalar with a supported component type (int8_t, uint8_t, int16_t, + * uint16_t, uint32_t, float), a glm vecN composed of one of the scalar types, + * or a glm matN containing one of the scalar types. + * + * If T does not match the type specified by the class property, this returns + * an invalid PropertyAttributePropertyView. Likewise, if the value of + * Normalized does not match the value of {@ClassProperty::normalized} for that + * class property, this returns an invalid property view. Only types with + * integer components may be normalized. + * + * @tparam T The C++ type corresponding to the type of the data retrieved. + * @tparam Normalized Whether the property is normalized. Only applicable to + * types with integer components. + * @param primitive The target primitive + * @param propertyName The name of the property to retrieve data from + * @return A {@link PropertyAttributePropertyView} of the property. If no valid + * property is found, the property view will be invalid. + */ + template + PropertyAttributePropertyView getPropertyView( + const std::string& propertyName, + const MeshPrimitive& primitive) const { + if (this->_status != PropertyAttributeViewStatus::Valid) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorInvalidPropertyAttribute); + } + const ClassProperty* pClassProperty = getClassProperty(propertyName); + if (!pClassProperty) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorNonexistentProperty); + } + + if constexpr ( + IsMetadataArray::value || IsMetadataBoolean::value || + IsMetadataString::value) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty); + } + + return getPropertyViewImpl( + propertyName, + *pClassProperty, + primitive); + } + + /** + * @brief Gets a {@link PropertyAttributePropertyView} through a callback that accepts a + * property name and a {@link PropertyAttributePropertyView} that views the data + * of the property with the specified name. + * + * This method will validate the EXT_structural_metadata format to ensure + * {@link PropertyAttributePropertyView} retrieves the correct data. T must + * be a scalar with a supported component type (int8_t, uint8_t, int16_t, + * uint16_t, uint32_t, float), a glm vecN composed of one of the scalar types, + * or a glm matN containing one of the scalar types. + * + * If the property is somehow invalid, an empty {@link PropertyAttributePropertyView} + * 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 PropertyAttributePropertyView} + */ + template + void getPropertyView( + const std::string& propertyName, + const MeshPrimitive& primitive, + Callback&& callback) const { + if (this->_status != PropertyAttributeViewStatus::Valid) { + callback( + propertyName, + PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus:: + ErrorInvalidPropertyAttribute)); + return; + } + + const ClassProperty* pClassProperty = getClassProperty(propertyName); + if (!pClassProperty) { + callback( + propertyName, + PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorNonexistentProperty)); + return; + } + + PropertyType type = convertStringToPropertyType(pClassProperty->type); + PropertyComponentType componentType = PropertyComponentType::None; + if (pClassProperty->componentType) { + componentType = + convertStringToPropertyComponentType(*pClassProperty->componentType); + } + + bool normalized = pClassProperty->normalized; + if (normalized && !isPropertyComponentTypeInteger(componentType)) { + callback( + propertyName, + PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorInvalidNormalization)); + return; + } + + if (type == PropertyType::Scalar) { + if (normalized) { + getScalarPropertyViewImpl( + propertyName, + *pClassProperty, + primitive, + componentType, + std::forward(callback)); + } else { + getScalarPropertyViewImpl( + propertyName, + *pClassProperty, + primitive, + componentType, + std::forward(callback)); + } + return; + } + + if (isPropertyTypeVecN(type)) { + if (normalized) { + getVecNPropertyViewImpl( + propertyName, + *pClassProperty, + primitive, + type, + componentType, + std::forward(callback)); + } else { + getVecNPropertyViewImpl( + propertyName, + *pClassProperty, + primitive, + type, + componentType, + std::forward(callback)); + } + return; + } + + if (isPropertyTypeMatN(type)) { + if (normalized) { + getMatNPropertyViewImpl( + propertyName, + *pClassProperty, + primitive, + type, + componentType, + std::forward(callback)); + } else { + getMatNPropertyViewImpl( + propertyName, + *pClassProperty, + primitive, + type, + componentType, + std::forward(callback)); + } + return; + } + + callback( + propertyName, + PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty)); + return; + } + + /** + * @brief Iterates over each property in the {@link PropertyAttribute} with a callback + * that accepts a property name and a {@link PropertyAttributePropertyView} to view + * the data stored in the {@link PropertyAttributeProperty}. + * + * This method will validate the EXT_structural_metadata format to ensure + * {@link PropertyAttributePropertyView} 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 PropertyAttributePropertyView} 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 PropertyAttributePropertyView} + */ + template + void + forEachProperty(const MeshPrimitive& primitive, Callback&& callback) const { + for (const auto& property : this->_pClass->properties) { + getPropertyView( + property.first, + primitive, + std::forward(callback)); + } + } + +private: + template + PropertyAttributePropertyView getPropertyViewImpl( + const std::string& propertyName, + const ClassProperty& classProperty, + const MeshPrimitive& primitive) const { + auto propertyAttributePropertyIter = + _pPropertyAttribute->properties.find(propertyName); + if (propertyAttributePropertyIter == + _pPropertyAttribute->properties.end()) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorNonexistentProperty); + } + + const PropertyAttributeProperty& propertyAttributeProperty = + propertyAttributePropertyIter->second; + + return createPropertyView( + classProperty, + propertyAttributeProperty, + primitive); + } + + template + void getScalarPropertyViewImpl( + const std::string& propertyName, + const ClassProperty& classProperty, + const MeshPrimitive& primitive, + PropertyComponentType componentType, + Callback&& callback) const { + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl( + propertyName, + classProperty, + primitive)); + return; + case PropertyComponentType::Uint8: + callback( + propertyName, + getPropertyViewImpl( + propertyName, + classProperty, + primitive)); + return; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl( + propertyName, + classProperty, + primitive)); + return; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Uint32: + callback( + propertyName, + getPropertyViewImpl( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Float32: + callback( + propertyName, + getPropertyViewImpl( + propertyName, + classProperty, + primitive)); + break; + default: + callback( + propertyName, + PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty)); + break; + } + } + + template + void getVecNPropertyViewImpl( + const std::string& propertyName, + const ClassProperty& classProperty, + const MeshPrimitive& primitive, + PropertyComponentType componentType, + Callback&& callback) const { + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl, Normalized>( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Uint8: + callback( + propertyName, + getPropertyViewImpl, Normalized>( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl, Normalized>( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl, Normalized>( + propertyName, + classProperty, + primitive)); + break; + default: + case PropertyComponentType::Uint32: + callback( + propertyName, + getPropertyViewImpl, Normalized>( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Float32: + callback( + propertyName, + getPropertyViewImpl, false>( + propertyName, + classProperty, + primitive)); + break; + default: + callback( + propertyName, + PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty)); + break; + } + } + + template + void getVecNPropertyViewImpl( + const std::string& propertyName, + const ClassProperty& classProperty, + const MeshPrimitive& primitive, + PropertyType type, + PropertyComponentType componentType, + Callback&& callback) const { + const glm::length_t N = getDimensionsFromPropertyType(type); + switch (N) { + case 2: + getVecNPropertyViewImpl( + propertyName, + classProperty, + primitive, + componentType, + std::forward(callback)); + break; + case 3: + getVecNPropertyViewImpl( + propertyName, + classProperty, + primitive, + componentType, + std::forward(callback)); + break; + case 4: + getVecNPropertyViewImpl( + propertyName, + classProperty, + primitive, + componentType, + std::forward(callback)); + break; + default: + callback( + propertyName, + PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorTypeMismatch)); + break; + } + } + + template + void getMatNPropertyViewImpl( + const std::string& propertyName, + const ClassProperty& classProperty, + const MeshPrimitive& primitive, + PropertyComponentType componentType, + Callback&& callback) const { + switch (componentType) { + case PropertyComponentType::Int8: + callback( + propertyName, + getPropertyViewImpl, Normalized>( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Uint8: + callback( + propertyName, + getPropertyViewImpl, Normalized>( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Int16: + callback( + propertyName, + getPropertyViewImpl, Normalized>( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Uint16: + callback( + propertyName, + getPropertyViewImpl, Normalized>( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Uint32: + callback( + propertyName, + getPropertyViewImpl, Normalized>( + propertyName, + classProperty, + primitive)); + break; + case PropertyComponentType::Float32: + callback( + propertyName, + getPropertyViewImpl, false>( + propertyName, + classProperty, + primitive)); + break; + default: + callback( + propertyName, + PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty)); + break; + } + } + + template + void getMatNPropertyViewImpl( + const std::string& propertyName, + const ClassProperty& classProperty, + const MeshPrimitive& primitive, + PropertyType type, + PropertyComponentType componentType, + Callback&& callback) const { + glm::length_t N = getDimensionsFromPropertyType(type); + switch (N) { + case 2: + getMatNPropertyViewImpl( + propertyName, + classProperty, + primitive, + componentType, + std::forward(callback)); + break; + case 3: + getMatNPropertyViewImpl( + propertyName, + classProperty, + primitive, + componentType, + std::forward(callback)); + break; + case 4: + getMatNPropertyViewImpl( + propertyName, + classProperty, + primitive, + componentType, + std::forward(callback)); + break; + default: + callback( + propertyName, + PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorTypeMismatch)); + break; + } + } + + template + PropertyAttributePropertyView createPropertyView( + const ClassProperty& classProperty, + const PropertyAttributeProperty& propertyAttributeProperty, + const MeshPrimitive& primitive) const { + const PropertyType type = convertStringToPropertyType(classProperty.type); + if (TypeToPropertyType::value != type) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + } + + const PropertyComponentType componentType = + convertStringToPropertyComponentType( + classProperty.componentType.value_or("")); + if (TypeToPropertyType::component != componentType) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + } + + if (classProperty.normalized != Normalized) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); + } + + if (primitive.attributes.find(propertyAttributeProperty.attribute) == + primitive.attributes.end()) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorMissingAttribute); + } + + const Accessor* pAccessor = _pModel->getSafe( + &_pModel->accessors, + primitive.attributes.at(propertyAttributeProperty.attribute)); + if (!pAccessor) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorInvalidAccessor); + } + + if (getAccessorTypeAsPropertyType(*pAccessor) != type) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorAccessorTypeMismatch); + } + + if (getAccessorComponentTypeAsPropertyComponentType(*pAccessor) != + componentType) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus:: + ErrorAccessorComponentTypeMismatch); + } + + if (pAccessor->normalized != Normalized) { + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus:: + ErrorAccessorNormalizationMismatch); + } + + AccessorView accessorView = AccessorView(*_pModel, *pAccessor); + if (accessorView.status() != AccessorViewStatus::Valid) { + switch (accessorView.status()) { + case AccessorViewStatus::InvalidBufferViewIndex: + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorInvalidBufferView); + case AccessorViewStatus::InvalidBufferIndex: + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorInvalidBuffer); + case AccessorViewStatus::BufferViewTooSmall: + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorAccessorOutOfBounds); + case AccessorViewStatus::BufferTooSmall: + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorBufferViewOutOfBounds); + default: + return PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorInvalidAccessor); + } + } + + return PropertyAttributePropertyView( + propertyAttributeProperty, + classProperty, + accessorView); + } + + const Model* _pModel; + const PropertyAttribute* _pPropertyAttribute; + const Class* _pClass; + + PropertyAttributeViewStatus _status; +}; +} // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h index bd18c705e..b92e991ba 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -184,25 +184,13 @@ class PropertyTableView { } bool normalized = pClassProperty->normalized; - if (normalized) { - switch (componentType) { - case PropertyComponentType::Int8: - case PropertyComponentType::Uint8: - case PropertyComponentType::Int16: - case PropertyComponentType::Uint16: - case PropertyComponentType::Int32: - case PropertyComponentType::Uint32: - case PropertyComponentType::Int64: - case PropertyComponentType::Uint64: - break; - default: - // Only integer components may be normalized. - callback( - propertyName, - PropertyTablePropertyView( - PropertyTablePropertyViewStatus::ErrorInvalidNormalization)); - return; - } + if (normalized && !isPropertyComponentTypeInteger(componentType)) { + // Only integer components may be normalized. + callback( + propertyName, + PropertyTablePropertyView( + PropertyTablePropertyViewStatus::ErrorInvalidNormalization)); + return; } if (pClassProperty->array) { diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 821e3932d..4c0e856b0 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -190,7 +190,7 @@ assembleValueFromChannels(const std::vector& bytes) noexcept { } } -inline double applySamplerWrapS(const double u, const int32_t wrapS) { +inline double applySamplerWrapS(const double u, const int32_t wrapS) noexcept { if (wrapS == Sampler::WrapS::REPEAT) { double integral = 0; double fraction = std::modf(u, &integral); @@ -208,7 +208,7 @@ inline double applySamplerWrapS(const double u, const int32_t wrapS) { return glm::clamp(u, 0.0, 1.0); } -inline double applySamplerWrapT(const double v, const int32_t wrapT) { +inline double applySamplerWrapT(const double v, const int32_t wrapT) noexcept { if (wrapT == Sampler::WrapT::REPEAT) { double integral = 0; double fraction = std::modf(v, &integral); diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index 39e65b077..ed2546110 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -165,25 +165,13 @@ class PropertyTextureView { } bool normalized = pClassProperty->normalized; - if (normalized) { - switch (componentType) { - case PropertyComponentType::Int8: - case PropertyComponentType::Uint8: - case PropertyComponentType::Int16: - case PropertyComponentType::Uint16: - case PropertyComponentType::Int32: - case PropertyComponentType::Uint32: - case PropertyComponentType::Int64: - case PropertyComponentType::Uint64: - break; - default: - // Only integer components may be normalized. - callback( - propertyName, - PropertyTexturePropertyView( - PropertyTexturePropertyViewStatus::ErrorInvalidNormalization)); - return; - } + if (normalized && !isPropertyComponentTypeInteger(componentType)) { + // Only integer components may be normalized. + callback( + propertyName, + PropertyTexturePropertyView( + PropertyTexturePropertyViewStatus::ErrorInvalidNormalization)); + return; } if (pClassProperty->array) { diff --git a/CesiumGltf/include/CesiumGltf/PropertyType.h b/CesiumGltf/include/CesiumGltf/PropertyType.h index 8f1c8deff..6739ed620 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyType.h +++ b/CesiumGltf/include/CesiumGltf/PropertyType.h @@ -55,6 +55,8 @@ bool isPropertyTypeVecN(PropertyType type); bool isPropertyTypeMatN(PropertyType type); +bool isPropertyComponentTypeInteger(PropertyComponentType componentType); + glm::length_t getDimensionsFromPropertyType(PropertyType type); size_t getSizeOfComponentType(PropertyComponentType componentType); diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 4bc809cf4..5257de32b 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -1,4 +1,5 @@ #include "CesiumGltf/ClassProperty.h" +#include "CesiumGltf/PropertyAttributeProperty.h" #include "CesiumGltf/PropertyTableProperty.h" #include "CesiumGltf/PropertyTextureProperty.h" #include "CesiumGltf/PropertyTypeTraits.h" @@ -367,6 +368,22 @@ template class PropertyView { getNumericPropertyValues(property); } + /** + * @brief Constructs a property instance from a property attribute property + * and its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyAttributeProperty& property) + : PropertyView(classProperty) { + if (_status != PropertyViewStatus::Valid) { + return; + } + + // If the property has its own values, override the class-provided values. + getNumericPropertyValues(property); + } + public: /** * @brief Gets the status of this property view, indicating whether an error @@ -494,8 +511,11 @@ template class PropertyView { } } - using PropertyDefinitionType = std:: - variant; + using PropertyDefinitionType = std::variant< + ClassProperty, + PropertyTableProperty, + PropertyTextureProperty, + PropertyAttributeProperty>; /** * @brief Attempts to parse offset, scale, min, and max properties from the @@ -690,6 +710,22 @@ template class PropertyView { getNumericPropertyValues(property); } + /** + * @brief Constructs a property instance from a property attribute property + * and its class definition. + */ + PropertyView( + const ClassProperty& classProperty, + const PropertyAttributeProperty& property) + : PropertyView(classProperty) { + if (_status != PropertyViewStatus::Valid) { + return; + } + + // If the property has its own values, override the class-provided values. + getNumericPropertyValues(property); + } + public: /** * @brief Gets the status of this property view, indicating whether an error @@ -784,8 +820,11 @@ template class PropertyView { } } - using PropertyDefinitionType = std:: - variant; + using PropertyDefinitionType = std::variant< + ClassProperty, + PropertyTableProperty, + PropertyTextureProperty, + PropertyAttributeProperty>; /** * @brief Attempts to parse offset, scale, min, and max properties from the @@ -890,15 +929,6 @@ template <> class PropertyView { const PropertyTableProperty& /*property*/) : PropertyView(classProperty) {} - /** - * @brief Constructs a property instance from a property texture property and - * its class definition. - */ - PropertyView( - const ClassProperty& classProperty, - const PropertyTextureProperty& /*property*/) - : PropertyView(classProperty) {} - public: /** * @copydoc PropertyView::status @@ -1040,15 +1070,6 @@ template <> class PropertyView { const PropertyTableProperty& /*property*/) : PropertyView(classProperty) {} - /** - * @brief Constructs a property instance from a property texture property and - * its class definition. - */ - PropertyView( - const ClassProperty& classProperty, - const PropertyTextureProperty& /*property*/) - : PropertyView(classProperty) {} - public: /** * @copydoc PropertyView::status @@ -1624,7 +1645,6 @@ class PropertyView, true> { } // If the property has its own values, override the class-provided values. - getNumericPropertyValues(property); } @@ -1906,15 +1926,6 @@ template <> class PropertyView> { const PropertyTableProperty& /*property*/) : PropertyView(classProperty) {} - /** - * @brief Constructs a property instance from a property texture property - * and its class definition. - */ - PropertyView( - const ClassProperty& classProperty, - const PropertyTextureProperty& /*property*/) - : PropertyView(classProperty) {} - public: /** * @copydoc PropertyView::status @@ -2139,15 +2150,6 @@ template <> class PropertyView> { const PropertyTableProperty& /*property*/) : PropertyView(classProperty) {} - /** - * @brief Constructs a property instance from a property texture property - * and its class definition. - */ - PropertyView( - const ClassProperty& classProperty, - const PropertyTextureProperty& /*property*/) - : PropertyView(classProperty) {} - public: /** * @copydoc PropertyView::status diff --git a/CesiumGltf/src/PropertyAttributeView.cpp b/CesiumGltf/src/PropertyAttributeView.cpp new file mode 100644 index 000000000..331ddfe2f --- /dev/null +++ b/CesiumGltf/src/PropertyAttributeView.cpp @@ -0,0 +1,94 @@ +#include "CesiumGltf/PropertyAttributeView.h" + +namespace CesiumGltf { +PropertyType getAccessorTypeAsPropertyType(const Accessor& accessor) { + if (accessor.type == Accessor::Type::SCALAR) { + return PropertyType::Scalar; + } + if (accessor.type == Accessor::Type::VEC2) { + return PropertyType::Vec2; + } + if (accessor.type == Accessor::Type::VEC3) { + return PropertyType::Vec3; + } + if (accessor.type == Accessor::Type::VEC4) { + return PropertyType::Vec4; + } + if (accessor.type == Accessor::Type::MAT2) { + return PropertyType::Mat2; + } + if (accessor.type == Accessor::Type::MAT3) { + return PropertyType::Mat3; + } + if (accessor.type == Accessor::Type::MAT4) { + return PropertyType::Mat4; + } + + return PropertyType::Invalid; +} + +PropertyComponentType +getAccessorComponentTypeAsPropertyComponentType(const Accessor& accessor) { + switch (accessor.componentType) { + case Accessor::ComponentType::BYTE: + return PropertyComponentType::Int8; + case Accessor::ComponentType::UNSIGNED_BYTE: + return PropertyComponentType::Uint8; + case Accessor::ComponentType::SHORT: + return PropertyComponentType::Int16; + case Accessor::ComponentType::UNSIGNED_SHORT: + return PropertyComponentType::Uint16; + case Accessor::ComponentType::UNSIGNED_INT: + return PropertyComponentType::Uint32; + case Accessor::ComponentType::FLOAT: + return PropertyComponentType::Float32; + default: + return PropertyComponentType::None; + } +} + +PropertyAttributeView::PropertyAttributeView( + const Model& model, + const PropertyAttribute& propertyAttribute) noexcept + : _pModel(&model), + _pPropertyAttribute(&propertyAttribute), + _pClass(nullptr), + _status() { + const ExtensionModelExtStructuralMetadata* pMetadata = + model.getExtension(); + + if (!pMetadata) { + this->_status = PropertyAttributeViewStatus::ErrorMissingMetadataExtension; + return; + } + + if (!pMetadata->schema) { + this->_status = PropertyAttributeViewStatus::ErrorMissingSchema; + return; + } + + const auto& classIt = + pMetadata->schema->classes.find(propertyAttribute.classProperty); + if (classIt == pMetadata->schema->classes.end()) { + this->_status = PropertyAttributeViewStatus::ErrorClassNotFound; + return; + } + + this->_pClass = &classIt->second; +} + +const ClassProperty* +PropertyAttributeView::getClassProperty(const std::string& propertyName) const { + if (_status != PropertyAttributeViewStatus::Valid) { + return nullptr; + } + + auto propertyIter = _pClass->properties.find(propertyName); + if (propertyIter == _pClass->properties.end()) { + return nullptr; + } + + return &propertyIter->second; +} + +} // namespace CesiumGltf diff --git a/CesiumGltf/src/PropertyType.cpp b/CesiumGltf/src/PropertyType.cpp index f30be7931..4e5b5402e 100644 --- a/CesiumGltf/src/PropertyType.cpp +++ b/CesiumGltf/src/PropertyType.cpp @@ -201,6 +201,17 @@ bool isPropertyTypeMatN(PropertyType type) { type == PropertyType::Mat4; } +bool isPropertyComponentTypeInteger(PropertyComponentType componentType) { + return componentType == PropertyComponentType::Int8 || + componentType == PropertyComponentType::Uint8 || + componentType == PropertyComponentType::Int16 || + componentType == PropertyComponentType::Uint16 || + componentType == PropertyComponentType::Int32 || + componentType == PropertyComponentType::Uint32 || + componentType == PropertyComponentType::Int64 || + componentType == PropertyComponentType::Uint64; +} + glm::length_t getDimensionsFromPropertyType(PropertyType type) { switch (type) { case PropertyType::Scalar: diff --git a/CesiumGltf/test/TestPropertyType.cpp b/CesiumGltf/test/TestPropertyType.cpp index acca55dd6..fffa7579b 100644 --- a/CesiumGltf/test/TestPropertyType.cpp +++ b/CesiumGltf/test/TestPropertyType.cpp @@ -234,6 +234,50 @@ TEST_CASE("Test convertStringOffsetTypeStringToPropertyComponentType") { PropertyComponentType::None); } +TEST_CASE("Test isPropertyTypeVecN") { + REQUIRE(isPropertyTypeVecN(PropertyType::Vec2)); + REQUIRE(isPropertyTypeVecN(PropertyType::Vec3)); + REQUIRE(isPropertyTypeVecN(PropertyType::Vec4)); + + REQUIRE(!isPropertyTypeVecN(PropertyType::Scalar)); + REQUIRE(!isPropertyTypeVecN(PropertyType::Mat2)); + REQUIRE(!isPropertyTypeVecN(PropertyType::Mat3)); + REQUIRE(!isPropertyTypeVecN(PropertyType::Mat4)); + REQUIRE(!isPropertyTypeVecN(PropertyType::Boolean)); + REQUIRE(!isPropertyTypeVecN(PropertyType::Enum)); + REQUIRE(!isPropertyTypeVecN(PropertyType::String)); + REQUIRE(!isPropertyTypeVecN(PropertyType::Invalid)); +} + +TEST_CASE("Test isPropertyTypeMatN") { + REQUIRE(isPropertyTypeMatN(PropertyType::Mat2)); + REQUIRE(isPropertyTypeMatN(PropertyType::Mat3)); + REQUIRE(isPropertyTypeMatN(PropertyType::Mat4)); + + REQUIRE(!isPropertyTypeVecN(PropertyType::Scalar)); + REQUIRE(!isPropertyTypeMatN(PropertyType::Vec2)); + REQUIRE(!isPropertyTypeMatN(PropertyType::Vec3)); + REQUIRE(!isPropertyTypeMatN(PropertyType::Vec4)); + REQUIRE(!isPropertyTypeMatN(PropertyType::Boolean)); + REQUIRE(!isPropertyTypeMatN(PropertyType::Enum)); + REQUIRE(!isPropertyTypeMatN(PropertyType::String)); +} + +TEST_CASE("Test isPropertyComponentTypeInteger") { + REQUIRE(isPropertyComponentTypeInteger(PropertyComponentType::Int8)); + REQUIRE(isPropertyComponentTypeInteger(PropertyComponentType::Uint8)); + REQUIRE(isPropertyComponentTypeInteger(PropertyComponentType::Int16)); + REQUIRE(isPropertyComponentTypeInteger(PropertyComponentType::Uint16)); + REQUIRE(isPropertyComponentTypeInteger(PropertyComponentType::Int32)); + REQUIRE(isPropertyComponentTypeInteger(PropertyComponentType::Uint32)); + REQUIRE(isPropertyComponentTypeInteger(PropertyComponentType::Int64)); + REQUIRE(isPropertyComponentTypeInteger(PropertyComponentType::Uint64)); + + REQUIRE(!isPropertyComponentTypeInteger(PropertyComponentType::None)); + REQUIRE(!isPropertyComponentTypeInteger(PropertyComponentType::Float32)); + REQUIRE(!isPropertyComponentTypeInteger(PropertyComponentType::Float64)); +} + TEST_CASE("Test getDimensionsFromPropertyType") { REQUIRE(getDimensionsFromPropertyType(PropertyType::Scalar) == 1); From 85ebd3ed7f7e684626f3bee87044ae5d3c90133e Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 29 Aug 2023 12:10:47 -0400 Subject: [PATCH 104/121] Add unit tests for new classes, reorganize old tests --- .../TestPropertyAttributePropertyView.cpp | 859 +++++++ CesiumGltf/test/TestPropertyAttributeView.cpp | 2282 +++++++++++++++++ .../test/TestPropertyTablePropertyView.cpp | 1141 +++++---- .../test/TestPropertyTexturePropertyView.cpp | 34 +- 4 files changed, 3804 insertions(+), 512 deletions(-) create mode 100644 CesiumGltf/test/TestPropertyAttributePropertyView.cpp create mode 100644 CesiumGltf/test/TestPropertyAttributeView.cpp diff --git a/CesiumGltf/test/TestPropertyAttributePropertyView.cpp b/CesiumGltf/test/TestPropertyAttributePropertyView.cpp new file mode 100644 index 000000000..c87139ab1 --- /dev/null +++ b/CesiumGltf/test/TestPropertyAttributePropertyView.cpp @@ -0,0 +1,859 @@ +#include "CesiumGltf/PropertyAttributePropertyView.h" + +#include +#include + +#include +#include + +using namespace CesiumGltf; +using namespace CesiumUtility; + +template +const Accessor& addValuesToModel(Model& model, const std::vector& values) { + Buffer& buffer = model.buffers.emplace_back(); + buffer.cesium.data.resize(values.size() * sizeof(T)); + buffer.byteLength = static_cast(buffer.cesium.data.size()); + std::memcpy( + buffer.cesium.data.data(), + values.data(), + buffer.cesium.data.size()); + + BufferView& bufferView = model.bufferViews.emplace_back(); + bufferView.buffer = static_cast(model.buffers.size() - 1); + bufferView.byteOffset = 0; + bufferView.byteLength = buffer.byteLength; + + Accessor& accessor = model.accessors.emplace_back(); + accessor.bufferView = static_cast(model.bufferViews.size() - 1); + accessor.count = values.size(); + accessor.byteOffset = 0; + + PropertyType type = TypeToPropertyType::value; + switch (type) { + case PropertyType::Scalar: + accessor.type = Accessor::Type::SCALAR; + break; + case PropertyType::Vec2: + accessor.type = Accessor::Type::VEC2; + break; + case PropertyType::Vec3: + accessor.type = Accessor::Type::VEC3; + break; + case PropertyType::Vec4: + accessor.type = Accessor::Type::VEC4; + break; + case PropertyType::Mat2: + accessor.type = Accessor::Type::MAT2; + break; + case PropertyType::Mat3: + accessor.type = Accessor::Type::MAT3; + break; + case PropertyType::Mat4: + accessor.type = Accessor::Type::MAT4; + break; + default: + assert(false && "Input type is not supported as an accessor type"); + break; + } + + PropertyComponentType componentType = TypeToPropertyType::component; + switch (componentType) { + case PropertyComponentType::Int8: + accessor.componentType = Accessor::ComponentType::BYTE; + break; + case PropertyComponentType::Uint8: + accessor.componentType = Accessor::ComponentType::UNSIGNED_BYTE; + break; + case PropertyComponentType::Int16: + accessor.componentType = Accessor::ComponentType::SHORT; + break; + case PropertyComponentType::Uint16: + accessor.componentType = Accessor::ComponentType::UNSIGNED_SHORT; + break; + case PropertyComponentType::Uint32: + accessor.componentType = Accessor::ComponentType::UNSIGNED_INT; + break; + case PropertyComponentType::Float32: + accessor.componentType = Accessor::ComponentType::FLOAT; + break; + default: + assert( + false && + "Input component type is not supported as an accessor component type"); + break; + } + + accessor.normalized = Normalized; + + return accessor; +} + +template void checkAttributeValues(const std::vector& values) { + Model model; + const Accessor& accessor = addValuesToModel(model, values); + AccessorView accessorView = AccessorView(model, accessor); + + PropertyAttributeProperty property; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + PropertyAttributePropertyView view(property, classProperty, accessorView); + + REQUIRE(view.size() == static_cast(values.size())); + REQUIRE(!view.normalized()); + + for (int64_t i = 0; i < view.size(); i++) { + REQUIRE(view.getRaw(i) == values[static_cast(i)]); + REQUIRE(view.get(i) == view.getRaw(i)); + } +} + +template +void checkAttributeValues( + const std::vector& values, + const std::vector>& expected, + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + Model model; + const Accessor& accessor = addValuesToModel(model, values); + AccessorView accessorView = AccessorView(model, accessor); + + PropertyAttributeProperty property; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; + + PropertyAttributePropertyView view(property, classProperty, accessorView); + + REQUIRE(view.size() == static_cast(values.size())); + REQUIRE(!view.normalized()); + + for (int64_t i = 0; i < view.size(); i++) { + REQUIRE(view.getRaw(i) == values[static_cast(i)]); + REQUIRE(view.get(i) == expected[static_cast(i)]); + } +} + +template ::type> +void checkNormalizedAttributeValues( + const std::vector& values, + const std::vector>& expected, + const std::optional offset = std::nullopt, + const std::optional scale = std::nullopt, + const std::optional noData = std::nullopt, + const std::optional defaultValue = std::nullopt) { + Model model; + const Accessor& accessor = addValuesToModel(model, values); + AccessorView accessorView = AccessorView(model, accessor); + + PropertyAttributeProperty property; + ClassProperty classProperty; + classProperty.type = + convertPropertyTypeToString(TypeToPropertyType::value); + + PropertyComponentType componentType = TypeToPropertyType::component; + classProperty.componentType = + convertPropertyComponentTypeToString(componentType); + + classProperty.normalized = true; + + classProperty.offset = offset; + classProperty.scale = scale; + classProperty.noData = noData; + classProperty.defaultProperty = defaultValue; + + PropertyAttributePropertyView view( + property, + classProperty, + accessorView); + + REQUIRE(view.size() == static_cast(values.size())); + REQUIRE(view.normalized()); + + for (int64_t i = 0; i < view.size(); i++) { + REQUIRE(view.getRaw(i) == values[static_cast(i)]); + REQUIRE(view.get(i) == expected[static_cast(i)]); + } +} + +TEST_CASE("Check scalar PropertyAttributePropertyView") { + SECTION("Uint8") { + std::vector data{12, 33, 56, 67}; + checkAttributeValues(data); + } + + SECTION("Int16") { + std::vector data{-1, -32511, 768, 438}; + checkAttributeValues(data); + } + + SECTION("uint32_t") { + std::vector data{16777216, 65545, 131604, 16777480}; + checkAttributeValues(data); + } + + SECTION("float") { + std::vector data{12.3333f, -12.44555f, -5.6111f, 6.7421f}; + checkAttributeValues(data); + } + + SECTION("float with offset / scale") { + std::vector data{1.0f, 2.0f, 3.0f, 4.0f}; + + const float offset = 1.0f; + const float scale = 2.0f; + + std::vector> expected{3.0f, 5.0f, 7.0f, 9.0f}; + checkAttributeValues(data, expected, offset, scale); + } + + SECTION("uint8_t with noData") { + std::vector data{12, 33, 0, 128, 0, 56, 67}; + const uint8_t noData = 0; + std::vector> expected{ + data[0], + data[1], + std::nullopt, + data[3], + std::nullopt, + data[5], + data[6]}; + checkAttributeValues(data, expected, std::nullopt, std::nullopt, noData); + } + + SECTION("uint8_t with noData and defaultValue") { + std::vector data{12, 33, 0, 128, 0, 56, 67}; + const uint8_t noData = 0; + const uint8_t defaultValue = 255; + std::vector> expected{ + data[0], + data[1], + defaultValue, + data[3], + defaultValue, + data[5], + data[6]}; + checkAttributeValues( + data, + expected, + std::nullopt, + std::nullopt, + noData, + defaultValue); + } +} + +TEST_CASE("Check scalar PropertyAttributePropertyView (normalized)") { + SECTION("Uint8") { + std::vector data{12, 33, 56, 67}; + std::vector> expected{ + 12.0 / 255.0, + 33 / 255.0, + 56 / 255.0, + 67 / 255.0}; + checkNormalizedAttributeValues(data, expected); + } + + SECTION("Int16") { + std::vector data{-1, -32511, 768, 438}; + std::vector> expected{ + normalize(data[0]), + normalize(data[1]), + normalize(data[2]), + normalize(data[3])}; + checkNormalizedAttributeValues(data, expected); + } + + SECTION("Uint32") { + std::vector data{16777216, 65545, 131604, 16777480}; + std::vector> expected{ + normalize(data[0]), + normalize(data[1]), + normalize(data[2]), + normalize(data[3])}; + checkNormalizedAttributeValues(data, expected); + } + + SECTION("Uint8 with offset / scale") { + std::vector data{12, 33, 56, 67}; + const double offset = 1.0; + const double scale = 2.0; + std::vector> expected{ + normalize(data[0]) * scale + offset, + normalize(data[1]) * scale + offset, + normalize(data[2]) * scale + offset, + normalize(data[3]) * scale + offset, + }; + checkNormalizedAttributeValues(data, expected, offset, scale); + } + + SECTION("Uint8 with all properties") { + std::vector data{12, 33, 56, 0, 67}; + const double offset = 1.0; + const double scale = 2.0; + const uint8_t noData = 0; + const double defaultValue = 10.0; + std::vector> expected{ + normalize(data[0]) * scale + offset, + normalize(data[1]) * scale + offset, + normalize(data[2]) * scale + offset, + 10.0, + normalize(data[4]) * scale + offset, + }; + checkNormalizedAttributeValues( + data, + expected, + offset, + scale, + noData, + defaultValue); + } +} + +TEST_CASE("Check vecN PropertyAttributePropertyView") { + SECTION("glm::i8vec2") { + std::vector data{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(-74, 1)}; + checkAttributeValues(data); + } + + SECTION("glm::vec3") { + std::vector data{ + glm::vec3(1.5f, 2.0f, -3.3f), + glm::vec3(4.12f, -5.008f, 6.0f), + glm::vec3(7.0f, 8.0f, 9.01f), + glm::vec3(-0.28f, 5.0f, 1.2f)}; + checkAttributeValues(data); + } + + SECTION("glm::uvec4") { + std::vector data{ + glm::uvec4(0, 12, 324, 256), + glm::uvec4(9234, 12, 7, 1), + glm::uvec4(532, 2, 88, 16), + glm::uvec4(264, 256, 22, 101)}; + checkAttributeValues(data); + } + + SECTION("glm::vec3 with offset / scale") { + std::vector data{ + glm::vec3(1.0f, 2.0f, 3.0f), + glm::vec3(-1.0f, -2.0f, -3.0f), + glm::vec3(0.0f), + glm::vec3(1.0f)}; + + JsonValue::Array offset{1.0f, 0.0f, -1.0f}; + JsonValue::Array scale{2.0f, 2.0f, 2.0f}; + + std::vector> expected{ + glm::vec3(3.0f, 4.0f, 5.0f), + glm::vec3(-1.0f, -4.0f, -7.0f), + glm::vec3(1.0f, 0.0f, -1.0f), + glm::vec3(3.0f, 2.0f, 1.0f)}; + + checkAttributeValues(data, expected, offset, scale); + } + + SECTION("glm::i8vec2 with noData") { + std::vector data{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(0), + glm::i8vec2(-74, 1)}; + + JsonValue::Array noData{0, 0}; + + std::vector> expected{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + std::nullopt, + glm::i8vec2(-74, 1)}; + checkAttributeValues(data, expected, std::nullopt, std::nullopt, noData); + } + + SECTION("glm::i8vec2 with defaultValue") { + std::vector data{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(0, 0), + glm::i8vec2(-74, 1)}; + + JsonValue::Array noData{0, 0}; + JsonValue::Array defaultValue{127, 127}; + + std::vector> expected{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(127, 127), + glm::i8vec2(-74, 1)}; + checkAttributeValues( + data, + expected, + std::nullopt, + std::nullopt, + noData, + defaultValue); + } +} + +TEST_CASE("Check vecN PropertyAttributePropertyView (normalized)") { + SECTION("glm::i8vec2") { + std::vector data{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(-74, 1)}; + std::vector> expected{ + normalize(data[0]), + normalize(data[1]), + normalize(data[2]), + normalize(data[3])}; + checkNormalizedAttributeValues(data, expected); + } + + SECTION("glm::u8vec3") { + std::vector data{ + glm::u8vec3(1, 2, 3), + glm::u8vec3(4, 5, 6), + glm::u8vec3(7, 8, 9), + glm::u8vec3(0, 5, 2)}; + std::vector> expected{ + normalize(data[0]), + normalize(data[1]), + normalize(data[2]), + normalize(data[3])}; + checkNormalizedAttributeValues(data, expected); + } + + SECTION("glm::uvec4") { + std::vector data{ + glm::uvec4(123, 20, 13, 0), + glm::uvec4(43, 5, 86, 11), + glm::uvec4(7345, 448, 3219, 83), + glm::uvec4(0, 775, 12, 27)}; + std::vector> expected{ + normalize(data[0]), + normalize(data[1]), + normalize(data[2]), + normalize(data[3])}; + checkNormalizedAttributeValues(data, expected); + } + + SECTION("glm::i8vec2 with offset / scale") { + std::vector data{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(0), + glm::i8vec2(-74, 1)}; + + const glm::dvec2 offset(-1.0, 4.0); + const glm::dvec2 scale(2.0, 1.0); + + std::vector> expected{ + normalize(data[0]) * scale + offset, + normalize(data[1]) * scale + offset, + normalize(data[2]) * scale + offset, + normalize(data[3]) * scale + offset, + normalize(data[4]) * scale + offset, + }; + checkNormalizedAttributeValues( + data, + expected, + JsonValue::Array{offset[0], offset[1]}, + JsonValue::Array{scale[0], scale[1]}); + } + + SECTION("glm::i8vec2 with all properties") { + const glm::dvec2 offset(-1.0, 4.0); + const glm::dvec2 scale(2.0, 1.0); + const glm::i8vec2 noData(0); + const glm::dvec2 defaultValue(100.0, 5.5); + + std::vector data{ + glm::i8vec2(28, -1), + glm::i8vec2(-2, 1), + glm::i8vec2(0, 3), + glm::i8vec2(0), + glm::i8vec2(-74, 1)}; + std::vector> expected{ + normalize(data[0]) * scale + offset, + normalize(data[1]) * scale + offset, + normalize(data[2]) * scale + offset, + defaultValue, + normalize(data[4]) * scale + offset, + }; + checkNormalizedAttributeValues( + data, + expected, + JsonValue::Array{offset[0], offset[1]}, + JsonValue::Array{scale[0], scale[1]}, + JsonValue::Array{noData[0], noData[1]}, + JsonValue::Array{defaultValue[0], defaultValue[1]}); + } +} + +TEST_CASE("Check matN PropertyAttributePropertyView") { + SECTION("Float Mat2") { + // clang-format off + std::vector data{ + glm::mat2( + 1.0f, 2.0f, + 3.0f, 4.0f), + glm::mat2( + -10.0f, 40.0f, + 0.08f, 5.4f), + glm::mat2( + 9.99f, -2.0f, + -0.4f, 0.23f) + }; + // clang-format on + checkAttributeValues(data); + } + + SECTION("Int16 Mat3") { + // clang-format off + std::vector data{ + glm::i16mat3x3( + 1, 2, 3, + 4, 5, 6, + 7, 8, 9), + glm::i16mat3x3( + 10, 0, 5, + -14, 35, 16, + -2, 3, 4), + glm::i16mat3x3( + -6, 5, 2, + 14, 4, -33, + 2, 1, 0) + }; + // clang-format on + checkAttributeValues(data); + } + + SECTION("Float Mat4") { + // clang-format off + std::vector data{ + glm::mat4( + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 13.0f, 14.0f, 15.0f, 16.0f), + glm::mat4( + 0.1f, 0.2f, 0.3f, 0.4f, + 0.5f, 0.6f, 0.7f, 0.8f, + -9.0f, -10.0f, -11.0f, -12.0f, + 13.0f, 14.0f, 15.0f, 16.0f), + glm::mat4( + 1.0f, 0.0f, 0.0f, 10.0f, + 0.0f, 0.0f, -1.0f, -3.5f, + 0.0f, 1.0f, 0.0f, 20.4f, + 0.0f, 0.0f, 0.0f, 1.0f) + }; + // clang-format on + checkAttributeValues(data); + } + + SECTION("Float Mat2 with Offset / Scale") { + // clang-format off + std::vector data{ + glm::mat2( + 1.0f, 3.0f, + 4.0f, 2.0f), + glm::mat2( + 6.5f, 2.0f, + -2.0f, 0.0f), + glm::mat2( + 8.0f, -1.0f, + -3.0f, 1.0f), + }; + const JsonValue::Array offset{ + 1.0f, 2.0f, + 3.0f, 1.0f}; + const JsonValue::Array scale { + 2.0f, 0.0f, + 0.0f, 2.0f}; + + std::vector> expected{ + glm::mat2( + 3.0f, 2.0f, + 3.0f, 5.0f), + glm::mat2( + 14.0f, 2.0f, + 3.0f, 1.0f), + glm::mat2( + 17.0f, 2.0f, + 3.0f, 3.0f), + }; + // clang-format on + checkAttributeValues(data, expected, offset, scale); + } + + SECTION("Int16 Mat3 with NoData") { + // clang-format off + std::vector data{ + glm::i16mat3x3( + 1, 2, 3, + -1, -2, -3, + 0, 1, 0), + glm::i16mat3x3( + 1, -1, 0, + 0, 1, 2, + 0, 4, 5), + glm::i16mat3x3( + -1, -1, -1, + 0, 0, 0, + 1, 1, 1)}; + JsonValue::Array noData{ + -1, -1, -1, + 0, 0, 0, + 1, 1, 1}; + // clang-format on + std::vector> expected{ + data[0], + data[1], + std::nullopt}; + checkAttributeValues( + data, + expected, + std::nullopt, + std::nullopt, + noData, + std::nullopt); + }; + + SECTION("Int16 Mat3 with NoData and DefaultValue") { + // clang-format off + std::vector data{ + glm::i16mat3x3( + 1, 2, 3, + -1, -2, -3, + 0, 1, 0), + glm::i16mat3x3( + 1, -1, 0, + 0, 1, 2, + 0, 4, 5), + glm::i16mat3x3( + -1, -1, -1, + 0, 0, 0, + 1, 1, 1)}; + JsonValue::Array noData{ + -1, -1, -1, + 0, 0, 0, + 1, 1, 1}; + JsonValue::Array defaultValue{ + 1, 0, 0, + 0, 1, 0, + 0, 0, 1}; + // clang-format on + std::vector> expected{ + data[0], + data[1], + glm::i16mat3x3(1)}; + checkAttributeValues( + data, + expected, + std::nullopt, + std::nullopt, + noData, + defaultValue); + }; +} + +TEST_CASE("Check matN PropertyAttributePropertyView (normalized)") { + SECTION("Normalized Uint8 Mat2") { + // clang-format off + std::vector data{ + glm::u8mat2x2( + 0, 64, + 255, 255), + glm::u8mat2x2( + 255, 0, + 128, 0)}; + std::vector> expected{ + glm::dmat2( + 0.0, 64.0 / 255.0, + 1.0, 1.0), + glm::dmat2( + 1.0, 0.0, + 128.0 / 255.0, 0.0)}; + // clang-format on + checkNormalizedAttributeValues(data, expected); + } + + SECTION("Normalized Int16 Mat2") { + // clang-format off + std::vector data{ + glm::i16mat2x2( + -32768, 0, + 16384, 32767), + glm::i16mat2x2( + 0, 32767, + 32767, -32768)}; + std::vector> expected{ + glm::dmat2( + -1.0, 0.0, + 16384.0 / 32767.0, 1.0), + glm::dmat2( + 0.0, 1.0, + 1.0, -1.0), + }; + // clang-format on + checkNormalizedAttributeValues(data, expected); + } + + SECTION("Normalized Uint8 Mat2 with Offset and Scale") { + // clang-format off + std::vector values{ + glm::u8mat2x2( + 0, 64, + 255, 255), + glm::u8mat2x2( + 255, 0, + 128, 0)}; + JsonValue::Array offset{ + 0.0, 1.0, + 1.0, 0.0}; + JsonValue::Array scale{ + 2.0, 1.0, + 0.0, 2.0}; + std::vector> expected{ + glm::dmat2( + 0.0, 1 + 64.0 / 255.0, + 1.0, 2.0), + glm::dmat2( + 2.0, 1.0, + 1.0, 0.0)}; + // clang-format on + checkNormalizedAttributeValues(values, expected, offset, scale); + } + + SECTION("Normalized Uint8 Mat2 with all properties") { + // clang-format off + std::vector values{ + glm::u8mat2x2( + 0, 64, + 255, 255), + glm::u8mat2x2(0), + glm::u8mat2x2( + 255, 0, + 128, 0)}; + JsonValue::Array offset{ + 0.0, 1.0, + 1.0, 0.0}; + JsonValue::Array scale{ + 2.0, 1.0, + 0.0, 2.0}; + JsonValue::Array noData{ + 0, 0, + 0, 0}; + JsonValue::Array defaultValue{ + 1.0, 0.0, + 0.0, 1.0}; + + std::vector> expected{ + glm::dmat2( + 0.0, 1 + 64.0 / 255.0, + 1.0, 2.0), + glm::dmat2(1.0), + glm::dmat2( + 2.0, 1.0, + 1.0, 0.0)}; + // clang-format on + checkNormalizedAttributeValues( + values, + expected, + offset, + scale, + noData, + defaultValue); + } +} + +TEST_CASE("Check that PropertyAttributeProperty values override class property values") { + Model model; + std::vector data{1.0f, 2.0f, 3.0f, 4.0f}; + + Buffer& buffer = model.buffers.emplace_back(); + buffer.cesium.data.resize(data.size() * sizeof(float)); + buffer.byteLength = static_cast(buffer.cesium.data.size()); + std::memcpy( + buffer.cesium.data.data(), + data.data(), + buffer.cesium.data.size()); + + BufferView& bufferView = model.bufferViews.emplace_back(); + bufferView.buffer = static_cast(model.buffers.size() - 1); + bufferView.byteOffset = 0; + bufferView.byteLength = buffer.byteLength; + + Accessor& accessor = model.accessors.emplace_back(); + accessor.bufferView = static_cast(model.bufferViews.size() - 1); + accessor.count = data.size(); + accessor.byteOffset = 0; + accessor.type = Accessor::Type::SCALAR; + accessor.componentType = Accessor::ComponentType::FLOAT; + + AccessorView accessorView = AccessorView(model, accessor); + + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::SCALAR; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + + classProperty.offset = 0.0f; + classProperty.scale = 1.0f; + classProperty.min = -10.0f; + classProperty.max = 10.0f; + + const float offset = 1.0f; + const float scale = 2.0f; + const float min = 3.0f; + const float max = 9.0f; + + std::vector> expected{3.0f, 5.0f, 7.0f, 9.0f}; + + PropertyAttributeProperty property; + property.offset = offset; + property.scale = scale; + property.min = min; + property.max = max; + + PropertyAttributePropertyView view( + property, + classProperty, + accessorView); + REQUIRE(view.offset() == offset); + REQUIRE(view.scale() == scale); + REQUIRE(view.min() == min); + REQUIRE(view.max() == max); + + REQUIRE(view.size() == static_cast(data.size())); + for (int64_t i = 0; i < view.size(); i++) { + REQUIRE(view.getRaw(i) == data[static_cast(i)]); + REQUIRE(view.get(i) == expected[static_cast(i)]); + } +} diff --git a/CesiumGltf/test/TestPropertyAttributeView.cpp b/CesiumGltf/test/TestPropertyAttributeView.cpp new file mode 100644 index 000000000..a242bb6df --- /dev/null +++ b/CesiumGltf/test/TestPropertyAttributeView.cpp @@ -0,0 +1,2282 @@ +#include "CesiumGltf/PropertyAttributeView.h" + +#include +#include + +#include +#include + +using namespace CesiumGltf; + +namespace { +template +void addAttributeToModel( + Model& model, + MeshPrimitive& primitive, + const std::string& name, + const std::vector& values) { + Buffer& buffer = model.buffers.emplace_back(); + buffer.cesium.data.resize(values.size() * sizeof(T)); + buffer.byteLength = static_cast(buffer.cesium.data.size()); + std::memcpy( + buffer.cesium.data.data(), + values.data(), + buffer.cesium.data.size()); + + BufferView& bufferView = model.bufferViews.emplace_back(); + bufferView.buffer = static_cast(model.buffers.size() - 1); + bufferView.byteOffset = 0; + bufferView.byteLength = buffer.byteLength; + + Accessor& accessor = model.accessors.emplace_back(); + accessor.bufferView = static_cast(model.bufferViews.size() - 1); + accessor.count = values.size(); + accessor.byteOffset = 0; + + PropertyType type = TypeToPropertyType::value; + switch (type) { + case PropertyType::Scalar: + accessor.type = Accessor::Type::SCALAR; + break; + case PropertyType::Vec2: + accessor.type = Accessor::Type::VEC2; + break; + case PropertyType::Vec3: + accessor.type = Accessor::Type::VEC3; + break; + case PropertyType::Vec4: + accessor.type = Accessor::Type::VEC4; + break; + case PropertyType::Mat2: + accessor.type = Accessor::Type::MAT2; + break; + case PropertyType::Mat3: + accessor.type = Accessor::Type::MAT3; + break; + case PropertyType::Mat4: + accessor.type = Accessor::Type::MAT4; + break; + default: + assert(false && "Input type is not supported as an accessor type"); + break; + } + + PropertyComponentType componentType = TypeToPropertyType::component; + switch (componentType) { + case PropertyComponentType::Int8: + accessor.componentType = Accessor::ComponentType::BYTE; + break; + case PropertyComponentType::Uint8: + accessor.componentType = Accessor::ComponentType::UNSIGNED_BYTE; + break; + case PropertyComponentType::Int16: + accessor.componentType = Accessor::ComponentType::SHORT; + break; + case PropertyComponentType::Uint16: + accessor.componentType = Accessor::ComponentType::UNSIGNED_SHORT; + break; + case PropertyComponentType::Uint32: + accessor.componentType = Accessor::ComponentType::UNSIGNED_INT; + break; + case PropertyComponentType::Float32: + accessor.componentType = Accessor::ComponentType::FLOAT; + break; + default: + assert( + false && + "Input component type is not supported as an accessor component type"); + break; + } + + accessor.normalized = Normalized; + + primitive.attributes[name] = static_cast(model.accessors.size() - 1); +} +} // namespace + +TEST_CASE("Test PropertyAttributeView on model without EXT_structural_metadata " + "extension") { + Model model; + + // Create an erroneously isolated property Attribute. + PropertyAttribute propertyAttribute; + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = "_ATTRIBUTE"; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE( + view.status() == + PropertyAttributeViewStatus::ErrorMissingMetadataExtension); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test PropertyAttributeView on model without metadata schema") { + Model model; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = "_ATTRIBUTE"; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::ErrorMissingSchema); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test property attribute with nonexistent class") { + Model model; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "I Don't Exist"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = "_ATTRIBUTE"; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::ErrorClassNotFound); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); +} + +TEST_CASE("Test scalar PropertyAttributeProperty") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + const std::string attributeName = "_ATTRIBUTE"; + std::vector data = {12, 34, 30, 11}; + + addAttributeToModel(model, primitive, attributeName, data); + size_t accessorIndex = model.accessors.size() - 1; + size_t bufferIndex = model.buffers.size() - 1; + size_t bufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + 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; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT16); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); + + SECTION("Access correct type") { + PropertyAttributePropertyView uint16Property = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + uint16Property.status() == PropertyAttributePropertyViewStatus::Valid); + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(uint16Property.getRaw(static_cast(i)) == data[i]); + REQUIRE(uint16Property.get(static_cast(i)) == data[i]); + } + } + + SECTION("Access wrong type") { + PropertyAttributePropertyView u16vec2Invalid = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + u16vec2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyAttributePropertyView uint8Invalid = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + uint8Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyAttributePropertyView int32Invalid = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + int32Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyAttributePropertyView uint64Invalid = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + uint64Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as normalized") { + PropertyAttributePropertyView normalizedInvalid = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + normalizedInvalid.status() == + PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[bufferIndex].cesium.data.resize(4); + PropertyAttributePropertyView property = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Wrong buffer index") { + model.bufferViews[bufferViewIndex].buffer = 2; + PropertyAttributePropertyView property = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidBuffer); + } + + SECTION("Wrong buffer view index") { + model.accessors[accessorIndex].bufferView = -1; + PropertyAttributePropertyView property = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidBufferView); + } + + SECTION("Wrong accessor normalization") { + model.accessors[accessorIndex].normalized = true; + PropertyAttributePropertyView property = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + property.status() == PropertyAttributePropertyViewStatus:: + ErrorAccessorNormalizationMismatch); + } + + SECTION("Wrong accessor component type") { + model.accessors[accessorIndex].componentType = + Accessor::ComponentType::SHORT; + PropertyAttributePropertyView property = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + property.status() == PropertyAttributePropertyViewStatus:: + ErrorAccessorComponentTypeMismatch); + } + + SECTION("Wrong accessor type") { + model.accessors[accessorIndex].type = Accessor::Type::VEC2; + PropertyAttributePropertyView property = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorAccessorTypeMismatch); + } + + SECTION("Wrong accessor index") { + primitive.attributes[attributeName] = -1; + PropertyAttributePropertyView property = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidAccessor); + } + + SECTION("Missing attribute") { + primitive.attributes.clear(); + PropertyAttributePropertyView property = + view.getPropertyView("TestClassProperty", primitive); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorMissingAttribute); + } +} + +// TEST_CASE("Test scalar PropertyAttributeProperty (normalized)") { +// Model model; +// std::vector data = {12, 34, 30, 11}; +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 1, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// size_t imageIndex = model.images.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; testClassProperty.normalized = true; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE(classProperty->componentType == +// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == +// std::nullopt); REQUIRE(!classProperty->array); +// REQUIRE(classProperty->normalized); +// +// SECTION("Access correct type") { +// PropertyAttributePropertyView uint8Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(uint8Property.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// REQUIRE(uint8Property.getRaw(uv[0], uv[1]) == data[i]); +// REQUIRE(uint8Property.get(uv[0], uv[1]) == normalize(data[i])); +// } +// } +// +// SECTION("Access wrong type") { +// PropertyAttributePropertyView u8vec2Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec2Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorTypeMismatch); +// } +// +// SECTION("Access wrong component type") { +// PropertyAttributePropertyView uint16Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint16Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyAttributePropertyView int32Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// int32Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Access incorrectly as array") { +// PropertyAttributePropertyView, true> +// arrayInvalid +// = +// view.getPropertyView, true>( +// "TestClassProperty"); +// REQUIRE( +// arrayInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Access incorrectly as non-normalized") { +// PropertyAttributePropertyView normalizedInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// normalizedInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); +// } +// +// SECTION("Access incorrectly as double") { +// PropertyAttributePropertyView doubleInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// doubleInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Channel and type mismatch") { +// model.images[imageIndex].cesium.channels = 2; +// propertyAttributeProperty.channels = {0, 1}; +// PropertyAttributePropertyView uint8Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint8Property.status() == +// PropertyAttributePropertyViewStatus::ErrorChannelsAndTypeMismatch); +// } +//} +// +// TEST_CASE("Test vecN PropertyAttributeProperty") { +// Model model; +// std::vector data = {12, 34, 10, 3, 40, 0, 30, 11}; +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 2, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// size_t imageIndex = model.images.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::VEC2; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::VEC2); +// REQUIRE(classProperty->componentType == +// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == +// std::nullopt); REQUIRE(!classProperty->array); +// REQUIRE(!classProperty->normalized); +// +// SECTION("Access correct type") { +// PropertyAttributePropertyView u8vec2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec2Property.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// std::vector expected{ +// glm::u8vec2(12, 34), +// glm::u8vec2(10, 3), +// glm::u8vec2(40, 0), +// glm::u8vec2(30, 11)}; +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// REQUIRE(u8vec2Property.getRaw(uv[0], uv[1]) == expected[i]); +// REQUIRE(u8vec2Property.get(uv[0], uv[1]) == expected[i]); +// } +// } +// +// SECTION("Access wrong type") { +// PropertyAttributePropertyView uint8Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint8Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyAttributePropertyView u8vec3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec3Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorTypeMismatch); +// } +// +// SECTION("Access wrong component type") { +// PropertyAttributePropertyView u16vec2Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u16vec2Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyAttributePropertyView i8vec2Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// i8vec2Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Access incorrectly as array") { +// PropertyAttributePropertyView> arrayInvalid +// = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// arrayInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Access incorrectly as normalized") { +// PropertyAttributePropertyView normalizedInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// normalizedInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); +// } +// +// SECTION("Channel and type mismatch") { +// model.images[imageIndex].cesium.channels = 4; +// propertyAttributeProperty.channels = {0, 1, 2, 3}; +// PropertyAttributePropertyView u8vec2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec2Property.status() == +// PropertyAttributePropertyViewStatus::ErrorChannelsAndTypeMismatch); +// } +// +// SECTION("Invalid channel values") { +// propertyAttributeProperty.channels = {0, 4}; +// PropertyAttributePropertyView u8vec2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec2Property.status() == +// PropertyAttributePropertyViewStatus::ErrorInvalidChannels); +// } +// +// SECTION("Invalid bytes per channel") { +// model.images[imageIndex].cesium.bytesPerChannel = 2; +// PropertyAttributePropertyView u8vec2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec2Property.status() == +// PropertyAttributePropertyViewStatus::ErrorInvalidBytesPerChannel); +// } +//} +// +// TEST_CASE("Test vecN PropertyAttributeProperty (normalized)") { +// Model model; +// std::vector data = {12, 34, 10, 3, 40, 0, 30, 11}; +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 2, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// size_t imageIndex = model.images.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::VEC2; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; testClassProperty.normalized = true; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::VEC2); +// REQUIRE(classProperty->componentType == +// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == +// std::nullopt); REQUIRE(!classProperty->array); +// REQUIRE(classProperty->normalized); +// +// SECTION("Access correct type") { +// PropertyAttributePropertyView u8vec2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec2Property.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// std::vector expected{ +// glm::u8vec2(12, 34), +// glm::u8vec2(10, 3), +// glm::u8vec2(40, 0), +// glm::u8vec2(30, 11)}; +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// REQUIRE(u8vec2Property.getRaw(uv[0], uv[1]) == expected[i]); +// REQUIRE(u8vec2Property.get(uv[0], uv[1]) == normalize(expected[i])); +// } +// } +// +// SECTION("Access wrong type") { +// PropertyAttributePropertyView uint8Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint8Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorTypeMismatch); +// +// PropertyAttributePropertyView u8vec3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec3Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorTypeMismatch); +// } +// +// SECTION("Access wrong component type") { +// PropertyAttributePropertyView u16vec2Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u16vec2Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyAttributePropertyView i8vec2Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// i8vec2Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Access incorrectly as array") { +// PropertyAttributePropertyView, true> +// arrayInvalid = +// view.getPropertyView, true>( +// "TestClassProperty"); +// REQUIRE( +// arrayInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Access incorrectly as non-normalized") { +// PropertyAttributePropertyView normalizedInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// normalizedInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); +// } +// +// SECTION("Access incorrectly as dvec2") { +// PropertyAttributePropertyView normalizedInvalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// normalizedInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Channel and type mismatch") { +// model.images[imageIndex].cesium.channels = 4; +// propertyAttributeProperty.channels = {0, 1, 2, 3}; +// PropertyAttributePropertyView u8vec2Property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec2Property.status() == +// PropertyAttributePropertyViewStatus::ErrorChannelsAndTypeMismatch); +// } +//} +// +// TEST_CASE("Test array PropertyAttributeProperty") { +// Model model; +// // clang-format off +// std::vector data = { +// 12, 34, 10, +// 40, 0, 30, +// 80, 4, 2, +// 6, 3, 4, +// }; +// // clang-format on +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 3, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// size_t imageIndex = model.images.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; testClassProperty.array = true; +// testClassProperty.count = 3; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1, 2}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE(classProperty->componentType == +// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 3); +// REQUIRE(!classProperty->normalized); +// +// SECTION("Access correct type") { +// PropertyAttributePropertyView> +// uint8ArrayProperty +// = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// uint8ArrayProperty.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// int64_t size = static_cast(texCoords.size()); +// for (int64_t i = 0; i < size; ++i) { +// glm::dvec2 uv = texCoords[static_cast(i)]; +// +// auto dataStart = data.begin() + i * 3; +// std::vector expected(dataStart, dataStart + 3); +// +// const PropertyArrayView& value = +// uint8ArrayProperty.getRaw(uv[0], uv[1]); +// REQUIRE(static_cast(value.size()) == expected.size()); +// for (int64_t j = 0; j < value.size(); j++) { +// REQUIRE(value[j] == expected[static_cast(j)]); +// } +// +// auto maybeValue = uint8ArrayProperty.get(uv[0], uv[1]); +// REQUIRE(maybeValue); +// for (int64_t j = 0; j < maybeValue->size(); j++) { +// REQUIRE((*maybeValue)[j] == value[j]); +// } +// } +// } +// +// SECTION("Access wrong component type") { +// PropertyAttributePropertyView> int8ArrayInvalid +// = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// int8ArrayInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyAttributePropertyView> +// uint16ArrayInvalid = +// view.getPropertyView>( +// "TestClassProperty"); +// REQUIRE( +// uint16ArrayInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Access incorrectly as non-array") { +// PropertyAttributePropertyView uint8Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint8Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); +// +// PropertyAttributePropertyView u8vec3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec3Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Access incorrectly as normalized") { +// PropertyAttributePropertyView, true> +// normalizedInvalid = +// view.getPropertyView, true>( +// "TestClassProperty"); +// REQUIRE( +// normalizedInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); +// } +// +// SECTION("Channel and type mismatch") { +// model.images[imageIndex].cesium.channels = 4; +// propertyAttributeProperty.channels = {0, 1, 2, 3}; +// PropertyAttributePropertyView> +// uint8ArrayProperty +// = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// uint8ArrayProperty.status() == +// PropertyAttributePropertyViewStatus::ErrorChannelsAndTypeMismatch); +// } +// +// SECTION("Invalid channel values") { +// propertyAttributeProperty.channels = {0, 4, 1}; +// PropertyAttributePropertyView> +// uint8ArrayProperty +// = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// uint8ArrayProperty.status() == +// PropertyAttributePropertyViewStatus::ErrorInvalidChannels); +// } +// +// SECTION("Invalid bytes per channel") { +// model.images[imageIndex].cesium.bytesPerChannel = 2; +// PropertyAttributePropertyView> +// uint8ArrayProperty +// = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// uint8ArrayProperty.status() == +// PropertyAttributePropertyViewStatus::ErrorInvalidBytesPerChannel); +// } +//} +// +// TEST_CASE("Test array PropertyAttributeProperty (normalized)") { +// Model model; +// // clang-format off +// std::vector data = { +// 12, 34, 10, +// 40, 0, 30, +// 80, 4, 2, +// 6, 3, 4, +// }; +// // clang-format on +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 3, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// size_t imageIndex = model.images.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; testClassProperty.array = true; +// testClassProperty.count = 3; +// testClassProperty.normalized = true; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1, 2}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE(classProperty->componentType == +// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 3); +// REQUIRE(classProperty->normalized); +// +// SECTION("Access correct type") { +// PropertyAttributePropertyView, true> +// uint8ArrayProperty = +// view.getPropertyView, true>( +// "TestClassProperty"); +// REQUIRE( +// uint8ArrayProperty.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// int64_t size = static_cast(texCoords.size()); +// for (int64_t i = 0; i < size; ++i) { +// glm::dvec2 uv = texCoords[static_cast(i)]; +// +// auto dataStart = data.begin() + i * 3; +// std::vector expected(dataStart, dataStart + 3); +// +// const PropertyArrayView& value = +// uint8ArrayProperty.getRaw(uv[0], uv[1]); +// REQUIRE(static_cast(value.size()) == expected.size()); +// for (int64_t j = 0; j < value.size(); j++) { +// REQUIRE(value[j] == expected[static_cast(j)]); +// } +// +// auto maybeValue = uint8ArrayProperty.get(uv[0], uv[1]); +// REQUIRE(maybeValue); +// for (int64_t j = 0; j < maybeValue->size(); j++) { +// REQUIRE((*maybeValue)[j] == normalize(value[j])); +// } +// } +// } +// +// SECTION("Access wrong component type") { +// PropertyAttributePropertyView, true> +// int8ArrayInvalid = +// view.getPropertyView, true>( +// "TestClassProperty"); +// REQUIRE( +// int8ArrayInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// +// PropertyAttributePropertyView, true> +// uint16ArrayInvalid = +// view.getPropertyView, true>( +// "TestClassProperty"); +// REQUIRE( +// uint16ArrayInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); +// } +// +// SECTION("Access incorrectly as non-array") { +// PropertyAttributePropertyView uint8Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// uint8Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); +// +// PropertyAttributePropertyView u8vec3Invalid = +// view.getPropertyView("TestClassProperty"); +// REQUIRE( +// u8vec3Invalid.status() == +// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); +// } +// +// SECTION("Access incorrectly as normalized") { +// PropertyAttributePropertyView> +// normalizedInvalid +// = +// view.getPropertyView>("TestClassProperty"); +// REQUIRE( +// normalizedInvalid.status() == +// PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); +// } +// +// SECTION("Channel and type mismatch") { +// model.images[imageIndex].cesium.channels = 4; +// propertyAttributeProperty.channels = {0, 1, 2, 3}; +// PropertyAttributePropertyView, true> +// uint8ArrayProperty = +// view.getPropertyView, true>( +// "TestClassProperty"); +// REQUIRE( +// uint8ArrayProperty.status() == +// PropertyAttributePropertyViewStatus::ErrorChannelsAndTypeMismatch); +// } +//} +// +// TEST_CASE("Test with PropertyAttributeProperty offset, scale, min, max") { +// Model model; +// // clang-format off +// std::vector data{ +// 0, 0, 0, 1, +// 9, 0, 1, 0, +// 20, 2, 2, 0, +// 8, 1, 0, 1}; +// // clang-format on +// +// std::vector expectedUint{16777216, 65545, 131604, 16777480}; +// +// const float offset = 1.0f; +// const float scale = 2.0f; +// const float min = -10.0f; +// const float max = 10.0f; +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 4, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::FLOAT32; testClassProperty.offset = offset; +// testClassProperty.scale = scale; +// testClassProperty.min = min; +// testClassProperty.max = max; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1, 2, 3}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE( +// classProperty->componentType == ClassProperty::ComponentType::FLOAT32); +// REQUIRE(classProperty->count == std::nullopt); +// REQUIRE(!classProperty->array); +// REQUIRE(!classProperty->normalized); +// REQUIRE(classProperty->offset); +// REQUIRE(classProperty->scale); +// REQUIRE(classProperty->min); +// REQUIRE(classProperty->max); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// SECTION("Use class property values") { +// PropertyAttributePropertyView property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); +// REQUIRE(property.offset() == offset); +// REQUIRE(property.scale() == scale); +// REQUIRE(property.min() == min); +// REQUIRE(property.max() == max); +// +// std::vector expectedRaw(expectedUint.size()); +// std::vector expectedTransformed(expectedUint.size()); +// for (size_t i = 0; i < expectedUint.size(); i++) { +// float value = *reinterpret_cast(&expectedUint[i]); +// expectedRaw[i] = value; +// expectedTransformed[i] = value * scale + offset; +// } +// +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// REQUIRE(property.getRaw(uv[0], uv[1]) == expectedRaw[i]); +// REQUIRE(property.get(uv[0], uv[1]) == expectedTransformed[i]); +// } +// } +// +// SECTION("Use own property values") { +// const float newOffset = 1.0f; +// const float newScale = -1.0f; +// const float newMin = -3.0f; +// const float newMax = 0.0f; +// propertyAttributeProperty.offset = newOffset; +// propertyAttributeProperty.scale = newScale; +// propertyAttributeProperty.min = newMin; +// propertyAttributeProperty.max = newMax; +// +// PropertyAttributePropertyView property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); +// REQUIRE(property.offset() == newOffset); +// REQUIRE(property.scale() == newScale); +// REQUIRE(property.min() == newMin); +// REQUIRE(property.max() == newMax); +// +// std::vector expectedRaw(expectedUint.size()); +// std::vector expectedTransformed(expectedUint.size()); +// for (size_t i = 0; i < expectedUint.size(); i++) { +// float value = *reinterpret_cast(&expectedUint[i]); +// expectedRaw[i] = value; +// expectedTransformed[i] = value * newScale + newOffset; +// } +// +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// REQUIRE(property.getRaw(uv[0], uv[1]) == expectedRaw[i]); +// REQUIRE(property.get(uv[0], uv[1]) == expectedTransformed[i]); +// } +// } +//} +// +// TEST_CASE( +// "Test with PropertyAttributeProperty offset, scale, min, max +// (normalized)") +// { +// Model model; +// std::vector data = {12, 34, 30, 11}; +// +// const double offset = 1.0; +// const double scale = 2.0; +// const double min = 1.0; +// const double max = 3.0; +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 1, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; testClassProperty.normalized = true; +// testClassProperty.offset = offset; +// testClassProperty.scale = scale; +// testClassProperty.min = min; +// testClassProperty.max = max; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE(classProperty->componentType == +// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == +// std::nullopt); REQUIRE(!classProperty->array); +// REQUIRE(classProperty->normalized); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// SECTION("Use class property values") { +// PropertyAttributePropertyView property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); +// REQUIRE(property.offset() == offset); +// REQUIRE(property.scale() == scale); +// REQUIRE(property.min() == min); +// REQUIRE(property.max() == max); +// +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// REQUIRE(property.getRaw(uv[0], uv[1]) == data[i]); +// REQUIRE( +// property.get(uv[0], uv[1]) == normalize(data[i]) * scale + offset); +// } +// } +// +// SECTION("Use own property values") { +// const double newOffset = 2.0; +// const double newScale = 5.0; +// const double newMin = 10.0; +// const double newMax = 11.0; +// propertyAttributeProperty.offset = newOffset; +// propertyAttributeProperty.scale = newScale; +// propertyAttributeProperty.min = newMin; +// propertyAttributeProperty.max = newMax; +// +// PropertyAttributePropertyView property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); +// REQUIRE(property.offset() == newOffset); +// REQUIRE(property.scale() == newScale); +// REQUIRE(property.min() == newMin); +// REQUIRE(property.max() == newMax); +// +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// REQUIRE(property.getRaw(uv[0], uv[1]) == data[i]); +// REQUIRE( +// property.get(uv[0], uv[1]) == +// normalize(data[i]) * newScale + newOffset); +// } +// } +//} +// +// TEST_CASE("Test with PropertyAttributeProperty noData") { +// Model model; +// std::vector data = {12, 34, 30, 11}; +// const uint8_t noData = 34; +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 1, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; testClassProperty.noData = noData; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE(classProperty->componentType == +// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == +// std::nullopt); REQUIRE(!classProperty->array); +// REQUIRE(!classProperty->normalized); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// SECTION("Without default value") { +// PropertyAttributePropertyView property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); +// +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// auto value = property.getRaw(uv[0], uv[1]); +// REQUIRE(value == data[i]); +// +// auto maybeValue = property.get(uv[0], uv[1]); +// if (value == noData) { +// REQUIRE(!maybeValue); +// } else { +// REQUIRE(maybeValue == data[i]); +// } +// } +// } +// +// SECTION("With default value") { +// const uint8_t defaultValue = 255; +// testClassProperty.defaultProperty = defaultValue; +// +// PropertyAttributePropertyView property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); +// +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// auto value = property.getRaw(uv[0], uv[1]); +// REQUIRE(value == data[i]); +// +// auto maybeValue = property.get(uv[0], uv[1]); +// if (value == noData) { +// REQUIRE(maybeValue == defaultValue); +// } else { +// REQUIRE(maybeValue == data[i]); +// } +// } +// } +//} +// +// TEST_CASE("Test with PropertyAttributeProperty noData (normalized)") { +// Model model; +// std::vector data = {12, 34, 30, 11}; +// const uint8_t noData = 34; +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 1, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::UINT8; testClassProperty.normalized = true; +// testClassProperty.noData = noData; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE(classProperty->componentType == +// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == +// std::nullopt); REQUIRE(!classProperty->array); +// REQUIRE(classProperty->normalized); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// SECTION("Without default value") { +// PropertyAttributePropertyView property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); +// +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// auto value = property.getRaw(uv[0], uv[1]); +// REQUIRE(value == data[i]); +// +// auto maybeValue = property.get(uv[0], uv[1]); +// if (value == noData) { +// REQUIRE(!maybeValue); +// } else { +// REQUIRE(maybeValue == normalize(data[i])); +// } +// } +// } +// +// SECTION("With default value") { +// const double defaultValue = -1.0; +// testClassProperty.defaultProperty = defaultValue; +// +// PropertyAttributePropertyView property = +// view.getPropertyView("TestClassProperty"); +// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); +// +// for (size_t i = 0; i < texCoords.size(); ++i) { +// glm::dvec2 uv = texCoords[i]; +// auto value = property.getRaw(uv[0], uv[1]); +// REQUIRE(value == data[i]); +// +// auto maybeValue = property.get(uv[0], uv[1]); +// if (value == noData) { +// REQUIRE(maybeValue == defaultValue); +// } else { +// REQUIRE(maybeValue == normalize(data[i])); +// } +// } +// } +//} +// +// TEST_CASE("Test callback on invalid property Attribute view") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// metadata.schema.emplace(); +// +// // Property Attribute has a nonexistent class. +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = -1; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::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() == +// PropertyAttributePropertyViewStatus::ErrorInvalidPropertyAttribute); +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +// TEST_CASE("Test callback on invalid PropertyAttributeProperty") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// 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; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["InvalidProperty"]; +// propertyAttributeProperty.index = -1; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::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() != +// PropertyAttributePropertyViewStatus::Valid); +// }; +// +// view.getPropertyView("InvalidProperty", testCallback); +// view.getPropertyView("NonexistentProperty", testCallback); +// +// REQUIRE(invokedCallbackCount == 2); +//} +// +// TEST_CASE("Test callback on invalid normalized PropertyAttributeProperty") { +// Model model; +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// ClassProperty& testClassProperty = +// testClass.properties["TestClassProperty"]; testClassProperty.type = +// ClassProperty::Type::SCALAR; testClassProperty.componentType = +// ClassProperty::ComponentType::FLOAT32; testClassProperty.normalized = true; +// // This is erroneous. +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(0); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("TestClassProperty"); +// REQUIRE(classProperty); +// +// uint32_t invokedCallbackCount = 0; +// auto testCallback = [&invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) mutable { +// invokedCallbackCount++; +// REQUIRE( +// propertyValue.status() == +// PropertyAttributePropertyViewStatus::ErrorInvalidNormalization); +// }; +// +// view.getPropertyView("TestClassProperty", testCallback); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +// TEST_CASE("Test callback for scalar PropertyAttributeProperty") { +// Model model; +// std::vector data = {255, 255, 12, 1, 30, 2, 0, 255}; +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 2, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// 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; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::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); +// REQUIRE(!classProperty->normalized); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// std::vector expected{-1, 268, 542, -256}; +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&expected, &texCoords, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) mutable { +// invokedCallbackCount++; +// if constexpr (std::is_same_v< +// PropertyAttributePropertyView, +// decltype(propertyValue)>) { +// REQUIRE( +// propertyValue.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// for (size_t i = 0; i < expected.size(); ++i) { +// glm::dvec2& uv = texCoords[i]; +// REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); +// REQUIRE(propertyValue.get(uv[0], uv[1]) == expected[i]); +// } +// } else { +// FAIL("getPropertyView returned PropertyAttributePropertyView of " +// "incorrect type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +// TEST_CASE("Test callback for scalar PropertyAttributeProperty (normalized)") +// { +// Model model; +// std::vector data = {255, 255, 12, 1, 30, 2, 0, 255}; +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 2, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// 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; testClassProperty.normalized = true; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::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); +// REQUIRE(classProperty->normalized); +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(0.5, 0.5)}; +// +// std::vector expected{-1, 268, 542, -256}; +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "TestClassProperty", +// [&expected, &texCoords, &invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) mutable { +// invokedCallbackCount++; +// if constexpr (std::is_same_v< +// PropertyAttributePropertyView, +// decltype(propertyValue)>) { +// REQUIRE( +// propertyValue.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// for (size_t i = 0; i < expected.size(); ++i) { +// glm::dvec2& uv = texCoords[i]; +// REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); +// REQUIRE(propertyValue.get(uv[0], uv[1]) == +// normalize(expected[i])); +// } +// } else { +// FAIL("getPropertyView returned PropertyAttributePropertyView of " +// "incorrect type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +// TEST_CASE("Test callback for vecN PropertyAttributeProperty") { +// Model model; +// // clang-format off +// std::vector data = { +// 255, 255, +// 12, 1, +// 30, 2, +// 0, 255}; +// // clang-format on +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 2, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// 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; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::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); +// REQUIRE(!classProperty->normalized); +// +// std::vector expected{ +// glm::i8vec2(-1, -1), +// glm::i8vec2(12, 1), +// glm::i8vec2(30, 2), +// glm::i8vec2(0, -1)}; +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(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< +// PropertyAttributePropertyView, +// decltype(propertyValue)>) { +// REQUIRE( +// propertyValue.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// for (size_t i = 0; i < expected.size(); ++i) { +// glm::dvec2& uv = texCoords[i]; +// REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); +// REQUIRE(propertyValue.get(uv[0], uv[1]) == expected[i]); +// } +// } else { +// FAIL("getPropertyView returned PropertyAttributePropertyView of " +// "incorrect type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +// TEST_CASE("Test callback for vecN PropertyAttributeProperty (normalized)") { +// Model model; +// // clang-format off +// std::vector data = { +// 255, 255, +// 12, 1, +// 30, 2, +// 0, 255}; +// // clang-format on +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 2, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// 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; testClassProperty.normalized = true; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::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); +// REQUIRE(classProperty->normalized); +// +// std::vector expected{ +// glm::i8vec2(-1, -1), +// glm::i8vec2(12, 1), +// glm::i8vec2(30, 2), +// glm::i8vec2(0, -1)}; +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(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< +// PropertyAttributePropertyView, +// decltype(propertyValue)>) { +// REQUIRE( +// propertyValue.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// for (size_t i = 0; i < expected.size(); ++i) { +// glm::dvec2& uv = texCoords[i]; +// REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); +// REQUIRE(propertyValue.get(uv[0], uv[1]) == +// normalize(expected[i])); +// } +// } else { +// FAIL("getPropertyView returned PropertyAttributePropertyView of " +// "incorrect type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +// TEST_CASE("Test callback for array PropertyAttributeProperty") { +// Model model; +// // clang-format off +// std::vector data = { +// 254, 0, 253, 1, +// 10, 2, 40, 3, +// 30, 0, 0, 2, +// 10, 2, 255, 4}; +// // clang-format on +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 4, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// 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; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1, 2, 3}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::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); +// REQUIRE(!classProperty->normalized); +// +// std::vector> expected{ +// {254, 509}, +// {522, 808}, +// {30, 512}, +// {522, 1279}}; +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(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< +// PropertyAttributePropertyView< +// PropertyArrayView>, +// decltype(propertyValue)>) { +// REQUIRE( +// propertyValue.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// for (size_t i = 0; i < expected.size(); ++i) { +// std::vector& expectedArray = expected[i]; +// glm::dvec2& uv = texCoords[i]; +// PropertyArrayView array = +// propertyValue.getRaw(uv[0], uv[1]); +// +// REQUIRE(static_cast(array.size()) == +// expectedArray.size()); for (int64_t j = 0; j < array.size(); j++) +// { +// REQUIRE(array[j] == expectedArray[static_cast(j)]); +// } +// +// auto maybeArray = propertyValue.get(uv[0], uv[1]); +// REQUIRE(maybeArray); +// REQUIRE( +// static_cast(maybeArray->size()) == +// expectedArray.size()); +// for (int64_t j = 0; j < array.size(); j++) { +// REQUIRE( +// (*maybeArray)[j] == expectedArray[static_cast(j)]); +// } +// } +// } else { +// FAIL("getPropertyView returned PropertyAttributePropertyView of " +// "incorrect type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +// TEST_CASE("Test callback for array PropertyAttributeProperty (normalized)") { +// Model model; +// // clang-format off +// std::vector data = { +// 254, 0, 253, 1, +// 10, 2, 40, 3, +// 30, 0, 0, 2, +// 10, 2, 255, 4}; +// // clang-format on +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 2, +// 4, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// 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; +// testClassProperty.normalized = true; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& propertyAttributeProperty = +// propertyAttribute.properties["TestClassProperty"]; +// propertyAttributeProperty.index = static_cast(AttributeIndex); +// propertyAttributeProperty.texCoord = 0; +// propertyAttributeProperty.channels = {0, 1, 2, 3}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::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); +// REQUIRE(classProperty->normalized); +// +// std::vector> expected{ +// {254, 509}, +// {522, 808}, +// {30, 512}, +// {522, 1279}}; +// +// std::vector texCoords{ +// glm::dvec2(0, 0), +// glm::dvec2(0.5, 0), +// glm::dvec2(0, 0.5), +// glm::dvec2(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< +// PropertyAttributePropertyView, +// true>, decltype(propertyValue)>) { +// REQUIRE( +// propertyValue.status() == +// PropertyAttributePropertyViewStatus::Valid); +// +// for (size_t i = 0; i < expected.size(); ++i) { +// std::vector& expectedArray = expected[i]; +// glm::dvec2& uv = texCoords[i]; +// PropertyArrayView array = +// propertyValue.getRaw(uv[0], uv[1]); +// +// REQUIRE(static_cast(array.size()) == +// expectedArray.size()); for (int64_t j = 0; j < array.size(); j++) +// { +// REQUIRE(array[j] == expectedArray[static_cast(j)]); +// } +// +// auto maybeArray = propertyValue.get(uv[0], uv[1]); +// REQUIRE(maybeArray); +// REQUIRE( +// static_cast(maybeArray->size()) == +// expectedArray.size()); +// for (int64_t j = 0; j < array.size(); j++) { +// auto rawValue = expectedArray[static_cast(j)]; +// REQUIRE((*maybeArray)[j] == normalize(rawValue)); +// } +// } +// } else { +// FAIL("getPropertyView returned PropertyAttributePropertyView of " +// "incorrect type for TestClassProperty."); +// } +// }); +// +// REQUIRE(invokedCallbackCount == 1); +//} +// +// TEST_CASE("Test callback on unsupported PropertyAttributeProperty") { +// Model model; +// // clang-format off +// std::vector data = { +// 254, 0, 253, 1, +// 10, 2, 40, 3, +// 30, 0, 0, 2, +// 10, 2, 255, 4}; +// // clang-format on +// +// addAttributeToModel( +// model, +// Sampler::WrapS::CLAMP_TO_EDGE, +// Sampler::WrapS::CLAMP_TO_EDGE, +// 2, +// 1, +// 8, +// data); +// size_t AttributeIndex = model.Attributes.size() - 1; +// +// ExtensionModelExtStructuralMetadata& metadata = +// model.addExtension(); +// +// Schema& schema = metadata.schema.emplace(); +// Class& testClass = schema.classes["TestClass"]; +// +// ClassProperty& doubleClassProperty = +// testClass.properties["DoubleClassProperty"]; +// doubleClassProperty.type = ClassProperty::Type::SCALAR; +// doubleClassProperty.componentType = ClassProperty::ComponentType::FLOAT64; +// +// ClassProperty& arrayClassProperty = +// testClass.properties["ArrayClassProperty"]; +// arrayClassProperty.type = ClassProperty::Type::VEC4; +// arrayClassProperty.componentType = ClassProperty::ComponentType::UINT8; +// arrayClassProperty.array = true; +// arrayClassProperty.count = 2; +// +// PropertyAttribute& propertyAttribute = +// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty +// = "TestClass"; +// +// PropertyAttributeProperty& doubleProperty = +// propertyAttribute.properties["DoubleClassProperty"]; +// doubleProperty.index = static_cast(AttributeIndex); +// doubleProperty.texCoord = 0; +// doubleProperty.channels = {0, 1, 2, 3, 4, 5, 6, 7}; +// +// PropertyAttributeProperty& arrayProperty = +// propertyAttribute.properties["ArrayClassProperty"]; +// arrayProperty.index = static_cast(AttributeIndex); +// arrayProperty.texCoord = 0; +// arrayProperty.channels = {0, 1, 2, 3, 4, 5, 6, 7}; +// +// PropertyAttributeView view(model, propertyAttribute); +// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); +// +// const ClassProperty* classProperty = +// view.getClassProperty("DoubleClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); +// REQUIRE( +// classProperty->componentType == ClassProperty::ComponentType::FLOAT64); +// REQUIRE(!classProperty->array); +// +// classProperty = view.getClassProperty("ArrayClassProperty"); +// REQUIRE(classProperty); +// REQUIRE(classProperty->type == ClassProperty::Type::VEC4); +// REQUIRE(classProperty->componentType == +// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->array); +// REQUIRE(classProperty->count == 2); +// +// uint32_t invokedCallbackCount = 0; +// view.getPropertyView( +// "DoubleClassProperty", +// [&invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) mutable { +// invokedCallbackCount++; +// REQUIRE( +// propertyValue.status() == +// PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty); +// }); +// REQUIRE(invokedCallbackCount == 1); +// +// view.getPropertyView( +// "ArrayClassProperty", +// [&invokedCallbackCount]( +// const std::string& /*propertyName*/, +// auto propertyValue) mutable { +// invokedCallbackCount++; +// REQUIRE( +// propertyValue.status() == +// PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty); +// }); +// REQUIRE(invokedCallbackCount == 2); +//} diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 5149eb536..12011cabb 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -202,7 +202,7 @@ static void checkVariableLengthArray( } template -static void checkVariableLengthArrayWithProperties( +static void checkVariableLengthArray( const std::vector& data, const std::vector& offsets, PropertyComponentType offsetType, @@ -414,7 +414,7 @@ static void checkFixedLengthArray( } template -static void checkFixedLengthArrayWithProperties( +static void checkFixedLengthArray( const std::vector& data, int64_t fixedLengthArrayCount, const std::vector>>& expected, @@ -586,26 +586,6 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { checkNumeric(data); } - SECTION("Normalized Uint8") { - std::vector values{0, 64, 128, 255}; - std::vector> expected{ - 0.0, - 64.0 / 255.0, - 128.0 / 255.0, - 1.0}; - checkNormalizedNumeric(values, expected); - } - - SECTION("Normalized Int16") { - std::vector values{-32768, 0, 16384, 32767}; - std::vector> expected{ - -1.0, - 0.0, - 16384.0 / 32767.0, - 1.0}; - checkNormalizedNumeric(values, expected); - } - SECTION("Float with Offset / Scale") { std::vector values{12.5f, -12.5f, -5.0f, 6.75f}; const float offset = 1.0f; @@ -614,18 +594,6 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { checkNumeric(values, expected, offset, scale); } - SECTION("Normalized Uint8 with Offset and Scale") { - std::vector values{0, 64, 128, 255}; - const double offset = 1.0; - const double scale = 2.0; - std::vector> expected{ - 1.0, - 1 + 2 * (64.0 / 255.0), - 1 + 2 * (128.0 / 255.0), - 3.0}; - checkNormalizedNumeric(values, expected, offset, scale); - } - SECTION("Int16 with NoData") { std::vector values{-1, 3, 7, -1}; const int16_t noData = -1; @@ -661,26 +629,6 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { defaultValue); } - SECTION("Normalized Uint8 with all properties") { - std::vector values{0, 64, 128, 255}; - const double offset = 1.0; - const double scale = 2.0; - const uint8_t noData = 0; - const double defaultValue = 10.0; - std::vector> expected{ - 10.0, - 1 + 2 * (64.0 / 255.0), - 1 + 2 * (128.0 / 255.0), - 3.0}; - checkNormalizedNumeric( - values, - expected, - offset, - scale, - noData, - defaultValue); - } - SECTION("Overrides class property values") { std::vector values{1.0f, 3.0f, 2.0f, 4.0f}; std::vector data; @@ -720,6 +668,60 @@ TEST_CASE("Check scalar PropertyTablePropertyView") { } } +TEST_CASE("Check scalar PropertyTablePropertyView (normalized)") { + SECTION("Uint8") { + std::vector values{0, 64, 128, 255}; + std::vector> expected{ + 0.0, + 64.0 / 255.0, + 128.0 / 255.0, + 1.0}; + checkNormalizedNumeric(values, expected); + } + + SECTION("Int16") { + std::vector values{-32768, 0, 16384, 32767}; + std::vector> expected{ + -1.0, + 0.0, + 16384.0 / 32767.0, + 1.0}; + checkNormalizedNumeric(values, expected); + } + + SECTION("Uint8 with Offset and Scale") { + std::vector values{0, 64, 128, 255}; + const double offset = 1.0; + const double scale = 2.0; + std::vector> expected{ + 1.0, + 1 + 2 * (64.0 / 255.0), + 1 + 2 * (128.0 / 255.0), + 3.0}; + checkNormalizedNumeric(values, expected, offset, scale); + } + + SECTION("Uint8 with all properties") { + std::vector values{0, 64, 128, 255}; + const double offset = 1.0; + const double scale = 2.0; + const uint8_t noData = 0; + const double defaultValue = 10.0; + std::vector> expected{ + 10.0, + 1 + 2 * (64.0 / 255.0), + 1 + 2 * (128.0 / 255.0), + 3.0}; + checkNormalizedNumeric( + values, + expected, + offset, + scale, + noData, + defaultValue); + } +} + TEST_CASE("Check vecN PropertyTablePropertyView") { SECTION("Float Vec2") { std::vector data{ @@ -748,31 +750,6 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { checkNumeric(data); } - SECTION("Normalized Uint8 Vec2") { - std::vector values{ - glm::u8vec2(0, 64), - glm::u8vec2(128, 255), - glm::u8vec2(255, 0)}; - std::vector> expected{ - glm::dvec2(0.0, 64.0 / 255.0), - glm::dvec2(128.0 / 255.0, 1.0), - glm::dvec2(1.0, 0.0)}; - checkNormalizedNumeric(values, expected); - } - - SECTION("Normalized Int16 Vec2") { - std::vector values{ - glm::i16vec2(-32768, 0), - glm::i16vec2(16384, 32767), - glm::i16vec2(32767, -32768)}; - std::vector> expected{ - glm::dvec2(-1.0, 0.0), - glm::dvec2(16384.0 / 32767.0, 1.0), - glm::dvec2(1.0, -1.0), - }; - checkNormalizedNumeric(values, expected); - } - SECTION("Float Vec3 with Offset / Scale") { std::vector values{ glm::vec3(0.0f, -1.5f, -5.0f), @@ -789,20 +766,6 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { checkNumeric(values, expected, offset, scale); } - SECTION("Normalized Uint8 Vec2 with Offset and Scale") { - std::vector values{ - glm::u8vec2(0, 64), - glm::u8vec2(128, 255), - glm::u8vec2(255, 0)}; - JsonValue::Array offset{0.0, 1.0}; - JsonValue::Array scale{2.0, 1.0}; - std::vector> expected{ - glm::dvec2(0.0, 1 + (64.0 / 255.0)), - glm::dvec2(2 * (128.0 / 255.0), 2.0), - glm::dvec2(2.0, 1.0)}; - checkNormalizedNumeric(values, expected, offset, scale); - } - SECTION("Int16 Vec2 with NoData") { std::vector values{ glm::i16vec2(-1, 3), @@ -842,30 +805,6 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { defaultValue); }; - SECTION("Normalized Uint8 Vec2 with all properties") { - std::vector values{ - glm::u8vec2(0, 64), - glm::u8vec2(128, 255), - glm::u8vec2(255, 0), - glm::u8vec2(0, 0)}; - JsonValue::Array offset{0.0, 1.0}; - JsonValue::Array scale{2.0, 1.0}; - JsonValue::Array noData{0, 0}; - JsonValue::Array defaultValue{5.0, 15.0}; - std::vector> expected{ - glm::dvec2(0.0, 1 + (64.0 / 255.0)), - glm::dvec2(2 * (128.0 / 255.0), 2.0), - glm::dvec2(2.0, 1.0), - glm::dvec2(5.0, 15.0)}; - checkNormalizedNumeric( - values, - expected, - offset, - scale, - noData, - defaultValue); - } - SECTION("Overrides class property values") { std::vector values{ glm::vec2(1.0f, 3.0f), @@ -911,6 +850,71 @@ TEST_CASE("Check vecN PropertyTablePropertyView") { } } +TEST_CASE("Check vecN PropertyTablePropertyView (normalized)") { + SECTION("Uint8 Vec2") { + std::vector values{ + glm::u8vec2(0, 64), + glm::u8vec2(128, 255), + glm::u8vec2(255, 0)}; + std::vector> expected{ + glm::dvec2(0.0, 64.0 / 255.0), + glm::dvec2(128.0 / 255.0, 1.0), + glm::dvec2(1.0, 0.0)}; + checkNormalizedNumeric(values, expected); + } + + SECTION("Int16 Vec2") { + std::vector values{ + glm::i16vec2(-32768, 0), + glm::i16vec2(16384, 32767), + glm::i16vec2(32767, -32768)}; + std::vector> expected{ + glm::dvec2(-1.0, 0.0), + glm::dvec2(16384.0 / 32767.0, 1.0), + glm::dvec2(1.0, -1.0), + }; + checkNormalizedNumeric(values, expected); + } + + SECTION("Uint8 Vec2 with Offset and Scale") { + std::vector values{ + glm::u8vec2(0, 64), + glm::u8vec2(128, 255), + glm::u8vec2(255, 0)}; + JsonValue::Array offset{0.0, 1.0}; + JsonValue::Array scale{2.0, 1.0}; + std::vector> expected{ + glm::dvec2(0.0, 1 + (64.0 / 255.0)), + glm::dvec2(2 * (128.0 / 255.0), 2.0), + glm::dvec2(2.0, 1.0)}; + checkNormalizedNumeric(values, expected, offset, scale); + } + + SECTION("Uint8 Vec2 with all properties") { + std::vector values{ + glm::u8vec2(0, 64), + glm::u8vec2(128, 255), + glm::u8vec2(255, 0), + glm::u8vec2(0, 0)}; + JsonValue::Array offset{0.0, 1.0}; + JsonValue::Array scale{2.0, 1.0}; + JsonValue::Array noData{0, 0}; + JsonValue::Array defaultValue{5.0, 15.0}; + std::vector> expected{ + glm::dvec2(0.0, 1 + (64.0 / 255.0)), + glm::dvec2(2 * (128.0 / 255.0), 2.0), + glm::dvec2(2.0, 1.0), + glm::dvec2(5.0, 15.0)}; + checkNormalizedNumeric( + values, + expected, + offset, + scale, + noData, + defaultValue); + } +} + TEST_CASE("Check matN PropertyTablePropertyView") { SECTION("Float Mat2") { // clang-format off @@ -972,48 +976,7 @@ TEST_CASE("Check matN PropertyTablePropertyView") { checkNumeric(data); } - SECTION("Normalized Uint8 Mat2") { - // clang-format off - std::vector values{ - glm::u8mat2x2( - 0, 64, - 255, 255), - glm::u8mat2x2( - 255, 0, - 128, 0)}; - std::vector> expected{ - glm::dmat2( - 0.0, 64.0 / 255.0, - 1.0, 1.0), - glm::dmat2( - 1.0, 0.0, - 128.0 / 255.0, 0.0)}; - // clang-format on - checkNormalizedNumeric(values, expected); - } - - SECTION("Normalized Int16 Mat2") { - // clang-format off - std::vector values{ - glm::i16mat2x2( - -32768, 0, - 16384, 32767), - glm::i16mat2x2( - 0, 32767, - 32767, -32768)}; - std::vector> expected{ - glm::dmat2( - -1.0, 0.0, - 16384.0 / 32767.0, 1.0), - glm::dmat2( - 0.0, 1.0, - 1.0, -1.0), - }; - // clang-format on - checkNormalizedNumeric(values, expected); - } - - SECTION("Float Mat2 with Offset / Scale") { + SECTION("Float Mat2 with Offset / Scale") { // clang-format off std::vector values{ glm::mat2( @@ -1047,32 +1010,6 @@ TEST_CASE("Check matN PropertyTablePropertyView") { checkNumeric(values, expected, offset, scale); } - SECTION("Normalized Uint8 Mat2 with Offset and Scale") { - // clang-format off - std::vector values{ - glm::u8mat2x2( - 0, 64, - 255, 255), - glm::u8mat2x2( - 255, 0, - 128, 0)}; - JsonValue::Array offset{ - 0.0, 1.0, - 1.0, 0.0}; - JsonValue::Array scale{ - 2.0, 1.0, - 0.0, 2.0}; - std::vector> expected{ - glm::dmat2( - 0.0, 1 + 64.0 / 255.0, - 1.0, 2.0), - glm::dmat2( - 2.0, 1.0, - 1.0, 0.0)}; - // clang-format on - checkNormalizedNumeric(values, expected, offset, scale); - } - SECTION("Int16 Mat3 with NoData") { // clang-format off std::vector values{ @@ -1106,7 +1043,7 @@ TEST_CASE("Check matN PropertyTablePropertyView") { std::nullopt); }; - SECTION("Int16 Mat3 with NoData") { + SECTION("Int16 Mat3 with NoData and DefaultValue") { // clang-format off std::vector values{ glm::i16mat3x3( @@ -1143,47 +1080,6 @@ TEST_CASE("Check matN PropertyTablePropertyView") { defaultValue); }; - SECTION("Normalized Uint8 Mat2 with all properties") { - // clang-format off - std::vector values{ - glm::u8mat2x2( - 0, 64, - 255, 255), - glm::u8mat2x2(0), - glm::u8mat2x2( - 255, 0, - 128, 0)}; - JsonValue::Array offset{ - 0.0, 1.0, - 1.0, 0.0}; - JsonValue::Array scale{ - 2.0, 1.0, - 0.0, 2.0}; - JsonValue::Array noData{ - 0, 0, - 0, 0}; - JsonValue::Array defaultValue{ - 1.0, 0.0, - 0.0, 1.0}; - - std::vector> expected{ - glm::dmat2( - 0.0, 1 + 64.0 / 255.0, - 1.0, 2.0), - glm::dmat2(1.0), - glm::dmat2( - 2.0, 1.0, - 1.0, 0.0)}; - // clang-format on - checkNormalizedNumeric( - values, - expected, - offset, - scale, - noData, - defaultValue); - } - SECTION("Overrides class property values") { // clang-fomrat off std::vector values{ @@ -1267,6 +1163,116 @@ TEST_CASE("Check matN PropertyTablePropertyView") { } } +TEST_CASE("Check matN PropertyTablePropertyView (normalized)") { + SECTION("Uint8 Mat2") { + // clang-format off + std::vector values{ + glm::u8mat2x2( + 0, 64, + 255, 255), + glm::u8mat2x2( + 255, 0, + 128, 0)}; + std::vector> expected{ + glm::dmat2( + 0.0, 64.0 / 255.0, + 1.0, 1.0), + glm::dmat2( + 1.0, 0.0, + 128.0 / 255.0, 0.0)}; + // clang-format on + checkNormalizedNumeric(values, expected); + } + + SECTION("Int16 Mat2") { + // clang-format off + std::vector values{ + glm::i16mat2x2( + -32768, 0, + 16384, 32767), + glm::i16mat2x2( + 0, 32767, + 32767, -32768)}; + std::vector> expected{ + glm::dmat2( + -1.0, 0.0, + 16384.0 / 32767.0, 1.0), + glm::dmat2( + 0.0, 1.0, + 1.0, -1.0), + }; + // clang-format on + checkNormalizedNumeric(values, expected); + } + + SECTION("Uint8 Mat2 with Offset and Scale") { + // clang-format off + std::vector values{ + glm::u8mat2x2( + 0, 64, + 255, 255), + glm::u8mat2x2( + 255, 0, + 128, 0)}; + JsonValue::Array offset{ + 0.0, 1.0, + 1.0, 0.0}; + JsonValue::Array scale{ + 2.0, 1.0, + 0.0, 2.0}; + std::vector> expected{ + glm::dmat2( + 0.0, 1 + 64.0 / 255.0, + 1.0, 2.0), + glm::dmat2( + 2.0, 1.0, + 1.0, 0.0)}; + // clang-format on + checkNormalizedNumeric(values, expected, offset, scale); + } + + SECTION("Normalized Uint8 Mat2 with all properties") { + // clang-format off + std::vector values{ + glm::u8mat2x2( + 0, 64, + 255, 255), + glm::u8mat2x2(0), + glm::u8mat2x2( + 255, 0, + 128, 0)}; + JsonValue::Array offset{ + 0.0, 1.0, + 1.0, 0.0}; + JsonValue::Array scale{ + 2.0, 1.0, + 0.0, 2.0}; + JsonValue::Array noData{ + 0, 0, + 0, 0}; + JsonValue::Array defaultValue{ + 1.0, 0.0, + 0.0, 1.0}; + + std::vector> expected{ + glm::dmat2( + 0.0, 1 + 64.0 / 255.0, + 1.0, 2.0), + glm::dmat2(1.0), + glm::dmat2( + 2.0, 1.0, + 1.0, 0.0)}; + // clang-format on + checkNormalizedNumeric( + values, + expected, + offset, + scale, + noData, + defaultValue); + } +} + TEST_CASE("Check boolean PropertyTablePropertyView") { std::bitset bits = 0b11110101; unsigned long val = bits.to_ulong(); @@ -1501,18 +1507,6 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { checkFixedLengthArray(data, 4); } - SECTION("Array of 4 normalized uint8_ts") { - // clang-format off - std::vector data{ - 255, 64, 0, 255, - 128, 0, 255, 0}; - // clang-format on - std::vector>> expected{ - std::vector{1.0, 64.0 / 255.0, 0.0, 1.0}, - std::vector{128.0 / 255.0, 0.0, 1.0, 0.0}}; - checkNormalizedFixedLengthArray(data, 4, expected); - } - SECTION("Array of 4 floats with offset / scale") { // clang-format off std::vector data{ @@ -1527,7 +1521,7 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { std::vector>> expected{ std::vector{2.0f, 4.0f, 2.0f, 8.0f}, std::vector{6.0f, -2.0f, -1.0f, 4.0f}}; - checkFixedLengthArrayWithProperties(data, 4, expected, offset, scale); + checkFixedLengthArray(data, 4, expected, offset, scale); } SECTION("Array of 2 int32_ts with noData value") { @@ -1542,7 +1536,7 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { std::vector{122, 12}, std::nullopt, std::vector{-3, 44}}; - checkFixedLengthArrayWithProperties( + checkFixedLengthArray( data, 2, expected, @@ -1565,7 +1559,7 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { std::vector{122, 12}, std::vector{0, 1}, std::vector{-3, 44}}; - checkFixedLengthArrayWithProperties( + checkFixedLengthArray( data, 2, expected, @@ -1575,33 +1569,6 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { defaultValue); } - SECTION("Array of 3 normalized int8_ts with all properties") { - // clang-format off - std::vector data{ - -128, 0, 64, - -64, 127, -128, - 0, 0, 0}; - // clang-format on - JsonValue::Array offset{0, 1, 1}; - JsonValue::Array scale{1, -1, 2}; - JsonValue::Array noData{0, 0, 0}; - JsonValue::Array defaultValue{10, 8, 2}; - - std::vector>> expected{ - std::vector{-1.0, 1.0, 1 + 2 * (64.0 / 127.0)}, - std::vector{-64.0 / 127.0, 0.0, -1.0}, - std::vector{10.0, 8.0, 2.0}, - }; - checkNormalizedFixedLengthArray( - data, - 3, - expected, - offset, - scale, - noData, - defaultValue); - } - SECTION("Overrides class property values") { // clang-format off std::vector data{ @@ -1676,6 +1643,48 @@ TEST_CASE("Check fixed-length scalar array PropertyTablePropertyView") { } } +TEST_CASE( + "Check fixed-length scalar array PropertyTablePropertyView (normalized)") { + SECTION("Array of 4 uint8_ts") { + // clang-format off + std::vector data{ + 255, 64, 0, 255, + 128, 0, 255, 0}; + // clang-format on + std::vector>> expected{ + std::vector{1.0, 64.0 / 255.0, 0.0, 1.0}, + std::vector{128.0 / 255.0, 0.0, 1.0, 0.0}}; + checkNormalizedFixedLengthArray(data, 4, expected); + } + + SECTION("Array of 3 normalized int8_ts with all properties") { + // clang-format off + std::vector data{ + -128, 0, 64, + -64, 127, -128, + 0, 0, 0}; + // clang-format on + JsonValue::Array offset{0, 1, 1}; + JsonValue::Array scale{1, -1, 2}; + JsonValue::Array noData{0, 0, 0}; + JsonValue::Array defaultValue{10, 8, 2}; + + std::vector>> expected{ + std::vector{-1.0, 1.0, 1 + 2 * (64.0 / 127.0)}, + std::vector{-64.0 / 127.0, 0.0, -1.0}, + std::vector{10.0, 8.0, 2.0}, + }; + checkNormalizedFixedLengthArray( + data, + 3, + expected, + offset, + scale, + noData, + defaultValue); + } +} + TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { SECTION("Array of 4 u8vec2s") { std::vector data{ @@ -1712,22 +1721,6 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { checkFixedLengthArray(data, 3); } - SECTION("Array of 2 normalized u8vec2s") { - std::vector data{ - glm::u8vec2(255, 64), - glm::u8vec2(0, 255), - glm::u8vec2(128, 0), - glm::u8vec2(255, 0)}; - std::vector>> expected{ - std::vector{ - glm::dvec2(1.0, 64.0 / 255.0), - glm::dvec2(0.0, 1.0)}, - std::vector{ - glm::dvec2(128.0 / 255.0, 0.0), - glm::dvec2(1.0, 0.0)}}; - checkNormalizedFixedLengthArray(data, 2, expected); - } - SECTION("Array of 2 vec2s with offset / scale") { // clang-format off std::vector data{ @@ -1742,7 +1735,7 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { std::vector>> expected{ std::vector{glm::vec2(2.0f, 4.0f), glm::vec2(2.0f, 8.0f)}, std::vector{glm::vec2(6.0f, -2.0f), glm::vec2(-1.0f, 4.0f)}}; - checkFixedLengthArrayWithProperties(data, 2, expected, offset, scale); + checkFixedLengthArray(data, 2, expected, offset, scale); } SECTION("Array of 2 ivec2 with noData value") { @@ -1757,7 +1750,7 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { std::vector{glm::ivec2(122, 12), glm::ivec2(-1, -1)}, std::vector{glm::ivec2(-3, 44), glm::ivec2(0, 7)}, std::nullopt}; - checkFixedLengthArrayWithProperties( + checkFixedLengthArray( data, 2, expected, @@ -1780,7 +1773,7 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { std::vector{glm::ivec2(122, 12), glm::ivec2(-1, -1)}, std::vector{glm::ivec2(-3, 44), glm::ivec2(0, 7)}, std::vector{glm::ivec2(1, 1), glm::ivec2(1, 2)}}; - checkFixedLengthArrayWithProperties( + checkFixedLengthArray( data, 2, expected, @@ -1790,7 +1783,103 @@ TEST_CASE("Check fixed-length vecN array PropertyTablePropertyView") { defaultValue); } - SECTION("Array of 2 normalized i8vec2 with all properties") { + SECTION("Overrides class property values") { + // clang-format off + std::vector data{ + glm::vec2(1.0f, 2.0f), glm::vec2(3.0f, 4.0f), + glm::vec2(0.0f, -1.0f), glm::vec2(1.0f, -2.0f)}; + // clang-format on + const int64_t count = 2; + const int64_t instanceCount = 2; + + std::vector buffer; + buffer.resize(data.size() * sizeof(glm::vec2)); + std::memcpy(buffer.data(), data.data(), buffer.size()); + + ClassProperty classProperty; + classProperty.type = ClassProperty::Type::VEC2; + classProperty.componentType = ClassProperty::ComponentType::FLOAT32; + + classProperty.array = true; + classProperty.count = count; + classProperty.offset = JsonValue::Array{{0, 0}, {0, 0}}; + classProperty.scale = JsonValue::Array{{1, 1}, {1, 1}}; + classProperty.min = JsonValue::Array{{0.0f, -1.0f}, {1.0f, -2.0f}}; + classProperty.max = JsonValue::Array{{1.0f, 2.0f}, {3.0f, 4.0f}}; + + PropertyTableProperty propertyTableProperty; + propertyTableProperty.offset = JsonValue::Array{{2, 1}, {0, -1}}; + propertyTableProperty.scale = JsonValue::Array{{1, 0}, {1, -1}}; + propertyTableProperty.min = JsonValue::Array{{0.0f, 1.0f}, {1.0f, -2.0f}}; + propertyTableProperty.max = JsonValue::Array{{1.0f, 1.0f}, {3.0f, 4.0f}}; + + PropertyTablePropertyView> property( + propertyTableProperty, + classProperty, + instanceCount, + gsl::span(buffer.data(), buffer.size()), + gsl::span(), + gsl::span(), + PropertyComponentType::None, + PropertyComponentType::None); + + REQUIRE(property.arrayCount() == count); + REQUIRE(property.size() == instanceCount); + + REQUIRE(property.offset()); + checkArrayEqual(*property.offset(), {glm::vec2{2, 1}, glm::vec2{0, -1}}); + + REQUIRE(property.scale()); + checkArrayEqual(*property.scale(), {glm::vec2{1, 0}, glm::vec2{1, -1}}); + + REQUIRE(property.min()); + checkArrayEqual( + *property.min(), + {glm::vec2{0.0f, 1.0f}, glm::vec2{1.0f, -2.0f}}); + + REQUIRE(property.max()); + checkArrayEqual( + *property.max(), + {glm::vec2(1.0f, 1.0f), glm::vec2(3.0f, 4.0f)}); + + std::vector> expected{ + {glm::vec2(3.0f, 1.0f), glm::vec2(3.0f, -5.0f)}, + {glm::vec2(2.0f, 1.0f), glm::vec2(1.0f, 1.0f)}}; + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView rawValues = property.getRaw(i); + auto values = property.get(i); + REQUIRE(values); + for (int64_t j = 0; j < rawValues.size(); ++j) { + REQUIRE(rawValues[j] == data[expectedIdx]); + REQUIRE( + (*values)[j] == + expected[static_cast(i)][static_cast(j)]); + ++expectedIdx; + } + } + } +} + +TEST_CASE( + "Check fixed-length vecN array PropertyTablePropertyView (normalized)") { + SECTION("Array of 2 u8vec2s") { + std::vector data{ + glm::u8vec2(255, 64), + glm::u8vec2(0, 255), + glm::u8vec2(128, 0), + glm::u8vec2(255, 0)}; + std::vector>> expected{ + std::vector{ + glm::dvec2(1.0, 64.0 / 255.0), + glm::dvec2(0.0, 1.0)}, + std::vector{ + glm::dvec2(128.0 / 255.0, 0.0), + glm::dvec2(1.0, 0.0)}}; + checkNormalizedFixedLengthArray(data, 2, expected); + } + + SECTION("Array of 2 i8vec2 with all properties") { // clang-format off std::vector data{ glm::i8vec2(-128, 0), glm::i8vec2(64, -64), @@ -1997,44 +2086,6 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { checkFixedLengthArray(data, 3); } - SECTION("Array of 2 normalized u8mat2x2s") { - // clang-format off - std::vector data{ - glm::u8mat2x2( - 255, 64, - 0, 255), - glm::u8mat2x2( - 0, 255, - 64, 128), - glm::u8mat2x2( - 128, 0, - 0, 255), - glm::u8mat2x2( - 255, 32, - 255, 0)}; - - std::vector>> expected{ - std::vector{ - glm::dmat2( - 1.0, 64.0 / 255.0, - 0.0, 1.0), - glm::dmat2( - 0.0, 1.0, - 64.0 / 255.0, 128.0 / 255.0), - }, - std::vector{ - glm::dmat2( - 128.0 / 255.0, 0.0, - 0.0, 1.0), - glm::dmat2( - 1.0, 32.0 / 255.0, - 1.0, 0.0), - }}; - // clang-format on - - checkNormalizedFixedLengthArray(data, 2, expected); - } - SECTION("Array of 2 mat2s with offset / scale") { // clang-format off std::vector data{ @@ -2078,7 +2129,7 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { -1.0f, 2.0f, -4.0f, 8.0f)}}; // clang-format on - checkFixedLengthArrayWithProperties(data, 2, expected, offset, scale); + checkFixedLengthArray(data, 2, expected, offset, scale); } SECTION("Array of 2 imat2x2 with noData value") { @@ -2116,7 +2167,7 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { -1, 0)}, std::nullopt}; // clang-format on - checkFixedLengthArrayWithProperties( + checkFixedLengthArray( data, 2, expected, @@ -2170,7 +2221,7 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { glm::imat2x2(1) }}; // clang-format on - checkFixedLengthArrayWithProperties( + checkFixedLengthArray( data, 2, expected, @@ -2180,72 +2231,6 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { defaultValue); } - SECTION("Array of 2 normalized i8mat2x2 with all properties") { - // clang-format off - std::vector data{ - glm::i8mat2x2(-128), - glm::i8mat2x2( - 64, -64, - 0, 255), - glm::i8mat2x2( - 127, -128, - -128, 0), - glm::i8mat2x2(0), - glm::i8mat2x2(0), - glm::i8mat2x2( - -128, -128, - -128, -128)}; - JsonValue::Array offset{ - {0, 1, - 2, 3}, - {1, 2, - 0, -2}}; - JsonValue::Array scale{ - {1, -1, - 0, 1}, - {2, 1, - -1, 0}}; - JsonValue::Array noData{ - {0, 0, - 0, 0}, - {-128, -128, - -128, -128}}; - JsonValue::Array defaultValue{ - {1, 0, - 0, 1}, - {2, 0, - 0, 2}}; - - std::vector>> expected{ - std::vector{ - glm::dmat2( - -1.0, 1.0, - 2.0, 2.0), - glm::dmat2( - 1 + 2 * (64.0 / 127.0), 2 - (64.0 / 127.0), - 0, -2)}, - std::vector{ - glm::dmat2( - 1.0, 2.0, - 2.0, 3.0), - glm::dmat2( - 1.0, 2.0, - 0.0, -2.0)}, - std::vector{ - glm::dmat2(1), - glm::dmat2(2)}, - }; - // clang-format on - checkNormalizedFixedLengthArray( - data, - 2, - expected, - offset, - scale, - noData, - defaultValue); - } - SECTION("Overrides class property values") { // clang-format off std::vector data{ @@ -2364,33 +2349,140 @@ TEST_CASE("Check fixed-length matN array PropertyTablePropertyView") { 4.0f, -1.0f, 4.0f, 8.0f)}); - std::vector> expected{ - {glm::mat2( - 3.0f, 1.0f, - -1.0f, 0.0f), - glm::mat2( - 2.0f, -1.0f, - 4.0f, 4.0f)}, - {glm::mat2( - 5.0f, 1.0f, - -1.0f, 4.0f), - glm::mat2( - 4.0f, -1.0f, - 4.0f, 8.0f)}}; + std::vector> expected{ + {glm::mat2( + 3.0f, 1.0f, + -1.0f, 0.0f), + glm::mat2( + 2.0f, -1.0f, + 4.0f, 4.0f)}, + {glm::mat2( + 5.0f, 1.0f, + -1.0f, 4.0f), + glm::mat2( + 4.0f, -1.0f, + 4.0f, 8.0f)}}; + // clang-format on + size_t expectedIdx = 0; + for (int64_t i = 0; i < property.size(); ++i) { + PropertyArrayView rawValues = property.getRaw(i); + auto values = property.get(i); + REQUIRE(values); + for (int64_t j = 0; j < rawValues.size(); ++j) { + REQUIRE(rawValues[j] == data[expectedIdx]); + REQUIRE( + (*values)[j] == + expected[static_cast(i)][static_cast(j)]); + ++expectedIdx; + } + } + } +} + +TEST_CASE( + "Check fixed-length matN array PropertyTablePropertyView (normalized)") { + SECTION("Array of 2 u8mat2x2s") { + // clang-format off + std::vector data{ + glm::u8mat2x2( + 255, 64, + 0, 255), + glm::u8mat2x2( + 0, 255, + 64, 128), + glm::u8mat2x2( + 128, 0, + 0, 255), + glm::u8mat2x2( + 255, 32, + 255, 0)}; + + std::vector>> expected{ + std::vector{ + glm::dmat2( + 1.0, 64.0 / 255.0, + 0.0, 1.0), + glm::dmat2( + 0.0, 1.0, + 64.0 / 255.0, 128.0 / 255.0), + }, + std::vector{ + glm::dmat2( + 128.0 / 255.0, 0.0, + 0.0, 1.0), + glm::dmat2( + 1.0, 32.0 / 255.0, + 1.0, 0.0), + }}; + // clang-format on + + checkNormalizedFixedLengthArray(data, 2, expected); + } + + SECTION("Array of 2 i8mat2x2 with all properties") { + // clang-format off + std::vector data{ + glm::i8mat2x2(-128), + glm::i8mat2x2( + 64, -64, + 0, 255), + glm::i8mat2x2( + 127, -128, + -128, 0), + glm::i8mat2x2(0), + glm::i8mat2x2(0), + glm::i8mat2x2( + -128, -128, + -128, -128)}; + JsonValue::Array offset{ + {0, 1, + 2, 3}, + {1, 2, + 0, -2}}; + JsonValue::Array scale{ + {1, -1, + 0, 1}, + {2, 1, + -1, 0}}; + JsonValue::Array noData{ + {0, 0, + 0, 0}, + {-128, -128, + -128, -128}}; + JsonValue::Array defaultValue{ + {1, 0, + 0, 1}, + {2, 0, + 0, 2}}; + + std::vector>> expected{ + std::vector{ + glm::dmat2( + -1.0, 1.0, + 2.0, 2.0), + glm::dmat2( + 1 + 2 * (64.0 / 127.0), 2 - (64.0 / 127.0), + 0, -2)}, + std::vector{ + glm::dmat2( + 1.0, 2.0, + 2.0, 3.0), + glm::dmat2( + 1.0, 2.0, + 0.0, -2.0)}, + std::vector{ + glm::dmat2(1), + glm::dmat2(2)}, + }; // clang-format on - size_t expectedIdx = 0; - for (int64_t i = 0; i < property.size(); ++i) { - PropertyArrayView rawValues = property.getRaw(i); - auto values = property.get(i); - REQUIRE(values); - for (int64_t j = 0; j < rawValues.size(); ++j) { - REQUIRE(rawValues[j] == data[expectedIdx]); - REQUIRE( - (*values)[j] == - expected[static_cast(i)][static_cast(j)]); - ++expectedIdx; - } - } + checkNormalizedFixedLengthArray( + data, + 2, + expected, + offset, + scale, + noData, + defaultValue); } } @@ -2496,7 +2588,7 @@ TEST_CASE("Check variable-length scalar array PropertyTablePropertyView") { std::vector{1, 3, 2}, std::nullopt, std::vector{1, 3, 4, 1}}; - checkVariableLengthArrayWithProperties( + checkVariableLengthArray( data, offsets, PropertyComponentType::Uint32, @@ -2532,7 +2624,7 @@ TEST_CASE("Check variable-length scalar array PropertyTablePropertyView") { std::vector{1, 3, 2}, std::vector{1}, std::vector{1, 3, 4, 1}}; - checkVariableLengthArrayWithProperties( + checkVariableLengthArray( data, offsets, PropertyComponentType::Uint32, @@ -2576,6 +2668,67 @@ TEST_CASE("Check variable-length scalar array PropertyTablePropertyView") { } } +TEST_CASE("Check variable-length scalar array PropertyTablePropertyView " + "(normalized)") { + SECTION("Array of uint8_t") { + // clang-format off + std::vector data{ + 255, 0, + 0, 255, 128, + 64, + }; + std::vector offsets{ + 0, 2, 5, 6 + }; + // clang-format on + + std::vector>> expected{ + std::vector{1.0, 0.0}, + std::vector{0.0, 1.0, 128.0 / 255.0}, + std::vector{64.0 / 255.0}, + }; + checkNormalizedVariableLengthArray( + data, + offsets, + PropertyComponentType::Uint32, + 3, + expected); + } + + SECTION("Array of uint8_t with NoData and DefaultValue") { + // clang-format off + std::vector data{ + 255, 0, + 0, 255, 128, + 64, + 255, 255 + }; + std::vector offsets{ + 0, 2, 5, 6, 8 + }; + // clang-format on + + JsonValue::Array noData{255, 255}; + JsonValue::Array defaultValue{-1.0}; + + std::vector>> expected{ + std::vector{1.0, 0.0}, + std::vector{0.0, 1.0, 128.0 / 255.0}, + std::vector{64.0 / 255}, + std::vector{-1.0}, + }; + + checkNormalizedVariableLengthArray( + data, + offsets, + PropertyComponentType::Uint32, + 4, + expected, + noData, + defaultValue); + } +} + TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { SECTION("Array of ivec2") { // clang-format off @@ -2639,38 +2792,6 @@ TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 5); } - SECTION("Array of normalized u8vec2") { - // clang-format off - std::vector data{ - glm::u8vec2(255, 0), glm::u8vec2(0, 64), - glm::u8vec2(0, 0), - glm::u8vec2(128, 255), glm::u8vec2(255, 255), glm::u8vec2(32, 64) - }; - // clang-format on - std::vector offsets{ - 0 * sizeof(glm::u8vec2), - 2 * sizeof(glm::u8vec2), - 3 * sizeof(glm::u8vec2), - 6 * sizeof(glm::u8vec2)}; - - std::vector>> expected{ - std::vector{ - glm::dvec2(1.0, 0.0), - glm::dvec2(0.0, 64.0 / 255.0)}, - std::vector{glm::dvec2(0.0, 0.0)}, - std::vector{ - glm::dvec2(128.0 / 255.0, 1.0), - glm::dvec2(1.0, 1.0), - glm::dvec2(32.0 / 255.0, 64.0 / 255.0)}, - }; - checkNormalizedVariableLengthArray( - data, - offsets, - PropertyComponentType::Uint32, - 3, - expected); - } - SECTION("Array of ivec3 with NoData") { // clang-format off std::vector data{ @@ -2701,7 +2822,7 @@ TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { glm::ivec3(0)}, std::nullopt, std::vector{glm::ivec3(1, 3, 4), glm::ivec3(1, 0, 1)}}; - checkVariableLengthArrayWithProperties( + checkVariableLengthArray( data, offsets, PropertyComponentType::Uint32, @@ -2742,7 +2863,7 @@ TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { glm::ivec3(0)}, std::vector{glm::ivec3(0)}, std::vector{glm::ivec3(1, 3, 4), glm::ivec3(1, 0, 1)}}; - checkVariableLengthArrayWithProperties( + checkVariableLengthArray( data, offsets, PropertyComponentType::Uint32, @@ -2751,6 +2872,41 @@ TEST_CASE("Check variable-length vecN array PropertyTablePropertyView") { noData, defaultValue); } +} + +TEST_CASE( + "Check variable-length vecN array PropertyTablePropertyView (normalized)") { + SECTION("Array of u8vec2") { + // clang-format off + std::vector data{ + glm::u8vec2(255, 0), glm::u8vec2(0, 64), + glm::u8vec2(0, 0), + glm::u8vec2(128, 255), glm::u8vec2(255, 255), glm::u8vec2(32, 64) + }; + // clang-format on + std::vector offsets{ + 0 * sizeof(glm::u8vec2), + 2 * sizeof(glm::u8vec2), + 3 * sizeof(glm::u8vec2), + 6 * sizeof(glm::u8vec2)}; + + std::vector>> expected{ + std::vector{ + glm::dvec2(1.0, 0.0), + glm::dvec2(0.0, 64.0 / 255.0)}, + std::vector{glm::dvec2(0.0, 0.0)}, + std::vector{ + glm::dvec2(128.0 / 255.0, 1.0), + glm::dvec2(1.0, 1.0), + glm::dvec2(32.0 / 255.0, 64.0 / 255.0)}, + }; + checkNormalizedVariableLengthArray( + data, + offsets, + PropertyComponentType::Uint32, + 3, + expected); + } SECTION("Array of normalized u8vec2 with NoData and DefaultValue") { // clang-format off @@ -2941,36 +3097,6 @@ TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { checkVariableLengthArray(data, offsets, PropertyComponentType::Uint32, 3); } - SECTION("Array of normalized u8mat2x2") { - // clang-format off - std::vector data{ - glm::u8mat2x2(255), glm::u8mat2x2(64), - glm::u8mat2x2(0), - glm::u8mat2x2(128), glm::u8mat2x2(255), glm::u8mat2x2(32) - }; - // clang-format on - std::vector offsets{ - 0 * sizeof(glm::u8mat2x2), - 2 * sizeof(glm::u8mat2x2), - 3 * sizeof(glm::u8mat2x2), - 6 * sizeof(glm::u8mat2x2)}; - - std::vector>> expected{ - std::vector{glm::dmat2(1.0), glm::dmat2(64.0 / 255.0)}, - std::vector{glm::dmat2(0.0)}, - std::vector{ - glm::dmat2(128.0 / 255.0), - glm::dmat2(1.0), - glm::dmat2(32.0 / 255.0)}, - }; - checkNormalizedVariableLengthArray( - data, - offsets, - PropertyComponentType::Uint32, - 3, - expected); - } - SECTION("Array of imat3x3 with NoData") { // clang-format off std::vector data{ @@ -3006,7 +3132,7 @@ TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { glm::imat3x3(0)}, std::nullopt, std::vector{glm::imat3x3(1), glm::imat3x3(24)}}; - checkVariableLengthArrayWithProperties( + checkVariableLengthArray( data, offsets, PropertyComponentType::Uint32, @@ -3055,7 +3181,7 @@ TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { glm::imat3x3(0)}, std::vector{glm::imat3x3(99)}, std::vector{glm::imat3x3(1), glm::imat3x3(24)}}; - checkVariableLengthArrayWithProperties( + checkVariableLengthArray( data, offsets, PropertyComponentType::Uint32, @@ -3064,8 +3190,41 @@ TEST_CASE("Check variable-length matN array PropertyTablePropertyView") { noData, defaultValue); } +} + +TEST_CASE( + "Check variable-length matN array PropertyTablePropertyView (normalized)") { + SECTION("Array of u8mat2x2") { + // clang-format off + std::vector data{ + glm::u8mat2x2(255), glm::u8mat2x2(64), + glm::u8mat2x2(0), + glm::u8mat2x2(128), glm::u8mat2x2(255), glm::u8mat2x2(32) + }; + // clang-format on + std::vector offsets{ + 0 * sizeof(glm::u8mat2x2), + 2 * sizeof(glm::u8mat2x2), + 3 * sizeof(glm::u8mat2x2), + 6 * sizeof(glm::u8mat2x2)}; + + std::vector>> expected{ + std::vector{glm::dmat2(1.0), glm::dmat2(64.0 / 255.0)}, + std::vector{glm::dmat2(0.0)}, + std::vector{ + glm::dmat2(128.0 / 255.0), + glm::dmat2(1.0), + glm::dmat2(32.0 / 255.0)}, + }; + checkNormalizedVariableLengthArray( + data, + offsets, + PropertyComponentType::Uint32, + 3, + expected); + } - SECTION("Array of normalized u8mat2x2 with NoData and DefaultValue") { + SECTION("Array of u8mat2x2 with NoData and DefaultValue") { // clang-format off std::vector data{ glm::u8mat2x2(255), glm::u8mat2x2(64), diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index 638c721a4..7805964a1 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -3,10 +3,8 @@ #include #include -#include #include #include -#include #include using namespace CesiumGltf; @@ -696,7 +694,7 @@ TEST_CASE("Check scalar PropertyTexturePropertyView (normalized)") { } SECTION("uint8_t with all properties") { - std::vector data{12, 33, 56, 0, 67}; + std::vector data{12, 33, 56, 0}; const double offset = 1.0; const double scale = 2.0; const uint8_t noData = 0; @@ -706,7 +704,6 @@ TEST_CASE("Check scalar PropertyTexturePropertyView (normalized)") { normalize(data[1]) * scale + offset, normalize(data[2]) * scale + offset, 10.0, - normalize(data[4]) * scale + offset, }; checkNormalizedTextureValues( data, @@ -857,7 +854,7 @@ TEST_CASE("Check vecN PropertyTexturePropertyView") { 0, 0, 182, 1}; // clang-format on - std::optional noData = JsonValue::Array{0, 0}; + JsonValue::Array noData{0, 0}; std::vector expectedRaw{ glm::i8vec2(28, -1), glm::i8vec2(-2, 1), @@ -1144,7 +1141,7 @@ TEST_CASE("Check array PropertyTexturePropertyView") { 0, 0, 0, 0,}; // clang-format on - std::optional noData = JsonValue::Array{0, 0, 0, 0}; + JsonValue::Array noData{0, 0, 0, 0}; std::vector> expectedRaw{ {1, 2, 3, 0}, {4, 5, 6, 11}, @@ -1167,8 +1164,8 @@ TEST_CASE("Check array PropertyTexturePropertyView") { 0, 0, 0, 0,}; // clang-format on - std::optional noData = JsonValue::Array{0, 0, 0, 0}; - std::optional defaultValue = JsonValue::Array{255, 8, 12, 5}; + JsonValue::Array noData{0, 0, 0, 0}; + JsonValue::Array defaultValue{255, 8, 12, 5}; std::vector> expectedRaw{ {1, 2, 3, 0}, {4, 5, 6, 11}, @@ -1299,7 +1296,7 @@ TEST_CASE("Check array PropertyTexturePropertyView (normalized)") { 0, 0, 0, 0,}; // clang-format on - std::optional noData = JsonValue::Array{0, 0, 0, 0}; + JsonValue::Array noData{0, 0, 0, 0}; std::vector> expectedRaw{ {1, 2, 3, 0}, {4, 5, 6, 11}, @@ -1340,9 +1337,8 @@ TEST_CASE("Check array PropertyTexturePropertyView (normalized)") { const std::vector offset{1, 2, 0, 4}; const std::vector scale{1, -1, 3, -2}; - std::optional noData = JsonValue::Array{0, 0, 0, 0}; - std::optional defaultValue = - JsonValue::Array{1.0, 2.0, 3.0, 4.0}; + JsonValue::Array noData{0, 0, 0, 0}; + JsonValue::Array defaultValue{1.0, 2.0, 3.0, 4.0}; std::vector> expectedRaw{ {1, 2, 3, 0}, @@ -1375,7 +1371,7 @@ TEST_CASE("Check array PropertyTexturePropertyView (normalized)") { } } -TEST_CASE("Check that property values override class property values") { +TEST_CASE("Check that PropertyTextureProperty values override class property values") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; @@ -1427,14 +1423,10 @@ TEST_CASE("Check that property values override class property values") { view(property, classProperty, sampler, image, channels); CHECK(view.getSwizzle() == "rgba"); - REQUIRE(view.offset()); - REQUIRE(*view.offset() == offset); - REQUIRE(view.scale()); - REQUIRE(*view.scale() == scale); - REQUIRE(view.min()); - REQUIRE(*view.min() == std::numeric_limits::lowest()); - REQUIRE(view.max()); - REQUIRE(*view.max() == std::numeric_limits::max()); + REQUIRE(view.offset() == offset); + REQUIRE(view.scale() == scale); + REQUIRE(view.min() == std::numeric_limits::lowest()); + REQUIRE(view.max() == std::numeric_limits::max()); std::vector texCoords{ glm::dvec2(0, 0), From a56f7eddec540003d5ee5b92ec48a63065f55138 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 29 Aug 2023 12:31:44 -0400 Subject: [PATCH 105/121] Move function bodies to cpp --- .../CesiumGltf/PropertyTablePropertyView.h | 15 +------ .../CesiumGltf/PropertyTexturePropertyView.h | 37 +---------------- CesiumGltf/src/PropertyTablePropertyView.cpp | 19 ++++++++- .../src/PropertyTexturePropertyView.cpp | 40 ++++++++++++++++++- 4 files changed, 59 insertions(+), 52 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h index 1a86d0972..e4804a67f 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTablePropertyView.h @@ -133,20 +133,7 @@ class PropertyTablePropertyViewStatus : public PropertyViewStatus { static const PropertyViewStatusType ErrorStringOffsetOutOfBounds = 29; }; -inline int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { - switch (offsetType) { - case PropertyComponentType::Uint8: - return sizeof(uint8_t); - case PropertyComponentType::Uint16: - return sizeof(uint16_t); - case PropertyComponentType::Uint32: - return sizeof(uint32_t); - case PropertyComponentType::Uint64: - return sizeof(uint64_t); - default: - return 0; - } -} +int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept; /** * @brief A view on the data of the {@link PropertyTableProperty} that is created diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index 821e3932d..da9bc456f 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -190,41 +190,8 @@ assembleValueFromChannels(const std::vector& bytes) noexcept { } } -inline double applySamplerWrapS(const double u, const int32_t wrapS) { - if (wrapS == Sampler::WrapS::REPEAT) { - double integral = 0; - double fraction = std::modf(u, &integral); - return fraction < 0 ? 1.0 - fraction : fraction; - } - - if (wrapS == Sampler::WrapS::MIRRORED_REPEAT) { - double integral = 0; - double fraction = std::abs(std::modf(u, &integral)); - int64_t integer = static_cast(std::abs(integral)); - // If the integer part is odd, the direction is reversed. - return integer % 2 == 1 ? 1.0 - fraction : fraction; - } - - return glm::clamp(u, 0.0, 1.0); -} - -inline double applySamplerWrapT(const double v, const int32_t wrapT) { - if (wrapT == Sampler::WrapT::REPEAT) { - double integral = 0; - double fraction = std::modf(v, &integral); - return fraction < 0 ? 1.0 - fraction : fraction; - } - - if (wrapT == Sampler::WrapT::MIRRORED_REPEAT) { - double integral = 0; - double fraction = std::abs(std::modf(v, &integral)); - int64_t integer = static_cast(std::abs(integral)); - // If the integer part is odd, the direction is reversed. - return integer % 2 == 1 ? 1.0 - fraction : fraction; - } - - return glm::clamp(v, 0.0, 1.0); -} +double applySamplerWrapS(const double u, const int32_t wrapS); +double applySamplerWrapT(const double v, const int32_t wrapT); /** * @brief A view of the data specified by a {@link PropertyTextureProperty}. diff --git a/CesiumGltf/src/PropertyTablePropertyView.cpp b/CesiumGltf/src/PropertyTablePropertyView.cpp index 48f162915..8d2dabf53 100644 --- a/CesiumGltf/src/PropertyTablePropertyView.cpp +++ b/CesiumGltf/src/PropertyTablePropertyView.cpp @@ -1,7 +1,6 @@ #include "CesiumGltf/PropertyTablePropertyView.h" -using namespace CesiumGltf; - +namespace CesiumGltf { // Re-initialize consts here to avoid "undefined reference" errors with GCC / // Clang. const PropertyViewStatusType @@ -40,3 +39,19 @@ const PropertyViewStatusType PropertyTablePropertyViewStatus::ErrorArrayOffsetOutOfBounds; const PropertyViewStatusType PropertyTablePropertyViewStatus::ErrorStringOffsetOutOfBounds; + +int64_t getOffsetTypeSize(PropertyComponentType offsetType) noexcept { + switch (offsetType) { + case PropertyComponentType::Uint8: + return sizeof(uint8_t); + case PropertyComponentType::Uint16: + return sizeof(uint16_t); + case PropertyComponentType::Uint32: + return sizeof(uint32_t); + case PropertyComponentType::Uint64: + return sizeof(uint64_t); + default: + return 0; + } +} +} // namespace CesiumGltf diff --git a/CesiumGltf/src/PropertyTexturePropertyView.cpp b/CesiumGltf/src/PropertyTexturePropertyView.cpp index f5bd80aed..5b7f654ba 100644 --- a/CesiumGltf/src/PropertyTexturePropertyView.cpp +++ b/CesiumGltf/src/PropertyTexturePropertyView.cpp @@ -1,6 +1,6 @@ #include "CesiumGltf/PropertyTexturePropertyView.h" -using namespace CesiumGltf; +namespace CesiumGltf { // Re-initialize consts here to avoid "undefined reference" errors with GCC / // Clang. @@ -21,3 +21,41 @@ const PropertyViewStatusType PropertyTexturePropertyViewStatus::ErrorInvalidChannels; const PropertyViewStatusType PropertyTexturePropertyViewStatus::ErrorChannelsAndTypeMismatch; + +double applySamplerWrapS(const double u, const int32_t wrapS) { + if (wrapS == Sampler::WrapS::REPEAT) { + double integral = 0; + double fraction = std::modf(u, &integral); + return fraction < 0 ? 1.0 - fraction : fraction; + } + + if (wrapS == Sampler::WrapS::MIRRORED_REPEAT) { + double integral = 0; + double fraction = std::abs(std::modf(u, &integral)); + int64_t integer = static_cast(std::abs(integral)); + // If the integer part is odd, the direction is reversed. + return integer % 2 == 1 ? 1.0 - fraction : fraction; + } + + return glm::clamp(u, 0.0, 1.0); +} + +double applySamplerWrapT(const double v, const int32_t wrapT) { + if (wrapT == Sampler::WrapT::REPEAT) { + double integral = 0; + double fraction = std::modf(v, &integral); + return fraction < 0 ? 1.0 - fraction : fraction; + } + + if (wrapT == Sampler::WrapT::MIRRORED_REPEAT) { + double integral = 0; + double fraction = std::abs(std::modf(v, &integral)); + int64_t integer = static_cast(std::abs(integral)); + // If the integer part is odd, the direction is reversed. + return integer % 2 == 1 ? 1.0 - fraction : fraction; + } + + return glm::clamp(v, 0.0, 1.0); +} + +} // namespace CesiumGltf From 7bf2d18d05744fc40afe5821332a8720f3fdf48a Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 29 Aug 2023 15:32:42 -0400 Subject: [PATCH 106/121] Finish writing tests for PropertyAttributeView --- .../CesiumGltf/PropertyAttributeView.h | 139 +- .../CesiumGltf/PropertyTexturePropertyView.h | 6 +- .../src/PropertyAttributePropertyView.cpp | 28 + .../TestPropertyAttributePropertyView.cpp | 6 +- CesiumGltf/test/TestPropertyAttributeView.cpp | 3714 ++++++++--------- .../test/TestPropertyTablePropertyView.cpp | 3 + CesiumGltf/test/TestPropertyTableView.cpp | 172 +- .../test/TestPropertyTexturePropertyView.cpp | 5 +- CesiumGltf/test/TestPropertyTextureView.cpp | 4 +- 9 files changed, 1951 insertions(+), 2126 deletions(-) create mode 100644 CesiumGltf/src/PropertyAttributePropertyView.cpp diff --git a/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h b/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h index eb76620c5..af4949567 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h @@ -108,8 +108,8 @@ class PropertyAttributeView { */ template PropertyAttributePropertyView getPropertyView( - const std::string& propertyName, - const MeshPrimitive& primitive) const { + const MeshPrimitive& primitive, + const std::string& propertyName) const { if (this->_status != PropertyAttributeViewStatus::Valid) { return PropertyAttributePropertyView( PropertyAttributePropertyViewStatus::ErrorInvalidPropertyAttribute); @@ -128,9 +128,9 @@ class PropertyAttributeView { } return getPropertyViewImpl( + primitive, propertyName, - *pClassProperty, - primitive); + *pClassProperty); } /** @@ -148,14 +148,15 @@ class PropertyAttributeView { * with an error status will be passed to the callback. Otherwise, a valid * property view will be passed to the callback. * + * @param primitive The target primitive * @param propertyName The name of the property to retrieve data from * @tparam callback A callback function that accepts a property name and a * {@link PropertyAttributePropertyView} */ template void getPropertyView( - const std::string& propertyName, const MeshPrimitive& primitive, + const std::string& propertyName, Callback&& callback) const { if (this->_status != PropertyAttributeViewStatus::Valid) { callback( @@ -175,6 +176,14 @@ class PropertyAttributeView { return; } + if (pClassProperty->array) { + callback( + propertyName, + PropertyAttributePropertyView( + PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty)); + return; + } + PropertyType type = convertStringToPropertyType(pClassProperty->type); PropertyComponentType componentType = PropertyComponentType::None; if (pClassProperty->componentType) { @@ -194,16 +203,16 @@ class PropertyAttributeView { if (type == PropertyType::Scalar) { if (normalized) { getScalarPropertyViewImpl( + primitive, propertyName, *pClassProperty, - primitive, componentType, std::forward(callback)); } else { getScalarPropertyViewImpl( + primitive, propertyName, *pClassProperty, - primitive, componentType, std::forward(callback)); } @@ -213,17 +222,17 @@ class PropertyAttributeView { if (isPropertyTypeVecN(type)) { if (normalized) { getVecNPropertyViewImpl( + primitive, propertyName, *pClassProperty, - primitive, type, componentType, std::forward(callback)); } else { getVecNPropertyViewImpl( + primitive, propertyName, *pClassProperty, - primitive, type, componentType, std::forward(callback)); @@ -234,17 +243,17 @@ class PropertyAttributeView { if (isPropertyTypeMatN(type)) { if (normalized) { getMatNPropertyViewImpl( + primitive, propertyName, *pClassProperty, - primitive, type, componentType, std::forward(callback)); } else { getMatNPropertyViewImpl( + primitive, propertyName, *pClassProperty, - primitive, type, componentType, std::forward(callback)); @@ -292,9 +301,9 @@ class PropertyAttributeView { private: template PropertyAttributePropertyView getPropertyViewImpl( + const MeshPrimitive& primitive, const std::string& propertyName, - const ClassProperty& classProperty, - const MeshPrimitive& primitive) const { + const ClassProperty& classProperty) const { auto propertyAttributePropertyIter = _pPropertyAttribute->properties.find(propertyName); if (propertyAttributePropertyIter == @@ -307,16 +316,16 @@ class PropertyAttributeView { propertyAttributePropertyIter->second; return createPropertyView( + primitive, classProperty, - propertyAttributeProperty, - primitive); + propertyAttributeProperty); } template void getScalarPropertyViewImpl( + const MeshPrimitive& primitive, const std::string& propertyName, const ClassProperty& classProperty, - const MeshPrimitive& primitive, PropertyComponentType componentType, Callback&& callback) const { switch (componentType) { @@ -324,49 +333,49 @@ class PropertyAttributeView { callback( propertyName, getPropertyViewImpl( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); return; case PropertyComponentType::Uint8: callback( propertyName, getPropertyViewImpl( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); return; case PropertyComponentType::Int16: callback( propertyName, getPropertyViewImpl( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); return; case PropertyComponentType::Uint16: callback( propertyName, getPropertyViewImpl( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, getPropertyViewImpl( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, getPropertyViewImpl( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; default: callback( @@ -379,9 +388,9 @@ class PropertyAttributeView { template void getVecNPropertyViewImpl( + const MeshPrimitive& primitive, const std::string& propertyName, const ClassProperty& classProperty, - const MeshPrimitive& primitive, PropertyComponentType componentType, Callback&& callback) const { switch (componentType) { @@ -389,50 +398,49 @@ class PropertyAttributeView { callback( propertyName, getPropertyViewImpl, Normalized>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, getPropertyViewImpl, Normalized>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, getPropertyViewImpl, Normalized>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, getPropertyViewImpl, Normalized>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; - default: case PropertyComponentType::Uint32: callback( propertyName, getPropertyViewImpl, Normalized>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, getPropertyViewImpl, false>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; default: callback( @@ -445,9 +453,9 @@ class PropertyAttributeView { template void getVecNPropertyViewImpl( + const MeshPrimitive& primitive, const std::string& propertyName, const ClassProperty& classProperty, - const MeshPrimitive& primitive, PropertyType type, PropertyComponentType componentType, Callback&& callback) const { @@ -455,25 +463,25 @@ class PropertyAttributeView { switch (N) { case 2: getVecNPropertyViewImpl( + primitive, propertyName, classProperty, - primitive, componentType, std::forward(callback)); break; case 3: getVecNPropertyViewImpl( + primitive, propertyName, classProperty, - primitive, componentType, std::forward(callback)); break; case 4: getVecNPropertyViewImpl( + primitive, propertyName, classProperty, - primitive, componentType, std::forward(callback)); break; @@ -488,9 +496,9 @@ class PropertyAttributeView { template void getMatNPropertyViewImpl( + const MeshPrimitive& primitive, const std::string& propertyName, const ClassProperty& classProperty, - const MeshPrimitive& primitive, PropertyComponentType componentType, Callback&& callback) const { switch (componentType) { @@ -498,49 +506,49 @@ class PropertyAttributeView { callback( propertyName, getPropertyViewImpl, Normalized>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Uint8: callback( propertyName, getPropertyViewImpl, Normalized>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Int16: callback( propertyName, getPropertyViewImpl, Normalized>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Uint16: callback( propertyName, getPropertyViewImpl, Normalized>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Uint32: callback( propertyName, getPropertyViewImpl, Normalized>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; case PropertyComponentType::Float32: callback( propertyName, getPropertyViewImpl, false>( + primitive, propertyName, - classProperty, - primitive)); + classProperty)); break; default: callback( @@ -553,9 +561,9 @@ class PropertyAttributeView { template void getMatNPropertyViewImpl( + const MeshPrimitive& primitive, const std::string& propertyName, const ClassProperty& classProperty, - const MeshPrimitive& primitive, PropertyType type, PropertyComponentType componentType, Callback&& callback) const { @@ -563,25 +571,25 @@ class PropertyAttributeView { switch (N) { case 2: getMatNPropertyViewImpl( + primitive, propertyName, classProperty, - primitive, componentType, std::forward(callback)); break; case 3: getMatNPropertyViewImpl( + primitive, propertyName, classProperty, - primitive, componentType, std::forward(callback)); break; case 4: getMatNPropertyViewImpl( + primitive, propertyName, classProperty, - primitive, componentType, std::forward(callback)); break; @@ -596,9 +604,9 @@ class PropertyAttributeView { template PropertyAttributePropertyView createPropertyView( + const MeshPrimitive& primitive, const ClassProperty& classProperty, - const PropertyAttributeProperty& propertyAttributeProperty, - const MeshPrimitive& primitive) const { + const PropertyAttributeProperty& propertyAttributeProperty) const { const PropertyType type = convertStringToPropertyType(classProperty.type); if (TypeToPropertyType::value != type) { return PropertyAttributePropertyView( @@ -683,4 +691,5 @@ class PropertyAttributeView { PropertyAttributeViewStatus _status; }; + } // namespace CesiumGltf diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index da9bc456f..c1c82413e 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -620,9 +620,9 @@ class PropertyTexturePropertyView static_cast(0), static_cast(this->_pImage->height) - 1); - int64_t pixelIndex = this->_pImage->bytesPerChannel * - this->_pImage->channels * - (y * this->_pImage->width + x); + int64_t pixelIndex = static_cast(this->_pImage->bytesPerChannel) * + static_cast(this->_pImage->channels) * + (y * static_cast(this->_pImage->width) + x); // TODO: Currently stb only outputs uint8 pixel types. If that // changes this should account for additional pixel byte sizes. diff --git a/CesiumGltf/src/PropertyAttributePropertyView.cpp b/CesiumGltf/src/PropertyAttributePropertyView.cpp new file mode 100644 index 000000000..378486cda --- /dev/null +++ b/CesiumGltf/src/PropertyAttributePropertyView.cpp @@ -0,0 +1,28 @@ +#include "CesiumGltf/PropertyAttributePropertyView.h" + +namespace CesiumGltf { +// Re-initialize consts here to avoid "undefined reference" errors with GCC / +// Clang. +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorInvalidPropertyAttribute; +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty; +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorMissingAttribute; +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorInvalidAccessor; +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorAccessorTypeMismatch; +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorAccessorComponentTypeMismatch; +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorAccessorNormalizationMismatch; +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorInvalidBufferView; +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorInvalidBuffer; +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorAccessorOutOfBounds; +const PropertyViewStatusType + PropertyAttributePropertyViewStatus::ErrorBufferViewOutOfBounds; +} // namespace CesiumGltf diff --git a/CesiumGltf/test/TestPropertyAttributePropertyView.cpp b/CesiumGltf/test/TestPropertyAttributePropertyView.cpp index c87139ab1..0dab05f2e 100644 --- a/CesiumGltf/test/TestPropertyAttributePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyAttributePropertyView.cpp @@ -9,6 +9,8 @@ using namespace CesiumGltf; using namespace CesiumUtility; +namespace { + template const Accessor& addValuesToModel(Model& model, const std::vector& values) { Buffer& buffer = model.buffers.emplace_back(); @@ -192,6 +194,7 @@ void checkNormalizedAttributeValues( REQUIRE(view.get(i) == expected[static_cast(i)]); } } +} // namespace TEST_CASE("Check scalar PropertyAttributePropertyView") { SECTION("Uint8") { @@ -794,7 +797,8 @@ TEST_CASE("Check matN PropertyAttributePropertyView (normalized)") { } } -TEST_CASE("Check that PropertyAttributeProperty values override class property values") { +TEST_CASE("Check that PropertyAttributeProperty values override class property " + "values") { Model model; std::vector data{1.0f, 2.0f, 3.0f, 4.0f}; diff --git a/CesiumGltf/test/TestPropertyAttributeView.cpp b/CesiumGltf/test/TestPropertyAttributeView.cpp index a242bb6df..d7d13c7b1 100644 --- a/CesiumGltf/test/TestPropertyAttributeView.cpp +++ b/CesiumGltf/test/TestPropertyAttributeView.cpp @@ -210,7 +210,7 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { SECTION("Access correct type") { PropertyAttributePropertyView uint16Property = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( uint16Property.status() == PropertyAttributePropertyViewStatus::Valid); for (size_t i = 0; i < data.size(); ++i) { @@ -221,7 +221,7 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { SECTION("Access wrong type") { PropertyAttributePropertyView u16vec2Invalid = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( u16vec2Invalid.status() == PropertyAttributePropertyViewStatus::ErrorTypeMismatch); @@ -229,19 +229,19 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { SECTION("Access wrong component type") { PropertyAttributePropertyView uint8Invalid = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( uint8Invalid.status() == PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); PropertyAttributePropertyView int32Invalid = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( int32Invalid.status() == PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); PropertyAttributePropertyView uint64Invalid = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( uint64Invalid.status() == PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); @@ -249,7 +249,7 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { SECTION("Access incorrectly as normalized") { PropertyAttributePropertyView normalizedInvalid = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( normalizedInvalid.status() == PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); @@ -258,7 +258,7 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { SECTION("Buffer view points outside of the real buffer length") { model.buffers[bufferIndex].cesium.data.resize(4); PropertyAttributePropertyView property = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( property.status() == PropertyAttributePropertyViewStatus::ErrorBufferViewOutOfBounds); @@ -267,16 +267,25 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { SECTION("Wrong buffer index") { model.bufferViews[bufferViewIndex].buffer = 2; PropertyAttributePropertyView property = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( property.status() == PropertyAttributePropertyViewStatus::ErrorInvalidBuffer); } + SECTION("Accessor view points outside of buffer viwe length") { + model.accessors[accessorIndex].count = 10; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorAccessorOutOfBounds); + } + SECTION("Wrong buffer view index") { model.accessors[accessorIndex].bufferView = -1; PropertyAttributePropertyView property = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( property.status() == PropertyAttributePropertyViewStatus::ErrorInvalidBufferView); @@ -285,7 +294,7 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { SECTION("Wrong accessor normalization") { model.accessors[accessorIndex].normalized = true; PropertyAttributePropertyView property = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( property.status() == PropertyAttributePropertyViewStatus:: ErrorAccessorNormalizationMismatch); @@ -295,7 +304,7 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { model.accessors[accessorIndex].componentType = Accessor::ComponentType::SHORT; PropertyAttributePropertyView property = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( property.status() == PropertyAttributePropertyViewStatus:: ErrorAccessorComponentTypeMismatch); @@ -304,7 +313,7 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { SECTION("Wrong accessor type") { model.accessors[accessorIndex].type = Accessor::Type::VEC2; PropertyAttributePropertyView property = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( property.status() == PropertyAttributePropertyViewStatus::ErrorAccessorTypeMismatch); @@ -313,7 +322,7 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { SECTION("Wrong accessor index") { primitive.attributes[attributeName] = -1; PropertyAttributePropertyView property = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( property.status() == PropertyAttributePropertyViewStatus::ErrorInvalidAccessor); @@ -322,1961 +331,1736 @@ TEST_CASE("Test scalar PropertyAttributeProperty") { SECTION("Missing attribute") { primitive.attributes.clear(); PropertyAttributePropertyView property = - view.getPropertyView("TestClassProperty", primitive); + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorMissingAttribute); + } +} + +TEST_CASE("Test scalar PropertyAttributeProperty (normalized)") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + const std::string attributeName = "_ATTRIBUTE"; + std::vector data = {12, 34, 30, 11}; + + addAttributeToModel(model, primitive, attributeName, data); + size_t accessorIndex = model.accessors.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.normalized = true; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + SECTION("Access correct type") { + PropertyAttributePropertyView uint8Property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + uint8Property.status() == PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(uint8Property.getRaw(static_cast(i)) == data[i]); + REQUIRE(uint8Property.get(static_cast(i)) == normalize(data[i])); + } + } + + SECTION("Access wrong type") { + PropertyAttributePropertyView u8vec2Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + u8vec2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyAttributePropertyView uint16Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + uint16Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyAttributePropertyView int32Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + int32Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as non-normalized") { + PropertyAttributePropertyView normalizedInvalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); + } + + SECTION("Access incorrectly as double") { + PropertyAttributePropertyView doubleInvalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + doubleInvalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Wrong accessor normalization") { + model.accessors[accessorIndex].normalized = false; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == PropertyAttributePropertyViewStatus:: + ErrorAccessorNormalizationMismatch); + } +} + +TEST_CASE("Test vecN PropertyAttributeProperty") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + const std::string attributeName = "_ATTRIBUTE"; + std::vector data = { + glm::u8vec2(12, 34), + glm::u8vec2(10, 3), + glm::u8vec2(40, 0), + glm::u8vec2(30, 11)}; + + addAttributeToModel(model, primitive, attributeName, data); + size_t accessorIndex = model.accessors.size() - 1; + size_t bufferIndex = model.buffers.size() - 1; + size_t bufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); + + SECTION("Access correct type") { + PropertyAttributePropertyView u8vec2Property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + u8vec2Property.status() == PropertyAttributePropertyViewStatus::Valid); + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(u8vec2Property.getRaw(static_cast(i)) == data[i]); + REQUIRE(u8vec2Property.get(static_cast(i)) == data[i]); + } + } + + SECTION("Access wrong type") { + PropertyAttributePropertyView uint8Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + uint8Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + + PropertyAttributePropertyView u8vec3Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + u8vec3Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyAttributePropertyView vec2Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + vec2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as normalized") { + PropertyAttributePropertyView normalizedInvalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[bufferIndex].cesium.data.resize(4); + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Wrong buffer index") { + model.bufferViews[bufferViewIndex].buffer = 2; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidBuffer); + } + + SECTION("Accessor view points outside of buffer viwe length") { + model.accessors[accessorIndex].count = 10; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorAccessorOutOfBounds); + } + + SECTION("Wrong buffer view index") { + model.accessors[accessorIndex].bufferView = -1; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidBufferView); + } + + SECTION("Wrong accessor normalization") { + model.accessors[accessorIndex].normalized = true; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == PropertyAttributePropertyViewStatus:: + ErrorAccessorNormalizationMismatch); + } + + SECTION("Wrong accessor component type") { + model.accessors[accessorIndex].componentType = + Accessor::ComponentType::BYTE; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == PropertyAttributePropertyViewStatus:: + ErrorAccessorComponentTypeMismatch); + } + + SECTION("Wrong accessor type") { + model.accessors[accessorIndex].type = Accessor::Type::SCALAR; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorAccessorTypeMismatch); + } + + SECTION("Wrong accessor index") { + primitive.attributes[attributeName] = -1; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidAccessor); + } + + SECTION("Missing attribute") { + primitive.attributes.clear(); + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); REQUIRE( property.status() == PropertyAttributePropertyViewStatus::ErrorMissingAttribute); } } -// TEST_CASE("Test scalar PropertyAttributeProperty (normalized)") { -// Model model; -// std::vector data = {12, 34, 30, 11}; -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 1, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// size_t imageIndex = model.images.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; testClassProperty.normalized = true; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE(classProperty->componentType == -// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == -// std::nullopt); REQUIRE(!classProperty->array); -// REQUIRE(classProperty->normalized); -// -// SECTION("Access correct type") { -// PropertyAttributePropertyView uint8Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(uint8Property.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// REQUIRE(uint8Property.getRaw(uv[0], uv[1]) == data[i]); -// REQUIRE(uint8Property.get(uv[0], uv[1]) == normalize(data[i])); -// } -// } -// -// SECTION("Access wrong type") { -// PropertyAttributePropertyView u8vec2Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec2Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorTypeMismatch); -// } -// -// SECTION("Access wrong component type") { -// PropertyAttributePropertyView uint16Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint16Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyAttributePropertyView int32Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// int32Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Access incorrectly as array") { -// PropertyAttributePropertyView, true> -// arrayInvalid -// = -// view.getPropertyView, true>( -// "TestClassProperty"); -// REQUIRE( -// arrayInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Access incorrectly as non-normalized") { -// PropertyAttributePropertyView normalizedInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// normalizedInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); -// } -// -// SECTION("Access incorrectly as double") { -// PropertyAttributePropertyView doubleInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// doubleInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Channel and type mismatch") { -// model.images[imageIndex].cesium.channels = 2; -// propertyAttributeProperty.channels = {0, 1}; -// PropertyAttributePropertyView uint8Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint8Property.status() == -// PropertyAttributePropertyViewStatus::ErrorChannelsAndTypeMismatch); -// } -//} -// -// TEST_CASE("Test vecN PropertyAttributeProperty") { -// Model model; -// std::vector data = {12, 34, 10, 3, 40, 0, 30, 11}; -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 2, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// size_t imageIndex = model.images.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::VEC2; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::VEC2); -// REQUIRE(classProperty->componentType == -// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == -// std::nullopt); REQUIRE(!classProperty->array); -// REQUIRE(!classProperty->normalized); -// -// SECTION("Access correct type") { -// PropertyAttributePropertyView u8vec2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec2Property.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// std::vector expected{ -// glm::u8vec2(12, 34), -// glm::u8vec2(10, 3), -// glm::u8vec2(40, 0), -// glm::u8vec2(30, 11)}; -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// REQUIRE(u8vec2Property.getRaw(uv[0], uv[1]) == expected[i]); -// REQUIRE(u8vec2Property.get(uv[0], uv[1]) == expected[i]); -// } -// } -// -// SECTION("Access wrong type") { -// PropertyAttributePropertyView uint8Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint8Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyAttributePropertyView u8vec3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec3Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorTypeMismatch); -// } -// -// SECTION("Access wrong component type") { -// PropertyAttributePropertyView u16vec2Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u16vec2Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyAttributePropertyView i8vec2Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// i8vec2Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Access incorrectly as array") { -// PropertyAttributePropertyView> arrayInvalid -// = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// arrayInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Access incorrectly as normalized") { -// PropertyAttributePropertyView normalizedInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// normalizedInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); -// } -// -// SECTION("Channel and type mismatch") { -// model.images[imageIndex].cesium.channels = 4; -// propertyAttributeProperty.channels = {0, 1, 2, 3}; -// PropertyAttributePropertyView u8vec2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec2Property.status() == -// PropertyAttributePropertyViewStatus::ErrorChannelsAndTypeMismatch); -// } -// -// SECTION("Invalid channel values") { -// propertyAttributeProperty.channels = {0, 4}; -// PropertyAttributePropertyView u8vec2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec2Property.status() == -// PropertyAttributePropertyViewStatus::ErrorInvalidChannels); -// } -// -// SECTION("Invalid bytes per channel") { -// model.images[imageIndex].cesium.bytesPerChannel = 2; -// PropertyAttributePropertyView u8vec2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec2Property.status() == -// PropertyAttributePropertyViewStatus::ErrorInvalidBytesPerChannel); -// } -//} -// -// TEST_CASE("Test vecN PropertyAttributeProperty (normalized)") { -// Model model; -// std::vector data = {12, 34, 10, 3, 40, 0, 30, 11}; -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 2, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// size_t imageIndex = model.images.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::VEC2; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; testClassProperty.normalized = true; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::VEC2); -// REQUIRE(classProperty->componentType == -// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == -// std::nullopt); REQUIRE(!classProperty->array); -// REQUIRE(classProperty->normalized); -// -// SECTION("Access correct type") { -// PropertyAttributePropertyView u8vec2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec2Property.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// std::vector expected{ -// glm::u8vec2(12, 34), -// glm::u8vec2(10, 3), -// glm::u8vec2(40, 0), -// glm::u8vec2(30, 11)}; -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// REQUIRE(u8vec2Property.getRaw(uv[0], uv[1]) == expected[i]); -// REQUIRE(u8vec2Property.get(uv[0], uv[1]) == normalize(expected[i])); -// } -// } -// -// SECTION("Access wrong type") { -// PropertyAttributePropertyView uint8Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint8Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorTypeMismatch); -// -// PropertyAttributePropertyView u8vec3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec3Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorTypeMismatch); -// } -// -// SECTION("Access wrong component type") { -// PropertyAttributePropertyView u16vec2Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u16vec2Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyAttributePropertyView i8vec2Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// i8vec2Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Access incorrectly as array") { -// PropertyAttributePropertyView, true> -// arrayInvalid = -// view.getPropertyView, true>( -// "TestClassProperty"); -// REQUIRE( -// arrayInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Access incorrectly as non-normalized") { -// PropertyAttributePropertyView normalizedInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// normalizedInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); -// } -// -// SECTION("Access incorrectly as dvec2") { -// PropertyAttributePropertyView normalizedInvalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// normalizedInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Channel and type mismatch") { -// model.images[imageIndex].cesium.channels = 4; -// propertyAttributeProperty.channels = {0, 1, 2, 3}; -// PropertyAttributePropertyView u8vec2Property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec2Property.status() == -// PropertyAttributePropertyViewStatus::ErrorChannelsAndTypeMismatch); -// } -//} -// -// TEST_CASE("Test array PropertyAttributeProperty") { -// Model model; -// // clang-format off -// std::vector data = { -// 12, 34, 10, -// 40, 0, 30, -// 80, 4, 2, -// 6, 3, 4, -// }; -// // clang-format on -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 3, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// size_t imageIndex = model.images.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; testClassProperty.array = true; -// testClassProperty.count = 3; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1, 2}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE(classProperty->componentType == -// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 3); -// REQUIRE(!classProperty->normalized); -// -// SECTION("Access correct type") { -// PropertyAttributePropertyView> -// uint8ArrayProperty -// = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// uint8ArrayProperty.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// int64_t size = static_cast(texCoords.size()); -// for (int64_t i = 0; i < size; ++i) { -// glm::dvec2 uv = texCoords[static_cast(i)]; -// -// auto dataStart = data.begin() + i * 3; -// std::vector expected(dataStart, dataStart + 3); -// -// const PropertyArrayView& value = -// uint8ArrayProperty.getRaw(uv[0], uv[1]); -// REQUIRE(static_cast(value.size()) == expected.size()); -// for (int64_t j = 0; j < value.size(); j++) { -// REQUIRE(value[j] == expected[static_cast(j)]); -// } -// -// auto maybeValue = uint8ArrayProperty.get(uv[0], uv[1]); -// REQUIRE(maybeValue); -// for (int64_t j = 0; j < maybeValue->size(); j++) { -// REQUIRE((*maybeValue)[j] == value[j]); -// } -// } -// } -// -// SECTION("Access wrong component type") { -// PropertyAttributePropertyView> int8ArrayInvalid -// = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// int8ArrayInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyAttributePropertyView> -// uint16ArrayInvalid = -// view.getPropertyView>( -// "TestClassProperty"); -// REQUIRE( -// uint16ArrayInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Access incorrectly as non-array") { -// PropertyAttributePropertyView uint8Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint8Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); -// -// PropertyAttributePropertyView u8vec3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec3Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Access incorrectly as normalized") { -// PropertyAttributePropertyView, true> -// normalizedInvalid = -// view.getPropertyView, true>( -// "TestClassProperty"); -// REQUIRE( -// normalizedInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); -// } -// -// SECTION("Channel and type mismatch") { -// model.images[imageIndex].cesium.channels = 4; -// propertyAttributeProperty.channels = {0, 1, 2, 3}; -// PropertyAttributePropertyView> -// uint8ArrayProperty -// = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// uint8ArrayProperty.status() == -// PropertyAttributePropertyViewStatus::ErrorChannelsAndTypeMismatch); -// } -// -// SECTION("Invalid channel values") { -// propertyAttributeProperty.channels = {0, 4, 1}; -// PropertyAttributePropertyView> -// uint8ArrayProperty -// = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// uint8ArrayProperty.status() == -// PropertyAttributePropertyViewStatus::ErrorInvalidChannels); -// } -// -// SECTION("Invalid bytes per channel") { -// model.images[imageIndex].cesium.bytesPerChannel = 2; -// PropertyAttributePropertyView> -// uint8ArrayProperty -// = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// uint8ArrayProperty.status() == -// PropertyAttributePropertyViewStatus::ErrorInvalidBytesPerChannel); -// } -//} -// -// TEST_CASE("Test array PropertyAttributeProperty (normalized)") { -// Model model; -// // clang-format off -// std::vector data = { -// 12, 34, 10, -// 40, 0, 30, -// 80, 4, 2, -// 6, 3, 4, -// }; -// // clang-format on -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 3, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// size_t imageIndex = model.images.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; testClassProperty.array = true; -// testClassProperty.count = 3; -// testClassProperty.normalized = true; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1, 2}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE(classProperty->componentType == -// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 3); -// REQUIRE(classProperty->normalized); -// -// SECTION("Access correct type") { -// PropertyAttributePropertyView, true> -// uint8ArrayProperty = -// view.getPropertyView, true>( -// "TestClassProperty"); -// REQUIRE( -// uint8ArrayProperty.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// int64_t size = static_cast(texCoords.size()); -// for (int64_t i = 0; i < size; ++i) { -// glm::dvec2 uv = texCoords[static_cast(i)]; -// -// auto dataStart = data.begin() + i * 3; -// std::vector expected(dataStart, dataStart + 3); -// -// const PropertyArrayView& value = -// uint8ArrayProperty.getRaw(uv[0], uv[1]); -// REQUIRE(static_cast(value.size()) == expected.size()); -// for (int64_t j = 0; j < value.size(); j++) { -// REQUIRE(value[j] == expected[static_cast(j)]); -// } -// -// auto maybeValue = uint8ArrayProperty.get(uv[0], uv[1]); -// REQUIRE(maybeValue); -// for (int64_t j = 0; j < maybeValue->size(); j++) { -// REQUIRE((*maybeValue)[j] == normalize(value[j])); -// } -// } -// } -// -// SECTION("Access wrong component type") { -// PropertyAttributePropertyView, true> -// int8ArrayInvalid = -// view.getPropertyView, true>( -// "TestClassProperty"); -// REQUIRE( -// int8ArrayInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// -// PropertyAttributePropertyView, true> -// uint16ArrayInvalid = -// view.getPropertyView, true>( -// "TestClassProperty"); -// REQUIRE( -// uint16ArrayInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); -// } -// -// SECTION("Access incorrectly as non-array") { -// PropertyAttributePropertyView uint8Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// uint8Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); -// -// PropertyAttributePropertyView u8vec3Invalid = -// view.getPropertyView("TestClassProperty"); -// REQUIRE( -// u8vec3Invalid.status() == -// PropertyAttributePropertyViewStatus::ErrorArrayTypeMismatch); -// } -// -// SECTION("Access incorrectly as normalized") { -// PropertyAttributePropertyView> -// normalizedInvalid -// = -// view.getPropertyView>("TestClassProperty"); -// REQUIRE( -// normalizedInvalid.status() == -// PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); -// } -// -// SECTION("Channel and type mismatch") { -// model.images[imageIndex].cesium.channels = 4; -// propertyAttributeProperty.channels = {0, 1, 2, 3}; -// PropertyAttributePropertyView, true> -// uint8ArrayProperty = -// view.getPropertyView, true>( -// "TestClassProperty"); -// REQUIRE( -// uint8ArrayProperty.status() == -// PropertyAttributePropertyViewStatus::ErrorChannelsAndTypeMismatch); -// } -//} -// -// TEST_CASE("Test with PropertyAttributeProperty offset, scale, min, max") { -// Model model; -// // clang-format off -// std::vector data{ -// 0, 0, 0, 1, -// 9, 0, 1, 0, -// 20, 2, 2, 0, -// 8, 1, 0, 1}; -// // clang-format on -// -// std::vector expectedUint{16777216, 65545, 131604, 16777480}; -// -// const float offset = 1.0f; -// const float scale = 2.0f; -// const float min = -10.0f; -// const float max = 10.0f; -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 4, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::FLOAT32; testClassProperty.offset = offset; -// testClassProperty.scale = scale; -// testClassProperty.min = min; -// testClassProperty.max = max; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1, 2, 3}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE( -// classProperty->componentType == ClassProperty::ComponentType::FLOAT32); -// REQUIRE(classProperty->count == std::nullopt); -// REQUIRE(!classProperty->array); -// REQUIRE(!classProperty->normalized); -// REQUIRE(classProperty->offset); -// REQUIRE(classProperty->scale); -// REQUIRE(classProperty->min); -// REQUIRE(classProperty->max); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// SECTION("Use class property values") { -// PropertyAttributePropertyView property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); -// REQUIRE(property.offset() == offset); -// REQUIRE(property.scale() == scale); -// REQUIRE(property.min() == min); -// REQUIRE(property.max() == max); -// -// std::vector expectedRaw(expectedUint.size()); -// std::vector expectedTransformed(expectedUint.size()); -// for (size_t i = 0; i < expectedUint.size(); i++) { -// float value = *reinterpret_cast(&expectedUint[i]); -// expectedRaw[i] = value; -// expectedTransformed[i] = value * scale + offset; -// } -// -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// REQUIRE(property.getRaw(uv[0], uv[1]) == expectedRaw[i]); -// REQUIRE(property.get(uv[0], uv[1]) == expectedTransformed[i]); -// } -// } -// -// SECTION("Use own property values") { -// const float newOffset = 1.0f; -// const float newScale = -1.0f; -// const float newMin = -3.0f; -// const float newMax = 0.0f; -// propertyAttributeProperty.offset = newOffset; -// propertyAttributeProperty.scale = newScale; -// propertyAttributeProperty.min = newMin; -// propertyAttributeProperty.max = newMax; -// -// PropertyAttributePropertyView property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); -// REQUIRE(property.offset() == newOffset); -// REQUIRE(property.scale() == newScale); -// REQUIRE(property.min() == newMin); -// REQUIRE(property.max() == newMax); -// -// std::vector expectedRaw(expectedUint.size()); -// std::vector expectedTransformed(expectedUint.size()); -// for (size_t i = 0; i < expectedUint.size(); i++) { -// float value = *reinterpret_cast(&expectedUint[i]); -// expectedRaw[i] = value; -// expectedTransformed[i] = value * newScale + newOffset; -// } -// -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// REQUIRE(property.getRaw(uv[0], uv[1]) == expectedRaw[i]); -// REQUIRE(property.get(uv[0], uv[1]) == expectedTransformed[i]); -// } -// } -//} -// -// TEST_CASE( -// "Test with PropertyAttributeProperty offset, scale, min, max -// (normalized)") -// { -// Model model; -// std::vector data = {12, 34, 30, 11}; -// -// const double offset = 1.0; -// const double scale = 2.0; -// const double min = 1.0; -// const double max = 3.0; -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 1, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; testClassProperty.normalized = true; -// testClassProperty.offset = offset; -// testClassProperty.scale = scale; -// testClassProperty.min = min; -// testClassProperty.max = max; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE(classProperty->componentType == -// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == -// std::nullopt); REQUIRE(!classProperty->array); -// REQUIRE(classProperty->normalized); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// SECTION("Use class property values") { -// PropertyAttributePropertyView property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); -// REQUIRE(property.offset() == offset); -// REQUIRE(property.scale() == scale); -// REQUIRE(property.min() == min); -// REQUIRE(property.max() == max); -// -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// REQUIRE(property.getRaw(uv[0], uv[1]) == data[i]); -// REQUIRE( -// property.get(uv[0], uv[1]) == normalize(data[i]) * scale + offset); -// } -// } -// -// SECTION("Use own property values") { -// const double newOffset = 2.0; -// const double newScale = 5.0; -// const double newMin = 10.0; -// const double newMax = 11.0; -// propertyAttributeProperty.offset = newOffset; -// propertyAttributeProperty.scale = newScale; -// propertyAttributeProperty.min = newMin; -// propertyAttributeProperty.max = newMax; -// -// PropertyAttributePropertyView property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); -// REQUIRE(property.offset() == newOffset); -// REQUIRE(property.scale() == newScale); -// REQUIRE(property.min() == newMin); -// REQUIRE(property.max() == newMax); -// -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// REQUIRE(property.getRaw(uv[0], uv[1]) == data[i]); -// REQUIRE( -// property.get(uv[0], uv[1]) == -// normalize(data[i]) * newScale + newOffset); -// } -// } -//} -// -// TEST_CASE("Test with PropertyAttributeProperty noData") { -// Model model; -// std::vector data = {12, 34, 30, 11}; -// const uint8_t noData = 34; -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 1, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; testClassProperty.noData = noData; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE(classProperty->componentType == -// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == -// std::nullopt); REQUIRE(!classProperty->array); -// REQUIRE(!classProperty->normalized); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// SECTION("Without default value") { -// PropertyAttributePropertyView property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); -// -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// auto value = property.getRaw(uv[0], uv[1]); -// REQUIRE(value == data[i]); -// -// auto maybeValue = property.get(uv[0], uv[1]); -// if (value == noData) { -// REQUIRE(!maybeValue); -// } else { -// REQUIRE(maybeValue == data[i]); -// } -// } -// } -// -// SECTION("With default value") { -// const uint8_t defaultValue = 255; -// testClassProperty.defaultProperty = defaultValue; -// -// PropertyAttributePropertyView property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); -// -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// auto value = property.getRaw(uv[0], uv[1]); -// REQUIRE(value == data[i]); -// -// auto maybeValue = property.get(uv[0], uv[1]); -// if (value == noData) { -// REQUIRE(maybeValue == defaultValue); -// } else { -// REQUIRE(maybeValue == data[i]); -// } -// } -// } -//} -// -// TEST_CASE("Test with PropertyAttributeProperty noData (normalized)") { -// Model model; -// std::vector data = {12, 34, 30, 11}; -// const uint8_t noData = 34; -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 1, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::UINT8; testClassProperty.normalized = true; -// testClassProperty.noData = noData; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE(classProperty->componentType == -// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->count == -// std::nullopt); REQUIRE(!classProperty->array); -// REQUIRE(classProperty->normalized); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// SECTION("Without default value") { -// PropertyAttributePropertyView property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); -// -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// auto value = property.getRaw(uv[0], uv[1]); -// REQUIRE(value == data[i]); -// -// auto maybeValue = property.get(uv[0], uv[1]); -// if (value == noData) { -// REQUIRE(!maybeValue); -// } else { -// REQUIRE(maybeValue == normalize(data[i])); -// } -// } -// } -// -// SECTION("With default value") { -// const double defaultValue = -1.0; -// testClassProperty.defaultProperty = defaultValue; -// -// PropertyAttributePropertyView property = -// view.getPropertyView("TestClassProperty"); -// REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); -// -// for (size_t i = 0; i < texCoords.size(); ++i) { -// glm::dvec2 uv = texCoords[i]; -// auto value = property.getRaw(uv[0], uv[1]); -// REQUIRE(value == data[i]); -// -// auto maybeValue = property.get(uv[0], uv[1]); -// if (value == noData) { -// REQUIRE(maybeValue == defaultValue); -// } else { -// REQUIRE(maybeValue == normalize(data[i])); -// } -// } -// } -//} -// -// TEST_CASE("Test callback on invalid property Attribute view") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// metadata.schema.emplace(); -// -// // Property Attribute has a nonexistent class. -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = -1; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::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() == -// PropertyAttributePropertyViewStatus::ErrorInvalidPropertyAttribute); -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -// TEST_CASE("Test callback on invalid PropertyAttributeProperty") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// 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; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["InvalidProperty"]; -// propertyAttributeProperty.index = -1; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::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() != -// PropertyAttributePropertyViewStatus::Valid); -// }; -// -// view.getPropertyView("InvalidProperty", testCallback); -// view.getPropertyView("NonexistentProperty", testCallback); -// -// REQUIRE(invokedCallbackCount == 2); -//} -// -// TEST_CASE("Test callback on invalid normalized PropertyAttributeProperty") { -// Model model; -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// ClassProperty& testClassProperty = -// testClass.properties["TestClassProperty"]; testClassProperty.type = -// ClassProperty::Type::SCALAR; testClassProperty.componentType = -// ClassProperty::ComponentType::FLOAT32; testClassProperty.normalized = true; -// // This is erroneous. -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(0); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("TestClassProperty"); -// REQUIRE(classProperty); -// -// uint32_t invokedCallbackCount = 0; -// auto testCallback = [&invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) mutable { -// invokedCallbackCount++; -// REQUIRE( -// propertyValue.status() == -// PropertyAttributePropertyViewStatus::ErrorInvalidNormalization); -// }; -// -// view.getPropertyView("TestClassProperty", testCallback); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -// TEST_CASE("Test callback for scalar PropertyAttributeProperty") { -// Model model; -// std::vector data = {255, 255, 12, 1, 30, 2, 0, 255}; -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 2, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// 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; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::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); -// REQUIRE(!classProperty->normalized); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// std::vector expected{-1, 268, 542, -256}; -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&expected, &texCoords, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) mutable { -// invokedCallbackCount++; -// if constexpr (std::is_same_v< -// PropertyAttributePropertyView, -// decltype(propertyValue)>) { -// REQUIRE( -// propertyValue.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// for (size_t i = 0; i < expected.size(); ++i) { -// glm::dvec2& uv = texCoords[i]; -// REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); -// REQUIRE(propertyValue.get(uv[0], uv[1]) == expected[i]); -// } -// } else { -// FAIL("getPropertyView returned PropertyAttributePropertyView of " -// "incorrect type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -// TEST_CASE("Test callback for scalar PropertyAttributeProperty (normalized)") -// { -// Model model; -// std::vector data = {255, 255, 12, 1, 30, 2, 0, 255}; -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 2, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// 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; testClassProperty.normalized = true; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::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); -// REQUIRE(classProperty->normalized); -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(0.5, 0.5)}; -// -// std::vector expected{-1, 268, 542, -256}; -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "TestClassProperty", -// [&expected, &texCoords, &invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) mutable { -// invokedCallbackCount++; -// if constexpr (std::is_same_v< -// PropertyAttributePropertyView, -// decltype(propertyValue)>) { -// REQUIRE( -// propertyValue.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// for (size_t i = 0; i < expected.size(); ++i) { -// glm::dvec2& uv = texCoords[i]; -// REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); -// REQUIRE(propertyValue.get(uv[0], uv[1]) == -// normalize(expected[i])); -// } -// } else { -// FAIL("getPropertyView returned PropertyAttributePropertyView of " -// "incorrect type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -// TEST_CASE("Test callback for vecN PropertyAttributeProperty") { -// Model model; -// // clang-format off -// std::vector data = { -// 255, 255, -// 12, 1, -// 30, 2, -// 0, 255}; -// // clang-format on -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 2, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// 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; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::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); -// REQUIRE(!classProperty->normalized); -// -// std::vector expected{ -// glm::i8vec2(-1, -1), -// glm::i8vec2(12, 1), -// glm::i8vec2(30, 2), -// glm::i8vec2(0, -1)}; -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(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< -// PropertyAttributePropertyView, -// decltype(propertyValue)>) { -// REQUIRE( -// propertyValue.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// for (size_t i = 0; i < expected.size(); ++i) { -// glm::dvec2& uv = texCoords[i]; -// REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); -// REQUIRE(propertyValue.get(uv[0], uv[1]) == expected[i]); -// } -// } else { -// FAIL("getPropertyView returned PropertyAttributePropertyView of " -// "incorrect type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -// TEST_CASE("Test callback for vecN PropertyAttributeProperty (normalized)") { -// Model model; -// // clang-format off -// std::vector data = { -// 255, 255, -// 12, 1, -// 30, 2, -// 0, 255}; -// // clang-format on -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 2, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// 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; testClassProperty.normalized = true; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::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); -// REQUIRE(classProperty->normalized); -// -// std::vector expected{ -// glm::i8vec2(-1, -1), -// glm::i8vec2(12, 1), -// glm::i8vec2(30, 2), -// glm::i8vec2(0, -1)}; -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(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< -// PropertyAttributePropertyView, -// decltype(propertyValue)>) { -// REQUIRE( -// propertyValue.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// for (size_t i = 0; i < expected.size(); ++i) { -// glm::dvec2& uv = texCoords[i]; -// REQUIRE(propertyValue.getRaw(uv[0], uv[1]) == expected[i]); -// REQUIRE(propertyValue.get(uv[0], uv[1]) == -// normalize(expected[i])); -// } -// } else { -// FAIL("getPropertyView returned PropertyAttributePropertyView of " -// "incorrect type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -// TEST_CASE("Test callback for array PropertyAttributeProperty") { -// Model model; -// // clang-format off -// std::vector data = { -// 254, 0, 253, 1, -// 10, 2, 40, 3, -// 30, 0, 0, 2, -// 10, 2, 255, 4}; -// // clang-format on -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 4, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// 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; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1, 2, 3}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::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); -// REQUIRE(!classProperty->normalized); -// -// std::vector> expected{ -// {254, 509}, -// {522, 808}, -// {30, 512}, -// {522, 1279}}; -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(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< -// PropertyAttributePropertyView< -// PropertyArrayView>, -// decltype(propertyValue)>) { -// REQUIRE( -// propertyValue.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// for (size_t i = 0; i < expected.size(); ++i) { -// std::vector& expectedArray = expected[i]; -// glm::dvec2& uv = texCoords[i]; -// PropertyArrayView array = -// propertyValue.getRaw(uv[0], uv[1]); -// -// REQUIRE(static_cast(array.size()) == -// expectedArray.size()); for (int64_t j = 0; j < array.size(); j++) -// { -// REQUIRE(array[j] == expectedArray[static_cast(j)]); -// } -// -// auto maybeArray = propertyValue.get(uv[0], uv[1]); -// REQUIRE(maybeArray); -// REQUIRE( -// static_cast(maybeArray->size()) == -// expectedArray.size()); -// for (int64_t j = 0; j < array.size(); j++) { -// REQUIRE( -// (*maybeArray)[j] == expectedArray[static_cast(j)]); -// } -// } -// } else { -// FAIL("getPropertyView returned PropertyAttributePropertyView of " -// "incorrect type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -// TEST_CASE("Test callback for array PropertyAttributeProperty (normalized)") { -// Model model; -// // clang-format off -// std::vector data = { -// 254, 0, 253, 1, -// 10, 2, 40, 3, -// 30, 0, 0, 2, -// 10, 2, 255, 4}; -// // clang-format on -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 2, -// 4, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// 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; -// testClassProperty.normalized = true; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& propertyAttributeProperty = -// propertyAttribute.properties["TestClassProperty"]; -// propertyAttributeProperty.index = static_cast(AttributeIndex); -// propertyAttributeProperty.texCoord = 0; -// propertyAttributeProperty.channels = {0, 1, 2, 3}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::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); -// REQUIRE(classProperty->normalized); -// -// std::vector> expected{ -// {254, 509}, -// {522, 808}, -// {30, 512}, -// {522, 1279}}; -// -// std::vector texCoords{ -// glm::dvec2(0, 0), -// glm::dvec2(0.5, 0), -// glm::dvec2(0, 0.5), -// glm::dvec2(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< -// PropertyAttributePropertyView, -// true>, decltype(propertyValue)>) { -// REQUIRE( -// propertyValue.status() == -// PropertyAttributePropertyViewStatus::Valid); -// -// for (size_t i = 0; i < expected.size(); ++i) { -// std::vector& expectedArray = expected[i]; -// glm::dvec2& uv = texCoords[i]; -// PropertyArrayView array = -// propertyValue.getRaw(uv[0], uv[1]); -// -// REQUIRE(static_cast(array.size()) == -// expectedArray.size()); for (int64_t j = 0; j < array.size(); j++) -// { -// REQUIRE(array[j] == expectedArray[static_cast(j)]); -// } -// -// auto maybeArray = propertyValue.get(uv[0], uv[1]); -// REQUIRE(maybeArray); -// REQUIRE( -// static_cast(maybeArray->size()) == -// expectedArray.size()); -// for (int64_t j = 0; j < array.size(); j++) { -// auto rawValue = expectedArray[static_cast(j)]; -// REQUIRE((*maybeArray)[j] == normalize(rawValue)); -// } -// } -// } else { -// FAIL("getPropertyView returned PropertyAttributePropertyView of " -// "incorrect type for TestClassProperty."); -// } -// }); -// -// REQUIRE(invokedCallbackCount == 1); -//} -// -// TEST_CASE("Test callback on unsupported PropertyAttributeProperty") { -// Model model; -// // clang-format off -// std::vector data = { -// 254, 0, 253, 1, -// 10, 2, 40, 3, -// 30, 0, 0, 2, -// 10, 2, 255, 4}; -// // clang-format on -// -// addAttributeToModel( -// model, -// Sampler::WrapS::CLAMP_TO_EDGE, -// Sampler::WrapS::CLAMP_TO_EDGE, -// 2, -// 1, -// 8, -// data); -// size_t AttributeIndex = model.Attributes.size() - 1; -// -// ExtensionModelExtStructuralMetadata& metadata = -// model.addExtension(); -// -// Schema& schema = metadata.schema.emplace(); -// Class& testClass = schema.classes["TestClass"]; -// -// ClassProperty& doubleClassProperty = -// testClass.properties["DoubleClassProperty"]; -// doubleClassProperty.type = ClassProperty::Type::SCALAR; -// doubleClassProperty.componentType = ClassProperty::ComponentType::FLOAT64; -// -// ClassProperty& arrayClassProperty = -// testClass.properties["ArrayClassProperty"]; -// arrayClassProperty.type = ClassProperty::Type::VEC4; -// arrayClassProperty.componentType = ClassProperty::ComponentType::UINT8; -// arrayClassProperty.array = true; -// arrayClassProperty.count = 2; -// -// PropertyAttribute& propertyAttribute = -// metadata.propertyAttributes.emplace_back(); propertyAttribute.classProperty -// = "TestClass"; -// -// PropertyAttributeProperty& doubleProperty = -// propertyAttribute.properties["DoubleClassProperty"]; -// doubleProperty.index = static_cast(AttributeIndex); -// doubleProperty.texCoord = 0; -// doubleProperty.channels = {0, 1, 2, 3, 4, 5, 6, 7}; -// -// PropertyAttributeProperty& arrayProperty = -// propertyAttribute.properties["ArrayClassProperty"]; -// arrayProperty.index = static_cast(AttributeIndex); -// arrayProperty.texCoord = 0; -// arrayProperty.channels = {0, 1, 2, 3, 4, 5, 6, 7}; -// -// PropertyAttributeView view(model, propertyAttribute); -// REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); -// -// const ClassProperty* classProperty = -// view.getClassProperty("DoubleClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); -// REQUIRE( -// classProperty->componentType == ClassProperty::ComponentType::FLOAT64); -// REQUIRE(!classProperty->array); -// -// classProperty = view.getClassProperty("ArrayClassProperty"); -// REQUIRE(classProperty); -// REQUIRE(classProperty->type == ClassProperty::Type::VEC4); -// REQUIRE(classProperty->componentType == -// ClassProperty::ComponentType::UINT8); REQUIRE(classProperty->array); -// REQUIRE(classProperty->count == 2); -// -// uint32_t invokedCallbackCount = 0; -// view.getPropertyView( -// "DoubleClassProperty", -// [&invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) mutable { -// invokedCallbackCount++; -// REQUIRE( -// propertyValue.status() == -// PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty); -// }); -// REQUIRE(invokedCallbackCount == 1); -// -// view.getPropertyView( -// "ArrayClassProperty", -// [&invokedCallbackCount]( -// const std::string& /*propertyName*/, -// auto propertyValue) mutable { -// invokedCallbackCount++; -// REQUIRE( -// propertyValue.status() == -// PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty); -// }); -// REQUIRE(invokedCallbackCount == 2); -//} +TEST_CASE("Test vecN PropertyAttributeProperty (normalized)") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + const std::string attributeName = "_ATTRIBUTE"; + std::vector data = { + glm::u8vec2(12, 34), + glm::u8vec2(10, 3), + glm::u8vec2(40, 0), + glm::u8vec2(30, 11)}; + + addAttributeToModel(model, primitive, attributeName, data); + size_t accessorIndex = model.accessors.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::VEC2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.normalized = true; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::VEC2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + SECTION("Access correct type") { + PropertyAttributePropertyView u8vec2Property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + u8vec2Property.status() == PropertyAttributePropertyViewStatus::Valid); + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(u8vec2Property.getRaw(static_cast(i)) == data[i]); + REQUIRE( + u8vec2Property.get(static_cast(i)) == normalize(data[i])); + } + } + + SECTION("Access wrong type") { + PropertyAttributePropertyView uint8Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + uint8Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + + PropertyAttributePropertyView u8vec3Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + u8vec3Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyAttributePropertyView u16vec2Invalid = + view.getPropertyView( + primitive, + "TestClassProperty"); + REQUIRE( + u16vec2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + + PropertyAttributePropertyView i8vec2Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + i8vec2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as non-normalized") { + PropertyAttributePropertyView normalizedInvalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); + } + + SECTION("Access incorrectly as dvec2") { + PropertyAttributePropertyView dvec2Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + dvec2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Wrong accessor normalization") { + model.accessors[accessorIndex].normalized = false; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == PropertyAttributePropertyViewStatus:: + ErrorAccessorNormalizationMismatch); + } +} + +TEST_CASE("Test matN PropertyAttributeProperty") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + const std::string attributeName = "_ATTRIBUTE"; + // clang-format off + std::vector data = { + glm::umat2x2( + 12, 34, + 30, 1), + glm::umat2x2( + 11, 8, + 73, 102), + glm::umat2x2( + 1, 0, + 63, 2), + glm::umat2x2( + 4, 8, + 3, 23)}; + // clang-format on + + addAttributeToModel(model, primitive, attributeName, data); + size_t accessorIndex = model.accessors.size() - 1; + size_t bufferIndex = model.buffers.size() - 1; + size_t bufferViewIndex = model.bufferViews.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); + + SECTION("Access correct type") { + PropertyAttributePropertyView umat2x2Property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + umat2x2Property.status() == PropertyAttributePropertyViewStatus::Valid); + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(umat2x2Property.getRaw(static_cast(i)) == data[i]); + REQUIRE(umat2x2Property.get(static_cast(i)) == data[i]); + } + } + + SECTION("Access wrong type") { + PropertyAttributePropertyView uint32Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + uint32Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + + PropertyAttributePropertyView uvec2Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + uvec2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + + PropertyAttributePropertyView umat4x4Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + umat4x4Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyAttributePropertyView mat2Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + mat2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as normalized") { + PropertyAttributePropertyView normalizedInvalid = + view.getPropertyView( + primitive, + "TestClassProperty"); + REQUIRE( + normalizedInvalid.status() == + PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); + } + + SECTION("Buffer view points outside of the real buffer length") { + model.buffers[bufferIndex].cesium.data.resize(4); + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorBufferViewOutOfBounds); + } + + SECTION("Wrong buffer index") { + model.bufferViews[bufferViewIndex].buffer = 2; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidBuffer); + } + + SECTION("Accessor view points outside of buffer viwe length") { + model.accessors[accessorIndex].count = 10; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorAccessorOutOfBounds); + } + + SECTION("Wrong buffer view index") { + model.accessors[accessorIndex].bufferView = -1; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidBufferView); + } + + SECTION("Wrong accessor normalization") { + model.accessors[accessorIndex].normalized = true; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == PropertyAttributePropertyViewStatus:: + ErrorAccessorNormalizationMismatch); + } + + SECTION("Wrong accessor component type") { + model.accessors[accessorIndex].componentType = + Accessor::ComponentType::BYTE; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == PropertyAttributePropertyViewStatus:: + ErrorAccessorComponentTypeMismatch); + } + + SECTION("Wrong accessor type") { + model.accessors[accessorIndex].type = Accessor::Type::SCALAR; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorAccessorTypeMismatch); + } + + SECTION("Wrong accessor index") { + primitive.attributes[attributeName] = -1; + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidAccessor); + } + + SECTION("Missing attribute") { + primitive.attributes.clear(); + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + property.status() == + PropertyAttributePropertyViewStatus::ErrorMissingAttribute); + } +} + +TEST_CASE("Test matN PropertyAttributeProperty (normalized)") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + const std::string attributeName = "_ATTRIBUTE"; + // clang-format off + std::vector data = { + glm::umat2x2( + 12, 34, + 30, 1), + glm::umat2x2( + 11, 8, + 73, 102), + glm::umat2x2( + 1, 0, + 63, 2), + glm::umat2x2( + 4, 8, + 3, 23)}; + // clang-format on + + addAttributeToModel( + model, + primitive, + attributeName, + data); + size_t accessorIndex = model.accessors.size() - 1; + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.normalized = true; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + SECTION("Access correct type") { + PropertyAttributePropertyView umat2x2Property = + view.getPropertyView( + primitive, + "TestClassProperty"); + REQUIRE( + umat2x2Property.status() == PropertyAttributePropertyViewStatus::Valid); + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(umat2x2Property.getRaw(static_cast(i)) == data[i]); + REQUIRE( + umat2x2Property.get(static_cast(i)) == normalize(data[i])); + } + } + + SECTION("Access wrong type") { + PropertyAttributePropertyView uint32Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + uint32Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + + PropertyAttributePropertyView uvec2Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + uvec2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + + PropertyAttributePropertyView umat4x4Invalid = + view.getPropertyView( + primitive, + "TestClassProperty"); + REQUIRE( + umat4x4Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorTypeMismatch); + } + + SECTION("Access wrong component type") { + PropertyAttributePropertyView imat2Invalid = + view.getPropertyView( + primitive, + "TestClassProperty"); + REQUIRE( + imat2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Access incorrectly as non-normalized") { + PropertyAttributePropertyView nonNormalizedInvalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + nonNormalizedInvalid.status() == + PropertyAttributePropertyViewStatus::ErrorNormalizationMismatch); + } + + SECTION("Access incorrectly as dmat2") { + PropertyAttributePropertyView dmat2Invalid = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE( + dmat2Invalid.status() == + PropertyAttributePropertyViewStatus::ErrorComponentTypeMismatch); + } + + SECTION("Wrong accessor normalization") { + model.accessors[accessorIndex].normalized = false; + PropertyAttributePropertyView property = + view.getPropertyView( + primitive, + "TestClassProperty"); + REQUIRE( + property.status() == PropertyAttributePropertyViewStatus:: + ErrorAccessorNormalizationMismatch); + } +} + +TEST_CASE("Test with PropertyAttributeProperty offset, scale, min, max") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector data{1.0f, 2.0f, 3.0f, 4.0f}; + + const float offset = 1.0f; + const float scale = 2.0f; + const float min = 3.0f; + const float max = 9.0f; + + const std::string attributeName = "_ATTRIBUTE"; + addAttributeToModel(model, primitive, attributeName, data); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::FLOAT32; + testClassProperty.offset = offset; + testClassProperty.scale = scale; + testClassProperty.min = min; + testClassProperty.max = max; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE( + classProperty->componentType == ClassProperty::ComponentType::FLOAT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); + REQUIRE(classProperty->offset); + REQUIRE(classProperty->scale); + REQUIRE(classProperty->min); + REQUIRE(classProperty->max); + + SECTION("Use class property values") { + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); + REQUIRE(property.offset() == offset); + REQUIRE(property.scale() == scale); + REQUIRE(property.min() == min); + REQUIRE(property.max() == max); + + std::vector expected{3.0f, 5.0f, 7.0f, 9.0f}; + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(property.getRaw(static_cast(i)) == data[i]); + REQUIRE(property.get(static_cast(i)) == expected[i]); + } + } + + SECTION("Use own property values") { + const float newOffset = 0.5f; + const float newScale = -1.0f; + const float newMin = -3.5f; + const float newMax = -0.5f; + propertyAttributeProperty.offset = newOffset; + propertyAttributeProperty.scale = newScale; + propertyAttributeProperty.min = newMin; + propertyAttributeProperty.max = newMax; + + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); + REQUIRE(property.offset() == newOffset); + REQUIRE(property.scale() == newScale); + REQUIRE(property.min() == newMin); + REQUIRE(property.max() == newMax); + + std::vector expected{-0.5f, -1.5f, -2.5f, -3.5f}; + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(property.getRaw(static_cast(i)) == data[i]); + REQUIRE(property.get(static_cast(i)) == expected[i]); + } + } +} + +TEST_CASE("Test with PropertyAttributeProperty offset, scale, min, max " + "(normalized)") { + Model model; + + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector data{0, 128, 255, 32}; + + const double offset = 1.0; + const double scale = 2.0; + const double min = 1.0; + const double max = 3.0; + + const std::string attributeName = "_ATTRIBUTE"; + addAttributeToModel(model, primitive, attributeName, data); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.normalized = true; + testClassProperty.offset = offset; + testClassProperty.scale = scale; + testClassProperty.min = min; + testClassProperty.max = max; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + std::vector texCoords{ + glm::dvec2(0, 0), + glm::dvec2(0.5, 0), + glm::dvec2(0, 0.5), + glm::dvec2(0.5, 0.5)}; + + SECTION("Use class property values") { + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); + REQUIRE(property.offset() == offset); + REQUIRE(property.scale() == scale); + REQUIRE(property.min() == min); + REQUIRE(property.max() == max); + + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(property.getRaw(static_cast(i)) == data[i]); + REQUIRE( + property.get(static_cast(i)) == + normalize(data[i]) * scale + offset); + } + } + + SECTION("Use own property values") { + const double newOffset = 2.0; + const double newScale = 5.0; + const double newMin = 10.0; + const double newMax = 11.0; + propertyAttributeProperty.offset = newOffset; + propertyAttributeProperty.scale = newScale; + propertyAttributeProperty.min = newMin; + propertyAttributeProperty.max = newMax; + + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); + REQUIRE(property.offset() == newOffset); + REQUIRE(property.scale() == newScale); + REQUIRE(property.min() == newMin); + REQUIRE(property.max() == newMax); + + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(property.getRaw(static_cast(i)) == data[i]); + REQUIRE( + property.get(static_cast(i)) == + normalize(data[i]) * newScale + newOffset); + } + } +} + +TEST_CASE("Test with PropertyAttributeProperty noData") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector data = {12, 34, 30, 11}; + const uint8_t noData = 34; + + const std::string attributeName = "_ATTRIBUTE"; + addAttributeToModel(model, primitive, attributeName, data); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.noData = noData; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); + + SECTION("Without default value") { + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + auto value = property.getRaw(static_cast(i)); + REQUIRE(value == data[i]); + + auto maybeValue = property.get(static_cast(i)); + if (value == noData) { + REQUIRE(!maybeValue); + } else { + REQUIRE(maybeValue == data[i]); + } + } + } + + SECTION("With default value") { + const uint8_t defaultValue = 255; + testClassProperty.defaultProperty = defaultValue; + + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + auto value = property.getRaw(static_cast(i)); + REQUIRE(value == data[i]); + + auto maybeValue = property.get(static_cast(i)); + if (value == noData) { + REQUIRE(maybeValue == defaultValue); + } else { + REQUIRE(maybeValue == data[i]); + } + } + } +} + +TEST_CASE("Test with PropertyAttributeProperty noData (normalized)") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector data = {12, 34, 30, 11}; + const uint8_t noData = 34; + + const std::string attributeName = "_ATTRIBUTE"; + addAttributeToModel(model, primitive, attributeName, data); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::UINT8; + testClassProperty.normalized = true; + testClassProperty.noData = noData; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + SECTION("Without default value") { + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + auto value = property.getRaw(static_cast(i)); + REQUIRE(value == data[i]); + + auto maybeValue = property.get(static_cast(i)); + if (value == noData) { + REQUIRE(!maybeValue); + } else { + REQUIRE(maybeValue == normalize(data[i])); + } + } + } + + SECTION("With default value") { + const double defaultValue = -1.0; + testClassProperty.defaultProperty = defaultValue; + + PropertyAttributePropertyView property = + view.getPropertyView(primitive, "TestClassProperty"); + REQUIRE(property.status() == PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + auto value = property.getRaw(static_cast(i)); + REQUIRE(value == data[i]); + + auto maybeValue = property.get(static_cast(i)); + if (value == noData) { + REQUIRE(maybeValue == defaultValue); + } else { + REQUIRE(maybeValue == normalize(data[i])); + } + } + } +} + +TEST_CASE("Test callback on invalid property Attribute view") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + metadata.schema.emplace(); + + // Property Attribute has a nonexistent class. + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = "_INVALID"; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::ErrorClassNotFound); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(!classProperty); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + primitive, + "TestClassProperty", + [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidPropertyAttribute); + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback on invalid PropertyAttributeProperty") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + 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; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["InvalidProperty"]; + propertyAttributeProperty.attribute = "_INVALID"; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::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() != PropertyAttributePropertyViewStatus::Valid); + }; + + view.getPropertyView(primitive, "InvalidProperty", testCallback); + view.getPropertyView(primitive, "NonexistentProperty", testCallback); + + REQUIRE(invokedCallbackCount == 2); +} + +TEST_CASE("Test callback on invalid normalized PropertyAttributeProperty") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::SCALAR; + testClassProperty.componentType = ClassProperty::ComponentType::FLOAT32; + testClassProperty.normalized = true; // This is erroneous. + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = "_INVALID"; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + + uint32_t invokedCallbackCount = 0; + auto testCallback = [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == + PropertyAttributePropertyViewStatus::ErrorInvalidNormalization); + }; + + view.getPropertyView(primitive, "TestClassProperty", testCallback); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for scalar PropertyAttributeProperty") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector data{-1, 268, 542, -256}; + + const std::string attributeName = "_ATTRIBUTE"; + addAttributeToModel(model, primitive, attributeName, data); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + 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; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::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); + REQUIRE(!classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + primitive, + "TestClassProperty", + [&data, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + if constexpr (std::is_same_v< + PropertyAttributePropertyView, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == + PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(propertyValue.getRaw(static_cast(i)) == data[i]); + REQUIRE(propertyValue.get(static_cast(i)) == data[i]); + } + } else { + FAIL("getPropertyView returned PropertyAttributePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for scalar PropertyAttributeProperty (normalized)") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector data{-1, 268, 542, -256}; + + const std::string attributeName = "_ATTRIBUTE"; + addAttributeToModel(model, primitive, attributeName, data); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + 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; + testClassProperty.normalized = true; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::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); + REQUIRE(classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + primitive, + "TestClassProperty", + [&data, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + if constexpr (std::is_same_v< + PropertyAttributePropertyView, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == + PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(propertyValue.getRaw(static_cast(i)) == data[i]); + REQUIRE( + propertyValue.get(static_cast(i)) == + normalize(data[i])); + } + } else { + FAIL("getPropertyView returned PropertyAttributePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for vecN PropertyAttributeProperty") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector data{ + glm::i8vec2(-1, -1), + glm::i8vec2(12, 1), + glm::i8vec2(30, 2), + glm::i8vec2(0, -1)}; + + const std::string attributeName = "_ATTRIBUTE"; + addAttributeToModel(model, primitive, attributeName, data); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + 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; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::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); + REQUIRE(!classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + primitive, + "TestClassProperty", + [&data, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + if constexpr (std::is_same_v< + PropertyAttributePropertyView, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == + PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(propertyValue.getRaw(static_cast(i)) == data[i]); + REQUIRE(propertyValue.get(static_cast(i)) == data[i]); + } + } else { + FAIL("getPropertyView returned PropertyAttributePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for vecN PropertyAttributeProperty (normalized)") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + std::vector data{ + glm::i8vec2(-1, -1), + glm::i8vec2(12, 1), + glm::i8vec2(30, 2), + glm::i8vec2(0, -1)}; + + const std::string attributeName = "_ATTRIBUTE"; + addAttributeToModel(model, primitive, attributeName, data); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + 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; + testClassProperty.normalized = true; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::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); + REQUIRE(classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + primitive, + "TestClassProperty", + [&data, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + if constexpr (std::is_same_v< + PropertyAttributePropertyView, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == + PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(propertyValue.getRaw(static_cast(i)) == data[i]); + REQUIRE( + propertyValue.get(static_cast(i)) == + normalize(data[i])); + } + } else { + FAIL("getPropertyView returned PropertyAttributePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for matN PropertyAttributeProperty") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + // clang-format off + std::vector data = { + glm::umat2x2( + 12, 34, + 30, 1), + glm::umat2x2( + 11, 8, + 73, 102), + glm::umat2x2( + 1, 0, + 63, 2), + glm::umat2x2( + 4, 8, + 3, 23)}; + // clang-format on + + const std::string attributeName = "_ATTRIBUTE"; + addAttributeToModel(model, primitive, attributeName, data); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(!classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + primitive, + "TestClassProperty", + [&data, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + if constexpr (std::is_same_v< + PropertyAttributePropertyView, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == + PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(propertyValue.getRaw(static_cast(i)) == data[i]); + REQUIRE(propertyValue.get(static_cast(i)) == data[i]); + } + } else { + FAIL("getPropertyView returned PropertyAttributePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback for matN PropertyAttributeProperty (normalized)") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + // clang-format off + std::vector data = { + glm::umat2x2( + 12, 34, + 30, 1), + glm::umat2x2( + 11, 8, + 73, 102), + glm::umat2x2( + 1, 0, + 63, 2), + glm::umat2x2( + 4, 8, + 3, 23)}; + // clang-format on + + const std::string attributeName = "_ATTRIBUTE"; + addAttributeToModel( + model, + primitive, + attributeName, + data); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + ClassProperty& testClassProperty = testClass.properties["TestClassProperty"]; + testClassProperty.type = ClassProperty::Type::MAT2; + testClassProperty.componentType = ClassProperty::ComponentType::UINT32; + testClassProperty.normalized = true; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& propertyAttributeProperty = + propertyAttribute.properties["TestClassProperty"]; + propertyAttributeProperty.attribute = attributeName; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("TestClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::MAT2); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT32); + REQUIRE(classProperty->count == std::nullopt); + REQUIRE(!classProperty->array); + REQUIRE(classProperty->normalized); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + primitive, + "TestClassProperty", + [&data, &invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + if constexpr (std::is_same_v< + PropertyAttributePropertyView, + decltype(propertyValue)>) { + REQUIRE( + propertyValue.status() == + PropertyAttributePropertyViewStatus::Valid); + + for (size_t i = 0; i < data.size(); ++i) { + REQUIRE(propertyValue.getRaw(static_cast(i)) == data[i]); + REQUIRE( + propertyValue.get(static_cast(i)) == + normalize(data[i])); + } + } else { + FAIL("getPropertyView returned PropertyAttributePropertyView of " + "incorrect type for TestClassProperty."); + } + }); + + REQUIRE(invokedCallbackCount == 1); +} + +TEST_CASE("Test callback on unsupported PropertyAttributeProperty") { + Model model; + Mesh& mesh = model.meshes.emplace_back(); + MeshPrimitive& primitive = mesh.primitives.emplace_back(); + + ExtensionModelExtStructuralMetadata& metadata = + model.addExtension(); + + Schema& schema = metadata.schema.emplace(); + Class& testClass = schema.classes["TestClass"]; + + ClassProperty& doubleClassProperty = + testClass.properties["DoubleClassProperty"]; + doubleClassProperty.type = ClassProperty::Type::SCALAR; + doubleClassProperty.componentType = ClassProperty::ComponentType::FLOAT64; + + ClassProperty& arrayClassProperty = + testClass.properties["ArrayClassProperty"]; + arrayClassProperty.type = ClassProperty::Type::SCALAR; + arrayClassProperty.componentType = ClassProperty::ComponentType::UINT8; + arrayClassProperty.array = true; + arrayClassProperty.count = 2; + + PropertyAttribute& propertyAttribute = + metadata.propertyAttributes.emplace_back(); + propertyAttribute.classProperty = "TestClass"; + + PropertyAttributeProperty& doubleProperty = + propertyAttribute.properties["DoubleClassProperty"]; + doubleProperty.attribute = "_DOUBLE"; + PropertyAttributeProperty& arrayProperty = + propertyAttribute.properties["ArrayClassProperty"]; + arrayProperty.attribute = "_ARRAY"; + + PropertyAttributeView view(model, propertyAttribute); + REQUIRE(view.status() == PropertyAttributeViewStatus::Valid); + + const ClassProperty* classProperty = + view.getClassProperty("DoubleClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE( + classProperty->componentType == ClassProperty::ComponentType::FLOAT64); + REQUIRE(!classProperty->array); + + classProperty = view.getClassProperty("ArrayClassProperty"); + REQUIRE(classProperty); + REQUIRE(classProperty->type == ClassProperty::Type::SCALAR); + REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT8); + REQUIRE(classProperty->array); + REQUIRE(classProperty->count == 2); + + uint32_t invokedCallbackCount = 0; + view.getPropertyView( + primitive, + "DoubleClassProperty", + [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == + PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty); + }); + REQUIRE(invokedCallbackCount == 1); + + view.getPropertyView( + primitive, + "ArrayClassProperty", + [&invokedCallbackCount]( + const std::string& /*propertyName*/, + auto propertyValue) mutable { + invokedCallbackCount++; + REQUIRE( + propertyValue.status() == + PropertyAttributePropertyViewStatus::ErrorUnsupportedProperty); + }); + REQUIRE(invokedCallbackCount == 2); +} diff --git a/CesiumGltf/test/TestPropertyTablePropertyView.cpp b/CesiumGltf/test/TestPropertyTablePropertyView.cpp index 12011cabb..524222d26 100644 --- a/CesiumGltf/test/TestPropertyTablePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTablePropertyView.cpp @@ -12,6 +12,8 @@ using namespace CesiumGltf; using namespace CesiumUtility; +namespace { + template static void checkArrayEqual(PropertyArrayView arrayView, std::vector expected) { @@ -560,6 +562,7 @@ static void checkNormalizedFixedLengthArray( } } } +} // namespace TEST_CASE("Check scalar PropertyTablePropertyView") { SECTION("Uint8") { diff --git a/CesiumGltf/test/TestPropertyTableView.cpp b/CesiumGltf/test/TestPropertyTableView.cpp index b3c4e33ef..6e7e85a32 100644 --- a/CesiumGltf/test/TestPropertyTableView.cpp +++ b/CesiumGltf/test/TestPropertyTableView.cpp @@ -155,10 +155,10 @@ TEST_CASE("Test scalar PropertyTableProperty") { uvec3Invalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); - PropertyTablePropertyView u32mat3x3Invalid = - view.getPropertyView("TestClassProperty"); + PropertyTablePropertyView umat3x3Invalid = + view.getPropertyView("TestClassProperty"); REQUIRE( - u32mat3x3Invalid.status() == + umat3x3Invalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); PropertyTablePropertyView boolInvalid = @@ -644,17 +644,17 @@ TEST_CASE("Test vecN PropertyTableProperty (normalized)") { TEST_CASE("Test matN PropertyTableProperty") { Model model; // clang-format off - std::vector values = { - glm::u32mat2x2( + std::vector values = { + glm::umat2x2( 12, 34, 30, 1), - glm::u32mat2x2( + glm::umat2x2( 11, 8, 73, 102), - glm::u32mat2x2( + glm::umat2x2( 1, 0, 63, 2), - glm::u32mat2x2( + glm::umat2x2( 4, 8, 3, 23)}; // clang-format on @@ -694,15 +694,14 @@ TEST_CASE("Test matN PropertyTableProperty") { REQUIRE(!classProperty->normalized); SECTION("Access correct type") { - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(u32mat2x2Property.size() > 0); - - for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { - REQUIRE(u32mat2x2Property.getRaw(i) == values[static_cast(i)]); - REQUIRE(u32mat2x2Property.get(i) == u32mat2x2Property.getRaw(i)); + PropertyTablePropertyView umat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(umat2x2Property.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(umat2x2Property.size() > 0); + + for (int64_t i = 0; i < umat2x2Property.size(); ++i) { + REQUIRE(umat2x2Property.getRaw(i) == values[static_cast(i)]); + REQUIRE(umat2x2Property.get(i) == umat2x2Property.getRaw(i)); } } @@ -719,10 +718,10 @@ TEST_CASE("Test matN PropertyTableProperty") { uvec2Invalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); - PropertyTablePropertyView u32mat4x4Invalid = - view.getPropertyView("TestClassProperty"); + PropertyTablePropertyView umat4x4Invalid = + view.getPropertyView("TestClassProperty"); REQUIRE( - u32mat4x4Invalid.status() == + umat4x4Invalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); PropertyTablePropertyView boolInvalid = @@ -759,8 +758,8 @@ TEST_CASE("Test matN PropertyTableProperty") { } SECTION("Access incorrectly as array") { - PropertyTablePropertyView> arrayInvalid = - view.getPropertyView>( + PropertyTablePropertyView> arrayInvalid = + view.getPropertyView>( "TestClassProperty"); REQUIRE( arrayInvalid.status() == @@ -768,8 +767,8 @@ TEST_CASE("Test matN PropertyTableProperty") { } SECTION("Access incorrectly as normalized") { - PropertyTablePropertyView normalizedInvalid = - view.getPropertyView("TestClassProperty"); + PropertyTablePropertyView normalizedInvalid = + view.getPropertyView("TestClassProperty"); REQUIRE( normalizedInvalid.status() == PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); @@ -777,49 +776,49 @@ TEST_CASE("Test matN PropertyTableProperty") { SECTION("Wrong buffer index") { model.bufferViews[valueBufferViewIndex].buffer = 2; - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); + PropertyTablePropertyView umat2x2Property = + view.getPropertyView("TestClassProperty"); REQUIRE( - u32mat2x2Property.status() == + umat2x2Property.status() == PropertyTablePropertyViewStatus::ErrorInvalidValueBuffer); } SECTION("Wrong buffer view index") { propertyTableProperty.values = -1; - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); + PropertyTablePropertyView umat2x2Property = + view.getPropertyView("TestClassProperty"); REQUIRE( - u32mat2x2Property.status() == + umat2x2Property.status() == PropertyTablePropertyViewStatus::ErrorInvalidValueBufferView); } SECTION("Buffer view points outside of the real buffer length") { - model.buffers[valueBufferIndex].cesium.data.resize(sizeof(glm::u32mat2x2)); - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); + model.buffers[valueBufferIndex].cesium.data.resize(sizeof(glm::umat2x2)); + PropertyTablePropertyView umat2x2Property = + view.getPropertyView("TestClassProperty"); REQUIRE( - u32mat2x2Property.status() == + umat2x2Property.status() == PropertyTablePropertyViewStatus::ErrorBufferViewOutOfBounds); } SECTION("Buffer view length isn't multiple of sizeof(T)") { model.bufferViews[valueBufferViewIndex].byteLength = - sizeof(glm::u32mat2x2) * 4 - 1; - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); + sizeof(glm::umat2x2) * 4 - 1; + PropertyTablePropertyView umat2x2Property = + view.getPropertyView("TestClassProperty"); REQUIRE( - u32mat2x2Property.status() == + umat2x2Property.status() == PropertyTablePropertyViewStatus:: ErrorBufferViewSizeNotDivisibleByTypeSize); } SECTION("Buffer view length doesn't match with propertyTableCount") { - model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::u32mat2x2); + model.bufferViews[valueBufferViewIndex].byteLength = sizeof(glm::umat2x2); - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); + PropertyTablePropertyView umat2x2Property = + view.getPropertyView("TestClassProperty"); REQUIRE( - u32mat2x2Property.status() == + umat2x2Property.status() == PropertyTablePropertyViewStatus:: ErrorBufferViewSizeDoesNotMatchPropertyTableCount); } @@ -828,17 +827,17 @@ TEST_CASE("Test matN PropertyTableProperty") { TEST_CASE("Test matN PropertyTableProperty (normalized)") { Model model; // clang-format off - std::vector values = { - glm::u32mat2x2( + std::vector values = { + glm::umat2x2( 12, 34, 30, 1), - glm::u32mat2x2( + glm::umat2x2( 11, 8, 73, 102), - glm::u32mat2x2( + glm::umat2x2( 1, 0, 63, 2), - glm::u32mat2x2( + glm::umat2x2( 4, 8, 3, 23)}; // clang-format on @@ -878,16 +877,15 @@ TEST_CASE("Test matN PropertyTableProperty (normalized)") { REQUIRE(classProperty->normalized); SECTION("Access correct type") { - PropertyTablePropertyView u32mat2x2Property = - view.getPropertyView("TestClassProperty"); - REQUIRE( - u32mat2x2Property.status() == PropertyTablePropertyViewStatus::Valid); - REQUIRE(u32mat2x2Property.size() > 0); + PropertyTablePropertyView umat2x2Property = + view.getPropertyView("TestClassProperty"); + REQUIRE(umat2x2Property.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(umat2x2Property.size() > 0); - for (int64_t i = 0; i < u32mat2x2Property.size(); ++i) { - auto value = u32mat2x2Property.getRaw(i); + for (int64_t i = 0; i < umat2x2Property.size(); ++i) { + auto value = umat2x2Property.getRaw(i); REQUIRE(value == values[static_cast(i)]); - REQUIRE(u32mat2x2Property.get(i) == normalize(value)); + REQUIRE(umat2x2Property.get(i) == normalize(value)); } } @@ -904,10 +902,10 @@ TEST_CASE("Test matN PropertyTableProperty (normalized)") { uvec2Invalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); - PropertyTablePropertyView u32mat4x4Invalid = - view.getPropertyView("TestClassProperty"); + PropertyTablePropertyView umat4x4Invalid = + view.getPropertyView("TestClassProperty"); REQUIRE( - u32mat4x4Invalid.status() == + umat4x4Invalid.status() == PropertyTablePropertyViewStatus::ErrorTypeMismatch); } @@ -926,9 +924,9 @@ TEST_CASE("Test matN PropertyTableProperty (normalized)") { } SECTION("Access incorrectly as array") { - PropertyTablePropertyView, true> + PropertyTablePropertyView, true> arrayInvalid = - view.getPropertyView, true>( + view.getPropertyView, true>( "TestClassProperty"); REQUIRE( arrayInvalid.status() == @@ -936,8 +934,8 @@ TEST_CASE("Test matN PropertyTableProperty (normalized)") { } SECTION("Access incorrectly as non-normalized") { - PropertyTablePropertyView nonNormalizedInvalid = - view.getPropertyView("TestClassProperty"); + PropertyTablePropertyView nonNormalizedInvalid = + view.getPropertyView("TestClassProperty"); REQUIRE( nonNormalizedInvalid.status() == PropertyTablePropertyViewStatus::ErrorNormalizationMismatch); @@ -2297,12 +2295,12 @@ TEST_CASE("Test fixed-length matN array") { } SECTION("Wrong component type") { - PropertyTablePropertyView> - u32mat2x2ArrayInvalid = - view.getPropertyView>( + PropertyTablePropertyView> + umat2x2ArrayInvalid = + view.getPropertyView>( "TestClassProperty"); REQUIRE( - u32mat2x2ArrayInvalid.status() == + umat2x2ArrayInvalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } @@ -2457,12 +2455,12 @@ TEST_CASE("Test fixed-length matN array (normalized)") { } SECTION("Wrong component type") { - PropertyTablePropertyView, true> - u32mat2x2ArrayInvalid = - view.getPropertyView, true>( + PropertyTablePropertyView, true> + umat2x2ArrayInvalid = + view.getPropertyView, true>( "TestClassProperty"); REQUIRE( - u32mat2x2ArrayInvalid.status() == + umat2x2ArrayInvalid.status() == PropertyTablePropertyViewStatus::ErrorComponentTypeMismatch); } @@ -4237,9 +4235,7 @@ TEST_CASE("Test callback for vecN PropertyTableProperty (normalized)") { decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { auto expectedValue = values[static_cast(i)]; - REQUIRE( - static_cast(propertyValue.getRaw(i)) == - expectedValue); + REQUIRE(propertyValue.getRaw(i) == expectedValue); REQUIRE(propertyValue.get(i) == normalize(expectedValue)); } } else { @@ -4254,17 +4250,17 @@ TEST_CASE("Test callback for vecN PropertyTableProperty (normalized)") { TEST_CASE("Test callback for matN PropertyTableProperty") { Model model; // clang-format off - std::vector values = { - glm::u32mat2x2( + std::vector values = { + glm::umat2x2( 12, 34, 30, 1), - glm::u32mat2x2( + glm::umat2x2( 11, 8, 73, 102), - glm::u32mat2x2( + glm::umat2x2( 1, 0, 63, 2), - glm::u32mat2x2( + glm::umat2x2( 4, 8, 3, 23)}; // clang-format on @@ -4313,13 +4309,11 @@ TEST_CASE("Test callback for matN PropertyTableProperty") { REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - PropertyTablePropertyView, + PropertyTablePropertyView, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { auto expectedValue = values[static_cast(i)]; - REQUIRE( - static_cast(propertyValue.getRaw(i)) == - expectedValue); + REQUIRE(propertyValue.getRaw(i) == expectedValue); REQUIRE(propertyValue.get(i) == expectedValue); } } else { @@ -4335,17 +4329,17 @@ TEST_CASE("Test callback for matN PropertyTableProperty") { TEST_CASE("Test callback for matN PropertyTableProperty (normalized)") { Model model; // clang-format off - std::vector values = { - glm::u32mat2x2( + std::vector values = { + glm::umat2x2( 12, 34, 30, 1), - glm::u32mat2x2( + glm::umat2x2( 11, 8, 73, 102), - glm::u32mat2x2( + glm::umat2x2( 1, 0, 63, 2), - glm::u32mat2x2( + glm::umat2x2( 4, 8, 3, 23)}; // clang-format on @@ -4395,12 +4389,12 @@ TEST_CASE("Test callback for matN PropertyTableProperty (normalized)") { REQUIRE(propertyValue.size() > 0); if constexpr (std::is_same_v< - PropertyTablePropertyView, + PropertyTablePropertyView, decltype(propertyValue)>) { for (int64_t i = 0; i < propertyValue.size(); ++i) { auto expectedValue = values[static_cast(i)]; REQUIRE( - static_cast(propertyValue.getRaw(i)) == + static_cast(propertyValue.getRaw(i)) == expectedValue); REQUIRE(propertyValue.get(i) == normalize(expectedValue)); } diff --git a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp index 7805964a1..227d6e385 100644 --- a/CesiumGltf/test/TestPropertyTexturePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyTexturePropertyView.cpp @@ -10,6 +10,7 @@ using namespace CesiumGltf; using namespace CesiumUtility; +namespace { template void checkTextureValues( const std::vector& data, @@ -487,6 +488,7 @@ void checkNormalizedTextureArrayValues( } } } +} // namespace TEST_CASE("Check scalar PropertyTexturePropertyView") { SECTION("uint8_t") { @@ -1371,7 +1373,8 @@ TEST_CASE("Check array PropertyTexturePropertyView (normalized)") { } } -TEST_CASE("Check that PropertyTextureProperty values override class property values") { +TEST_CASE("Check that PropertyTextureProperty values override class property " + "values") { ClassProperty classProperty; classProperty.type = ClassProperty::Type::SCALAR; classProperty.componentType = ClassProperty::ComponentType::FLOAT32; diff --git a/CesiumGltf/test/TestPropertyTextureView.cpp b/CesiumGltf/test/TestPropertyTextureView.cpp index 626dd3891..13be12580 100644 --- a/CesiumGltf/test/TestPropertyTextureView.cpp +++ b/CesiumGltf/test/TestPropertyTextureView.cpp @@ -676,10 +676,10 @@ TEST_CASE("Test vecN PropertyTextureProperty (normalized)") { } SECTION("Access incorrectly as dvec2") { - PropertyTexturePropertyView normalizedInvalid = + PropertyTexturePropertyView dvec2Invalid = view.getPropertyView("TestClassProperty"); REQUIRE( - normalizedInvalid.status() == + dvec2Invalid.status() == PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch); } From 7a3a5f0d8671f0d4052920c44fd255f182be021d Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Tue, 29 Aug 2023 15:48:28 -0400 Subject: [PATCH 107/121] Update changelog and fix sign conversions --- CHANGES.md | 3 +++ CesiumGltf/test/TestPropertyAttributePropertyView.cpp | 4 ++-- CesiumGltf/test/TestPropertyAttributeView.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index e4b438c46..865cbfc8e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,6 +28,9 @@ - Added `PropertyViewStatus`, which defines public `static const` values for various property errors. - Added `PropertyTableViewStatus` to indicate whether a `PropertyTableView` is valid. - Added `PropertyComponentType` to reflect the values of `componentType` in a `ClassProperty` from `EXT_structural_metadata`. +- Added `PropertyAttributeView`, which views a `PropertyAttribute` in `EXT_structural_metadata`. +- Added `PropertyAttributePropertyView`, which views a `PropertyAttributeProperty` in `EXT_structural_metadata`. +- Added `PropertyAttributePropertyViewStatus`, which reflects the sattus of a `PropertyAttributePropertyView`. ### v0.25.0 - 2023-06-01 diff --git a/CesiumGltf/test/TestPropertyAttributePropertyView.cpp b/CesiumGltf/test/TestPropertyAttributePropertyView.cpp index 0dab05f2e..150dc5393 100644 --- a/CesiumGltf/test/TestPropertyAttributePropertyView.cpp +++ b/CesiumGltf/test/TestPropertyAttributePropertyView.cpp @@ -28,7 +28,7 @@ const Accessor& addValuesToModel(Model& model, const std::vector& values) { Accessor& accessor = model.accessors.emplace_back(); accessor.bufferView = static_cast(model.bufferViews.size() - 1); - accessor.count = values.size(); + accessor.count = static_cast(values.size()); accessor.byteOffset = 0; PropertyType type = TypeToPropertyType::value; @@ -817,7 +817,7 @@ TEST_CASE("Check that PropertyAttributeProperty values override class property " Accessor& accessor = model.accessors.emplace_back(); accessor.bufferView = static_cast(model.bufferViews.size() - 1); - accessor.count = data.size(); + accessor.count = static_cast(data.size()); accessor.byteOffset = 0; accessor.type = Accessor::Type::SCALAR; accessor.componentType = Accessor::ComponentType::FLOAT; diff --git a/CesiumGltf/test/TestPropertyAttributeView.cpp b/CesiumGltf/test/TestPropertyAttributeView.cpp index d7d13c7b1..5e9bae689 100644 --- a/CesiumGltf/test/TestPropertyAttributeView.cpp +++ b/CesiumGltf/test/TestPropertyAttributeView.cpp @@ -30,7 +30,7 @@ void addAttributeToModel( Accessor& accessor = model.accessors.emplace_back(); accessor.bufferView = static_cast(model.bufferViews.size() - 1); - accessor.count = values.size(); + accessor.count = static_cast(values.size()); accessor.byteOffset = 0; PropertyType type = TypeToPropertyType::value; From c7f01d437c7d6d24edcf59e4862ec7515441dc39 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 30 Aug 2023 15:28:06 -0400 Subject: [PATCH 108/121] Warn about EXT_feature_metadata --- CesiumGltfReader/src/GltfReader.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CesiumGltfReader/src/GltfReader.cpp b/CesiumGltfReader/src/GltfReader.cpp index 080896bc1..c4045c190 100644 --- a/CesiumGltfReader/src/GltfReader.cpp +++ b/CesiumGltfReader/src/GltfReader.cpp @@ -225,6 +225,18 @@ void postprocess( const GltfReaderOptions& options) { Model& model = readGltf.model.value(); + auto extFeatureMetadataIter = std::find( + model.extensionsUsed.begin(), + model.extensionsUsed.end(), + "EXT_feature_metadata"); + + if (extFeatureMetadataIter != model.extensionsUsed.end()) { + readGltf.warnings.emplace_back( + "glTF contains EXT_feature_metadata extension, which is no longer " + "supported. The model will still be loaded, but views cannot be " + "constructed on its metadata."); + } + if (options.decodeDataUrls) { decodeDataUrls(reader, readGltf, options); } From 09e84e2c52b3babe49d396080791f9f6595cd068 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 30 Aug 2023 15:28:20 -0400 Subject: [PATCH 109/121] Add getters for name, semantic, description --- .../CesiumGltf/PropertyAttributeView.h | 8 + .../include/CesiumGltf/PropertyTableView.h | 8 + .../include/CesiumGltf/PropertyTextureView.h | 8 + CesiumGltf/include/CesiumGltf/PropertyView.h | 402 ++++++++++++++---- 4 files changed, 345 insertions(+), 81 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h b/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h index af4949567..aac020193 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyAttributeView.h @@ -72,6 +72,14 @@ class PropertyAttributeView { */ PropertyAttributeViewStatus status() const noexcept { return this->_status; } + /** + * @brief Gets the name of the property attribute being viewed. Returns + * std::nullopt if no name was specified. + */ + const std::optional& name() const noexcept { + return _pPropertyAttribute->name; + } + /** * @brief Finds the {@link ClassProperty} that * describes the type information of the property with the specified name. diff --git a/CesiumGltf/include/CesiumGltf/PropertyTableView.h b/CesiumGltf/include/CesiumGltf/PropertyTableView.h index b92e991ba..c4c89cdf0 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTableView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTableView.h @@ -71,6 +71,14 @@ class PropertyTableView { */ PropertyTableViewStatus status() const noexcept { return _status; } + /** + * @brief Gets the name of the property table being viewed. Returns + * std::nullopt if no name was specified. + */ + const std::optional& name() const noexcept { + return _pPropertyTable->name; + } + /** * @brief Get the number of elements in this PropertyTableView. If the * view is valid, this returns {@link PropertyTable::count}. Otherwise, this returns 0. diff --git a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h index ed2546110..4573ddf77 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTextureView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTextureView.h @@ -68,6 +68,14 @@ class PropertyTextureView { */ PropertyTextureViewStatus status() const noexcept { return this->_status; } + /** + * @brief Gets the name of the property texture being viewed. Returns + * std::nullopt if no name was specified. + */ + const std::optional& name() const noexcept { + return _pPropertyTexture->name; + } + /** * @brief Finds the {@link ClassProperty} that * describes the type information of the property with the specified name. diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 5257de32b..ec6f05730 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -258,6 +258,9 @@ template class PropertyView { */ PropertyView() : _status(PropertyViewStatus::ErrorNonexistentProperty), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -271,6 +274,9 @@ template class PropertyView { */ PropertyView(const ClassProperty& classProperty) : _status(validatePropertyType(classProperty)), + _name(classProperty.name), + _semantic(classProperty.semantic), + _description(classProperty.description), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -328,6 +334,9 @@ template class PropertyView { */ PropertyView(PropertyViewStatusType status) : _status(status), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -393,6 +402,30 @@ template class PropertyView { */ PropertyViewStatusType status() const noexcept { return _status; } + /** + * @brief Gets the name of the property being viewed. Returns std::nullopt if + * no description was provided. + */ + const std::optional& name() const noexcept { return _name; } + + /** + * @brief Gets the semantic of the property being viewed. The semantic is an + * identifier that describes how this property should be interpreted, and + * cannot be used by other properties in the class. Returns std::nullopt if no + * semantic was specified. + */ + const std::optional& semantic() const noexcept { + return _semantic; + } + + /** + * @brief Gets the description of the property being viewed. Returns + * std::nullopt if no name was specified. + */ + const std::optional& description() const noexcept { + return _description; + } + /** * @brief Get the element count of the fixed-length arrays in this property. * Only applicable when the property is an array type. @@ -403,8 +436,6 @@ template class PropertyView { /** * @brief Whether this property has a normalized integer type. - * - * @return Whether this property has a normalized integer type. */ bool normalized() const noexcept { return false; } @@ -460,6 +491,9 @@ template class PropertyView { * in the property wherever it appears. Also known as a sentinel value. This * is given as the plain property value, without the transforms from the * normalized, offset, and scale properties. + * + * @returns The property's "no data" value, or std::nullopt if it was not + * specified. */ std::optional noData() const noexcept { return _noData; } @@ -467,6 +501,9 @@ template class PropertyView { * @brief Gets the default value to use when encountering a "no data" value or * an omitted property. The value is given in its final form, taking the * effect of normalized, offset, and scale properties into account. + * + * @returns The property's default value, or std::nullopt if it was not + * specified. */ std::optional defaultValue() const noexcept { return _defaultValue; @@ -476,6 +513,10 @@ template class PropertyView { PropertyViewStatusType _status; private: + std::optional _name; + std::optional _semantic; + std::optional _description; + bool _required; std::optional _offset; @@ -603,6 +644,9 @@ template class PropertyView { */ PropertyView() : _status(PropertyViewStatus::ErrorNonexistentProperty), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -616,6 +660,9 @@ template class PropertyView { */ PropertyView(const ClassProperty& classProperty) : _status(validatePropertyType(classProperty)), + _name(classProperty.name), + _semantic(classProperty.semantic), + _description(classProperty.description), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -670,6 +717,9 @@ template class PropertyView { */ PropertyView(PropertyViewStatusType status) : _status(status), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _offset(std::nullopt), _scale(std::nullopt), _max(std::nullopt), @@ -728,13 +778,29 @@ template class PropertyView { public: /** - * @brief Gets the status of this property view, indicating whether an error - * occurred. - * - * @return The status of this property view. + * @copydoc PropertyView::status */ PropertyViewStatusType status() const noexcept { return _status; } + /** + * @copydoc PropertyView::name + */ + const std::optional& name() const noexcept { return _name; } + + /** + * @copydoc PropertyView::semantic + */ + const std::optional& semantic() const noexcept { + return _semantic; + } + + /** + * @copydoc PropertyView::description + */ + const std::optional& description() const noexcept { + return _description; + } + /** * @copydoc PropertyView::arrayCount */ @@ -786,6 +852,10 @@ template class PropertyView { PropertyViewStatusType _status; private: + std::optional _name; + std::optional _semantic; + std::optional _description; + bool _required; std::optional _offset; @@ -884,6 +954,9 @@ template <> class PropertyView { */ PropertyView() : _status(PropertyViewStatus::ErrorNonexistentProperty), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _required(false), _defaultValue(std::nullopt) {} @@ -892,6 +965,9 @@ template <> class PropertyView { */ PropertyView(const ClassProperty& classProperty) : _status(validatePropertyType(classProperty)), + _name(classProperty.name), + _semantic(classProperty.semantic), + _description(classProperty.description), _required(classProperty.required), _defaultValue(std::nullopt) { if (_status != PropertyViewStatus::Valid) { @@ -918,7 +994,12 @@ template <> class PropertyView { * @param status The value of {@link PropertyViewStatus} indicating the error with the property. */ PropertyView(PropertyViewStatusType status) - : _status(status), _required(false), _defaultValue(std::nullopt) {} + : _status(status), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), + _required(false), + _defaultValue(std::nullopt) {} /** * @brief Constructs a property instance from a property table property and @@ -935,6 +1016,25 @@ template <> class PropertyView { */ PropertyViewStatusType status() const noexcept { return _status; } + /** + * @copydoc PropertyView::name + */ + const std::optional& name() const noexcept { return _name; } + + /** + * @copydoc PropertyView::semantic + */ + const std::optional& semantic() const noexcept { + return _semantic; + } + + /** + * @copydoc PropertyView::description + */ + const std::optional& description() const noexcept { + return _description; + } + /** * @copydoc PropertyView::arrayCount */ @@ -984,6 +1084,10 @@ template <> class PropertyView { PropertyViewStatusType _status; private: + std::optional _name; + std::optional _semantic; + std::optional _description; + bool _required; std::optional _defaultValue; @@ -1008,6 +1112,9 @@ template <> class PropertyView { */ PropertyView() : _status(PropertyViewStatus::ErrorNonexistentProperty), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _required(false), _noData(std::nullopt), _defaultValue(std::nullopt) {} @@ -1017,6 +1124,9 @@ template <> class PropertyView { */ PropertyView(const ClassProperty& classProperty) : _status(validatePropertyType(classProperty)), + _name(classProperty.name), + _semantic(classProperty.semantic), + _description(classProperty.description), _required(classProperty.required), _noData(std::nullopt), _defaultValue(std::nullopt) { @@ -1057,6 +1167,9 @@ template <> class PropertyView { */ PropertyView(PropertyViewStatusType status) : _status(status), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _required(false), _noData(std::nullopt), _defaultValue(std::nullopt) {} @@ -1076,6 +1189,25 @@ template <> class PropertyView { */ PropertyViewStatusType status() const noexcept { return _status; } + /** + * @copydoc PropertyView::name + */ + const std::optional& name() const noexcept { return _name; } + + /** + * @copydoc PropertyView::semantic + */ + const std::optional& semantic() const noexcept { + return _semantic; + } + + /** + * @copydoc PropertyView::description + */ + const std::optional& description() const noexcept { + return _description; + } + /** * @copydoc PropertyView::arrayCount */ @@ -1139,6 +1271,10 @@ template <> class PropertyView { PropertyViewStatusType _status; private: + std::optional _name; + std::optional _semantic; + std::optional _description; + bool _required; std::optional _noData; std::optional _defaultValue; @@ -1174,6 +1310,9 @@ class PropertyView, false> { */ PropertyView() : _status(PropertyViewStatus::ErrorNonexistentProperty), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _count(0), _offset(std::nullopt), _scale(std::nullopt), @@ -1189,6 +1328,9 @@ class PropertyView, false> { PropertyView(const ClassProperty& classProperty) : _status(validateArrayPropertyType>( classProperty)), + _name(classProperty.name), + _semantic(classProperty.semantic), + _description(classProperty.description), _count(_count = classProperty.count ? *classProperty.count : 0), _offset(std::nullopt), _scale(std::nullopt), @@ -1243,6 +1385,9 @@ class PropertyView, false> { */ PropertyView(PropertyViewStatusType status) : _status(status), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _count(0), _offset(std::nullopt), _scale(std::nullopt), @@ -1290,6 +1435,25 @@ class PropertyView, false> { */ PropertyViewStatusType status() const noexcept { return _status; } + /** + * @copydoc PropertyView::name + */ + const std::optional& name() const noexcept { return _name; } + + /** + * @copydoc PropertyView::semantic + */ + const std::optional& semantic() const noexcept { + return _semantic; + } + + /** + * @copydoc PropertyView::description + */ + const std::optional& description() const noexcept { + return _description; + } + /** * @copydoc PropertyView::arrayCount */ @@ -1382,6 +1546,10 @@ class PropertyView, false> { PropertyViewStatusType _status; private: + std::optional _name; + std::optional _semantic; + std::optional _description; + int64_t _count; std::optional> _offset; @@ -1538,6 +1706,9 @@ class PropertyView, true> { */ PropertyView() : _status(PropertyViewStatus::ErrorNonexistentProperty), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _count(0), _offset(std::nullopt), _scale(std::nullopt), @@ -1553,6 +1724,9 @@ class PropertyView, true> { PropertyView(const ClassProperty& classProperty) : _status(validateArrayPropertyType>( classProperty)), + _name(classProperty.name), + _semantic(classProperty.semantic), + _description(classProperty.description), _count(_count = classProperty.count ? *classProperty.count : 0), _offset(std::nullopt), _scale(std::nullopt), @@ -1607,6 +1781,9 @@ class PropertyView, true> { */ PropertyView(PropertyViewStatusType status) : _status(status), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _count(0), _offset(std::nullopt), _scale(std::nullopt), @@ -1654,6 +1831,25 @@ class PropertyView, true> { */ PropertyViewStatusType status() const noexcept { return _status; } + /** + * @copydoc PropertyView::name + */ + const std::optional& name() const noexcept { return _name; } + + /** + * @copydoc PropertyView::semantic + */ + const std::optional& semantic() const noexcept { + return _semantic; + } + + /** + * @copydoc PropertyView::description + */ + const std::optional& description() const noexcept { + return _description; + } + /** * @copydoc PropertyView::arrayCount */ @@ -1747,6 +1943,10 @@ class PropertyView, true> { PropertyViewStatusType _status; private: + std::optional _name; + std::optional _semantic; + std::optional _description; + int64_t _count; std::optional> _offset; @@ -1872,6 +2072,9 @@ template <> class PropertyView> { */ PropertyView() : _status(PropertyViewStatus::ErrorNonexistentProperty), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _count(0), _required(false), _defaultValue(), @@ -1883,6 +2086,9 @@ template <> class PropertyView> { PropertyView(const ClassProperty& classProperty) : _status( validateArrayPropertyType>(classProperty)), + _name(classProperty.name), + _semantic(classProperty.semantic), + _description(classProperty.description), _count(classProperty.count ? *classProperty.count : 0), _required(classProperty.required), _defaultValue(), @@ -1912,6 +2118,9 @@ template <> class PropertyView> { */ PropertyView(PropertyViewStatusType status) : _status(status), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _count(0), _required(false), _defaultValue(), @@ -1932,6 +2141,25 @@ template <> class PropertyView> { */ PropertyViewStatusType status() const noexcept { return _status; } + /** + * @copydoc PropertyView::name + */ + const std::optional& name() const noexcept { return _name; } + + /** + * @copydoc PropertyView::semantic + */ + const std::optional& semantic() const noexcept { + return _semantic; + } + + /** + * @copydoc PropertyView::description + */ + const std::optional& description() const noexcept { + return _description; + } + /** * @copydoc PropertyView::arrayCount */ @@ -2002,6 +2230,10 @@ template <> class PropertyView> { PropertyViewStatusType _status; private: + std::optional _name; + std::optional _semantic; + std::optional _description; + int64_t _count; bool _required; @@ -2059,16 +2291,13 @@ template <> class PropertyView> { */ PropertyView() : _status(PropertyViewStatus::ErrorNonexistentProperty), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _count(0), _required(false), _noData(), - _noDataOffsets(), - _noDataOffsetType(PropertyComponentType::None), - _noDataSize(0), - _defaultValue(), - _defaultValueOffsets(), - _defaultValueOffsetType(PropertyComponentType::None), - _defaultValueSize(0) {} + _defaultValue() {} /** * @brief Constructs a property instance from a class definition only. @@ -2076,30 +2305,23 @@ template <> class PropertyView> { PropertyView(const ClassProperty& classProperty) : _status(validateArrayPropertyType>( classProperty)), + _name(classProperty.name), + _semantic(classProperty.semantic), + _description(classProperty.description), _count(classProperty.count ? *classProperty.count : 0), _required(classProperty.required), _noData(), - _noDataOffsets(), - _noDataOffsetType(PropertyComponentType::None), - _noDataSize(0), - _defaultValue(), - _defaultValueOffsets(), - _defaultValueOffsetType(PropertyComponentType::None), - _defaultValueSize(0) { + _defaultValue() { if (_status != PropertyViewStatus::Valid) { return; } if (classProperty.noData) { if (!_required) { - _noData = getStringArrayValue( - *classProperty.noData, - _noDataOffsets, - _noDataOffsetType, - _noDataSize); + _noData = getStringArrayValue(*classProperty.noData); } - if (_noDataSize == 0 || (_count > 0 && _noDataSize != _count)) { + if (_noData.size == 0 || (_count > 0 && _noData.size != _count)) { _status = PropertyViewStatus::ErrorInvalidNoDataValue; return; } @@ -2107,14 +2329,11 @@ template <> class PropertyView> { if (classProperty.defaultProperty) { if (!_required) { - _defaultValue = getStringArrayValue( - *classProperty.defaultProperty, - _defaultValueOffsets, - _defaultValueOffsetType, - _defaultValueSize); + _defaultValue = getStringArrayValue(*classProperty.defaultProperty); } - if (_defaultValueSize == 0 || (_count > 0 && _noDataSize != _count)) { + if (_defaultValue.size == 0 || + (_count > 0 && _defaultValue.size != _count)) { // The value was specified but something went wrong. _status = PropertyViewStatus::ErrorInvalidDefaultValue; return; @@ -2130,16 +2349,13 @@ template <> class PropertyView> { */ PropertyView(PropertyViewStatusType status) : _status(status), + _name(std::nullopt), + _semantic(std::nullopt), + _description(std::nullopt), _count(0), _required(false), _noData(), - _noDataOffsets(), - _noDataOffsetType(PropertyComponentType::None), - _noDataSize(0), - _defaultValue(), - _defaultValueOffsets(), - _defaultValueOffsetType(PropertyComponentType::None), - _defaultValueSize(0) {} + _defaultValue() {} /** * @brief Constructs a property instance from a property table property @@ -2156,6 +2372,25 @@ template <> class PropertyView> { */ PropertyViewStatusType status() const noexcept { return _status; } + /** + * @copydoc PropertyView::name + */ + const std::optional& name() const noexcept { return _name; } + + /** + * @copydoc PropertyView::semantic + */ + const std::optional& semantic() const noexcept { + return _semantic; + } + + /** + * @copydoc PropertyView::description + */ + const std::optional& description() const noexcept { + return _description; + } + /** * @copydoc PropertyView::arrayCount */ @@ -2203,14 +2438,14 @@ template <> class PropertyView> { * @copydoc PropertyView::noData */ std::optional> noData() const noexcept { - if (_noDataSize > 0) { + if (_noData.size > 0) { return PropertyArrayView( - gsl::span(_noData.data(), _noData.size()), + gsl::span(_noData.data.data(), _noData.data.size()), gsl::span( - _noDataOffsets.data(), - _noDataOffsets.size()), - _noDataOffsetType, - _noDataSize); + _noData.offsets.data(), + _noData.offsets.size()), + _noData.offsetType, + _noData.size); } return std::nullopt; @@ -2221,16 +2456,16 @@ template <> class PropertyView> { */ std::optional> defaultValue() const noexcept { - if (_defaultValueSize > 0) { + if (_defaultValue.size > 0) { return PropertyArrayView( gsl::span( - _defaultValue.data(), - _defaultValue.size()), + _defaultValue.data.data(), + _defaultValue.data.size()), gsl::span( - _defaultValueOffsets.data(), - _defaultValueOffsets.size()), - _defaultValueOffsetType, - _defaultValueSize); + _defaultValue.offsets.data(), + _defaultValue.offsets.size()), + _defaultValue.offsetType, + _defaultValue.size); } return std::nullopt; @@ -2243,23 +2478,25 @@ template <> class PropertyView> { int64_t _count; bool _required; - std::vector _noData; - std::vector _noDataOffsets; - PropertyComponentType _noDataOffsetType; - int64_t _noDataSize; + std::optional _name; + std::optional _semantic; + std::optional _description; - std::vector _defaultValue; - std::vector _defaultValueOffsets; - PropertyComponentType _defaultValueOffsetType; - int64_t _defaultValueSize; + struct StringArrayValue { + std::vector data; + std::vector offsets; + PropertyComponentType offsetType = PropertyComponentType::None; + int64_t size = 0; + }; - static std::vector getStringArrayValue( - const CesiumUtility::JsonValue& jsonValue, - std::vector& offsets, - PropertyComponentType& offsetType, - int64_t& size) { + StringArrayValue _noData; + StringArrayValue _defaultValue; + + static StringArrayValue + getStringArrayValue(const CesiumUtility::JsonValue& jsonValue) { + StringArrayValue result; if (!jsonValue.isArray()) { - return std::vector(); + return result; } std::vector strings; @@ -2273,7 +2510,7 @@ template <> class PropertyView> { for (size_t i = 0; i < array.size(); i++) { if (!array[i].isString()) { // The entire array is invalidated; return. - return std::vector(); + return result; } const std::string& string = array[i].getString(); @@ -2282,32 +2519,35 @@ template <> class PropertyView> { } uint64_t totalLength = stringOffsets.back(); - std::vector values(totalLength); + result.data.resize(totalLength); for (size_t i = 0; i < strings.size(); ++i) { std::memcpy( - values.data() + stringOffsets[i], + result.data.data() + stringOffsets[i], strings[i].data(), strings[i].size()); }; if (totalLength <= std::numeric_limits::max()) { - offsets = narrowOffsetsBuffer(stringOffsets); - offsetType = PropertyComponentType::Uint8; + result.offsets = narrowOffsetsBuffer(stringOffsets); + result.offsetType = PropertyComponentType::Uint8; } else if (totalLength <= std::numeric_limits::max()) { - offsets = narrowOffsetsBuffer(stringOffsets); - offsetType = PropertyComponentType::Uint16; + result.offsets = narrowOffsetsBuffer(stringOffsets); + result.offsetType = PropertyComponentType::Uint16; } else if (totalLength <= std::numeric_limits::max()) { - offsets = narrowOffsetsBuffer(stringOffsets); - offsetType = PropertyComponentType::Uint32; + result.offsets = narrowOffsetsBuffer(stringOffsets); + result.offsetType = PropertyComponentType::Uint32; } else { - offsets.resize(stringOffsets.size() * sizeof(uint64_t)); - std::memcpy(offsets.data(), stringOffsets.data(), offsets.size()); - offsetType = PropertyComponentType::Uint64; + result.offsets.resize(stringOffsets.size() * sizeof(uint64_t)); + std::memcpy( + result.offsets.data(), + stringOffsets.data(), + result.offsets.size()); + result.offsetType = PropertyComponentType::Uint64; } - size = static_cast(strings.size()); + result.size = static_cast(strings.size()); - return values; + return result; } template From bdf630b86fe170649c528eae2c9c17a98703c165 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 30 Aug 2023 18:25:03 -0400 Subject: [PATCH 110/121] Add support for sentinel values in batch tables --- .../BatchTableToGltfStructuralMetadata.cpp | 268 ++++++++++++++++-- ...gradeBatchTableToExtStructuralMetadata.cpp | 227 ++++++++++++--- 2 files changed, 433 insertions(+), 62 deletions(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index b78b73764..c475c4ccc 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -71,6 +71,16 @@ struct MaskedType { isFloat64 &= source.isFloat64; isBool &= source.isBool; } + + /** + * Whether this is incompatible with every type. Fully-incompatible types will + * be treated as strings. + */ + bool isIncompatible() const noexcept { + return !isInt8 && !isUint8 && !isInt16 && !isUint16 && !isInt32 && + !isUint32 && !isInt64 && !isUint64 && !isFloat32 && !isFloat64 && + !isBool; + } }; /** @@ -109,22 +119,49 @@ struct MaskedArrayType { minArrayCount = glm::min(minArrayCount, source.minArrayCount); maxArrayCount = glm::max(maxArrayCount, source.maxArrayCount); } + + /** + * Whether this is incompatible with every type. Fully-incompatible types will + * be treated as strings. + */ + bool isIncompatible() const noexcept { return elementType.isIncompatible(); } }; /** * Indicates a batch table property's compatibility with C++ types. */ struct CompatibleTypes { - // std::monostate represents "complete" compatibility, in that nothing has - // been determined to be incompatible yet. Once something is either a - // MaskedType or MaskedArrayType, they are considered incompatible with the - // other type. private: + /** + * std::monostate represents "complete" compatibility, in that nothing has + * been determined to be incompatible yet. Once something is either a + * MaskedType or MaskedArrayType, they are considered incompatible with the + * other type. + */ std::variant _type; + /** + * Whether the type encountered a null value. + */ + bool _hasNullValue = false; + + /** + * These booleans are for possible sentinel values for the property. If a + * property contains null values, but all other non-null values are of the + * same type, then we should simply indicate the null value with a "noData" + * value in an EXT_structural_metadata property. We reserve several values as + * possible sentinel values: + * + * - 0, for signed or unsigned integers + * - -1, for signed integers + * - "null", for strings + */ + bool _canUseZeroSentinel = true; + bool _canUseNegativeOneSentinel = true; + bool _canUseNullStringSentinel = true; + public: CompatibleTypes() : _type(){}; - CompatibleTypes(const MaskedType& maskedType) : _type(maskedType){}; CompatibleTypes(const MaskedArrayType& maskedArrayType) : _type(maskedArrayType){}; @@ -132,20 +169,71 @@ struct CompatibleTypes { /** * Whether this is exclusively compatible with array types. */ - bool isExclusivelyArray() const { + bool isExclusivelyArray() const noexcept { return std::holds_alternative(_type); } + /** + * Whether this is compatible with at least one unsigned integer type. Does + * not count arrays. + */ + bool isUnsignedInteger() const noexcept { + if (std::holds_alternative(_type)) { + return false; + } + + if (std::holds_alternative(_type)) { + return true; + } + + MaskedType type = std::get(_type); + return type.isUint8 || type.isUint16 || type.isUint32 || type.isUint64; + } + + /** + * Whether this is compatible with at least one signed integer type. Does not + * count arrays. + */ + bool isSignedInteger() const noexcept { + if (std::holds_alternative(_type)) { + return false; + } + + if (std::holds_alternative(_type)) { + return true; + } + + MaskedType type = std::get(_type); + return type.isInt8 || type.isInt16 || type.isInt32 || type.isInt64; + } + + /** + * Whether this is incompatible with every type. Fully-incompatible types will + * be treated as strings. + */ + bool isIncompatible() const noexcept { + if (std::holds_alternative(_type)) { + return std::get(_type).isIncompatible(); + } + + if (std::holds_alternative(_type)) { + return std::get(_type).isIncompatible(); + } + + // std::monostate means compatibility with all types. + return false; + } + /** * Marks as incompatible with every type. Fully-incompatible types will be * treated as strings. */ - void makeIncompatible() { _type = MaskedType(false); } + void makeIncompatible() noexcept { _type = MaskedType(false); } /** * Merges a MaskedType into this CompatibleTypes. */ - void operator&=(const MaskedType& inMaskedType) { + void operator&=(const MaskedType& inMaskedType) noexcept { if (std::holds_alternative(_type)) { MaskedType& maskedType = std::get(_type); maskedType &= inMaskedType; @@ -163,7 +251,7 @@ struct CompatibleTypes { /** * Merges a MaskedArrayType into this CompatibleTypes. */ - void operator&=(const MaskedArrayType& inArrayType) { + void operator&=(const MaskedArrayType& inArrayType) noexcept { if (std::holds_alternative(_type)) { MaskedArrayType& arrayType = std::get(_type); arrayType &= inArrayType; @@ -181,7 +269,7 @@ struct CompatibleTypes { /** * Merges another CompatibleTypes into this one. */ - void operator&=(const CompatibleTypes& inCompatibleTypes) { + void operator&=(const CompatibleTypes& inCompatibleTypes) noexcept { if (std::holds_alternative(inCompatibleTypes._type)) { // The other CompatibleTypes is compatible with everything, so it does not // change this one. @@ -205,7 +293,7 @@ struct CompatibleTypes { * is only compatible with arrays, this will return an incompatible * MaskedType. */ - MaskedType toMaskedType() const { + MaskedType toMaskedType() const noexcept { if (std::holds_alternative(_type)) { return std::get(_type); } @@ -219,7 +307,7 @@ struct CompatibleTypes { * CompatibleTypes is not compatible with arrays, this will return an * incompatible MaskedArrayType. */ - MaskedArrayType toMaskedArrayType() const { + MaskedArrayType toMaskedArrayType() const noexcept { if (std::holds_alternative(_type)) { return std::get(_type); } @@ -227,6 +315,80 @@ struct CompatibleTypes { bool isNonArray = std::holds_alternative(_type); return MaskedArrayType(!isNonArray); } + + /** + * Gets whether the type includes a null value. + */ + bool hasNullValue() const noexcept { return _hasNullValue; } + + /** + * Sets whether the type includes a null value. If a null value has been + * encountered, a sentinel value can try to be provided. + */ + void setHasNullValue(bool value) noexcept { _hasNullValue = value; } + + /** + * Gets the first possible sentinel value for this type. If no sentinel value + * can be used, this returns std::nullopt. + */ + const std::optional + getSentinelValue() const noexcept { + if (isUnsignedInteger()) { + return _canUseZeroSentinel + ? std::make_optional(0) + : std::nullopt; + } + + if (isSignedInteger()) { + if (_canUseZeroSentinel) { + return 0; + } + + if (_canUseNegativeOneSentinel) { + return -1; + } + } + + if (isIncompatible()) { + if (_canUseNullStringSentinel) { + return "null"; + } + } + + return std::nullopt; + } + + /** + * Removes any sentinel values that are incompatible with the given value + * type. This also removes the sentinel values that equal the given value. + * + * This is helpful for when a property contains a sentinel value as non-null + * data; the sentinel value can then be removed from consideration. + */ + void removeSentinelValues(CesiumUtility::JsonValue value) noexcept { + if (value.isNumber()) { + if (value.isUint64()) { + _canUseZeroSentinel &= (value.getUint64() != 0); + } + + if (value.isInt64()) { + auto intValue = value.getInt64(); + _canUseZeroSentinel &= (intValue != 0); + _canUseNegativeOneSentinel &= (intValue != -1); + } + + return; + } + + if (value.isString()) { + auto stringValue = value.getString(); + if (stringValue == "null") { + _canUseNullStringSentinel = false; + } + + return; + } + } }; struct BinaryProperty { @@ -410,9 +572,24 @@ CompatibleTypes findCompatibleTypes(const TValueGetter& propertyValue) { booleanType.isBool = true; compatibleTypes &= booleanType; - } else if (it->IsNumber()) { + continue; + } + + if (it->IsNumber()) { compatibleTypes &= getCompatibleTypesForNumber(it); - } else if (it->IsArray()) { + + // Check that the value does not equal one of the possible sentinel + // values. + if (it->IsInt64()) { + compatibleTypes.removeSentinelValues(it->GetInt64()); + } else if (it->IsUint64()) { + compatibleTypes.removeSentinelValues(it->GetUint64()); + } + + continue; + } + + if (it->IsArray()) { // Iterate over all of the elements in the array // and determine their compatible type. CompatibleTypes arrayElementCompatibleTypes = @@ -425,10 +602,30 @@ CompatibleTypes findCompatibleTypes(const TValueGetter& propertyValue) { MaskedArrayType arrayType(elementType, it->Size(), it->Size()); compatibleTypes &= arrayType; - } else { - // A string, null, or something else. - compatibleTypes.makeIncompatible(); + + continue; } + + if (it->IsNull()) { + compatibleTypes.setHasNullValue(true); + + // If the value is null, check if there is still a possible sentinel + // values. If none exist, default the type to string. + if (!compatibleTypes.getSentinelValue()) { + compatibleTypes.makeIncompatible(); + } + + continue; + } + + // If this is a string, check that the value does not equal one of the + // possible sentinel values. + if (it->IsString()) { + compatibleTypes.removeSentinelValues(it->GetString()); + } + + // If this code is reached, the value is a string or something else. + compatibleTypes.makeIncompatible(); } return compatibleTypes; @@ -462,13 +659,18 @@ void updateExtensionWithJsonStringProperty( rapidjsonOffsets.reserve(static_cast(propertyTable.count + 1)); rapidjsonOffsets.emplace_back(0); + std::optional noDataValue; + if (classProperty.noData) { + noDataValue = classProperty.noData->getString(); + } + auto it = propertyValue.begin(); for (int64_t i = 0; i < propertyTable.count; ++i) { if (it == propertyValue.end()) { rapidjsonOffsets.emplace_back(rapidjsonStrBuffer.GetLength()); continue; } - if (!it->IsString()) { + if (!it->IsString() || (it->IsNull() && !noDataValue)) { // Everything else that is not string will be serialized by json rapidjson::Writer writer(rapidjsonStrBuffer); it->Accept(writer); @@ -476,7 +678,7 @@ void updateExtensionWithJsonStringProperty( // Because serialized string json will add double quotations in the // buffer which is not needed by us, we will manually add the string to // the buffer - const auto& rapidjsonStr = it->GetString(); + const auto& rapidjsonStr = it->IsNull() ? *noDataValue : it->GetString(); rapidjsonStrBuffer.Reserve(it->GetStringLength()); for (rapidjson::SizeType j = 0; j < it->GetStringLength(); ++j) { rapidjsonStrBuffer.PutUnsafe(rapidjsonStr[j]); @@ -551,8 +753,18 @@ void updateExtensionWithJsonScalarProperty( T* p = reinterpret_cast(buffer.data()); auto it = propertyValue.begin(); + + std::optional noDataValue; + if (classProperty.noData) { + noDataValue = classProperty.noData->getSafeNumber(); + } + for (int64_t i = 0; i < propertyTable.count; ++i, ++p, ++it) { - *p = static_cast(it->template Get()); + if (it->IsNull()) { + *p = *noDataValue; + } else { + *p = static_cast(it->template Get()); + } } propertyTableProperty.values = addBufferToGltf(gltf, std::move(buffer)); @@ -854,8 +1066,8 @@ void updateStringArrayProperty( // Handle variable-length arrays. // For string arrays, arrayOffsets indexes into the stringOffsets buffer, - // the size of which is the number of stringElements + 1. This determines the - // component type of the array offsets. + // the size of which is the number of stringElements + 1. This determines + // the component type of the array offsets. std::vector arrayOffsetBuffer; PropertyComponentType arrayOffsetType = PropertyComponentType::None; if (isInRangeForUnsignedInteger(stringCount + 1)) { @@ -1157,6 +1369,10 @@ void updateExtensionWithJsonProperty( // Figure out which types we can use for this data. // Use the smallest type we can, and prefer signed to unsigned. const CompatibleTypes compatibleTypes = findCompatibleTypes(propertyValue); + if (compatibleTypes.hasNullValue()) { + classProperty.noData = compatibleTypes.getSentinelValue(); + } + if (compatibleTypes.isExclusivelyArray()) { MaskedArrayType arrayType = compatibleTypes.toMaskedArrayType(); updateExtensionWithArrayProperty( @@ -1365,10 +1581,10 @@ void updateExtensionWithBatchTableHierarchy( PropertyTable& propertyTable, ErrorList& result, const rapidjson::Value& batchTableHierarchy) { - // EXT_structural_metadata can't support hierarchy, so we need to flatten it. - // It also can't support multiple classes with a single set of feature IDs, - // because IDs can only specify one property table. So essentially every - // property of every class gets added to the one class definition. + // EXT_structural_metadata can't support hierarchy, so we need to flatten + // it. It also can't support multiple classes with a single set of feature + // IDs, because IDs can only specify one property table. So essentially + // every property of every class gets added to the one class definition. auto classesIt = batchTableHierarchy.FindMember("classes"); if (classesIt == batchTableHierarchy.MemberEnd()) { result.emplaceWarning( diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 3efdfec28..3086ba0f2 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -30,7 +30,8 @@ static void checkNonArrayProperty( const std::string& expectedType, const std::optional& expectedComponentType, const std::vector& expected, - size_t expectedTotalInstances) { + size_t expectedTotalInstances, + const std::optional& noDataValue = std::nullopt) { const ClassProperty& property = metaClass.properties.at(propertyName); REQUIRE(property.type == expectedType); REQUIRE(property.componentType == expectedComponentType); @@ -62,6 +63,12 @@ static void checkNonArrayProperty( static_cast(propertyView.getRaw(i)) == expected[static_cast(i)]); } + + if (noDataValue && propertyView.getRaw(i) == noDataValue) { + REQUIRE(!propertyView.get(i)); + } else { + REQUIRE(propertyView.get(i) == propertyView.getRaw(i)); + } } } @@ -110,6 +117,90 @@ static void checkArrayProperty( } } +template +static void createTestForNonArrayJson( + const std::vector& expected, + const std::string& expectedType, + const std::optional& expectedComponentType, + size_t totalInstances, + const std::optional expectedNoData) { + Model model; + + rapidjson::Document featureTableJson; + featureTableJson.SetObject(); + rapidjson::Value batchLength(rapidjson::kNumberType); + batchLength.SetUint64(totalInstances); + featureTableJson.AddMember( + "BATCH_LENGTH", + batchLength, + featureTableJson.GetAllocator()); + + rapidjson::Document batchTableJson; + batchTableJson.SetObject(); + rapidjson::Value scalarProperty(rapidjson::kArrayType); + for (size_t i = 0; i < expected.size(); ++i) { + if (static_cast(expected[i]) == expectedNoData) { + rapidjson::Value nullValue; + nullValue.SetNull(); + scalarProperty.PushBack(nullValue, batchTableJson.GetAllocator()); + continue; + } + + if constexpr (std::is_same_v) { + rapidjson::Value value(rapidjson::kStringType); + value.SetString( + expected[i].c_str(), + static_cast(expected[i].size()), + batchTableJson.GetAllocator()); + scalarProperty.PushBack(value, batchTableJson.GetAllocator()); + } else { + scalarProperty.PushBack( + ExpectedType(expected[i]), + batchTableJson.GetAllocator()); + } + } + + batchTableJson.AddMember( + "scalarProperty", + scalarProperty, + batchTableJson.GetAllocator()); + + auto errors = BatchTableToGltfStructuralMetadata::convertFromB3dm( + featureTableJson, + batchTableJson, + gsl::span(), + model); + + const ExtensionModelExtStructuralMetadata* pMetadata = + model.getExtension(); + REQUIRE(pMetadata); + + const std::optional schema = pMetadata->schema; + REQUIRE(schema); + + const std::unordered_map& classes = schema->classes; + REQUIRE(classes.size() == 1); + + const Class& defaultClass = classes.at("default"); + const std::unordered_map& properties = + defaultClass.properties; + REQUIRE(properties.size() == 1); + + REQUIRE(pMetadata->propertyTables.size() == 1); + + const PropertyTable& propertyTable = pMetadata->propertyTables[0]; + checkNonArrayProperty( + model, + propertyTable, + defaultClass, + "scalarProperty", + expectedType, + expectedComponentType, + expected, + totalInstances, + expectedNoData); +} + template static void createTestForNonArrayJson( const std::vector& expected, @@ -285,7 +376,7 @@ std::set getUniqueBufferViewIds( return result; } -TEST_CASE("Converts JSON B3DM batch table to EXT_feature_metadata") { +TEST_CASE("Converts JSON B3DM batch table to EXT_structural_metadata") { std::filesystem::path testFilePath = Cesium3DTilesSelection_TEST_DATA_DIR; testFilePath = testFilePath / "BatchTables" / "batchedWithJson.b3dm"; @@ -1709,6 +1800,59 @@ TEST_CASE("Upgrade JSON values") { } } +TEST_CASE("Uses sentinel values for JSON null values") { + SECTION("Uint32 with sentinel value 0") { + // Even though the values are typed uint32, they are small enough to be + // stored as int8s. Signed types are preferred over unsigned. + std::vector expected{32, 45, 0, 21, 0, 65, 78}; + createTestForNonArrayJson( + expected, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT8, + expected.size(), + static_cast(0)); + } + + SECTION("Int32 with sentinel value 0") { + // Even though the values are typed int32, they are small enough to be + // stored as int8s. Signed types are preferred over unsigned. + std::vector expected{32, 45, -3, 0, 21, 0, -65, 78}; + createTestForNonArrayJson( + expected, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT8, + expected.size(), + static_cast(0)); + } + + SECTION("Int32 with sentinel value -1") { + // Even though the values are typed int32, they are small enough to be + // stored as int8s. Signed types are preferred over unsigned. + std::vector expected{32, 45, -3, 0, 21, 0, -1, -65, 78}; + createTestForNonArrayJson( + expected, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT8, + expected.size(), + static_cast(-1)); + } + + SECTION("String with 'null'") { + std::vector expected{ + "Test 0", + "Test 1", + "Test 2", + "null" + "Test 3"}; + createTestForNonArrayJson( + expected, + ClassProperty::Type::STRING, + std::nullopt, + expected.size(), + std::string_view("null")); + } +} + TEST_CASE("Cannot write past batch table length") { SECTION("Uint32") { std::vector expected{32, 45, 21, 65, 78, 20, 33, 12}; @@ -1929,56 +2073,67 @@ TEST_CASE("Converts \"Feature Classes\" 3DTILES_batch_table_hierarchy example " CHECK(propertyTable.classProperty == "default"); REQUIRE(propertyTable.properties.size() == 6); - // Even though some of these properties are scalars, they become strings - // because not every feature has every property, and only strings can - // represent "null". - struct Expected { + struct ExpectedString { std::string name; - std::string type; - std::optional componentType; std::vector values; + std::optional noDataValue; + }; + + struct ExpectedScalar { + std::string name; + std::vector values; + std::optional noDataValue; }; - std::vector expectedProperties{ - {"lampStrength", - ClassProperty::Type::STRING, - std::nullopt, - {"10", "5", "7", "null", "null", "null", "null", "null"}}, + std::vector expectedScalar{ + {"lampStrength", {10, 5, 7, 0, 0, 0, 0, 0}, 0}, + {"treeHeight", {0, 0, 0, 0, 0, 0, 10, 15}, 0}, + {"treeAge", {0, 0, 0, 0, 0, 0, 5, 8}, 0}}; + + std::vector expectedString{ {"lampColor", - ClassProperty::Type::STRING, - std::nullopt, - {"yellow", "white", "white", "null", "null", "null", "null", "null"}}, + {"yellow", "white", "white", "null", "null", "null", "null", "null"}, + "null"}, {"carType", - ClassProperty::Type::STRING, - std::nullopt, - {"null", "null", "null", "truck", "bus", "sedan", "null", "null"}}, + {"null", "null", "null", "truck", "bus", "sedan", "null", "null"}, + "null"}, {"carColor", - ClassProperty::Type::STRING, - std::nullopt, - {"null", "null", "null", "green", "blue", "red", "null", "null"}}, - {"treeHeight", - ClassProperty::Type::STRING, - std::nullopt, - {"null", "null", "null", "null", "null", "null", "10", "15"}}, - {"treeAge", - ClassProperty::Type::STRING, - std::nullopt, - {"null", "null", "null", "null", "null", "null", "5", "8"}}}; - - for (const auto& expected : expectedProperties) { + {"null", "null", "null", "green", "blue", "red", "null", "null"}, + "null"}}; + + for (const auto& expected : expectedScalar) { auto it = defaultClass.properties.find(expected.name); REQUIRE(it != defaultClass.properties.end()); - CHECK(it->second.type == expected.type); + CHECK(it->second.type == ClassProperty::Type::SCALAR); + CHECK(it->second.componentType == ClassProperty::ComponentType::INT8); + + checkNonArrayProperty( + gltf, + propertyTable, + defaultClass, + expected.name, + ClassProperty::Type::SCALAR, + ClassProperty::ComponentType::INT8, + expected.values, + expected.values.size(), + expected.noDataValue); + } + + for (const auto& expected : expectedString) { + auto it = defaultClass.properties.find(expected.name); + REQUIRE(it != defaultClass.properties.end()); + CHECK(it->second.type == ClassProperty::Type::STRING); checkNonArrayProperty( gltf, propertyTable, defaultClass, expected.name, - expected.type, - expected.componentType, + ClassProperty::Type::STRING, + std::nullopt, expected.values, - expected.values.size()); + expected.values.size(), + expected.noDataValue); } } From b13b640147c7319d63c2bf8996f98dd1dddf3aba Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 31 Aug 2023 14:44:18 -0400 Subject: [PATCH 111/121] Cleanup, add unit tests --- .../BatchTableToGltfStructuralMetadata.cpp | 133 +++++++------ ...gradeBatchTableToExtStructuralMetadata.cpp | 181 +++++++++++++++++- 2 files changed, 256 insertions(+), 58 deletions(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index c475c4ccc..0f700dd46 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -24,8 +24,9 @@ using namespace Cesium3DTilesSelection::CesiumImpl; namespace Cesium3DTilesSelection { namespace { /** - * Indicates how a JSON value can be interpreted. Does not correspond one-to-one - * with types / component types in EXT_structural_metadata. + * Indicates how a JSON value can be interpreted as a primitive type. Does not + * correspond one-to-one with types / component types in + * EXT_structural_metadata. */ struct MaskedType { bool isInt8; @@ -73,8 +74,8 @@ struct MaskedType { } /** - * Whether this is incompatible with every type. Fully-incompatible types will - * be treated as strings. + * Whether this is incompatible with every primitive type. Fully-incompatible + * types will be treated as strings. */ bool isIncompatible() const noexcept { return !isInt8 && !isUint8 && !isInt16 && !isUint16 && !isInt32 && @@ -121,14 +122,15 @@ struct MaskedArrayType { } /** - * Whether this is incompatible with every type. Fully-incompatible types will - * be treated as strings. + * Whether this is incompatible with every primitive type. Fully-incompatible + * types will be treated as strings. */ bool isIncompatible() const noexcept { return elementType.isIncompatible(); } }; /** - * Indicates a batch table property's compatibility with C++ types. + * Represents information about a batch table property, indicating its + * compatibility with C++ types and whether it has encountered any null values. */ struct CompatibleTypes { private: @@ -141,20 +143,28 @@ struct CompatibleTypes { std::variant _type; /** - * Whether the type encountered a null value. + * Whether the property has encountered a null value. A + * property may contain null values even though all other values are of the + * same non-null type. In this case, it can simply replace the null with a + * "noData" value in the EXT_structural_metadata property. */ bool _hasNullValue = false; /** - * These booleans are for possible sentinel values for the property. If a - * property contains null values, but all other non-null values are of the - * same type, then we should simply indicate the null value with a "noData" - * value in an EXT_structural_metadata property. We reserve several values as - * possible sentinel values: + * The following booleans track possible "noData" (sentinel) values for the + * property. + * + * We don't want to spend too much effort finding a "noData" value, because + * with any given property there can be multiple candidates. Thus, there are + * only a few values that are reserved as potential sentinel values: * * - 0, for signed or unsigned integers * - -1, for signed integers * - "null", for strings + * + * If a property does not contain one of these values, then it may be used as + * the "noData" value in the property. The sentinel value will then be copied + * to the buffer, instead of the null value. */ bool _canUseZeroSentinel = true; bool _canUseNegativeOneSentinel = true; @@ -167,17 +177,19 @@ struct CompatibleTypes { : _type(maskedArrayType){}; /** - * Whether this is exclusively compatible with array types. + * Whether this is exclusively compatible with array types. This indicates an + * exclusively array property, as opposed to a newly initialized one that is + * "compatible" with everything. */ bool isExclusivelyArray() const noexcept { return std::holds_alternative(_type); } /** - * Whether this is compatible with at least one unsigned integer type. Does - * not count arrays. + * Whether this property is with at least one unsigned integer type. Does not + * count arrays. */ - bool isUnsignedInteger() const noexcept { + bool isCompatibleWithUnsignedInteger() const noexcept { if (std::holds_alternative(_type)) { return false; } @@ -191,10 +203,10 @@ struct CompatibleTypes { } /** - * Whether this is compatible with at least one signed integer type. Does not - * count arrays. + * Whether this property is compatible with at least one signed integer type. + * Does not count arrays. */ - bool isSignedInteger() const noexcept { + bool isCompatibleWithSignedInteger() const noexcept { if (std::holds_alternative(_type)) { return false; } @@ -208,8 +220,8 @@ struct CompatibleTypes { } /** - * Whether this is incompatible with every type. Fully-incompatible types will - * be treated as strings. + * Whether this property is incompatible with every primitive type. + * Fully-incompatible properties will be treated as string properties. */ bool isIncompatible() const noexcept { if (std::holds_alternative(_type)) { @@ -225,13 +237,13 @@ struct CompatibleTypes { } /** - * Marks as incompatible with every type. Fully-incompatible types will be - * treated as strings. + * Marks as incompatible with every primitive type. Fully-incompatible + * properties will be treated as string properties. */ void makeIncompatible() noexcept { _type = MaskedType(false); } /** - * Merges a MaskedType into this CompatibleTypes. + * Merges a MaskedType into this BatchTableProperty. */ void operator&=(const MaskedType& inMaskedType) noexcept { if (std::holds_alternative(_type)) { @@ -269,27 +281,29 @@ struct CompatibleTypes { /** * Merges another CompatibleTypes into this one. */ - void operator&=(const CompatibleTypes& inCompatibleTypes) noexcept { - if (std::holds_alternative(inCompatibleTypes._type)) { + void operator&=(const CompatibleTypes& inTypes) noexcept { + if (std::holds_alternative(inTypes._type)) { // The other CompatibleTypes is compatible with everything, so it does not // change this one. - return; - } + } else - if (std::holds_alternative(inCompatibleTypes._type)) { + if (std::holds_alternative(inTypes._type)) { const MaskedArrayType& arrayType = - std::get(inCompatibleTypes._type); + std::get(inTypes._type); operator&=(arrayType); - return; + } else { + const MaskedType& maskedType = std::get(inTypes._type); + operator&=(maskedType); } - const MaskedType& maskedType = - std::get(inCompatibleTypes._type); - operator&=(maskedType); + _hasNullValue |= inTypes._hasNullValue; + _canUseZeroSentinel &= inTypes._canUseZeroSentinel; + _canUseNegativeOneSentinel &= inTypes._canUseNegativeOneSentinel; + _canUseNullStringSentinel &= inTypes._canUseNullStringSentinel; } /** - * Derives MaskedType info from this CompatibleTypes. If this CompatibleTypes + * Derives MaskedType info from this CompatibleTypes. If this property * is only compatible with arrays, this will return an incompatible * MaskedType. */ @@ -304,8 +318,8 @@ struct CompatibleTypes { /** * Derives MaskedArrayType info from this CompatibleTypes. If this - * CompatibleTypes is not compatible with arrays, this will return an - * incompatible MaskedArrayType. + * property is not compatible with arrays, this will return an incompatible + * MaskedArrayType. */ MaskedArrayType toMaskedArrayType() const noexcept { if (std::holds_alternative(_type)) { @@ -317,29 +331,29 @@ struct CompatibleTypes { } /** - * Gets whether the type includes a null value. + * Gets whether the property of this type includes a null value. */ bool hasNullValue() const noexcept { return _hasNullValue; } /** - * Sets whether the type includes a null value. If a null value has been - * encountered, a sentinel value can try to be provided. + * Sets whether the property includes a null value. If a null value has been + * encountered, a sentinel value may potentially be provided. */ void setHasNullValue(bool value) noexcept { _hasNullValue = value; } /** - * Gets the first possible sentinel value for this type. If no sentinel value - * can be used, this returns std::nullopt. + * Gets a possible sentinel value for this type. If no value can be used, this + * returns std::nullopt. */ const std::optional getSentinelValue() const noexcept { - if (isUnsignedInteger()) { + if (isCompatibleWithUnsignedInteger()) { return _canUseZeroSentinel ? std::make_optional(0) : std::nullopt; } - if (isSignedInteger()) { + if (isCompatibleWithSignedInteger()) { if (_canUseZeroSentinel) { return 0; } @@ -359,14 +373,17 @@ struct CompatibleTypes { } /** - * Removes any sentinel values that are incompatible with the given value - * type. This also removes the sentinel values that equal the given value. + * Removes any sentinel values that are incompatible with the property. This + * also removes the sentinel values that equal the given value. * * This is helpful for when a property contains a sentinel value as non-null * data; the sentinel value can then be removed from consideration. */ void removeSentinelValues(CesiumUtility::JsonValue value) noexcept { if (value.isNumber()) { + _canUseNullStringSentinel = false; + + // Don't try to use string as sentinels for numbers. if (value.isUint64()) { _canUseZeroSentinel &= (value.getUint64() != 0); } @@ -376,17 +393,17 @@ struct CompatibleTypes { _canUseZeroSentinel &= (intValue != 0); _canUseNegativeOneSentinel &= (intValue != -1); } - - return; } if (value.isString()) { + // Don't try to use numbers as sentinels for strings. + _canUseZeroSentinel = false; + _canUseNegativeOneSentinel = false; + auto stringValue = value.getString(); if (stringValue == "null") { _canUseNullStringSentinel = false; } - - return; } } }; @@ -618,14 +635,14 @@ CompatibleTypes findCompatibleTypes(const TValueGetter& propertyValue) { continue; } + // If this code is reached, the value is a string or something else. + compatibleTypes.makeIncompatible(); + // If this is a string, check that the value does not equal one of the // possible sentinel values. if (it->IsString()) { compatibleTypes.removeSentinelValues(it->GetString()); } - - // If this code is reached, the value is a string or something else. - compatibleTypes.makeIncompatible(); } return compatibleTypes; @@ -1369,9 +1386,6 @@ void updateExtensionWithJsonProperty( // Figure out which types we can use for this data. // Use the smallest type we can, and prefer signed to unsigned. const CompatibleTypes compatibleTypes = findCompatibleTypes(propertyValue); - if (compatibleTypes.hasNullValue()) { - classProperty.noData = compatibleTypes.getSentinelValue(); - } if (compatibleTypes.isExclusivelyArray()) { MaskedArrayType arrayType = compatibleTypes.toMaskedArrayType(); @@ -1385,6 +1399,11 @@ void updateExtensionWithJsonProperty( return; } + // Set the "noData" value before copying the property (to avoid copying nulls) + if (compatibleTypes.hasNullValue()) { + classProperty.noData = compatibleTypes.getSentinelValue(); + } + MaskedType type = compatibleTypes.toMaskedType(); if (type.isBool) { updateExtensionWithJsonBooleanProperty( diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 3086ba0f2..7eae64841 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -36,7 +36,7 @@ static void checkNonArrayProperty( REQUIRE(property.type == expectedType); REQUIRE(property.componentType == expectedComponentType); REQUIRE(!property.array); - REQUIRE(property.count == std::nullopt); + REQUIRE(!property.count); PropertyTableView view(model, propertyTable); REQUIRE(view.status() == PropertyTableViewStatus::Valid); @@ -1853,6 +1853,185 @@ TEST_CASE("Uses sentinel values for JSON null values") { } } +TEST_CASE("Defaults to string if no sentinel values are available") { + SECTION("Uint32") { + Model model; + // Even though the values are typed uint32, they are small enough to be + // stored as uint8s. Signed types are preferred over unsigned, but this + // exceeds the range for int8. + std::vector> + expected{32, 45, 0, 255, std::nullopt, 0, 65, 78}; + + rapidjson::Document featureTableJson; + featureTableJson.SetObject(); + rapidjson::Value batchLength(rapidjson::kNumberType); + batchLength.SetUint64(static_cast(expected.size())); + featureTableJson.AddMember( + "BATCH_LENGTH", + batchLength, + featureTableJson.GetAllocator()); + + rapidjson::Document batchTableJson; + batchTableJson.SetObject(); + rapidjson::Value scalarProperty(rapidjson::kArrayType); + for (size_t i = 0; i < expected.size(); ++i) { + if (!expected[i]) { + rapidjson::Value nullValue; + nullValue.SetNull(); + scalarProperty.PushBack(nullValue, batchTableJson.GetAllocator()); + continue; + } + + scalarProperty.PushBack(*expected[i], batchTableJson.GetAllocator()); + } + + batchTableJson.AddMember( + "scalarProperty", + scalarProperty, + batchTableJson.GetAllocator()); + + auto errors = BatchTableToGltfStructuralMetadata::convertFromB3dm( + featureTableJson, + batchTableJson, + gsl::span(), + model); + + const ExtensionModelExtStructuralMetadata* pMetadata = + model.getExtension(); + REQUIRE(pMetadata); + + const std::optional schema = pMetadata->schema; + REQUIRE(schema); + + const std::unordered_map& classes = schema->classes; + REQUIRE(classes.size() == 1); + + const Class& defaultClass = classes.at("default"); + const std::unordered_map& properties = + defaultClass.properties; + REQUIRE(properties.size() == 1); + + REQUIRE(pMetadata->propertyTables.size() == 1); + + const PropertyTable& propertyTable = pMetadata->propertyTables[0]; + const ClassProperty& property = + defaultClass.properties.at("scalarProperty"); + REQUIRE(property.type == ClassProperty::Type::STRING); + REQUIRE(!property.componentType); + REQUIRE(!property.array); + REQUIRE(!property.count); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + PropertyTablePropertyView propertyView = + view.getPropertyView("scalarProperty"); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyView.size() == propertyTable.count); + REQUIRE(propertyView.size() == static_cast(expected.size())); + for (int64_t i = 0; i < propertyView.size(); ++i) { + auto expectedValue = expected[static_cast(i)]; + if (expectedValue) { + std::string asString = std::to_string(*expectedValue); + REQUIRE(propertyView.getRaw(i) == asString); + } else { + REQUIRE(propertyView.getRaw(i) == "null"); + } + + REQUIRE(propertyView.get(i) == propertyView.getRaw(i)); + } + } + + SECTION("Int32") { + Model model; + // Even though the values are typed int32, they are small enough to be + // stored as int8s. + std::vector> + expected{32, 45, 0, -1, std::nullopt, 0, 65, 78}; + + rapidjson::Document featureTableJson; + featureTableJson.SetObject(); + rapidjson::Value batchLength(rapidjson::kNumberType); + batchLength.SetUint64(static_cast(expected.size())); + featureTableJson.AddMember( + "BATCH_LENGTH", + batchLength, + featureTableJson.GetAllocator()); + + rapidjson::Document batchTableJson; + batchTableJson.SetObject(); + rapidjson::Value scalarProperty(rapidjson::kArrayType); + for (size_t i = 0; i < expected.size(); ++i) { + if (!expected[i]) { + rapidjson::Value nullValue; + nullValue.SetNull(); + scalarProperty.PushBack(nullValue, batchTableJson.GetAllocator()); + continue; + } + + scalarProperty.PushBack(*expected[i], batchTableJson.GetAllocator()); + } + + batchTableJson.AddMember( + "scalarProperty", + scalarProperty, + batchTableJson.GetAllocator()); + + auto errors = BatchTableToGltfStructuralMetadata::convertFromB3dm( + featureTableJson, + batchTableJson, + gsl::span(), + model); + + const ExtensionModelExtStructuralMetadata* pMetadata = + model.getExtension(); + REQUIRE(pMetadata); + + const std::optional schema = pMetadata->schema; + REQUIRE(schema); + + const std::unordered_map& classes = schema->classes; + REQUIRE(classes.size() == 1); + + const Class& defaultClass = classes.at("default"); + const std::unordered_map& properties = + defaultClass.properties; + REQUIRE(properties.size() == 1); + + REQUIRE(pMetadata->propertyTables.size() == 1); + + const PropertyTable& propertyTable = pMetadata->propertyTables[0]; + const ClassProperty& property = + defaultClass.properties.at("scalarProperty"); + REQUIRE(property.type == ClassProperty::Type::STRING); + REQUIRE(!property.componentType); + REQUIRE(!property.array); + REQUIRE(!property.count); + + PropertyTableView view(model, propertyTable); + REQUIRE(view.status() == PropertyTableViewStatus::Valid); + REQUIRE(view.size() == propertyTable.count); + + PropertyTablePropertyView propertyView = + view.getPropertyView("scalarProperty"); + REQUIRE(propertyView.status() == PropertyTablePropertyViewStatus::Valid); + REQUIRE(propertyView.size() == propertyTable.count); + REQUIRE(propertyView.size() == static_cast(expected.size())); + for (int64_t i = 0; i < propertyView.size(); ++i) { + auto expectedValue = expected[static_cast(i)]; + if (expectedValue) { + std::string asString = std::to_string(*expectedValue); + REQUIRE(propertyView.getRaw(i) == asString); + } else { + REQUIRE(propertyView.getRaw(i) == "null"); + } + + REQUIRE(propertyView.get(i) == propertyView.getRaw(i)); + } + } +} + TEST_CASE("Cannot write past batch table length") { SECTION("Uint32") { std::vector expected{32, 45, 21, 65, 78, 20, 33, 12}; From 36cf0673683be6517f47a9ef3eab8f2ceea2dd32 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 31 Aug 2023 15:08:29 -0400 Subject: [PATCH 112/121] Final unit test pass --- .../src/BatchTableToGltfStructuralMetadata.cpp | 2 +- Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp | 5 +++++ .../test/TestUpgradeBatchTableToExtStructuralMetadata.cpp | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index 0f700dd46..f56128b1e 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -1831,7 +1831,7 @@ ErrorList BatchTableToGltfStructuralMetadata::convertFromB3dm( FeatureId& featureID = extension.featureIds.emplace_back(); // No fast way to count the unique feature IDs in this primitive, so - // subtitute the batch table length. + // substitute the batch table length. featureID.featureCount = batchLength; featureID.attribute = 0; featureID.label = "_FEATURE_ID_0"; diff --git a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp index e93e333f2..8cce744a9 100644 --- a/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp +++ b/Cesium3DTilesSelection/test/TestPntsToGltfConverter.cpp @@ -681,6 +681,7 @@ TEST_CASE("Converts point cloud with batch IDs to glTF with " FeatureId& featureId = primitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 8); CHECK(featureId.attribute == 0); + CHECK(featureId.propertyTable == 0); CHECK(gltf.materials.size() == 1); @@ -760,6 +761,7 @@ TEST_CASE("Converts point cloud with per-point properties to glTF with " // Check for implicit feature IDs CHECK(featureId.featureCount == pointsLength); CHECK(!featureId.attribute); + CHECK(featureId.propertyTable == 0); CHECK(gltf.materials.size() == 1); @@ -818,6 +820,7 @@ TEST_CASE("Converts point cloud with Draco compression to glTF") { // Check for implicit feature IDs CHECK(featureId.featureCount == pointsLength); CHECK(!featureId.attribute); + CHECK(featureId.propertyTable == 0); REQUIRE(gltf.materials.size() == 1); Material& material = gltf.materials[0]; @@ -961,6 +964,7 @@ TEST_CASE("Converts point cloud with partial Draco compression to glTF") { // Check for implicit feature IDs CHECK(featureId.featureCount == pointsLength); CHECK(!featureId.attribute); + CHECK(featureId.propertyTable == 0); REQUIRE(gltf.materials.size() == 1); Material& material = gltf.materials[0]; @@ -1098,6 +1102,7 @@ TEST_CASE("Converts batched point cloud with Draco compression to glTF") { FeatureId& featureId = primitiveExtension->featureIds[0]; CHECK(featureId.featureCount == 8); CHECK(featureId.attribute == 0); + CHECK(featureId.propertyTable == 0); CHECK(gltf.materials.size() == 1); diff --git a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp index 7eae64841..93151e148 100644 --- a/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/test/TestUpgradeBatchTableToExtStructuralMetadata.cpp @@ -2265,9 +2265,9 @@ TEST_CASE("Converts \"Feature Classes\" 3DTILES_batch_table_hierarchy example " }; std::vector expectedScalar{ - {"lampStrength", {10, 5, 7, 0, 0, 0, 0, 0}, 0}, - {"treeHeight", {0, 0, 0, 0, 0, 0, 10, 15}, 0}, - {"treeAge", {0, 0, 0, 0, 0, 0, 5, 8}, 0}}; + {"lampStrength", {10, 5, 7, 0, 0, 0, 0, 0}, static_cast(0)}, + {"treeHeight", {0, 0, 0, 0, 0, 0, 10, 15}, static_cast(0)}, + {"treeAge", {0, 0, 0, 0, 0, 0, 5, 8}, static_cast(0)}}; std::vector expectedString{ {"lampColor", From af9707f14958a3498eeb92ecd229ce7ad9f39827 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 1 Sep 2023 13:20:49 -0400 Subject: [PATCH 113/121] Add additional PropertyView typedefs --- ...ropertyViewTypes.h => PropertyViewTypes.h} | 174 +++++++++++++++++- 1 file changed, 167 insertions(+), 7 deletions(-) rename CesiumGltf/include/CesiumGltf/{PropertyTablePropertyViewTypes.h => PropertyViewTypes.h} (68%) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewTypes.h b/CesiumGltf/include/CesiumGltf/PropertyViewTypes.h similarity index 68% rename from CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewTypes.h rename to CesiumGltf/include/CesiumGltf/PropertyViewTypes.h index 257c99615..f51a8b489 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTablePropertyViewTypes.h +++ b/CesiumGltf/include/CesiumGltf/PropertyViewTypes.h @@ -1,13 +1,11 @@ #pragma once +#include "CesiumGltf/PropertyAttributePropertyView.h" #include "CesiumGltf/PropertyTablePropertyView.h" +#include "CesiumGltf/PropertyTexturePropertyView.h" #include -#include -#include -#include -#include #include namespace CesiumGltf { @@ -166,11 +164,11 @@ typedef std::variant< View>, false>, View>>, View>>> - NonNormalizedPropertyTablePropertyView; + PropertyTablePropertyViewType; /** * @brief An alias for all of the potential types of - * {@link PropertyTablePropertyView} possible with normalization. + * {@link PropertyTablePropertyView} possible with normalization. * Can be useful for applications that want to implement abstract * representations of PropertyTablePropertyView, without the mess of templated * types. @@ -288,7 +286,169 @@ typedef std::variant< View>, true>, View>, true>, View>, true>> - NormalizedPropertyTablePropertyView; + NormalizedPropertyTablePropertyViewType; + +#undef View + +#define View PropertyTexturePropertyView +/** + * + * @brief An alias for all of the potential types of + * {@link PropertyTexturePropertyView} possible without normalization. + * Can be useful for applications that want to implement abstract + * representations of PropertyTexturePropertyView, without the mess of templated + * types. + */ +typedef std::variant< + View, + View, + View, + View, + View, + View, + View, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>> + PropertyTexturePropertyViewType; + +/** + * @brief An alias for all of the potential types of + * {@link PropertyTexturePropertyView} possible with normalization. + * Can be useful for applications that want to implement abstract + * representations of PropertyTexturePropertyView, without the mess of templated + * types. + */ +typedef std::variant< + View, + View, + View, + View, + View, + View, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>> + NormalizedPropertyTexturePropertyViewType; + +#undef View + +#define View PropertyAttributePropertyView +/** + * + * @brief An alias for all of the potential types of + * {@link PropertyAttributePropertyView} possible without normalization. + * Can be useful for applications that want to implement abstract + * representations of PropertyAttributePropertyView, without the mess of + * templated types. + */ +typedef std::variant< + View, + View, + View, + View, + View, + View, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View>, + View, false>, + View, false>, + View, false>, + View, false>, + View, false>, + View>> + PropertyAttributePropertyViewType; + +/** + * @brief An alias for all of the potential types of + * {@link PropertyAttributePropertyView} possible with normalization. + * Can be useful for applications that want to implement abstract + * representations of PropertyAttributePropertyView, without the mess of + * templated types. + */ +typedef std::variant< + View, + View, + View, + View, + View, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>, + View, true>> + NormalizedPropertyAttributePropertyViewType; #undef View } // namespace CesiumGltf From 74fbef5474e7bdd9b65215426f84711c9eedb2f9 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 1 Sep 2023 14:56:01 -0400 Subject: [PATCH 114/121] Add missing pragma once --- CesiumGltf/include/CesiumGltf/PropertyView.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index ec6f05730..133d57136 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -1,3 +1,5 @@ +#pragma once + #include "CesiumGltf/ClassProperty.h" #include "CesiumGltf/PropertyAttributeProperty.h" #include "CesiumGltf/PropertyTableProperty.h" From 5dba5686a5887ee40ebd409e2434a5185ea13238 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 1 Sep 2023 15:32:45 -0400 Subject: [PATCH 115/121] Reorder member variables to avoid initialization warnings --- CesiumGltf/include/CesiumGltf/PropertyView.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyView.h index 133d57136..034127750 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyView.h @@ -519,13 +519,12 @@ template class PropertyView { std::optional _semantic; std::optional _description; - bool _required; - std::optional _offset; std::optional _scale; std::optional _max; std::optional _min; + bool _required; std::optional _noData; std::optional _defaultValue; @@ -858,13 +857,12 @@ template class PropertyView { std::optional _semantic; std::optional _description; - bool _required; - std::optional _offset; std::optional _scale; std::optional _max; std::optional _min; + bool _required; std::optional _noData; std::optional _defaultValue; @@ -2477,13 +2475,13 @@ template <> class PropertyView> { PropertyViewStatusType _status; private: - int64_t _count; - bool _required; - std::optional _name; std::optional _semantic; std::optional _description; + int64_t _count; + bool _required; + struct StringArrayValue { std::vector data; std::vector offsets; From 0004ba45210743d31f12e474f5fb660f7cda57d6 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 7 Sep 2023 10:45:48 -0400 Subject: [PATCH 116/121] PR feedback --- .../include/CesiumGltf/PropertyArrayView.h | 13 +++ .../CesiumGltf/PropertyTexturePropertyView.h | 109 +++++------------- .../src/PropertyTexturePropertyView.cpp | 41 +++++++ 3 files changed, 80 insertions(+), 83 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h index bc58d0160..7f08dfe9c 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyArrayView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyArrayView.h @@ -70,6 +70,10 @@ template class PropertyArrayView { return true; } + bool operator!=(const PropertyArrayView& other) const noexcept { + return !operator==(other); + } + private: using ArrayType = std::variant, std::vector>; @@ -121,6 +125,10 @@ template <> class PropertyArrayView { return true; } + bool operator!=(const PropertyArrayView& other) const noexcept { + return !operator==(other); + } + private: gsl::span _values; int64_t _bitOffset; @@ -185,6 +193,11 @@ template <> class PropertyArrayView { return true; } + bool + operator!=(const PropertyArrayView& other) const noexcept { + return !operator==(other); + } + private: gsl::span _values; gsl::span _stringOffsets; diff --git a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h index da9bc456f..8b58998f5 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTexturePropertyView.h @@ -7,6 +7,7 @@ #include "CesiumGltf/PropertyView.h" #include "CesiumGltf/Sampler.h" +#include #include #include #include @@ -79,7 +80,7 @@ class PropertyTexturePropertyViewStatus : public PropertyViewStatus { }; template -ElementType assembleScalarValue(const std::vector& bytes) noexcept { +ElementType assembleScalarValue(const gsl::span bytes) noexcept { if constexpr (std::is_same_v) { assert( bytes.size() == sizeof(float) && @@ -106,7 +107,7 @@ ElementType assembleScalarValue(const std::vector& bytes) noexcept { } template -ElementType assembleVecNValue(const std::vector& bytes) noexcept { +ElementType assembleVecNValue(const gsl::span bytes) noexcept { ElementType result = ElementType(); const glm::length_t N = @@ -152,7 +153,7 @@ ElementType assembleVecNValue(const std::vector& bytes) noexcept { template PropertyArrayView -assembleArrayValue(const std::vector& bytes) noexcept { +assembleArrayValue(const gsl::span bytes) noexcept { std::vector result(bytes.size() / sizeof(T)); if constexpr (sizeof(T) == 2) { @@ -172,8 +173,7 @@ assembleArrayValue(const std::vector& bytes) noexcept { } template -ElementType -assembleValueFromChannels(const std::vector& bytes) noexcept { +ElementType assembleValueFromChannels(const gsl::span bytes) noexcept { assert(bytes.size() > 0 && "Channel input must have at least one value."); if constexpr (IsMetadataScalar::value) { @@ -193,16 +193,24 @@ assembleValueFromChannels(const std::vector& bytes) noexcept { double applySamplerWrapS(const double u, const int32_t wrapS); double applySamplerWrapT(const double v, const int32_t wrapT); +std::array sampleNearestPixel( + const ImageCesium& image, + const std::vector& channels, + const double u, + const double v); + /** * @brief A view of the data specified by a {@link PropertyTextureProperty}. * * Provides utilities to sample the property texture property using texture - * coordinates. + * 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. + * @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 class PropertyTexturePropertyView; @@ -352,43 +360,10 @@ class PropertyTexturePropertyView double wrappedU = applySamplerWrapS(u, this->_pSampler->wrapS); double wrappedV = applySamplerWrapT(v, this->_pSampler->wrapT); - // TODO: account for sampler's filter (can be nearest or linear) - - // For nearest filtering, std::floor is used instead of std::round. - // This is because filtering is supposed to consider the pixel centers. But - // memory access here acts as sampling the beginning of the pixel. Example: - // 0.4 * 2 = 0.8. In a 2x1 pixel image, that should be closer to the left - // pixel's center. But it will round to 1.0 which corresponds to the right - // pixel. So the right pixel has a bigger range than the left one, which is - // incorrect. - double xCoord = std::floor(wrappedU * this->_pImage->width); - double yCoord = std::floor(wrappedV * this->_pImage->height); - - // Clamp to ensure no out-of-bounds data access - int64_t x = glm::clamp( - static_cast(xCoord), - static_cast(0), - static_cast(this->_pImage->width) - 1); - int64_t y = glm::clamp( - static_cast(yCoord), - static_cast(0), - static_cast(this->_pImage->height) - 1); - - int64_t pixelIndex = this->_pImage->bytesPerChannel * - this->_pImage->channels * - (y * this->_pImage->width + x); - - // TODO: Currently stb only outputs uint8 pixel types. If that - // changes this should account for additional pixel byte sizes. - const uint8_t* pValue = reinterpret_cast( - this->_pImage->pixelData.data() + pixelIndex); - - std::vector channelValues(this->_channels.size()); - for (size_t i = 0; i < this->_channels.size(); i++) { - channelValues[i] = *(pValue + this->_channels[i]); - } - - return assembleValueFromChannels(channelValues); + std::array sample = + sampleNearestPixel(*this->_pImage, this->_channels, wrappedU, wrappedV); + return assembleValueFromChannels( + gsl::span(sample.data(), this->_channels.size())); } /** @@ -598,43 +573,11 @@ class PropertyTexturePropertyView double wrappedU = applySamplerWrapS(u, this->_pSampler->wrapS); double wrappedV = applySamplerWrapT(v, this->_pSampler->wrapT); - // TODO: account for sampler's filter (can be nearest or linear) - - // For nearest filtering, std::floor is used instead of std::round. - // This is because filtering is supposed to consider the pixel centers. But - // memory access here acts as sampling the beginning of the pixel. Example: - // 0.4 * 2 = 0.8. In a 2x1 pixel image, that should be closer to the left - // pixel's center. But it will round to 1.0 which corresponds to the right - // pixel. So the right pixel has a bigger range than the left one, which is - // incorrect. - double xCoord = std::floor(wrappedU * this->_pImage->width); - double yCoord = std::floor(wrappedV * this->_pImage->height); - - // Clamp to ensure no out-of-bounds data access - int64_t x = glm::clamp( - static_cast(xCoord), - static_cast(0), - static_cast(this->_pImage->width) - 1); - int64_t y = glm::clamp( - static_cast(yCoord), - static_cast(0), - static_cast(this->_pImage->height) - 1); - - int64_t pixelIndex = this->_pImage->bytesPerChannel * - this->_pImage->channels * - (y * this->_pImage->width + x); - - // TODO: Currently stb only outputs uint8 pixel types. If that - // changes this should account for additional pixel byte sizes. - const uint8_t* pValue = reinterpret_cast( - this->_pImage->pixelData.data() + pixelIndex); - - std::vector channelValues(this->_channels.size()); - for (size_t i = 0; i < this->_channels.size(); i++) { - channelValues[i] = *(pValue + this->_channels[i]); - } + std::array sample = + sampleNearestPixel(*this->_pImage, this->_channels, wrappedU, wrappedV); - return assembleValueFromChannels(channelValues); + return assembleValueFromChannels( + gsl::span(sample.data(), this->_channels.size())); } /** diff --git a/CesiumGltf/src/PropertyTexturePropertyView.cpp b/CesiumGltf/src/PropertyTexturePropertyView.cpp index 5b7f654ba..e759b6b03 100644 --- a/CesiumGltf/src/PropertyTexturePropertyView.cpp +++ b/CesiumGltf/src/PropertyTexturePropertyView.cpp @@ -58,4 +58,45 @@ double applySamplerWrapT(const double v, const int32_t wrapT) { return glm::clamp(v, 0.0, 1.0); } +std::array sampleNearestPixel( + const ImageCesium& image, + const std::vector& channels, + const double u, + const double v) { + // For nearest filtering, std::floor is used instead of std::round. + // This is because filtering is supposed to consider the pixel centers. But + // memory access here acts as sampling the beginning of the pixel. Example: + // 0.4 * 2 = 0.8. In a 2x1 pixel image, that should be closer to the left + // pixel's center. But it will round to 1.0 which corresponds to the right + // pixel. So the right pixel has a bigger range than the left one, which is + // incorrect. + double xCoord = std::floor(u * image.width); + double yCoord = std::floor(v * image.height); + + // Clamp to ensure no out-of-bounds data access + int64_t x = glm::clamp( + static_cast(xCoord), + static_cast(0), + static_cast(image.width) - 1); + int64_t y = glm::clamp( + static_cast(yCoord), + static_cast(0), + static_cast(image.height) - 1); + + int64_t pixelIndex = + image.bytesPerChannel * image.channels * (y * image.width + x); + + // TODO: Currently stb only outputs uint8 pixel types. If that + // changes this should account for additional pixel byte sizes. + const uint8_t* pValue = + reinterpret_cast(image.pixelData.data() + pixelIndex); + + std::array channelValues{0, 0, 0, 0}; + for (size_t i = 0; i < channels.size(); i++) { + channelValues[i] = *(pValue + channels[i]); + } + + return channelValues; +} + } // namespace CesiumGltf From b7c3daea055e84f9be175ed41383abc37c2e92d4 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 7 Sep 2023 14:55:35 -0400 Subject: [PATCH 117/121] Check for all-null properties --- .../src/BatchTableToGltfStructuralMetadata.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp index f56128b1e..4ff3abc25 100644 --- a/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp +++ b/Cesium3DTilesSelection/src/BatchTableToGltfStructuralMetadata.cpp @@ -219,6 +219,14 @@ struct CompatibleTypes { return type.isInt8 || type.isInt16 || type.isInt32 || type.isInt64; } + /** + * Whether this property is compatible with every type. This only really + * happens when a CompatibleTypes is initialized and never modified. + */ + bool isFullyCompatible() const noexcept { + return std::holds_alternative(_type); + } + /** * Whether this property is incompatible with every primitive type. * Fully-incompatible properties will be treated as string properties. @@ -1386,6 +1394,11 @@ void updateExtensionWithJsonProperty( // Figure out which types we can use for this data. // Use the smallest type we can, and prefer signed to unsigned. const CompatibleTypes compatibleTypes = findCompatibleTypes(propertyValue); + if (compatibleTypes.isFullyCompatible()) { + // If this is "fully compatible", then the property contained no values (or + // rather, no non-null values). Exclude it from the model to avoid errors. + return; + } if (compatibleTypes.isExclusivelyArray()) { MaskedArrayType arrayType = compatibleTypes.toMaskedArrayType(); From f3b43c57360f9a6410654508ca553d9605076a06 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Fri, 8 Sep 2023 11:43:48 +1000 Subject: [PATCH 118/121] Slightly improve safety of sampleNearestPixel. --- CesiumGltf/src/PropertyTexturePropertyView.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CesiumGltf/src/PropertyTexturePropertyView.cpp b/CesiumGltf/src/PropertyTexturePropertyView.cpp index e759b6b03..144b92e1d 100644 --- a/CesiumGltf/src/PropertyTexturePropertyView.cpp +++ b/CesiumGltf/src/PropertyTexturePropertyView.cpp @@ -92,7 +92,8 @@ std::array sampleNearestPixel( reinterpret_cast(image.pixelData.data() + pixelIndex); std::array channelValues{0, 0, 0, 0}; - for (size_t i = 0; i < channels.size(); i++) { + size_t len = glm::min(channels.size(), channelValues.size()); + for (size_t i = 0; i < len; i++) { channelValues[i] = *(pValue + channels[i]); } From 2002f0d3137c975367d4804f7775d66824943d46 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Fri, 8 Sep 2023 15:41:52 +1000 Subject: [PATCH 119/121] Add missing generated file. --- .../src/FeatureIdTextureJsonHandler.h | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 CesiumGltfReader/generated/src/FeatureIdTextureJsonHandler.h diff --git a/CesiumGltfReader/generated/src/FeatureIdTextureJsonHandler.h b/CesiumGltfReader/generated/src/FeatureIdTextureJsonHandler.h new file mode 100644 index 000000000..703c486b4 --- /dev/null +++ b/CesiumGltfReader/generated/src/FeatureIdTextureJsonHandler.h @@ -0,0 +1,39 @@ +// This file was generated by generate-classes. +// DO NOT EDIT THIS FILE! +#pragma once + +#include "TextureInfoJsonHandler.h" + +#include +#include +#include + +namespace CesiumJsonReader { +class JsonReaderOptions; +} + +namespace CesiumGltfReader { +class FeatureIdTextureJsonHandler : public TextureInfoJsonHandler { +public: + using ValueType = CesiumGltf::FeatureIdTexture; + + FeatureIdTextureJsonHandler( + const CesiumJsonReader::JsonReaderOptions& options) noexcept; + void + reset(IJsonHandler* pParentHandler, CesiumGltf::FeatureIdTexture* pObject); + + virtual IJsonHandler* readObjectKey(const std::string_view& str) override; + +protected: + IJsonHandler* readObjectKeyFeatureIdTexture( + const std::string& objectType, + const std::string_view& str, + CesiumGltf::FeatureIdTexture& o); + +private: + CesiumGltf::FeatureIdTexture* _pObject = nullptr; + CesiumJsonReader:: + ArrayJsonHandler> + _channels; +}; +} // namespace CesiumGltfReader From 272f0c95c89b66a081bdb6a3cb60929c0c78804f Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Fri, 8 Sep 2023 22:45:14 +1000 Subject: [PATCH 120/121] Formatting. --- .../include/CesiumGltf/PropertyTypeTraits.h | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h index 286cb0609..2dfeddce2 100644 --- a/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h +++ b/CesiumGltf/include/CesiumGltf/PropertyTypeTraits.h @@ -293,14 +293,30 @@ struct CanBeNormalized> : CanBeNormalized {}; */ template struct TypeToNormalizedType; -template <> struct TypeToNormalizedType { using type = double; }; -template <> struct TypeToNormalizedType { using type = double; }; -template <> struct TypeToNormalizedType { using type = double; }; -template <> struct TypeToNormalizedType { using type = double; }; -template <> struct TypeToNormalizedType { using type = double; }; -template <> struct TypeToNormalizedType { using type = double; }; -template <> struct TypeToNormalizedType { using type = double; }; -template <> struct TypeToNormalizedType { using type = double; }; +template <> struct TypeToNormalizedType { + using type = double; +}; +template <> struct TypeToNormalizedType { + using type = double; +}; +template <> struct TypeToNormalizedType { + using type = double; +}; +template <> struct TypeToNormalizedType { + using type = double; +}; +template <> struct TypeToNormalizedType { + using type = double; +}; +template <> struct TypeToNormalizedType { + using type = double; +}; +template <> struct TypeToNormalizedType { + using type = double; +}; +template <> struct TypeToNormalizedType { + using type = double; +}; template struct TypeToNormalizedType> { From c7a5c70e37db4e68d88e555b6bce493fad61c381 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Fri, 8 Sep 2023 22:57:38 +1000 Subject: [PATCH 121/121] Fix case of filename. --- .../{FeatureIDTextureReader.h => FeatureIdTextureReader.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CesiumGltfReader/generated/include/CesiumGltfReader/{FeatureIDTextureReader.h => FeatureIdTextureReader.h} (100%) diff --git a/CesiumGltfReader/generated/include/CesiumGltfReader/FeatureIDTextureReader.h b/CesiumGltfReader/generated/include/CesiumGltfReader/FeatureIdTextureReader.h similarity index 100% rename from CesiumGltfReader/generated/include/CesiumGltfReader/FeatureIDTextureReader.h rename to CesiumGltfReader/generated/include/CesiumGltfReader/FeatureIdTextureReader.h