mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-06 19:39:56 -05:00
Add the ability to have fallback textures
This commit is contained in:
@@ -68,6 +68,11 @@ return {
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
{
|
||||
Name = "Earth Bluemarble Height",
|
||||
FilePath = "textures/earth_bluemarble_height.jpg",
|
||||
Enabled = true,
|
||||
},
|
||||
{
|
||||
Name = "ESRI VIIRS Combo",
|
||||
Type = "ByLevelTileLayer",
|
||||
@@ -88,6 +93,11 @@ return {
|
||||
},
|
||||
},
|
||||
Enabled = true,
|
||||
Fallback = {
|
||||
Name = "Blue Marble",
|
||||
FilePath = "textures/earth_bluemarble.jpg",
|
||||
Enabled = true,
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = "BMNG",
|
||||
@@ -131,6 +141,16 @@ return {
|
||||
Gamma = 1.5,
|
||||
Multiplier = 15.0,
|
||||
},
|
||||
Fallback = {
|
||||
Name = "Earth Night",
|
||||
FilePath = "textures/earth_night.jpg",
|
||||
Enabled = true,
|
||||
Settings = {
|
||||
Opacity = 1.0,
|
||||
Gamma = 1.5,
|
||||
Multiplier = 15.0,
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
Type = "TemporalTileLayer",
|
||||
@@ -143,6 +163,11 @@ return {
|
||||
Name = "MODIS_Water_Mask",
|
||||
FilePath = "map_service_configs/GIBS/MODIS_Water_Mask.xml",
|
||||
Enabled = true,
|
||||
Fallback = {
|
||||
Name = "Earth Reflectance",
|
||||
FilePath = "textures/earth_reflectance.jpg",
|
||||
Enabled = true,
|
||||
}
|
||||
},
|
||||
{
|
||||
Name = "GEBCO",
|
||||
@@ -178,6 +203,11 @@ return {
|
||||
FilePath = "map_service_configs/ESRI/TERRAIN.wms",
|
||||
Enabled = true,
|
||||
TilePixelSize = 64,
|
||||
Fallback = {
|
||||
Name = "Earth Bluemarble Height",
|
||||
FilePath = "textures/earth_bluemarble_height.jpg",
|
||||
Enabled = true,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
namespace {
|
||||
const char* _loggerCat = "LayerGroup";
|
||||
|
||||
const char* KeyFallback = "Fallback";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
@@ -53,6 +55,19 @@ LayerGroup::LayerGroup(layergroupid::GroupID id, const ghoul::Dictionary& dict)
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC(e.component, e.message);
|
||||
|
||||
if (layerDict.hasKeyAndValue<ghoul::Dictionary>(KeyFallback)) {
|
||||
LWARNING("Unable to create layer. Initializing fallback layer.");
|
||||
ghoul::Dictionary fallbackLayerDict =
|
||||
layerDict.value<ghoul::Dictionary>(KeyFallback);
|
||||
try {
|
||||
addLayer(fallbackLayerDict);
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC(e.component, e.message);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,18 +124,12 @@ void RawTileDataReader::readImageData(
|
||||
static_cast<int>(_initData.nRasters()));
|
||||
|
||||
switch (_initData.ghoulTextureFormat()) {
|
||||
case ghoul::opengl::Texture::Format::Red:
|
||||
if (nRastersToRead == 1) { // One channel
|
||||
// The final destination pointer is offsetted by one datum byte size
|
||||
// for every raster (or data channel, i.e. R in RGB)
|
||||
char* dataDestination = imageDataDest + _initData.bytesPerDatum();
|
||||
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
|
||||
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
|
||||
worstError = std::max(worstError, err);
|
||||
}
|
||||
case ghoul::opengl::Texture::Format::Red: {
|
||||
char* dataDestination = imageDataDest;
|
||||
RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination);
|
||||
worstError = std::max(worstError, err);
|
||||
break;
|
||||
}
|
||||
case ghoul::opengl::Texture::Format::RG:
|
||||
case ghoul::opengl::Texture::Format::RGB:
|
||||
case ghoul::opengl::Texture::Format::RGBA: {
|
||||
|
||||
@@ -135,6 +135,9 @@ RawTile::ReadError SimpleRawTileDataReader::rasterRead(
|
||||
|
||||
glm::vec4 sourceTexel = _dataTexture->texelAsFloat(xInSource, yInSource);
|
||||
|
||||
// Different type reinterpreting depending on the type of the target texture
|
||||
// the _initData.glType() does not necessarily have to be the same type as
|
||||
// the type of the source texture. Therefore the value is cast to float first.
|
||||
switch (_initData.glType()) {
|
||||
case GL_UNSIGNED_BYTE: {
|
||||
unsigned char value = static_cast<unsigned char>(
|
||||
@@ -146,7 +149,7 @@ RawTile::ReadError SimpleRawTileDataReader::rasterRead(
|
||||
}
|
||||
case GL_BYTE: {
|
||||
char value = static_cast<char>(
|
||||
sourceTexel[rasterBand - 1]
|
||||
sourceTexel[rasterBand - 1] * 255
|
||||
);
|
||||
char* bytes = reinterpret_cast<char*>(&value);
|
||||
*pixelWriteDestination = *bytes;
|
||||
@@ -154,7 +157,7 @@ RawTile::ReadError SimpleRawTileDataReader::rasterRead(
|
||||
}
|
||||
case GL_UNSIGNED_SHORT: {
|
||||
unsigned short value = static_cast<unsigned short>(
|
||||
sourceTexel[rasterBand - 1]
|
||||
sourceTexel[rasterBand - 1] * 65535
|
||||
);
|
||||
char* bytes = reinterpret_cast<char*>(&value);
|
||||
*pixelWriteDestination = *bytes;
|
||||
@@ -162,7 +165,7 @@ RawTile::ReadError SimpleRawTileDataReader::rasterRead(
|
||||
}
|
||||
case GL_SHORT: {
|
||||
short value = static_cast<short>(
|
||||
sourceTexel[rasterBand - 1]
|
||||
sourceTexel[rasterBand - 1] * 65535
|
||||
);
|
||||
char* bytes = reinterpret_cast<char*>(&value);
|
||||
*pixelWriteDestination = *bytes;
|
||||
@@ -170,7 +173,7 @@ RawTile::ReadError SimpleRawTileDataReader::rasterRead(
|
||||
}
|
||||
case GL_UNSIGNED_INT: {
|
||||
unsigned int value = static_cast<unsigned int>(
|
||||
sourceTexel[rasterBand - 1]
|
||||
sourceTexel[rasterBand - 1] * 4294967295
|
||||
);
|
||||
char* bytes = reinterpret_cast<char*>(&value);
|
||||
*pixelWriteDestination = *bytes;
|
||||
@@ -178,14 +181,14 @@ RawTile::ReadError SimpleRawTileDataReader::rasterRead(
|
||||
}
|
||||
case GL_INT: {
|
||||
int value = static_cast<int>(
|
||||
sourceTexel[rasterBand - 1]
|
||||
sourceTexel[rasterBand - 1] * 4294967295
|
||||
);
|
||||
char* bytes = reinterpret_cast<char*>(&value);
|
||||
*pixelWriteDestination = *bytes;
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT: {
|
||||
float value = sourceTexel[rasterBand - 1];
|
||||
GLfloat value = sourceTexel[rasterBand - 1];
|
||||
char* bytes = reinterpret_cast<char*>(&value);
|
||||
*pixelWriteDestination = *bytes;
|
||||
break;
|
||||
|
||||
@@ -54,62 +54,57 @@ TileProviderByLevel::TileProviderByLevel(const ghoul::Dictionary& dictionary)
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < providers.size(); i++) {
|
||||
try {
|
||||
std::string dictKey = std::to_string(i + 1);
|
||||
ghoul::Dictionary levelProviderDict = providers.value<ghoul::Dictionary>(
|
||||
dictKey
|
||||
std::string dictKey = std::to_string(i + 1);
|
||||
ghoul::Dictionary levelProviderDict = providers.value<ghoul::Dictionary>(
|
||||
dictKey
|
||||
);
|
||||
double floatMaxLevel;
|
||||
int maxLevel = 0;
|
||||
if (!levelProviderDict.getValue<double>(KeyMaxLevel, floatMaxLevel)) {
|
||||
throw std::runtime_error(
|
||||
"Must define key '" + std::string(KeyMaxLevel) + "'"
|
||||
);
|
||||
double floatMaxLevel;
|
||||
int maxLevel = 0;
|
||||
if (!levelProviderDict.getValue<double>(KeyMaxLevel, floatMaxLevel)) {
|
||||
throw std::runtime_error(
|
||||
"Must define key '" + std::string(KeyMaxLevel) + "'"
|
||||
);
|
||||
}
|
||||
maxLevel = std::round(floatMaxLevel);
|
||||
|
||||
ghoul::Dictionary providerDict;
|
||||
if (!levelProviderDict.getValue<ghoul::Dictionary>(KeyTileProvider, providerDict)) {
|
||||
throw std::runtime_error(
|
||||
"Must define key '" + std::string(KeyTileProvider) + "'"
|
||||
);
|
||||
}
|
||||
providerDict.setValue(KeyLayerGroupID, layerGroupID);
|
||||
|
||||
std::string typeString;
|
||||
providerDict.getValue("Type", typeString);
|
||||
layergroupid::TypeID typeID = layergroupid::TypeID::Unknown;
|
||||
if (typeString.empty()) {
|
||||
typeID = layergroupid::TypeID::DefaultTileLayer;
|
||||
}
|
||||
else {
|
||||
typeID = layergroupid::getTypeIDFromTypeString(typeString);
|
||||
}
|
||||
|
||||
if (typeID == layergroupid::TypeID::Unknown) {
|
||||
throw ghoul::RuntimeError("Unknown layer type: " + typeString);
|
||||
}
|
||||
|
||||
_levelTileProviders.push_back(
|
||||
std::shared_ptr<TileProvider>(TileProvider::createFromDictionary(typeID, providerDict))
|
||||
);
|
||||
|
||||
std::string providerName;
|
||||
providerDict.getValue("Name", providerName);
|
||||
_levelTileProviders.back()->setName(providerName);
|
||||
addPropertySubOwner(_levelTileProviders.back().get());
|
||||
|
||||
// Ensure we can represent the max level
|
||||
if(static_cast<int>(_providerIndices.size()) < maxLevel){
|
||||
_providerIndices.resize(maxLevel+1, -1);
|
||||
}
|
||||
|
||||
// map this level to the tile provider index
|
||||
_providerIndices[maxLevel] = _levelTileProviders.size() - 1;
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LWARNING("Unable to create tile provider: " + std::string(e.what()));
|
||||
}
|
||||
maxLevel = std::round(floatMaxLevel);
|
||||
|
||||
ghoul::Dictionary providerDict;
|
||||
if (!levelProviderDict.getValue<ghoul::Dictionary>(KeyTileProvider, providerDict)) {
|
||||
throw std::runtime_error(
|
||||
"Must define key '" + std::string(KeyTileProvider) + "'"
|
||||
);
|
||||
}
|
||||
providerDict.setValue(KeyLayerGroupID, layerGroupID);
|
||||
|
||||
std::string typeString;
|
||||
providerDict.getValue("Type", typeString);
|
||||
layergroupid::TypeID typeID = layergroupid::TypeID::Unknown;
|
||||
if (typeString.empty()) {
|
||||
typeID = layergroupid::TypeID::DefaultTileLayer;
|
||||
}
|
||||
else {
|
||||
typeID = layergroupid::getTypeIDFromTypeString(typeString);
|
||||
}
|
||||
|
||||
if (typeID == layergroupid::TypeID::Unknown) {
|
||||
throw ghoul::RuntimeError("Unknown layer type: " + typeString);
|
||||
}
|
||||
|
||||
_levelTileProviders.push_back(
|
||||
std::shared_ptr<TileProvider>(TileProvider::createFromDictionary(typeID, providerDict))
|
||||
);
|
||||
|
||||
std::string providerName;
|
||||
providerDict.getValue("Name", providerName);
|
||||
_levelTileProviders.back()->setName(providerName);
|
||||
addPropertySubOwner(_levelTileProviders.back().get());
|
||||
|
||||
// Ensure we can represent the max level
|
||||
if(static_cast<int>(_providerIndices.size()) < maxLevel){
|
||||
_providerIndices.resize(maxLevel+1, -1);
|
||||
}
|
||||
|
||||
// map this level to the tile provider index
|
||||
_providerIndices[maxLevel] = _levelTileProviders.size() - 1;
|
||||
}
|
||||
|
||||
// Fill in the gaps (value -1) in provider indices, from back to end
|
||||
|
||||
Reference in New Issue
Block a user