mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-10 21:49:38 -06:00
310 lines
12 KiB
C++
310 lines
12 KiB
C++
/*****************************************************************************************
|
|
* *
|
|
* OpenSpace *
|
|
* *
|
|
* Copyright (c) 2014-2023 *
|
|
* *
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
|
* software and associated documentation files (the "Software"), to deal in the Software *
|
|
* without restriction, including without limitation the rights to use, copy, modify, *
|
|
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
|
* permit persons to whom the Software is furnished to do so, subject to the following *
|
|
* conditions: *
|
|
* *
|
|
* The above copyright notice and this permission notice shall be included in all copies *
|
|
* or substantial portions of the Software. *
|
|
* *
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
|
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
|
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
|
****************************************************************************************/
|
|
|
|
#include <modules/globebrowsing/src/tileprovider/defaulttileprovider.h>
|
|
|
|
#include <modules/globebrowsing/globebrowsingmodule.h>
|
|
#include <modules/globebrowsing/src/memoryawaretilecache.h>
|
|
#include <openspace/documentation/documentation.h>
|
|
#include <openspace/engine/globals.h>
|
|
#include <openspace/engine/moduleengine.h>
|
|
#include <optional>
|
|
|
|
namespace {
|
|
constexpr openspace::properties::Property::PropertyInfo FilePathInfo = {
|
|
"FilePath",
|
|
"File Path",
|
|
"The path of the GDAL file or the image file that is to be used in this tile "
|
|
"provider",
|
|
openspace::properties::Property::Visibility::AdvancedUser
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo TilePixelSizeInfo = {
|
|
"TilePixelSize",
|
|
"Tile Pixel Size",
|
|
"This value is the preferred size (in pixels) for each tile. Choosing the right "
|
|
"value is a tradeoff between more efficiency (larger images) and better quality "
|
|
"(smaller images). The tile pixel size has to be smaller than the size of the "
|
|
"complete image if a single image is used",
|
|
// @VISIBILITY(3.33)
|
|
openspace::properties::Property::Visibility::AdvancedUser
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo CompressionInfo = {
|
|
"Compression",
|
|
"Compression Algorithm",
|
|
"The compression algorithm to use for MRF cached tiles",
|
|
openspace::properties::Property::Visibility::AdvancedUser
|
|
};
|
|
|
|
enum class [[codegen::stringify()]] Compression {
|
|
PNG = 0,
|
|
JPEG,
|
|
LERC
|
|
};
|
|
|
|
struct [[codegen::Dictionary(DefaultTileProvider)]] Parameters {
|
|
// User-facing name of this tile provider
|
|
std::optional<std::string> name;
|
|
|
|
// Identifier of the enclosing layer to which tiles are provided
|
|
std::optional<std::string> identifier;
|
|
|
|
// The path to the file that is loaded by GDAL to produce tiles. Since GDAL
|
|
// supports it, this can also be the textual representation of the contents of a
|
|
// loading file
|
|
std::string filePath;
|
|
|
|
// The layer into which this tile provider is loaded
|
|
int layerGroupID;
|
|
|
|
// [[codegen::verbatim(TilePixelSizeInfo.description)]]
|
|
std::optional<int> tilePixelSize;
|
|
|
|
// Determines whether the tiles should have a padding zone around it, making the
|
|
// interpolation between tiles more pleasant
|
|
std::optional<bool> padTiles;
|
|
|
|
// Determines if the tiles should be preprocessed before uploading to the GPU
|
|
std::optional<bool> performPreProcessing;
|
|
|
|
struct CacheSettings {
|
|
// Specifies whether to use caching or not
|
|
std::optional<bool> enabled;
|
|
|
|
// [[codegen::verbatim(CompressionInfo.description)]]
|
|
enum class [[codegen::map(Compression)]] Compression {
|
|
PNG = 0,
|
|
JPEG,
|
|
LERC
|
|
};
|
|
|
|
// The compression algorithm to use for cached tiles
|
|
std::optional<Compression> compression;
|
|
|
|
// The quality setting of the compression alogrithm, only valid for JPEG
|
|
std::optional<int> quality [[codegen::inrange(0, 100)]];
|
|
|
|
// The block-size of the MRF cache
|
|
std::optional<int> blockSize [[codegen::greater(0)]];
|
|
};
|
|
// Specifies the cache settings that should be applied to this layer
|
|
std::optional<CacheSettings> cacheSettings;
|
|
|
|
// The name of the enclosing globe
|
|
std::optional<std::string> globeName;
|
|
|
|
};
|
|
#include "defaulttileprovider_codegen.cpp"
|
|
} // namespace
|
|
|
|
namespace openspace::globebrowsing {
|
|
|
|
documentation::Documentation DefaultTileProvider::Documentation() {
|
|
return codegen::doc<Parameters>("globebrowsing_defaulttileprovider");
|
|
}
|
|
|
|
DefaultTileProvider::DefaultTileProvider(const ghoul::Dictionary& dictionary)
|
|
: _filePath(FilePathInfo, "")
|
|
, _tilePixelSize(TilePixelSizeInfo, 32, 32, 2048)
|
|
{
|
|
ZoneScoped;
|
|
|
|
const Parameters p = codegen::bake<Parameters>(dictionary);
|
|
|
|
name = p.name.value_or("Name unspecified");
|
|
std::string _loggerCat = "DefaultTileProvider (" + name + ")";
|
|
|
|
// 1. Get required Keys
|
|
_filePath = p.filePath;
|
|
|
|
_layerGroupID = layers::Group::ID(p.layerGroupID);
|
|
|
|
// 2. Initialize default values for any optional Keys
|
|
// getValue does not work for integers
|
|
int pixelSize = p.tilePixelSize.value_or(0);
|
|
_padTiles = p.padTiles.value_or(_padTiles);
|
|
|
|
// Only preprocess height layers by default
|
|
_performPreProcessing = _layerGroupID == layers::Group::ID::HeightLayers;
|
|
_performPreProcessing = p.performPreProcessing.value_or(_performPreProcessing);
|
|
|
|
// Get the name of the layergroup to which this layer belongs
|
|
auto it = std::find_if(
|
|
layers::Groups.begin(),
|
|
layers::Groups.end(),
|
|
[id = _layerGroupID](const layers::Group& gi) {
|
|
return gi.id == id;
|
|
}
|
|
);
|
|
|
|
std::string layerGroup =
|
|
it != layers::Groups.end() ?
|
|
std::string(it->name) :
|
|
std::to_string(static_cast<int>(_layerGroupID));
|
|
|
|
std::string identifier = p.identifier.value_or("unspecified");
|
|
std::string enclosing = p.globeName.value_or("unspecified");
|
|
|
|
std::string path = fmt::format("{}/{}/{}/", enclosing, layerGroup, identifier);
|
|
|
|
GlobeBrowsingModule& module = *global::moduleEngine->module<GlobeBrowsingModule>();
|
|
bool enabled = module.isMRFCachingEnabled();
|
|
Compression compression =
|
|
_layerGroupID == layers::Group::ID::HeightLayers ?
|
|
Compression::LERC :
|
|
Compression::JPEG;
|
|
int quality = 75;
|
|
int blockSize = 1024;
|
|
if (p.cacheSettings.has_value()) {
|
|
enabled = p.cacheSettings->enabled.value_or(enabled);
|
|
if (p.cacheSettings->compression.has_value()) {
|
|
compression = codegen::map<Compression>(*p.cacheSettings->compression);
|
|
}
|
|
quality = p.cacheSettings->quality.value_or(quality);
|
|
blockSize = p.cacheSettings->blockSize.value_or(blockSize);
|
|
}
|
|
|
|
_cacheProperties.enabled = enabled;
|
|
_cacheProperties.path = path;
|
|
_cacheProperties.quality = quality;
|
|
_cacheProperties.blockSize = blockSize;
|
|
_cacheProperties.compression = codegen::toString(compression);
|
|
|
|
TileTextureInitData initData(
|
|
tileTextureInitData(_layerGroupID, _padTiles, pixelSize)
|
|
);
|
|
_tilePixelSize = initData.dimensions.x;
|
|
initAsyncTileDataReader(initData, _cacheProperties);
|
|
|
|
addProperty(_filePath);
|
|
addProperty(_tilePixelSize);
|
|
}
|
|
|
|
void DefaultTileProvider::initAsyncTileDataReader(TileTextureInitData initData,
|
|
TileCacheProperties cacheProperties)
|
|
{
|
|
ZoneScoped;
|
|
|
|
_asyncTextureDataProvider = std::make_unique<AsyncTileDataProvider>(
|
|
name,
|
|
std::make_unique<RawTileDataReader>(
|
|
_filePath,
|
|
initData,
|
|
cacheProperties,
|
|
RawTileDataReader::PerformPreprocessing(_performPreProcessing)
|
|
)
|
|
);
|
|
}
|
|
|
|
Tile DefaultTileProvider::tile(const TileIndex& tileIndex) {
|
|
ZoneScoped;
|
|
|
|
ghoul_assert(_asyncTextureDataProvider, "No data provider");
|
|
if (tileIndex.level > maxLevel()) {
|
|
return Tile{ nullptr, std::nullopt, Tile::Status::OutOfRange };
|
|
}
|
|
const cache::ProviderTileKey key = {
|
|
.tileIndex = tileIndex,
|
|
.providerID = uniqueIdentifier
|
|
};
|
|
cache::MemoryAwareTileCache* tileCache =
|
|
global::moduleEngine->module<GlobeBrowsingModule>()->tileCache();
|
|
Tile tile = tileCache->get(key);
|
|
if (!tile.texture) {
|
|
_asyncTextureDataProvider->enqueueTileIO(tileIndex);
|
|
}
|
|
|
|
return tile;
|
|
}
|
|
|
|
Tile::Status DefaultTileProvider::tileStatus(const TileIndex& index) {
|
|
ghoul_assert(_asyncTextureDataProvider, "No data provider");
|
|
const RawTileDataReader& reader = _asyncTextureDataProvider->rawTileDataReader();
|
|
|
|
if (index.level > reader.maxChunkLevel()) {
|
|
return Tile::Status::OutOfRange;
|
|
}
|
|
|
|
const cache::ProviderTileKey key = {
|
|
.tileIndex = index,
|
|
.providerID = uniqueIdentifier
|
|
};
|
|
cache::MemoryAwareTileCache* tileCache =
|
|
global::moduleEngine->module<GlobeBrowsingModule>()->tileCache();
|
|
return tileCache->get(key).status;
|
|
}
|
|
|
|
TileDepthTransform DefaultTileProvider::depthTransform() {
|
|
ghoul_assert(_asyncTextureDataProvider, "No data provider");
|
|
return _asyncTextureDataProvider->rawTileDataReader().depthTransform();
|
|
}
|
|
|
|
void DefaultTileProvider::update() {
|
|
ghoul_assert(_asyncTextureDataProvider, "No data provider");
|
|
_asyncTextureDataProvider->update();
|
|
|
|
std::optional<RawTile> tile = _asyncTextureDataProvider->popFinishedRawTile();
|
|
if (tile) {
|
|
const cache::ProviderTileKey key = {
|
|
.tileIndex = tile->tileIndex,
|
|
.providerID = uniqueIdentifier
|
|
};
|
|
cache::MemoryAwareTileCache* tileCache =
|
|
global::moduleEngine->module<GlobeBrowsingModule>()->tileCache();
|
|
ghoul_assert(!tileCache->exist(key), "Tile must not be existing in cache");
|
|
tileCache->createTileAndPut(key, std::move(*tile));
|
|
}
|
|
|
|
if (_asyncTextureDataProvider->shouldBeDeleted()) {
|
|
initAsyncTileDataReader(
|
|
tileTextureInitData(_layerGroupID, _padTiles, _tilePixelSize),
|
|
_cacheProperties
|
|
);
|
|
}
|
|
}
|
|
|
|
void DefaultTileProvider::reset() {
|
|
global::moduleEngine->module<GlobeBrowsingModule>()->tileCache()->clear();
|
|
ghoul_assert(_asyncTextureDataProvider, "No data provider");
|
|
_asyncTextureDataProvider->prepareToBeDeleted();
|
|
}
|
|
|
|
int DefaultTileProvider::minLevel() {
|
|
ghoul_assert(_asyncTextureDataProvider, "No data provider");
|
|
return 1;
|
|
}
|
|
|
|
int DefaultTileProvider::maxLevel() {
|
|
ghoul_assert(_asyncTextureDataProvider, "No data provider");
|
|
return _asyncTextureDataProvider->rawTileDataReader().maxChunkLevel();
|
|
}
|
|
|
|
float DefaultTileProvider::noDataValueAsFloat() {
|
|
ghoul_assert(_asyncTextureDataProvider, "No data provider");
|
|
return _asyncTextureDataProvider->noDataValueAsFloat();
|
|
}
|
|
|
|
} // namespace openspace::globebrowsing
|