Add the ability to have fallback textures

This commit is contained in:
Kalle Bladin
2017-07-13 23:49:39 +02:00
parent c22d1e3df4
commit 28a6365aa2
5 changed files with 108 additions and 71 deletions
+30
View File
@@ -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