Add test for async schema loading.
This commit is contained in:
parent
6145b547a6
commit
51e798e4ea
|
|
@ -494,9 +494,6 @@ private:
|
|||
// scratch variable so that it can allocate only when growing bigger.
|
||||
std::vector<const TileOcclusionRendererProxy*> _childOcclusionProxies;
|
||||
|
||||
CesiumAsync::Promise<void> _rootTileAvailablePromise;
|
||||
CesiumAsync::SharedFuture<void> _rootTileAvailableFuture;
|
||||
|
||||
CesiumUtility::IntrusivePointer<TilesetContentManager>
|
||||
_pTilesetContentManager;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,9 +43,6 @@ Tileset::Tileset(
|
|||
_previousFrameNumber(0),
|
||||
_distances(),
|
||||
_childOcclusionProxies(),
|
||||
_rootTileAvailablePromise{externals.asyncSystem.createPromise<void>()},
|
||||
_rootTileAvailableFuture{
|
||||
this->_rootTileAvailablePromise.getFuture().share()},
|
||||
_pTilesetContentManager{new TilesetContentManager(
|
||||
_externals,
|
||||
_options,
|
||||
|
|
@ -64,9 +61,6 @@ Tileset::Tileset(
|
|||
_previousFrameNumber(0),
|
||||
_distances(),
|
||||
_childOcclusionProxies(),
|
||||
_rootTileAvailablePromise{externals.asyncSystem.createPromise<void>()},
|
||||
_rootTileAvailableFuture{
|
||||
this->_rootTileAvailablePromise.getFuture().share()},
|
||||
_pTilesetContentManager{new TilesetContentManager(
|
||||
_externals,
|
||||
_options,
|
||||
|
|
@ -85,9 +79,6 @@ Tileset::Tileset(
|
|||
_previousFrameNumber(0),
|
||||
_distances(),
|
||||
_childOcclusionProxies(),
|
||||
_rootTileAvailablePromise{externals.asyncSystem.createPromise<void>()},
|
||||
_rootTileAvailableFuture{
|
||||
this->_rootTileAvailablePromise.getFuture().share()},
|
||||
_pTilesetContentManager{new TilesetContentManager(
|
||||
_externals,
|
||||
_options,
|
||||
|
|
@ -108,7 +99,7 @@ CesiumAsync::SharedFuture<void>& Tileset::getAsyncDestructionCompleteEvent() {
|
|||
}
|
||||
|
||||
CesiumAsync::SharedFuture<void>& Tileset::getRootTileAvailableEvent() {
|
||||
return this->_rootTileAvailableFuture;
|
||||
return this->_pTilesetContentManager->getRootTileAvailableEvent();
|
||||
}
|
||||
|
||||
const std::vector<Credit>& Tileset::getTilesetCredits() const noexcept {
|
||||
|
|
|
|||
|
|
@ -599,7 +599,12 @@ TilesetContentManager::TilesetContentManager(
|
|||
_tilesDataUsed{0},
|
||||
_destructionCompletePromise{externals.asyncSystem.createPromise<void>()},
|
||||
_destructionCompleteFuture{
|
||||
this->_destructionCompletePromise.getFuture().share()} {}
|
||||
this->_destructionCompletePromise.getFuture().share()},
|
||||
_rootTileAvailablePromise{externals.asyncSystem.createPromise<void>()},
|
||||
_rootTileAvailableFuture{
|
||||
this->_rootTileAvailablePromise.getFuture().share()} {
|
||||
this->_rootTileAvailablePromise.resolve();
|
||||
}
|
||||
|
||||
TilesetContentManager::TilesetContentManager(
|
||||
const TilesetExternals& externals,
|
||||
|
|
@ -623,7 +628,10 @@ TilesetContentManager::TilesetContentManager(
|
|||
_tilesDataUsed{0},
|
||||
_destructionCompletePromise{externals.asyncSystem.createPromise<void>()},
|
||||
_destructionCompleteFuture{
|
||||
this->_destructionCompletePromise.getFuture().share()} {
|
||||
this->_destructionCompletePromise.getFuture().share()},
|
||||
_rootTileAvailablePromise{externals.asyncSystem.createPromise<void>()},
|
||||
_rootTileAvailableFuture{
|
||||
this->_rootTileAvailablePromise.getFuture().share()} {
|
||||
if (!url.empty()) {
|
||||
this->notifyTileStartLoading(nullptr);
|
||||
|
||||
|
|
@ -721,13 +729,16 @@ TilesetContentManager::TilesetContentManager(
|
|||
TilesetLoadType::TilesetJson,
|
||||
errorCallback,
|
||||
std::move(result));
|
||||
thiz->_rootTileAvailablePromise.resolve();
|
||||
})
|
||||
.catchInMainThread([thiz](std::exception&& e) {
|
||||
thiz->notifyTileDoneLoading(nullptr);
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
thiz->_externals.pLogger,
|
||||
"An unexpected error occurs when loading tile: {}",
|
||||
"An unexpected error occurred when loading tile: {}",
|
||||
e.what());
|
||||
thiz->_rootTileAvailablePromise.reject(
|
||||
std::runtime_error("Root tile failed to load."));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -756,7 +767,10 @@ TilesetContentManager::TilesetContentManager(
|
|||
_tilesDataUsed{0},
|
||||
_destructionCompletePromise{externals.asyncSystem.createPromise<void>()},
|
||||
_destructionCompleteFuture{
|
||||
this->_destructionCompletePromise.getFuture().share()} {
|
||||
this->_destructionCompletePromise.getFuture().share()},
|
||||
_rootTileAvailablePromise{externals.asyncSystem.createPromise<void>()},
|
||||
_rootTileAvailableFuture{
|
||||
this->_rootTileAvailablePromise.getFuture().share()} {
|
||||
if (ionAssetID > 0) {
|
||||
auto authorizationChangeListener = [this](
|
||||
const std::string& header,
|
||||
|
|
@ -793,13 +807,16 @@ TilesetContentManager::TilesetContentManager(
|
|||
TilesetLoadType::CesiumIon,
|
||||
errorCallback,
|
||||
std::move(result));
|
||||
thiz->_rootTileAvailablePromise.resolve();
|
||||
})
|
||||
.catchInMainThread([thiz](std::exception&& e) {
|
||||
thiz->notifyTileDoneLoading(nullptr);
|
||||
SPDLOG_LOGGER_ERROR(
|
||||
thiz->_externals.pLogger,
|
||||
"An unexpected error occurs when loading tile: {}",
|
||||
"An unexpected error occurred when loading tile: {}",
|
||||
e.what());
|
||||
thiz->_rootTileAvailablePromise.reject(
|
||||
std::runtime_error("Root tile failed to load."));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -809,6 +826,11 @@ TilesetContentManager::getAsyncDestructionCompleteEvent() {
|
|||
return this->_destructionCompleteFuture;
|
||||
}
|
||||
|
||||
CesiumAsync::SharedFuture<void>&
|
||||
TilesetContentManager::getRootTileAvailableEvent() {
|
||||
return this->_rootTileAvailableFuture;
|
||||
}
|
||||
|
||||
TilesetContentManager::~TilesetContentManager() noexcept {
|
||||
assert(this->_tileLoadsInProgress == 0);
|
||||
this->unloadAll();
|
||||
|
|
|
|||
|
|
@ -51,6 +51,13 @@ public:
|
|||
*/
|
||||
CesiumAsync::SharedFuture<void>& getAsyncDestructionCompleteEvent();
|
||||
|
||||
/**
|
||||
* @brief A future that resolves when the details of the root tile of this
|
||||
* tileset are available. The root tile's content (e.g., 3D model), however,
|
||||
* will not necessarily be loaded yet.
|
||||
*/
|
||||
CesiumAsync::SharedFuture<void>& getRootTileAvailableEvent();
|
||||
|
||||
~TilesetContentManager() noexcept;
|
||||
|
||||
void loadTileContent(Tile& tile, const TilesetOptions& tilesetOptions);
|
||||
|
|
@ -146,5 +153,8 @@ private:
|
|||
|
||||
CesiumAsync::Promise<void> _destructionCompletePromise;
|
||||
CesiumAsync::SharedFuture<void> _destructionCompleteFuture;
|
||||
|
||||
CesiumAsync::Promise<void> _rootTileAvailablePromise;
|
||||
CesiumAsync::SharedFuture<void> _rootTileAvailableFuture;
|
||||
};
|
||||
} // namespace Cesium3DTilesSelection
|
||||
|
|
|
|||
|
|
@ -1312,6 +1312,186 @@ TEST_CASE("Allows access to material variants") {
|
|||
CHECK(variantsByGroup == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("Allows access to material variants in an external schema") {
|
||||
Cesium3DTilesSelection::registerAllTileContentTypes();
|
||||
|
||||
std::filesystem::path testDataPath = Cesium3DTilesSelection_TEST_DATA_DIR;
|
||||
testDataPath = testDataPath / "MaterialVariants";
|
||||
std::vector<std::string> files{
|
||||
"tileset-external-schema.json",
|
||||
"schema.json",
|
||||
"parent.b3dm"};
|
||||
|
||||
std::map<std::string, std::shared_ptr<SimpleAssetRequest>>
|
||||
mockCompletedRequests;
|
||||
for (const auto& file : files) {
|
||||
std::unique_ptr<SimpleAssetResponse> mockCompletedResponse =
|
||||
std::make_unique<SimpleAssetResponse>(
|
||||
static_cast<uint16_t>(200),
|
||||
"doesn't matter",
|
||||
CesiumAsync::HttpHeaders{},
|
||||
readFile(testDataPath / file));
|
||||
mockCompletedRequests.insert(
|
||||
{file,
|
||||
std::make_shared<SimpleAssetRequest>(
|
||||
"GET",
|
||||
file,
|
||||
CesiumAsync::HttpHeaders{},
|
||||
std::move(mockCompletedResponse))});
|
||||
}
|
||||
|
||||
std::shared_ptr<SimpleAssetAccessor> mockAssetAccessor =
|
||||
std::make_shared<SimpleAssetAccessor>(std::move(mockCompletedRequests));
|
||||
TilesetExternals tilesetExternals{
|
||||
mockAssetAccessor,
|
||||
std::make_shared<SimplePrepareRendererResource>(),
|
||||
AsyncSystem(std::make_shared<SimpleTaskProcessor>()),
|
||||
nullptr};
|
||||
|
||||
Tileset tileset(tilesetExternals, "tileset-external-schema.json");
|
||||
|
||||
// getMetadata returns nullptr before the root tile is loaded.
|
||||
CHECK(tileset.getMetadata() == nullptr);
|
||||
|
||||
bool wasCalled = false;
|
||||
tileset.loadMetadata().thenInMainThread(
|
||||
[&wasCalled](const TilesetMetadata* pMetadata) {
|
||||
wasCalled = true;
|
||||
REQUIRE(pMetadata);
|
||||
REQUIRE(pMetadata->schema);
|
||||
REQUIRE(pMetadata->metadata);
|
||||
|
||||
std::optional<Cesium3DTiles::FoundMetadataProperty> found1 =
|
||||
Cesium3DTiles::MetadataQuery::findFirstPropertyWithSemantic(
|
||||
*pMetadata->schema,
|
||||
*pMetadata->metadata,
|
||||
"MATERIAL_VARIANTS");
|
||||
REQUIRE(found1);
|
||||
CHECK(found1->classIdentifier == "MaterialVariants");
|
||||
CHECK(found1->classDefinition.properties.size() == 1);
|
||||
CHECK(found1->propertyIdentifier == "material_variants");
|
||||
CHECK(
|
||||
found1->propertyDefinition.description ==
|
||||
"Names of material variants to be expected in the glTF assets");
|
||||
REQUIRE(found1->propertyValue.isArray());
|
||||
|
||||
const JsonValue::Array& variantsJson = found1->propertyValue.getArray();
|
||||
std::vector<std::string> variants(variantsJson.size());
|
||||
std::transform(
|
||||
variantsJson.begin(),
|
||||
variantsJson.end(),
|
||||
variants.begin(),
|
||||
[](const JsonValue& value) {
|
||||
return value.getStringOrDefault("");
|
||||
});
|
||||
REQUIRE(variants.size() == 4);
|
||||
CHECK(variants[0] == "RGB");
|
||||
CHECK(variants[1] == "RRR");
|
||||
CHECK(variants[2] == "GGG");
|
||||
CHECK(variants[3] == "BBB");
|
||||
|
||||
std::vector<std::vector<std::string>> variantsByGroup;
|
||||
for (const Cesium3DTiles::GroupMetadata& group : pMetadata->groups) {
|
||||
std::vector<std::string>& groupVariants =
|
||||
variantsByGroup.emplace_back();
|
||||
|
||||
std::optional<Cesium3DTiles::FoundMetadataProperty> found2 =
|
||||
Cesium3DTiles::MetadataQuery::findFirstPropertyWithSemantic(
|
||||
*pMetadata->schema,
|
||||
group,
|
||||
"MATERIAL_VARIANTS");
|
||||
REQUIRE(found2);
|
||||
REQUIRE(found2->propertyValue.isArray());
|
||||
|
||||
const JsonValue::Array& groupVariantsJson =
|
||||
found2->propertyValue.getArray();
|
||||
groupVariants.reserve(groupVariantsJson.size());
|
||||
for (size_t i = 0; i < groupVariantsJson.size(); ++i) {
|
||||
groupVariants.emplace_back(
|
||||
groupVariantsJson[i].getStringOrDefault(""));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>> expected = {
|
||||
{"RGB", "RRR"},
|
||||
{"GGG", "BBB"}};
|
||||
|
||||
CHECK(variantsByGroup == expected);
|
||||
});
|
||||
|
||||
CHECK(!wasCalled);
|
||||
initializeTileset(tileset);
|
||||
CHECK(wasCalled);
|
||||
}
|
||||
|
||||
TEST_CASE("Future from loadSchema rejects if schemaUri can't be loaded") {
|
||||
Cesium3DTilesSelection::registerAllTileContentTypes();
|
||||
|
||||
std::filesystem::path testDataPath = Cesium3DTilesSelection_TEST_DATA_DIR;
|
||||
testDataPath = testDataPath / "MaterialVariants";
|
||||
std::vector<std::string> files{"tileset-external-schema.json", "parent.b3dm"};
|
||||
|
||||
std::map<std::string, std::shared_ptr<SimpleAssetRequest>>
|
||||
mockCompletedRequests;
|
||||
for (const auto& file : files) {
|
||||
std::unique_ptr<SimpleAssetResponse> mockCompletedResponse =
|
||||
std::make_unique<SimpleAssetResponse>(
|
||||
static_cast<uint16_t>(200),
|
||||
"doesn't matter",
|
||||
CesiumAsync::HttpHeaders{},
|
||||
readFile(testDataPath / file));
|
||||
mockCompletedRequests.insert(
|
||||
{file,
|
||||
std::make_shared<SimpleAssetRequest>(
|
||||
"GET",
|
||||
file,
|
||||
CesiumAsync::HttpHeaders{},
|
||||
std::move(mockCompletedResponse))});
|
||||
}
|
||||
|
||||
mockCompletedRequests.insert(
|
||||
{"schema.json",
|
||||
std::make_shared<SimpleAssetRequest>(
|
||||
"GET",
|
||||
"schema.json",
|
||||
CesiumAsync::HttpHeaders{},
|
||||
std::make_unique<SimpleAssetResponse>(
|
||||
404,
|
||||
"doesn't matter",
|
||||
CesiumAsync::HttpHeaders{},
|
||||
std::vector<std::byte>()))});
|
||||
|
||||
std::shared_ptr<SimpleAssetAccessor> mockAssetAccessor =
|
||||
std::make_shared<SimpleAssetAccessor>(std::move(mockCompletedRequests));
|
||||
TilesetExternals tilesetExternals{
|
||||
mockAssetAccessor,
|
||||
std::make_shared<SimplePrepareRendererResource>(),
|
||||
AsyncSystem(std::make_shared<SimpleTaskProcessor>()),
|
||||
nullptr};
|
||||
|
||||
Tileset tileset(tilesetExternals, "tileset-external-schema.json");
|
||||
|
||||
// getMetadata returns nullptr before the root tile is loaded.
|
||||
CHECK(tileset.getMetadata() == nullptr);
|
||||
|
||||
bool wasResolved = false;
|
||||
bool wasRejected = false;
|
||||
tileset.loadMetadata()
|
||||
.thenInMainThread(
|
||||
[&wasResolved](const TilesetMetadata*) { wasResolved = true; })
|
||||
.catchInMainThread([&wasRejected](const std::exception& exception) {
|
||||
CHECK(std::string(exception.what()).find("") != std::string::npos);
|
||||
wasRejected = true;
|
||||
});
|
||||
|
||||
CHECK(!wasResolved);
|
||||
CHECK(!wasRejected);
|
||||
|
||||
initializeTileset(tileset);
|
||||
CHECK(!wasResolved);
|
||||
CHECK(wasRejected);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void runUnconditionallyRefinedTestCase(const TilesetOptions& options) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"classes": {
|
||||
"MaterialVariants": {
|
||||
"properties": {
|
||||
"material_variants": {
|
||||
"type": "STRING",
|
||||
"array": true,
|
||||
"description": "Names of material variants to be expected in the glTF assets",
|
||||
"semantic": "MATERIAL_VARIANTS"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"asset": {
|
||||
"version": "1.0",
|
||||
"tilesetVersion": "1.2.3"
|
||||
},
|
||||
"extras": {
|
||||
"name": "Sample Tileset"
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"minimum": 0,
|
||||
"maximum": 9
|
||||
},
|
||||
"Longitude": {
|
||||
"minimum": -1.3197192952275933,
|
||||
"maximum": -1.319644104024109
|
||||
},
|
||||
"Latitude": {
|
||||
"minimum": 0.698848878034009,
|
||||
"maximum": 0.6989046192460953
|
||||
},
|
||||
"Height": {
|
||||
"minimum": 6.161747192963958,
|
||||
"maximum": 85.41026367992163
|
||||
}
|
||||
},
|
||||
"schemaUri": "schema.json",
|
||||
"metadata": {
|
||||
"class": "MaterialVariants",
|
||||
"properties": {
|
||||
"material_variants": ["RGB", "RRR", "GGG", "BBB"]
|
||||
}
|
||||
},
|
||||
"groups": [
|
||||
{
|
||||
"class": "MaterialVariants",
|
||||
"properties": {
|
||||
"material_variants": ["RGB", "RRR"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "MaterialVariants",
|
||||
"properties": {
|
||||
"material_variants": ["GGG", "BBB"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"geometricError": 240,
|
||||
"root": {
|
||||
"boundingVolume": {
|
||||
"region": [
|
||||
-1.3197209591796106,
|
||||
0.6988424218,
|
||||
-1.3196390408203893,
|
||||
0.6989055782,
|
||||
0,
|
||||
88
|
||||
]
|
||||
},
|
||||
"geometricError": 70,
|
||||
"refine": "ADD",
|
||||
"content": {
|
||||
"uri": "parent.b3dm",
|
||||
"boundingVolume": {
|
||||
"region": [
|
||||
-1.3197004795898053,
|
||||
0.6988582109,
|
||||
-1.3196595204101946,
|
||||
0.6988897891,
|
||||
0,
|
||||
88
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue