ralpha-assets/Plugins/CesiumForUnreal/Source/ThirdParty/include/Cesium3DTilesSelection/GltfModifier.h

274 lines
9.2 KiB
C++

#pragma once
#include <Cesium3DTilesSelection/GltfModifierState.h>
#include <Cesium3DTilesSelection/Tile.h>
#include <Cesium3DTilesSelection/TileLoadRequester.h>
#include <CesiumAsync/AsyncSystem.h>
#include <CesiumAsync/Future.h>
#include <CesiumGltf/Model.h>
#include <spdlog/fwd.h>
#include <memory>
#include <optional>
namespace CesiumAsync {
class IAssetAccessor;
} // namespace CesiumAsync
namespace Cesium3DTilesSelection {
class TilesetMetadata;
class TilesetContentManager;
/**
* @brief The input to @ref GltfModifier::apply.
*/
struct GltfModifierInput {
/**
* @brief The version of the @ref GltfModifier, as returned by
* @ref GltfModifier::getCurrentVersion at the start of the modification.
*
* This is provided because calling @ref GltfModifier::getCurrentVersion
* may return a newer version if @ref GltfModifier::trigger is called
* again while @ref GltfModifier::apply is running in a worker thread.
*/
int64_t version;
/**
* @brief The async system that can be used to do work in threads.
*/
CesiumAsync::AsyncSystem asyncSystem;
/**
* @brief An asset accessor that can be used to obtain additional assets.
*/
std::shared_ptr<CesiumAsync::IAssetAccessor> pAssetAccessor;
/**
* @brief The logger.
*/
std::shared_ptr<spdlog::logger> pLogger;
/**
* @brief The model to be modified.
*/
const CesiumGltf::Model& previousModel;
/**
* @brief The transformation of the model's coordinates to the tileset's
* coordinate system.
*/
glm::dmat4 tileTransform;
};
/**
* @brief The output of @ref GltfModifier::apply.
*/
struct GltfModifierOutput {
/**
* @brief The new, modified model.
*/
CesiumGltf::Model modifiedModel;
};
/**
* @brief An abstract class that allows modifying a tile's glTF model after it
* has been loaded.
*
* An example modification is merging or splitting the primitives in the glTF.
* Merging primitives can lead to improved rendering performance. Splitting
* primitives allows different materials to be assigned to parts that were
* initially in the same primitive.
*
* The `GltfModifier` can be applied several times during the lifetime of the
* model, depending on current needs. For this reason, the `GltfModifer` has a
* @ref getCurrentVersion, which can be incremented by calling
* @ref trigger. When the version is incremented, the `GltfModifier` will be
* re-applied to all previously-modified models.
*
* The version number of a modified glTF is stored in the
* @ref GltfModifierVersionExtension extension.
*
* A just-constructed modifier is considered nilpotent, meaning nothing will
* happen until @ref trigger has been called at least once.
*
* The @ref apply function is called from a worker thread. All other methods
* must only be called from the main thread.
*/
class GltfModifier : private TileLoadRequester {
public:
/**
* @brief Gets the current version number, or `std::nullopt` if the
* `GltfModifier` is currently inactive.
*
* Returns `std::nullopt` when in the default nilpotent state where glTFs will
* not be modified at all. Calling @ref trigger once will set the version
* number to 0 and activate the `GltfModifier`. Calling it successive times
* will increment the version number and re-apply modification to all
* previously-modified models.
*/
std::optional<int64_t> getCurrentVersion() const;
/**
* @brief Checks if this `GltfModifier` is active.
*
* This method returns true if the current version is greater than or equal to
* 0, indicating that @ref trigger has been called at least once.
*/
bool isActive() const;
/**
* @brief Call this the first time to activate this `GltfModifier` after it
* has been constructed in its default nilpotent state and set the
* @ref getCurrentVersion to 0. Call it successive times to increment
* @ref getCurrentVersion and reapply modification to all
* previously-modified models without unloading them.
*
* While the `GltfModifier` is being reapplied for a new version, the display
* may show a mix of tiles with the old and new versions.
*/
void trigger();
/**
* @brief Implement this method to apply custom modification to a glTF model.
* It is called by the @ref Tileset from within a worker thread.
*
* This method will be called for each @ref Tile during the content load
* process if @ref trigger has been called at least once. It will also be
* called again for already-loaded tiles for successive calls to
* @ref trigger.
*
* @param input The input to the glTF modification.
* @return A future that resolves to a @ref GltfModifierOutput with the
* new model, or to `std::nullopt` if the model does not need to be modified.
*/
virtual CesiumAsync::Future<std::optional<GltfModifierOutput>>
apply(GltfModifierInput&& input) = 0;
/**
* @brief Checks if the given tile needs to be processed by this
* `GltfModifier` in a worker thread.
*
* @param tile The tile to check.
* @returns `true` if the tile needs to be processed by the `GltfModifier` in
* a worker thread, or `false` otherwise.
*/
bool needsWorkerThreadModification(const Tile& tile) const;
/**
* @brief Checks if the given tile needs to be processed by this
* `GltfModifier` in the main thread.
* @param tile The tile to check.
* @returns `true` if the tile needs to be processed by the `GltfModifier` in
* the main thread, or `false` otherwise.
*/
bool needsMainThreadModification(const Tile& tile) const;
protected:
GltfModifier();
virtual ~GltfModifier();
/**
* @brief Notifies this instance that it has been registered with a
* @ref Tileset.
*
* This method is called after the tileset's root tile is known but
* before @ref Tileset::getRootTileAvailableEvent has been raised.
*
* This method is called from the main thread. Override this method to respond
* to this event.
*
* @param asyncSystem The async system with which to do background work.
* @param pAssetAccessor The asset accessor to use to retrieve any additional
* assets.
* @param pLogger The logger to which to log errors and warnings that occur
* during preparation of the `GltfModifier`.
* @param tilesetMetadata The metadata associated with the tileset.
* @param rootTile The root tile of the tileset.
* @returns A future that resolves when the `GltfModifier` is ready to modify
* glTF instances for this tileset. Tileset loading will not proceed until
* this future resolves. If the future rejects, tileset load will proceed but
* the `GltfModifier` will not be used.
*/
virtual CesiumAsync::Future<void> onRegister(
const CesiumAsync::AsyncSystem& asyncSystem,
const std::shared_ptr<CesiumAsync::IAssetAccessor>& pAssetAccessor,
const std::shared_ptr<spdlog::logger>& pLogger,
const TilesetMetadata& tilesetMetadata,
const Tile& rootTile);
private:
/**
* @private
*
* @brief Called by @ref Tileset when this instance has been registered
* with it. To add custom behavior on registration, override the other
* overload of this method.
*/
CesiumAsync::Future<void> onRegister(
TilesetContentManager& contentManager,
const TilesetMetadata& tilesetMetadata,
const Tile& rootTile);
/**
* @private
*
* @brief Called by @ref Tileset when this instance has been unregistered
* from it.
*/
void onUnregister(TilesetContentManager& contentManager);
/**
* @private
*
* @brief Called by @ref Tileset when the given tile leaves the
* @ref TileLoadState::ContentLoading state but it was loaded with an
* older @ref GltfModifier version. The tile will be queued for a call
* to @ref apply in a worker thread.
*
* This method is called from the main thread.
*
* @param tile The tile that has just left the
* @ref TileLoadState::ContentLoading state.
*/
void onOldVersionContentLoadingComplete(const Tile& tile);
/**
* @private
*
* @brief Called by @ref Tileset when @ref apply has finished running on a
* previously-loaded tile. The tile will be queued to finish its loading in
* the main thread.
*
* This method is called from the main thread.
*
* @param tile The tile that has just been processed by @ref apply.
*/
void onWorkerThreadApplyComplete(const Tile& tile);
// TileLoadRequester implementation
double getWeight() const override;
bool hasMoreTilesToLoadInWorkerThread() const override;
const Tile* getNextTileToLoadInWorkerThread() override;
bool hasMoreTilesToLoadInMainThread() const override;
const Tile* getNextTileToLoadInMainThread() override;
std::optional<int64_t> _currentVersion;
const Tile* _pRootTile;
// Ideally these would be weak pointers, but we don't currently have a good
// way to do that.
std::vector<Tile::ConstPointer> _workerThreadQueue;
std::vector<Tile::ConstPointer> _mainThreadQueue;
friend class TilesetContentManager;
friend class MockTilesetContentManagerForGltfModifier;
};
} // namespace Cesium3DTilesSelection