Merge branch 'master' into feature/horizons-framework

This commit is contained in:
Malin Ejdbo
2022-01-17 17:07:40 +01:00
46 changed files with 3061 additions and 2496 deletions
@@ -7,28 +7,46 @@ local path = asset.syncedResource({
Version = 1
})
local layer = {
Identifier = "ERA5_Land_HighRes_Monthly_2M_Temperature_Temporal",
Name = "ERA5 Land HighRes Monthly 2M Temperature (Temporal)",
local layer_prototype = {
Identifier = "ERA5_Land_HighRes_Monthly_2M_Temperature_Temporal_prototype",
Name = "ERA5 Land HighRes Monthly 2M Temperature (Temporal) [Prototype]",
Type = "TemporalTileLayer",
FilePath =
"<OpenSpaceTemporalGDALDataset>" ..
"<OpenSpaceTimeStart>1981-01-01</OpenSpaceTimeStart>" ..
"<OpenSpaceTimeEnd>1990-10-01</OpenSpaceTimeEnd>" ..
"<OpenSpaceTimeResolution>1M</OpenSpaceTimeResolution>" ..
"<OpenSpaceTimeIdFormat>YYYY-MM-DD</OpenSpaceTimeIdFormat>" ..
"<OpenSpaceTransferFunction>" .. path .. "rainbow.png</OpenSpaceTransferFunction>" ..
"<OpenSpaceTimeInterpolation>linear</OpenSpaceTimeInterpolation>" ..
"<FilePath>" .. path .. "${OpenSpaceTimeId}-land.png</FilePath>" ..
"</OpenSpaceTemporalGDALDataset>",
Mode = "Prototyped",
Prototyped = {
Time = {
Start = "1981-01-01",
End = "1990-10-01"
},
TemporalResolution = "1M",
TimeFormat = "YYYY-MM-DD",
Prototype = path .. "${OpenSpaceTimeId}-land.png"
},
Interpolation = true,
Colormap = path .. "rainbow.png",
Description = [[ Temporal coverage: 01 Jan 1981 - 31 Dec 2020.]]
}
local layer_folder = {
Identifier = "ERA5_Land_HighRes_Monthly_2M_Temperature_Temporal_folder",
Name = "ERA5 Land HighRes Monthly 2M Temperature (Temporal) [Folder]",
Type = "TemporalTileLayer",
Mode = "Folder",
Folder = {
Folder = "C:/Development/sync/http/earth_textures_climate/1",
Format = "%Y-%m-%d-land.png"
},
Interpolation = true,
Colormap = path .. "rainbow.png",
Description = [[ Temporal coverage: 01 Jan 1981 - 31 Dec 2020.]]
}
asset.onInitialize(function ()
openspace.globebrowsing.addLayer(globeIdentifier, "ColorLayers", layer)
openspace.globebrowsing.addLayer(globeIdentifier, "ColorLayers", layer_prototype)
openspace.globebrowsing.addLayer(globeIdentifier, "ColorLayers", layer_folder)
end)
asset.export("layer", layer)
asset.export("layer", layer_prototype)
asset.meta = {
Name = "Climate Earth Layers",
Version = "1.0",
@@ -4,14 +4,20 @@ local layer = {
Identifier = "AMSR2_GCOM_W1_Sea_Ice_Concentration_Temporal",
Name = "AMSR2 GCOM W1 Sea Ice Concentration (Temporal)",
Type = "TemporalTileLayer",
FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(
"AMSRU2_Sea_Ice_Concentration_12km",
"2012-05-08",
"Yesterday",
"1d",
"2km",
"png"
),
Mode = "Prototyped",
Prototyped = {
Time = {
Start = "2012-05-08",
End = "Yesterday"
},
TemporalResolution = "1d",
TimeFormat = "YYYY-MM-DD",
Prototype = openspace.globebrowsing.createTemporalGibsGdalXml(
"AMSRU2_Sea_Ice_Concentration_12km",
"2km",
"png"
)
},
Description = [[ Temporal coverage: 02 July 2012 - Present. The Advanced Microwave
Scanning Radiometer-E/Advanced Microwave Scanning Radiometer-2 (AMSR-E/AMSR2)
unified "Sea Ice Concentration (12 km)" layer displays the percent of sea ice
@@ -4,14 +4,20 @@ local layer = {
Identifier = "Aqua_Modis_Temporal",
Name = "Aqua Modis (Temporal)",
Type = "TemporalTileLayer",
FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(
"MODIS_Aqua_CorrectedReflectance_TrueColor",
"2002-07-04",
"Yesterday",
"1d",
"250m",
"jpg"
),
Mode = "Prototyped",
Prototyped = {
Time = {
Start = "2002-07-04",
End = "Yesterday"
},
TemporalResolution = "1d",
TimeFormat = "YYYY-MM-DD",
Prototype = openspace.globebrowsing.createTemporalGibsGdalXml(
"MODIS_Aqua_CorrectedReflectance_TrueColor",
"250m",
"jpg"
)
},
Description = [[ Temporal coverage: 03 July 2002 - Present. True Color: Red = Band 1,
Green = Band 4, Blue = Band 3. These images are called true-color or natural color
because this combination of wavelengths is similar to what the human eye would see.
@@ -13,14 +13,20 @@ local layer = {
Identifier = "Temporal_VIIRS_SNPP",
Name = "Temporal VIIRS SNPP",
Type = "TemporalTileLayer",
FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(
"VIIRS_SNPP_CorrectedReflectance_TrueColor",
"2015-11-24",
"Today",
"1d",
"250m",
"jpg"
),
Mode = "Prototyped",
Prototyped = {
Time = {
Start = "2015-11-24",
End = "Today"
},
TemporalResolution = "1d",
TimeFormat = "YYYY-MM-DD",
Prototype = openspace.globebrowsing.createTemporalGibsGdalXml(
"VIIRS_SNPP_CorrectedReflectance_TrueColor",
"250m",
"jpg"
)
},
PadTiles = false
}
},
@@ -4,14 +4,20 @@ local layer = {
Identifier = "GHRSST_L4_G1SST_Sea_Surface_Temperature_Temporal",
Name = "GHRSST L4 G1SST Sea Surface Temperature (Temporal)",
Type = "TemporalTileLayer",
FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(
"GHRSST_L4_G1SST_Sea_Surface_Temperature",
"2010-06-21",
"2019-12-08",
"1d",
"1km",
"png"
),
Mode = "Prototyped",
Prototyped = {
Time = {
Start = "2010-06-21",
End = "2019-12-08"
},
TemporalResolution = "1d",
TimeFormat = "YYYY-MM-DD",
Prototype = openspace.globebrowsing.createTemporalGibsGdalXml(
"GHRSST_L4_G1SST_Sea_Surface_Temperature",
"1km",
"png"
)
},
Description = [[ Temporal coverage: 21 June 2010 - 08 December 2019. The imagery
resolution is 1 km, and the temporal resolution is daily.]],
Author = "NASA EOSDIS Global Imagery Browse Services"
@@ -4,14 +4,20 @@ local layer = {
Identifier = "GHRSST_L4_MUR_Sea_Surface_Temperature_Temporal",
Name = "GHRSST L4 MUR Sea Surface Temperature (Temporal)",
Type = "TemporalTileLayer",
FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(
"GHRSST_L4_MUR_Sea_Surface_Temperature",
"2002-06-01",
"Yesterday",
"1d",
"1km",
"png"
),
Mode = "Prototyped",
Prototyped = {
Time = {
Start = "2002-06-01",
End = "Yesterday"
},
TemporalResolution = "1d",
TimeFormat = "YYYY-MM-DD",
Prototype = openspace.globebrowsing.createTemporalGibsGdalXml(
"GHRSST_L4_MUR_Sea_Surface_Temperature",
"1km",
"png"
)
},
Description = [[ Temporal coverage: 01 June 2002 - Present. The imagery resolution
is 1 km, and the temporal resolution is daily.]]
}
@@ -4,14 +4,20 @@ local layer = {
Identifier = "MODIS_Terra_Chlorophyll_A_Temporal",
Name = "MODIS Terra Chlorophyll A (Temporal)",
Type = "TemporalTileLayer",
FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(
Mode = "Prototyped",
Prototyped = {
Time = {
Start = "2013-07-02",
End = "Yesterday"
},
TemporalResolution = "1d",
TimeFormat = "YYYY-MM-DD",
Prototype = openspace.globebrowsing.createTemporalGibsGdalXml(
"MODIS_Terra_Chlorophyll_A",
"2013-07-02",
"Yesterday",
"1d",
"1km",
"png"
),
)
},
Description = [[ Temporal coverage: 02 July 2013 - Present. The imagery resolution
is 1 km, and the temporal resolution is daily.]]
}
@@ -4,14 +4,20 @@ local layer = {
Identifier = "Terra_Modis_Temporal",
Name = "Terra Modis (Temporal)",
Type = "TemporalTileLayer",
FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(
"MODIS_Terra_CorrectedReflectance_TrueColor",
"2000-02-24",
"Yesterday",
"1d",
"250m",
"jpg"
),
Mode = "Prototyped",
Prototyped = {
Time = {
Start = "2000-02-24",
End = "Yesterday"
},
TemporalResolution = "1d",
TimeFormat = "YYYY-MM-DD",
Prototype = openspace.globebrowsing.createTemporalGibsGdalXml(
"MODIS_Terra_CorrectedReflectance_TrueColor",
"250m",
"jpg"
)
},
Description = [[ Temporal coverage: 02 July 2013 - Present. The imagery resolution
is 1 km, and the temporal resolution is daily.]]
}
@@ -4,14 +4,20 @@ local layer = {
Identifier = "VIIRS_SNPP_Temporal",
Name = "VIIRS SNPP (Temporal)",
Type = "TemporalTileLayer",
FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(
"VIIRS_SNPP_CorrectedReflectance_TrueColor",
"2015-11-24",
"Yesterday",
"1d",
"250m",
"jpg"
),
Mode = "Prototyped",
Prototyped = {
Time = {
Start = "2015-11-24",
End = "Yesterday"
},
TemporalResolution = "1d",
TimeFormat = "YYYY-MM-DD",
Prototype = openspace.globebrowsing.createTemporalGibsGdalXml(
"VIIRS_SNPP_CorrectedReflectance_TrueColor",
"250m",
"jpg"
)
},
Description = [[ Temporal coverage: 11 November 2015 - Present. The imagery resolution
is 0.25 km, and the temporal resolution is daily.]]
}
@@ -4,14 +4,20 @@ local layer = {
Identifier = "Earth_at_Night_Temporal",
Name = "Earth at Night (Temporal)",
Type = "TemporalTileLayer",
FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(
"VIIRS_SNPP_DayNightBand_ENCC",
"2012-05-08",
"Yesterday",
"1d",
"500m",
"png"
),
Mode = "Prototyped",
Prototyped = {
Time = {
Start = "2012-05-08",
End = "Yesterday"
},
TemporalResolution = "1d",
TimeFormat = "YYYY-MM-DD",
Prototype = openspace.globebrowsing.createTemporalGibsGdalXml(
"VIIRS_SNPP_DayNightBand_ENCC",
"500m",
"png"
)
},
Description = [[ The VIIRS Nighttime Imagery (Day/Night Band, Enhanced Near Constant
Contrast) layer shows the Earth's surface and atmosphere using a sensor designed
to capture low-light emission sources, under varying illumination conditions. It
+20 -2
View File
@@ -57,9 +57,18 @@ set(HEADER_FILES
src/skirtedgrid.h
src/tileindex.h
src/tileloadjob.h
src/tileprovider.h
src/tiletextureinitdata.h
src/timequantizer.h
src/tileprovider/defaulttileprovider.h
src/tileprovider/imagesequencetileprovider.h
src/tileprovider/singleimagetileprovider.h
src/tileprovider/sizereferencetileprovider.h
src/tileprovider/temporaltileprovider.h
src/tileprovider/texttileprovider.h
src/tileprovider/tileindextileprovider.h
src/tileprovider/tileprovider.h
src/tileprovider/tileproviderbyindex.h
src/tileprovider/tileproviderbylevel.h
)
set(SOURCE_FILES
@@ -87,9 +96,18 @@ set(SOURCE_FILES
src/skirtedgrid.cpp
src/tileindex.cpp
src/tileloadjob.cpp
src/tileprovider.cpp
src/tiletextureinitdata.cpp
src/timequantizer.cpp
src/tileprovider/defaulttileprovider.cpp
src/tileprovider/imagesequencetileprovider.cpp
src/tileprovider/singleimagetileprovider.cpp
src/tileprovider/sizereferencetileprovider.cpp
src/tileprovider/temporaltileprovider.cpp
src/tileprovider/texttileprovider.cpp
src/tileprovider/tileindextileprovider.cpp
src/tileprovider/tileprovider.cpp
src/tileprovider/tileproviderbyindex.cpp
src/tileprovider/tileproviderbylevel.cpp
)
source_group("Source Files" FILES ${SOURCE_FILES})
+20 -14
View File
@@ -35,7 +35,15 @@
#include <modules/globebrowsing/src/layeradjustment.h>
#include <modules/globebrowsing/src/layermanager.h>
#include <modules/globebrowsing/src/memoryawaretilecache.h>
#include <modules/globebrowsing/src/tileprovider.h>
#include <modules/globebrowsing/src/tileprovider/defaulttileprovider.h>
#include <modules/globebrowsing/src/tileprovider/imagesequencetileprovider.h>
#include <modules/globebrowsing/src/tileprovider/singleimagetileprovider.h>
#include <modules/globebrowsing/src/tileprovider/sizereferencetileprovider.h>
#include <modules/globebrowsing/src/tileprovider/temporaltileprovider.h>
#include <modules/globebrowsing/src/tileprovider/tileindextileprovider.h>
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
#include <modules/globebrowsing/src/tileprovider/tileproviderbyindex.h>
#include <modules/globebrowsing/src/tileprovider/tileproviderbylevel.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globalscallbacks.h>
#include <openspace/navigation/navigationhandler.h>
@@ -236,7 +244,7 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) {
_tileCache = std::make_unique<cache::MemoryAwareTileCache>(_tileCacheSizeMB);
addPropertySubOwner(_tileCache.get());
tileprovider::initializeDefaultTile();
TileProvider::initializeDefaultTile();
// Convert from MB to Bytes
GdalWrapper::create(
@@ -249,10 +257,9 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) {
global::callback::deinitializeGL->emplace_back([]() {
ZoneScopedN("GlobeBrowsingModule")
tileprovider::deinitializeDefaultTile();
TileProvider::deinitializeDefaultTile();
});
// Render
global::callback::render->emplace_back([&]() {
ZoneScopedN("GlobeBrowsingModule")
@@ -279,46 +286,45 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) {
ghoul_assert(fRotation, "Rotation factory was not created");
fRotation->registerClass<globebrowsing::GlobeRotation>("GlobeRotation");
auto fTileProvider =
std::make_unique<ghoul::TemplateFactory<tileprovider::TileProvider>>();
auto fTileProvider = std::make_unique<ghoul::TemplateFactory<TileProvider>>();
ghoul_assert(fTileProvider, "TileProvider factory was not created");
fTileProvider->registerClass<tileprovider::DefaultTileProvider>(
fTileProvider->registerClass<DefaultTileProvider>(
layergroupid::LAYER_TYPE_NAMES[static_cast<int>(
layergroupid::TypeID::DefaultTileLayer
)]
);
fTileProvider->registerClass<tileprovider::SingleImageProvider>(
fTileProvider->registerClass<SingleImageProvider>(
layergroupid::LAYER_TYPE_NAMES[static_cast<int>(
layergroupid::TypeID::SingleImageTileLayer
)]
);
fTileProvider->registerClass<tileprovider::ImageSequenceTileProvider>(
fTileProvider->registerClass<ImageSequenceTileProvider>(
layergroupid::LAYER_TYPE_NAMES[static_cast<int>(
layergroupid::TypeID::ImageSequenceTileLayer
)]
);
fTileProvider->registerClass<tileprovider::TemporalTileProvider>(
fTileProvider->registerClass<TemporalTileProvider>(
layergroupid::LAYER_TYPE_NAMES[static_cast<int>(
layergroupid::TypeID::TemporalTileLayer
)]
);
fTileProvider->registerClass<tileprovider::TileIndexTileProvider>(
fTileProvider->registerClass<TileIndexTileProvider>(
layergroupid::LAYER_TYPE_NAMES[static_cast<int>(
layergroupid::TypeID::TileIndexTileLayer
)]
);
fTileProvider->registerClass<tileprovider::SizeReferenceTileProvider>(
fTileProvider->registerClass<SizeReferenceTileProvider>(
layergroupid::LAYER_TYPE_NAMES[static_cast<int>(
layergroupid::TypeID::SizeReferenceTileLayer
)]
);
fTileProvider->registerClass<tileprovider::TileProviderByLevel>(
fTileProvider->registerClass<TileProviderByLevel>(
layergroupid::LAYER_TYPE_NAMES[static_cast<int>(
layergroupid::TypeID::ByLevelTileLayer
)]
);
fTileProvider->registerClass<tileprovider::TileProviderByIndex>(
fTileProvider->registerClass<TileProviderByIndex>(
layergroupid::LAYER_TYPE_NAMES[static_cast<int>(
layergroupid::TypeID::ByIndexTileLayer
)]
+30 -39
View File
@@ -1,30 +1,11 @@
openspace.globebrowsing.documentation = {
{
Name = "createTemporalGibsGdalXml",
Arguments = "string, string, string, string, string, string, [string]",
Documentation =
"Creates an XML configuration for a temporal GIBS dataset." ..
"Arguments are: Name, Start date, end date, time resolution, time format," ..
"resolution, file format. The last parameter is the temporal format and " ..
"defaults to YYYY-MM-DD. For all specifications, see " ..
"https://wiki.earthdata.nasa.gov/display/GIBS/GIBS+Available+Imagery+Products" ..
"Usage:" ..
"openspace.globebrowsing.addLayer(" ..
"\"Earth\"," ..
"\"ColorLayers\"," ..
"{" ..
"Type = \"TemporalTileLayer\"," ..
"Name = \"MODIS_Terra_Chlorophyll_A\"," ..
"FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(" ..
"\"MODIS_Terra_Chlorophyll_A\"," ..
"\"2013-07-02\"," ..
"\"Yesterday\"," ..
"\"1d\"," ..
"\"1km\"," ..
"\"png\"" ..
")" ..
"}" ..
")"
Arguments = "string, string, string",
Documentation = [[
Creates an XML configuration for a temporal GIBS dataset to be used in
a TemporalTileprovider
]]
},
{
Name = "createGibsGdalXml",
@@ -40,7 +21,7 @@ openspace.globebrowsing.documentation = {
"\"ColorLayers\"," ..
"{" ..
"Name = \"MODIS_Terra_Chlorophyll_A\"," ..
"FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(" ..
"FilePath = openspace.globebrowsing.createGibsGdalXml(" ..
"\"MODIS_Terra_Chlorophyll_A\"," ..
"\"2013-07-02\"," ..
"\"1km\"," ..
@@ -111,21 +92,27 @@ openspace.globebrowsing.addGibsLayer = function(layer, resolution, format, start
if endDate == 'Present' then
endDate = ''
end
local xml = openspace.globebrowsing.createTemporalGibsGdalXml(layer, startDate, endDate, '1d', resolution, format)
openspace.globebrowsing.addLayer('Earth', 'ColorLayers', { Identifier = layer, Type = "TemporalTileLayer", FilePath = xml })
end
openspace.globebrowsing.createTemporalGibsGdalXml = function (layerName, startDate, endDate, timeResolution, resolution, format, temporalFormat)
temporalFormat = temporalFormat or 'YYYY-MM-DD'
local temporalTemplate =
"<OpenSpaceTemporalGDALDataset>" ..
"<OpenSpaceTimeStart>" .. startDate .. "</OpenSpaceTimeStart>" ..
"<OpenSpaceTimeEnd>" .. endDate .. "</OpenSpaceTimeEnd>" ..
"<OpenSpaceTimeResolution>" .. timeResolution .. "</OpenSpaceTimeResolution>" ..
"<OpenSpaceTimeIdFormat>" .. temporalFormat .. "</OpenSpaceTimeIdFormat>" ..
openspace.globebrowsing.createGibsGdalXml(layerName, "${OpenSpaceTimeId}", resolution, format) ..
"</OpenSpaceTemporalGDALDataset>"
return temporalTemplate
local layer = {
Identifier = layerName,
Type = "TemporalTileLayer",
Mode = "Prototyped",
Prototyped = {
Time = {
Start = startDate,
End = endDate
},
TemporalResolution = "1d",
TimeFormat = "YYYY-MM-DD",
Prototype = openspace.globebrowsing.createTemporalGibsGdalXml(layerName, resolution, format)
}
}
openspace.globebrowsing.addLayer(
'Earth',
'ColorLayers',
layer
)
end
openspace.globebrowsing.createGibsGdalXml = function (layerName, date, resolution, format)
@@ -196,6 +183,10 @@ openspace.globebrowsing.createGibsGdalXml = function (layerName, date, resolutio
return gdalWmsTemplate
end
openspace.globebrowsing.createTemporalGibsGdalXml = function (layerName, resolution, format)
return openspace.globebrowsing.createGibsGdalXml(layerName, "${OpenSpaceTimeId}", resolution, format)
end
openspace.globebrowsing.parseInfoFile = function (file)
-- We are loading these values from an external info file and since we are switching
-- to a strict Lua, we need to predefine these global variables
@@ -26,25 +26,23 @@
uniform sampler2D prevTexture;
uniform sampler2D nextTexture;
uniform sampler2D colormapTexture;
uniform sampler1D colormapTexture;
uniform float blendFactor;
in vec2 texCoord;
Fragment getFragment() {
vec4 texel0 = texture2D(prevTexture, texCoord);
vec4 texel1 = texture2D(nextTexture, texCoord);
vec4 texel0 = texture(prevTexture, texCoord);
vec4 texel1 = texture(nextTexture, texCoord);
vec4 mixedTexture = mix(texel0, texel1, blendFactor);
Fragment frag;
if (mixedTexture.r > 0.999) {
vec2 position = vec2(mixedTexture.r - 0.01, 0.5);
frag.color = texture2D(colormapTexture, position);
frag.color = texture(colormapTexture, mixedTexture.r - 0.01);
}
else {
vec2 position = vec2(mixedTexture.r , 0.5);
frag.color = texture2D(colormapTexture, position);
frag.color = texture(colormapTexture, mixedTexture.r);
}
frag.color.a = mixedTexture.a;
@@ -50,8 +50,6 @@ AsyncTileDataProvider::AsyncTileDataProvider(std::string name,
performReset(ResetRawTileDataReader::No);
}
AsyncTileDataProvider::~AsyncTileDataProvider() {} // NOLINT
const RawTileDataReader& AsyncTileDataProvider::rawTileDataReader() const {
return *_rawTileDataReader;
}
@@ -50,8 +50,6 @@ public:
AsyncTileDataProvider(std::string name,
std::unique_ptr<RawTileDataReader> rawTileDataReader);
~AsyncTileDataProvider();
/**
* Creates a job which asynchronously loads a raw tile. This job is enqueued.
*/
+2 -4
View File
@@ -115,9 +115,8 @@ struct TileMetaData {
class Tile {
public:
/**
* Describe if this Tile is good for usage (OK) or otherwise
* the reason why it is not.
*/
* Describe if this Tile is good for usage (OK) or otherwise the reason why it is not.
*/
enum class Status {
/**
* E.g when texture data is not currently in memory.
@@ -168,7 +167,6 @@ struct ChunkTile {
//using ChunkTilePile = std::vector<ChunkTile>;
// The ChunkTilePile either contains 1 or 3 ChunkTile, depending on if layer-blending is
// enabled. If it is enabled, we need the two adjacent levels, if it is not enabled, only
// the current layer is needed
+10 -10
View File
@@ -286,13 +286,13 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict,
_reset.onChange([&]() {
if (_tileProvider) {
tileprovider::reset(*_tileProvider);
_tileProvider->reset();
}
});
_remove.onChange([&]() {
if (_tileProvider) {
tileprovider::reset(*_tileProvider);
_tileProvider->reset();
_parent.deleteLayer(identifier());
}
});
@@ -360,13 +360,13 @@ void Layer::initialize() {
ZoneScoped
if (_tileProvider) {
tileprovider::initialize(*_tileProvider);
_tileProvider->initialize();
}
}
void Layer::deinitialize() {
if (_tileProvider) {
tileprovider::deinitialize(*_tileProvider);
_tileProvider->deinitialize();
}
}
@@ -374,7 +374,7 @@ ChunkTilePile Layer::chunkTilePile(const TileIndex& tileIndex, int pileSize) con
ZoneScoped
if (_tileProvider) {
return tileprovider::chunkTilePile(*_tileProvider, tileIndex, pileSize);
return _tileProvider->chunkTilePile(tileIndex, pileSize);
}
else {
ChunkTilePile chunkTilePile;
@@ -390,7 +390,7 @@ ChunkTilePile Layer::chunkTilePile(const TileIndex& tileIndex, int pileSize) con
Tile::Status Layer::tileStatus(const TileIndex& index) const {
return _tileProvider ?
tileprovider::tileStatus(*_tileProvider, index) :
_tileProvider->tileStatus(index) :
Tile::Status::Unavailable;
}
@@ -404,7 +404,7 @@ layergroupid::BlendModeID Layer::blendMode() const {
TileDepthTransform Layer::depthTransform() const {
return _tileProvider ?
tileprovider::depthTransform(*_tileProvider) :
_tileProvider->depthTransform() :
TileDepthTransform{ 1.f, 0.f };
}
@@ -416,7 +416,7 @@ bool Layer::enabled() const {
return _enabled;
}
tileprovider::TileProvider* Layer::tileProvider() const {
TileProvider* Layer::tileProvider() const {
return _tileProvider.get();
}
@@ -440,7 +440,7 @@ void Layer::update() {
ZoneScoped
if (_tileProvider) {
tileprovider::update(*_tileProvider);
_tileProvider->update();
}
}
@@ -483,7 +483,7 @@ void Layer::initializeBasedOnType(layergroupid::TypeID id, ghoul::Dictionary ini
std::string name = initDict.value<std::string>(KeyName);
LDEBUG("Initializing tile provider for layer: '" + name + "'");
}
_tileProvider = tileprovider::createFromDictionary(id, std::move(initDict));
_tileProvider = TileProvider::createFromDictionary(id, std::move(initDict));
break;
}
case layergroupid::TypeID::SolidColor: {
+4 -5
View File
@@ -30,7 +30,7 @@
#include <modules/globebrowsing/src/basictypes.h>
#include <modules/globebrowsing/src/layeradjustment.h>
#include <modules/globebrowsing/src/layerrendersettings.h>
#include <modules/globebrowsing/src/tileprovider.h>
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
#include <openspace/properties/optionproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
@@ -40,8 +40,7 @@ namespace openspace::globebrowsing {
struct LayerGroup;
struct TileIndex;
namespace tileprovider { struct TileProvider; }
struct TileProvider;
class Layer : public properties::PropertyOwner {
public:
@@ -59,7 +58,7 @@ public:
TileDepthTransform depthTransform() const;
void setEnabled(bool enabled);
bool enabled() const;
tileprovider::TileProvider* tileProvider() const;
TileProvider* tileProvider() const;
glm::vec3 solidColor() const;
const LayerRenderSettings& renderSettings() const;
const LayerAdjustment& layerAdjustment() const;
@@ -89,7 +88,7 @@ private:
properties::StringProperty _guiDescription;
layergroupid::TypeID _type;
std::unique_ptr<tileprovider::TileProvider> _tileProvider;
std::unique_ptr<TileProvider> _tileProvider;
properties::Vec3Property _solidColor;
LayerRenderSettings _renderSettings;
LayerAdjustment _layerAdjustment;
@@ -36,8 +36,6 @@ namespace openspace::documentation { struct Documentation; }
namespace openspace::globebrowsing {
namespace tileprovider { struct TileProvider; }
class LayerAdjustment : public properties::PropertyOwner {
public:
LayerAdjustment();
+1 -2
View File
@@ -33,8 +33,7 @@
namespace openspace::globebrowsing {
class Layer;
namespace tileprovider { struct TileProvider; }
struct TileProvider;
/**
* Convenience class for dealing with multiple <code>Layer</code>s.
+2 -2
View File
@@ -26,7 +26,7 @@
#include <modules/globebrowsing/src/layer.h>
#include <modules/globebrowsing/src/layergroup.h>
#include <modules/globebrowsing/src/tileprovider.h>
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
#include <modules/globebrowsing/src/tiletextureinitdata.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
@@ -155,7 +155,7 @@ void LayerManager::reset(bool includeDisabled) {
for (std::unique_ptr<LayerGroup>& layerGroup : _layerGroups) {
for (Layer* layer : layerGroup->layers()) {
if ((layer->enabled() || includeDisabled) && layer->tileProvider()) {
tileprovider::reset(*layer->tileProvider());
layer->tileProvider()->reset();
}
}
}
+10 -11
View File
@@ -30,7 +30,7 @@
#include <modules/globebrowsing/src/layer.h>
#include <modules/globebrowsing/src/layergroup.h>
#include <modules/globebrowsing/src/renderableglobe.h>
#include <modules/globebrowsing/src/tileprovider.h>
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
@@ -322,7 +322,7 @@ ChunkTileVector tilesAndSettingsUnsorted(const LayerGroup& layerGroup,
for (Layer* layer : layerGroup.activeLayers()) {
if (layer->tileProvider()) {
tilesAndSettings.emplace_back(
tileprovider::chunkTile(*layer->tileProvider(), tileIndex),
layer->tileProvider()->chunkTile(tileIndex),
&layer->renderSettings()
);
}
@@ -403,7 +403,7 @@ bool colorAvailableForChunk(const Chunk& chunk, const LayerManager& lm) {
for (Layer* lyr : colorLayers.activeLayers()) {
if (lyr->tileProvider()) {
ChunkTile t = tileprovider::chunkTile(*lyr->tileProvider(), chunk.tileIndex);
ChunkTile t = lyr->tileProvider()->chunkTile(chunk.tileIndex);
if (t.tile.status == Tile::Status::Unavailable) {
return false;
}
@@ -1886,16 +1886,15 @@ float RenderableGlobe::getHeight(const glm::dvec3& position) const {
_layerManager.layerGroup(layergroupid::GroupID::HeightLayers).activeLayers();
for (Layer* layer : heightMapLayers) {
tileprovider::TileProvider* tileProvider = layer->tileProvider();
TileProvider* tileProvider = layer->tileProvider();
if (!tileProvider) {
continue;
}
// Transform the uv coordinates to the current tile texture
const ChunkTile chunkTile = tileprovider::chunkTile(*tileProvider, tileIndex);
const ChunkTile chunkTile = tileProvider->chunkTile(tileIndex);
const Tile& tile = chunkTile.tile;
const TileUvTransform& uvTransform = chunkTile.uvTransform;
const TileDepthTransform& depthTransform =
tileprovider::depthTransform(*tileProvider);
const TileDepthTransform& depthTransform = tileProvider->depthTransform();
if (tile.status != Tile::Status::OK) {
return 0;
}
@@ -1953,10 +1952,10 @@ float RenderableGlobe::getHeight(const glm::dvec3& position) const {
std::isnan(sample11);
const bool anySampleIsNoData =
sample00 == tileprovider::noDataValueAsFloat(*tileProvider) ||
sample01 == tileprovider::noDataValueAsFloat(*tileProvider) ||
sample10 == tileprovider::noDataValueAsFloat(*tileProvider) ||
sample11 == tileprovider::noDataValueAsFloat(*tileProvider);
sample00 == tileProvider->noDataValueAsFloat() ||
sample01 == tileProvider->noDataValueAsFloat() ||
sample10 == tileProvider->noDataValueAsFloat() ||
sample11 == tileProvider->noDataValueAsFloat();
if (anySampleIsNaN || anySampleIsNoData) {
continue;
File diff suppressed because it is too large Load Diff
-292
View File
@@ -1,292 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_PROVIDER___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_PROVIDER___H__
#include <openspace/properties/propertyowner.h>
#include <modules/globebrowsing/src/basictypes.h>
#include <modules/globebrowsing/src/ellipsoid.h>
#include <modules/globebrowsing/src/layergroupid.h>
#include <modules/globebrowsing/src/tileindex.h>
#include <modules/globebrowsing/src/tiletextureinitdata.h>
#include <modules/globebrowsing/src/timequantizer.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/intproperty.h>
#include <unordered_map>
#include <ghoul/opengl/programobject.h>
struct CPLXMLNode;
namespace ghoul::fontrendering {
class Font;
class FontRenderer;
} // namespace ghoul::fontrendering
namespace openspace { class PixelBuffer; }
namespace openspace::globebrowsing {
class AsyncTileDataProvider;
struct RawTile;
struct TileIndex;
namespace cache { class MemoryAwareTileCache; }
} // namespace openspace::globebrowsing
namespace openspace::globebrowsing::tileprovider {
enum class Type {
DefaultTileProvider = 0,
SingleImageTileProvider,
ImageSequenceTileProvider,
SizeReferenceTileProvider,
TemporalTileProvider,
TileIndexTileProvider,
ByIndexTileProvider,
ByLevelTileProvider,
InterpolateTileProvider
};
struct TileProvider : public properties::PropertyOwner {
static unsigned int NumTileProviders;
Type type;
TileProvider();
virtual ~TileProvider() = default;
std::string name;
uint16_t uniqueIdentifier = 0;
bool isInitialized = false;
};
struct DefaultTileProvider : public TileProvider {
DefaultTileProvider(const ghoul::Dictionary& dictionary);
std::unique_ptr<AsyncTileDataProvider> asyncTextureDataProvider;
cache::MemoryAwareTileCache* tileCache = nullptr;
properties::StringProperty filePath;
properties::IntProperty tilePixelSize;
layergroupid::GroupID layerGroupID = layergroupid::GroupID::Unknown;
bool performPreProcessing = false;
bool padTiles = true;
};
struct SingleImageProvider : public TileProvider {
SingleImageProvider(const ghoul::Dictionary& dictionary);
std::unique_ptr<ghoul::opengl::Texture> tileTexture;
Tile tile;
properties::StringProperty filePath;
};
struct InterpolateTileProvider : public TileProvider {
InterpolateTileProvider(const ghoul::Dictionary&);
virtual ~InterpolateTileProvider();
Tile calculateTile(const TileIndex&);
TileProvider* before = nullptr;
TileProvider* t1 = nullptr;
TileProvider* t2 = nullptr;
TileProvider* future = nullptr;
float factor = 1.f;
GLuint vaoQuad = 0;
GLuint vboQuad = 0;
GLuint fbo = 0;
std::string colormap;
std::unique_ptr<ghoul::opengl::ProgramObject> shaderProgram;
std::unique_ptr<SingleImageProvider> singleImageProvider;
cache::MemoryAwareTileCache* tileCache = nullptr;
};
struct TextTileProvider : public TileProvider {
TextTileProvider(TileTextureInitData initData, size_t fontSize = 48);
const TileTextureInitData initData;
std::unique_ptr<ghoul::fontrendering::FontRenderer> fontRenderer;
std::shared_ptr<ghoul::fontrendering::Font> font;
size_t fontSize = 0;
std::string text;
glm::vec2 textPosition = glm::vec2(0.f);
glm::vec4 textColor = glm::vec4(0.f);
GLuint fbo = 0;
cache::MemoryAwareTileCache* tileCache;
};
struct SizeReferenceTileProvider : public TextTileProvider {
SizeReferenceTileProvider(const ghoul::Dictionary& dictionary);
Ellipsoid ellipsoid;
};
struct TileIndexTileProvider : public TextTileProvider {
TileIndexTileProvider(const ghoul::Dictionary& dictionary);
};
struct TileProviderByIndex : public TileProvider {
TileProviderByIndex(const ghoul::Dictionary& dictionary);
std::unordered_map<
TileIndex::TileHashKey, std::unique_ptr<TileProvider>
> tileProviderMap;
std::unique_ptr<TileProvider> defaultTileProvider;
};
struct TileProviderByLevel : public TileProvider {
TileProviderByLevel(const ghoul::Dictionary& dictionary);
std::vector<int> providerIndices;
std::vector<std::unique_ptr<TileProvider>> levelTileProviders;
};
struct ImageSequenceTileProvider : public TileProvider {
ImageSequenceTileProvider(const ghoul::Dictionary& dictionary);
std::unique_ptr<DefaultTileProvider> currentTileProvider = nullptr;
properties::IntProperty index;
properties::StringProperty currentImage;
properties::StringProperty folderPath;
ghoul::Dictionary initDict;
bool isImageDirty = true;
std::vector<std::filesystem::path> imagePaths;
};
/**
* Provide <code>Tile</code>s from web map services that have temporal resolution.
*
* TemporalTileProviders are instantiated using a ghoul::Dictionary,
* and must define a filepath to a Openspace Temporal dataset description file.
* This is an xml-file that defines the same meta data as the GDAL wms description
* (http://www.gdal.org/frmt_wms.html), but augmented with some
* extra tags describing the temporal properties of the dataset. See
* <code>TemporalTileProvider::TemporalXMLTags</code>
*
*/
struct TemporalTileProvider : public TileProvider {
enum class TimeFormatType {
YYYY_MM_DD = 0,
YYYYMMDD_hhmmss,
YYYYMMDD_hhmm,
YYYY_MM_DDThhColonmmColonssZ,
YYYY_MM_DDThh_mm_ssZ
};
using TimeKey = std::string;
TemporalTileProvider(const ghoul::Dictionary& dictionary);
ghoul::Dictionary initDict;
properties::StringProperty filePath;
properties::BoolProperty useFixedTime;
properties::StringProperty fixedTime;
std::string gdalXmlTemplate;
std::unordered_map<TimeKey, std::unique_ptr<TileProvider>> tileProviderMap;
bool interpolation = false;
TileProvider* currentTileProvider = nullptr;
double startTimeJ2000;
double endTimeJ2000;
TimeFormatType timeFormat;
TimeQuantizer timeQuantizer;
std::string colormap;
std::string myResolution;
std::unique_ptr<InterpolateTileProvider> interpolateTileProvider;
};
void initializeDefaultTile();
void deinitializeDefaultTile();
std::unique_ptr<TileProvider> createFromDictionary(layergroupid::TypeID layerTypeID,
const ghoul::Dictionary& dictionary);
bool initialize(TileProvider& tp);
bool deinitialize(TileProvider& tp);
Tile tile(TileProvider& tp, const TileIndex& tileIndex);
ChunkTile chunkTile(TileProvider& tp, TileIndex tileIndex, int parents = 0,
int maxParents = 1337);
ChunkTilePile chunkTilePile(TileProvider& tp, TileIndex tileIndex, int pileSize);
/**
* Returns the status of a <code>Tile</code>. The <code>Tile::Status</code>
* corresponds the <code>Tile</code> that would be returned
* if the function <code>tile</code> would be invoked with the same
* <code>TileIndex</code> argument at this point in time.
*/
Tile::Status tileStatus(TileProvider& tp, const TileIndex& index);
/**
* Get the associated depth transform for this TileProvider.
* This is necessary for TileProviders serving height map
* data, in order to correcly map pixel values to meters.
*/
TileDepthTransform depthTransform(TileProvider& tp);
/**
* This method should be called once per frame. Here, TileProviders
* are given the opportunity to update their internal state.
*/
void update(TileProvider& tp);
/**
* Provides a uniform way of all TileProviders to reload or
* restore all of its internal state. This is mainly useful
* for debugging purposes.
*/
void reset(TileProvider& tp);
/**
* \returns The maximum level as defined by <code>TileIndex</code>
* that this TileProvider is able provide.
*/
int maxLevel(TileProvider& tp);
/**
* \returns the no data value for the dataset. Default is the minimum float avalue.
*/
float noDataValueAsFloat(TileProvider& tp);
} // namespace openspace::globebrowsing::tileprovider
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_PROVIDER___H__
@@ -0,0 +1,204 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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."
};
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."
};
struct [[codegen::Dictionary(DefaultTileProvider)]] Parameters {
// User-facing name of this tile provider
std::optional<std::string> name;
// 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;
};
#include "defaulttileprovider_codegen.cpp"
} // namespace
namespace openspace::globebrowsing {
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 = layergroupid::GroupID(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
switch (_layerGroupID) {
case layergroupid::GroupID::HeightLayers: _performPreProcessing = true; break;
default: _performPreProcessing = false; break;
}
_performPreProcessing = p.performPreProcessing.value_or(_performPreProcessing);
TileTextureInitData initData(
tileTextureInitData(_layerGroupID, _padTiles, pixelSize)
);
_tilePixelSize = initData.dimensions.x;
initAsyncTileDataReader(initData);
addProperty(_filePath);
addProperty(_tilePixelSize);
}
void DefaultTileProvider::initAsyncTileDataReader(TileTextureInitData initData) {
ZoneScoped
_asyncTextureDataProvider = std::make_unique<AsyncTileDataProvider>(
name,
std::make_unique<RawTileDataReader>(
_filePath,
initData,
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, 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 = { index, 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 = { tile->tileIndex, 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)
);
}
}
void DefaultTileProvider::reset() {
global::moduleEngine->module<GlobeBrowsingModule>()->tileCache()->clear();
ghoul_assert(_asyncTextureDataProvider, "No data provider");
_asyncTextureDataProvider->prepareToBeDeleted();
}
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
@@ -0,0 +1,61 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__DEFAULTTILEPROVIDER___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__DEFAULTTILEPROVIDER___H__
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
#include <modules/globebrowsing/src/asynctiledataprovider.h>
#include <memory>
namespace openspace::globebrowsing {
class DefaultTileProvider : public TileProvider {
public:
DefaultTileProvider(const ghoul::Dictionary& dictionary);
Tile tile(const TileIndex& tileIndex) override final;
Tile::Status tileStatus(const TileIndex& index) override final;
TileDepthTransform depthTransform() override final;
void update() override final;
void reset() override final;
int maxLevel() override final;
float noDataValueAsFloat() override final;
private:
void initAsyncTileDataReader(TileTextureInitData initData);
properties::StringProperty _filePath;
properties::IntProperty _tilePixelSize;
std::unique_ptr<AsyncTileDataProvider> _asyncTextureDataProvider;
layergroupid::GroupID _layerGroupID = layergroupid::GroupID::Unknown;
bool _performPreProcessing = false;
bool _padTiles = true;
};
} // namespace openspace::globebrowsing
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__DEFAULTTILEPROVIDER___H__
@@ -0,0 +1,158 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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/imagesequencetileprovider.h>
#include <modules/globebrowsing/src/tileprovider/defaulttileprovider.h>
#include <openspace/documentation/documentation.h>
#include <optional>
namespace {
constexpr openspace::properties::Property::PropertyInfo IndexInfo = {
"Index",
"Index",
"The index into the list of images that is used to pick the currently displayed "
"image"
};
constexpr openspace::properties::Property::PropertyInfo CurrentImageInfo = {
"CurrentImage",
"Current Image",
"The read-only value of the currently selected image"
};
constexpr openspace::properties::Property::PropertyInfo FolderPathInfo = {
"FolderPath",
"Folder Path",
"The path that is used to look for images for this image provider. The path must "
"point to an existing folder that contains images"
};
struct [[codegen::Dictionary(ImageSequenceTileProvider)]] Parameters {
// [[codegen::verbatim(IndexInfo.description)]]
std::optional<int> index;
// [[codegen::verbatim(FolderPathInfo.description)]]
std::filesystem::path folderPath [[codegen::directory()]];
};
#include "imagesequencetileprovider_codegen.cpp"
} // namespace
namespace openspace::globebrowsing {
ImageSequenceTileProvider::ImageSequenceTileProvider(const ghoul::Dictionary& dictionary)
: _index(IndexInfo, 0)
, _currentImage(CurrentImageInfo)
, _folderPath(FolderPathInfo)
, _initDict(dictionary)
{
ZoneScoped
const Parameters p = codegen::bake<Parameters>(dictionary);
_index = p.index.value_or(_index);
_index.setMinValue(0);
_index.onChange([this]() { _isImageDirty = true; });
addProperty(_index);
_currentImage.setReadOnly(true);
addProperty(_currentImage);
_folderPath = p.folderPath.string();
addProperty(_folderPath);
reset();
}
Tile ImageSequenceTileProvider::tile(const TileIndex& tileIndex) {
ZoneScoped
return _currentTileProvider ? _currentTileProvider->tile(tileIndex) : Tile();
}
Tile::Status ImageSequenceTileProvider::tileStatus(const TileIndex& index) {
return _currentTileProvider ?
_currentTileProvider->tileStatus(index) :
Tile::Status::Unavailable;
}
TileDepthTransform ImageSequenceTileProvider::depthTransform() {
if (_currentTileProvider) {
return _currentTileProvider->depthTransform();
}
else {
return { 1.f, 0.f };
}
}
void ImageSequenceTileProvider::update() {
if (_isImageDirty && !_imagePaths.empty() &&
_index >= 0 && _index < _imagePaths.size())
{
if (_currentTileProvider) {
_currentTileProvider->deinitialize();
}
std::string p = _imagePaths[_index].string();
_currentImage = p;
_initDict.setValue("FilePath", p);
_currentTileProvider = std::make_unique<DefaultTileProvider>(_initDict);
_currentTileProvider->initialize();
_isImageDirty = false;
}
if (_currentTileProvider) {
_currentTileProvider->update();
}
}
void ImageSequenceTileProvider::reset() {
namespace fs = std::filesystem;
std::string path = _folderPath;
_imagePaths.clear();
for (const fs::directory_entry& p : fs::directory_iterator(path)) {
if (p.is_regular_file()) {
_imagePaths.push_back(p.path());
}
}
_index = 0;
_index.setMaxValue(static_cast<int>(_imagePaths.size() - 1));
if (_currentTileProvider) {
_currentTileProvider->reset();
}
}
int ImageSequenceTileProvider::maxLevel() {
return _currentTileProvider ? _currentTileProvider->maxLevel() : 0;
}
float ImageSequenceTileProvider::noDataValueAsFloat() {
return _currentTileProvider ?
_currentTileProvider->noDataValueAsFloat() :
std::numeric_limits<float>::min();
}
} // namespace openspace::globebrowsing
@@ -0,0 +1,60 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__IMAGESEQUENCETILEPROVIDER___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__IMAGESEQUENCETILEPROVIDER___H__
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
#include <modules/globebrowsing/src/tileprovider/defaulttileprovider.h>
namespace openspace::globebrowsing {
class ImageSequenceTileProvider : public TileProvider {
public:
ImageSequenceTileProvider(const ghoul::Dictionary& dictionary);
Tile tile(const TileIndex& tileIndex) override final;
Tile::Status tileStatus(const TileIndex& index) override final;
TileDepthTransform depthTransform() override final;
void update() override final;
void reset() override final;
int maxLevel() override final;
float noDataValueAsFloat() override final;
private:
std::unique_ptr<DefaultTileProvider> _currentTileProvider = nullptr;
properties::IntProperty _index;
properties::StringProperty _currentImage;
properties::StringProperty _folderPath;
ghoul::Dictionary _initDict;
bool _isImageDirty = true;
std::vector<std::filesystem::path> _imagePaths;
};
} // namespace openspace::globebrowsing
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__IMAGESEQUENCETILEPROVIDER___H__
@@ -0,0 +1,100 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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/singleimagetileprovider.h>
#include <openspace/documentation/documentation.h>
#include <ghoul/io/texture/texturereader.h>
namespace {
constexpr openspace::properties::Property::PropertyInfo FilePathInfo = {
"FilePath",
"File Path",
"The file path that is used for this image provider. The file must point to an "
"image that is then loaded and used for all tiles."
};
struct [[codegen::Dictionary(SingleImageProvider)]] Parameters {
// [[codegen::verbatim(FilePathInfo.description)]]
std::string filePath;
};
#include "singleimagetileprovider_codegen.cpp"
} // namespace
namespace openspace::globebrowsing {
SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary)
: _filePath(FilePathInfo)
{
ZoneScoped
const Parameters p = codegen::bake<Parameters>(dictionary);
_filePath = p.filePath;
addProperty(_filePath);
reset();
}
Tile SingleImageProvider::tile(const TileIndex&) {
ZoneScoped
return _tile;
}
Tile::Status SingleImageProvider::tileStatus(const TileIndex&) {
return _tile.status;
}
TileDepthTransform SingleImageProvider::depthTransform() {
return { 0.f, 1.f };
}
void SingleImageProvider::update() {}
void SingleImageProvider::reset() {
if (_filePath.value().empty()) {
return;
}
_tileTexture = ghoul::io::TextureReader::ref().loadTexture(_filePath, 2);
if (!_tileTexture) {
throw ghoul::RuntimeError(
fmt::format("Unable to load texture '{}'", _filePath.value())
);
}
_tileTexture->uploadTexture();
_tileTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap);
_tile = Tile{ _tileTexture.get(), std::nullopt, Tile::Status::OK };
}
int SingleImageProvider::maxLevel() {
return 1337; // unlimited
}
float SingleImageProvider::noDataValueAsFloat() {
return std::numeric_limits<float>::min();
}
} // namespace openspace::globebrowsing
@@ -0,0 +1,53 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__SINGLEIMAGETILEPROVIDER___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__SINGLEIMAGETILEPROVIDER___H__
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
namespace openspace::globebrowsing {
class SingleImageProvider : public TileProvider {
public:
SingleImageProvider(const ghoul::Dictionary& dictionary);
Tile tile(const TileIndex& tileIndex) override final;
Tile::Status tileStatus(const TileIndex& index) override final;
TileDepthTransform depthTransform() override final;
void update() override final;
void reset() override final;
int maxLevel() override final;
float noDataValueAsFloat() override final;
private:
properties::StringProperty _filePath;
std::unique_ptr<ghoul::opengl::Texture> _tileTexture;
Tile _tile;
};
} // namespace openspace::globebrowsing
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__SINGLEIMAGETILEPROVIDER___H__
@@ -0,0 +1,121 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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/sizereferencetileprovider.h>
#include <modules/globebrowsing/src/geodeticpatch.h>
#include <openspace/documentation/documentation.h>
#include <openspace/engine/globals.h>
#include <ghoul/font/fontmanager.h>
#include <optional>
#include <variant>
namespace {
struct [[codegen::Dictionary(SizeReferenceTileProvider)]] Parameters {
std::optional<std::variant<glm::dvec3, double>> radii;
};
#include "sizereferencetileprovider_codegen.cpp"
} // namespace
namespace openspace::globebrowsing {
SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary)
: TextTileProvider(tileTextureInitData(layergroupid::GroupID::ColorLayers, false))
{
ZoneScoped
const Parameters p = codegen::bake<Parameters>(dictionary);
font = global::fontManager->font("Mono", static_cast<float>(fontSize));
if (p.radii.has_value()) {
if (std::holds_alternative<glm::dvec3>(*p.radii)) {
_ellipsoid = std::get<glm::dvec3>(*p.radii);
}
else {
const double r = std::get<double>(*p.radii);
_ellipsoid = glm::dvec3(r, r, r);
}
}
}
Tile SizeReferenceTileProvider::tile(const TileIndex& tileIndex) {
ZoneScoped
const GeodeticPatch patch(tileIndex);
const bool aboveEquator = patch.isNorthern();
const double lat = aboveEquator ? patch.minLat() : patch.maxLat();
const double lon1 = patch.minLon();
const double lon2 = patch.maxLon();
int l = static_cast<int>(_ellipsoid.longitudalDistance(lat, lon1, lon2));
const bool useKm = l > 9999;
if (useKm) {
l /= 1000;
}
l = static_cast<int>(std::round(l));
if (useKm) {
l *= 1000;
}
double tileLongitudalLength = l;
const char* unit;
if (tileLongitudalLength > 9999) {
tileLongitudalLength *= 0.001;
unit = "km";
}
else {
unit = "m";
}
std::string text = fmt::format(" {:.0f} {:s}", tileLongitudalLength, unit);
glm::vec2 textPosition = {
0.f,
aboveEquator ?
fontSize / 2.f :
initData.dimensions.y - 3.f * fontSize / 2.f
};
return TextTileProvider::renderTile(tileIndex, text, textPosition, glm::vec4(1.f));
}
Tile::Status SizeReferenceTileProvider::tileStatus(const TileIndex& index) {
return Tile::Status::OK;
}
TileDepthTransform SizeReferenceTileProvider::depthTransform() {
return { 0.f, 1.f };
}
void SizeReferenceTileProvider::update() {}
int SizeReferenceTileProvider::maxLevel() {
return 1337; // unlimited
}
float SizeReferenceTileProvider::noDataValueAsFloat() {
return std::numeric_limits<float>::min();
}
} // namespace openspace::globebrowsing
@@ -0,0 +1,49 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__SIZEREFERENCETILEPROVIDER___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__SIZEREFERENCETILEPROVIDER___H__
#include <modules/globebrowsing/src/tileprovider/texttileprovider.h>
namespace openspace::globebrowsing {
class SizeReferenceTileProvider : public TextTileProvider {
public:
SizeReferenceTileProvider(const ghoul::Dictionary& dictionary);
Tile tile(const TileIndex& tileIndex) override final;
Tile::Status tileStatus(const TileIndex& index) override final;
TileDepthTransform depthTransform() override final;
void update() override final;
int maxLevel() override final;
float noDataValueAsFloat() override final;
private:
Ellipsoid _ellipsoid;
};
} // namespace openspace::globebrowsing
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__SIZEREFERENCETILEPROVIDER___H__
@@ -0,0 +1,822 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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/temporaltileprovider.h>
#include <modules/globebrowsing/globebrowsingmodule.h>
#include <modules/globebrowsing/src/memoryawaretilecache.h>
#include <modules/globebrowsing/src/tileprovider/defaulttileprovider.h>
#include <openspace/documentation/documentation.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/util/memorymanager.h>
#include <openspace/util/spicemanager.h>
#include <openspace/util/timemanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/opengl/openglstatecache.h>
#include <ghoul/opengl/textureunit.h>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>
namespace {
constexpr const char* KeyBasePath = "BasePath";
constexpr const char* TimePlaceholder = "${OpenSpaceTimeId}";
constexpr openspace::properties::Property::PropertyInfo FilePathInfo = {
"FilePath",
"File Path",
"This is the path to the XML configuration file that describes the temporal tile "
"information."
};
constexpr openspace::properties::Property::PropertyInfo UseFixedTimeInfo = {
"UseFixedTime",
"Use Fixed Time",
"If this value is enabled, the time-varying timevarying dataset will always use "
"the time that is specified in the 'FixedTime' property, rather than using the "
"actual time from OpenSpace"
};
constexpr openspace::properties::Property::PropertyInfo FixedTimeInfo = {
"FixedTime",
"Fixed Time",
"If the 'UseFixedTime' is enabled, this time will be used instead of the actual "
"time taken from OpenSpace for the displayed tiles."
};
struct [[codegen::Dictionary(TemporalTileProvider)]] Parameters {
// [[codegen::verbatim(UseFixedTimeInfo.description)]]
std::optional<bool> useFixedTime;
// [[codegen::verbatim(FixedTimeInfo.description)]]
std::optional<std::string> fixedTime;
enum class Mode {
Prototyped,
Folder
};
// The mode that his temporal tile provider operates in. In the `Prototyped` mode,
// a given start and end time, temporal resolution, and perscriptive time format
// is used to generate the information used by GDAL to access the data. In the
// `folder` method, a folder and a time format is provided and each file in the
// folder is scanned using the time format instead
Mode mode;
struct Prototyped {
struct Time {
// The (inclusive) starting time of the temporal image range
std::string start;
// The (inclusive) ending time of the temporal image range
std::string end;
};
// The starting and ending times for the range of values
Time time;
// The temporal resolution between each image
std::string temporalResolution;
// The specification of the date format that is used in the tile provider. The
// time format must be specified in a manner appropriate for the SPICE
// function `timout_c`.
// https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/timout_c.html
std::string timeFormat;
// The text that will be used as the prototype to generate the data to load
// the image layer. Any occurance of `${OpenSpaceTimeId}` in this prototype
// is replaced with the current date according to the remaining information
// such as the resolution and the format and the resulting text is used to
// load the corresponding images
std::string prototype;
};
std::optional<Prototyped> prototyped;
struct Folder {
// The folder that is parsed for files. Every file in the provided directory
// is checked against the provided format and added if it adheres to said
// format
std::filesystem::path folder [[codegen::directory()]];
// The format of files that is pared in the provided folder. The format string
// has to be compatible to the C++ function get_time.
// https://en.cppreference.com/w/cpp/io/manip/get_time
std::string format;
};
std::optional<Folder> folder;
// Determines whether this tile provider should interpolate between two adjacent
// layers
std::optional<bool> interpolation;
// If provided, the tile provider will use this color map to convert a greyscale
// image to color
std::optional<std::string> colormap;
};
#include "temporaltileprovider_codegen.cpp"
std::string_view timeStringify(const std::string& format, const openspace::Time& t) {
ZoneScoped
constexpr const int BufferSize = 64;
ghoul_assert(format.size() < BufferSize, "Format string too long");
using namespace openspace;
char FormatBuf[BufferSize];
std::memset(FormatBuf, '\0', BufferSize);
std::memcpy(FormatBuf, format.c_str(), format.size());
char* OutBuf = reinterpret_cast<char*>(
global::memoryManager->TemporaryMemory.allocate(BufferSize)
);
std::memset(OutBuf, '\0', BufferSize);
const double time = t.j2000Seconds();
SpiceManager::ref().dateFromEphemerisTime(time, OutBuf, BufferSize, FormatBuf);
return std::string_view(OutBuf, format.size());
}
} // namespace
namespace openspace::globebrowsing {
TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary)
: _initDict(dictionary)
, _useFixedTime(UseFixedTimeInfo, false)
, _fixedTime(FixedTimeInfo)
{
ZoneScoped
const Parameters p = codegen::bake<Parameters>(dictionary);
// Make sure that the user provided the data that they requested. The mode parameter
// is a required one and these two if statements tie the table requirement to the mode
if (p.mode == Parameters::Mode::Folder && !p.folder.has_value()) {
throw ghoul::RuntimeError(
"When selecting the `Folder` mode, a `Folder` table must be specified"
);
}
if (p.mode == Parameters::Mode::Prototyped && !p.prototyped.has_value()) {
throw ghoul::RuntimeError(
"When selecting the `Prototyped` mode, a `Prototyped` table must be specified"
);
}
_useFixedTime = p.useFixedTime.value_or(_useFixedTime);
_useFixedTime.onChange([this]() { _fixedTimeDirty = true; });
addProperty(_useFixedTime);
_fixedTime = p.fixedTime.value_or(_fixedTime);
_fixedTime.onChange([this]() { _fixedTimeDirty = true; });
addProperty(_fixedTime);
_colormap = p.colormap.value_or(_colormap);
if (p.prototyped.has_value()) {
_mode = Mode::Prototype;
Time start = Time(p.prototyped->time.start);
Time end = Time::now();
_prototyped.startTimeJ2000 = start.j2000Seconds();
_prototyped.endTimeJ2000 = Time(p.prototyped->time.end).j2000Seconds();
if (p.prototyped->time.end == "Yesterday") {
end.advanceTime(-60.0 * 60.0 * 24.0); // Go back one day
}
else if (p.prototyped->time.end != "Today") {
end.setTime(p.prototyped->time.end);
}
try {
_prototyped.timeQuantizer.setStartEndRange(
std::string(start.ISO8601()),
std::string(end.ISO8601())
);
_prototyped.timeQuantizer.setResolution(p.prototyped->temporalResolution);
_prototyped.temporalResolution = p.prototyped->temporalResolution;
}
catch (const ghoul::RuntimeError& e) {
throw ghoul::RuntimeError(fmt::format(
"Could not create time quantizer for Temporal GDAL dataset. {}", e.message
));
}
if (p.prototyped->timeFormat.size() >= 64) {
throw ghoul::RuntimeError(fmt::format(
"Time format string '{}' too large. Maximum length of 64 is allowed",
p.prototyped->timeFormat
));
}
_prototyped.timeFormat = p.prototyped->timeFormat;
_prototyped.prototype = p.prototyped->prototype;
}
if (p.folder.has_value()) {
_mode = Mode::Folder;
_folder.folder = p.folder->folder;
_folder.format = p.folder->format;
namespace fs = std::filesystem;
for (const fs::directory_entry& path : fs::directory_iterator(_folder.folder)) {
if (!path.is_regular_file()) {
continue;
}
std::string file = path.path().filename().string();
std::istringstream ss(file);
std::tm tm = {};
ss >> std::get_time(&tm, p.folder->format.c_str());
if (!ss.fail()) {
std::string date = fmt::format(
"{}-{}-{} {}:{}:{}",
tm.tm_year + 1900,
tm.tm_mon + 1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec
);
double et = SpiceManager::ref().ephemerisTimeFromDate(date);
_folder.files.push_back({ et, path.path().string() });
}
}
using K = double;
using V = std::string;
std::sort(
_folder.files.begin(),
_folder.files.end(),
[](const std::pair<K, V>& lhs, const std::pair<K, V>& rhs) {
return lhs.first < rhs.first;
}
);
}
_isInterpolating = p.interpolation.value_or(_isInterpolating);
if (_isInterpolating) {
_interpolateTileProvider = std::make_unique<InterpolateTileProvider>(dictionary);
_interpolateTileProvider->initialize();
_interpolateTileProvider->colormap =
ghoul::io::TextureReader::ref().loadTexture(_colormap, 1);
_interpolateTileProvider->colormap->uploadTexture();
_interpolateTileProvider->colormap->setFilter(
ghoul::opengl::Texture::FilterMode::AnisotropicMipMap
);
}
}
Tile TemporalTileProvider::tile(const TileIndex& tileIndex) {
ZoneScoped
if (!_currentTileProvider) {
update();
}
return _currentTileProvider->tile(tileIndex);
}
Tile::Status TemporalTileProvider::tileStatus(const TileIndex& index) {
if (!_currentTileProvider) {
update();
}
return _currentTileProvider->tileStatus(index);
}
TileDepthTransform TemporalTileProvider::depthTransform() {
if (!_currentTileProvider) {
update();
}
return _currentTileProvider->depthTransform();
}
void TemporalTileProvider::update() {
TileProvider* newCurr = nullptr;
try {
if (_useFixedTime && !_fixedTime.value().empty()) {
if (_fixedTimeDirty) {
std::string fixedTime = _fixedTime.value();
double et = SpiceManager::ref().ephemerisTimeFromDate(fixedTime);
newCurr = retrieveTileProvider(Time(et));
_fixedTimeDirty = false;
}
}
else {
newCurr = tileProvider(global::timeManager->time());
}
}
catch (const ghoul::RuntimeError& e) {
LERRORC("TemporalTileProvider", e.message);
}
if (newCurr) {
_currentTileProvider = newCurr;
}
if (_currentTileProvider) {
_currentTileProvider->update();
}
}
void TemporalTileProvider::reset() {
for (std::pair<const double, DefaultTileProvider>& it : _tileProviderMap) {
it.second.reset();
}
}
int TemporalTileProvider::maxLevel() {
if (!_currentTileProvider) {
update();
}
return _currentTileProvider->maxLevel();
}
float TemporalTileProvider::noDataValueAsFloat() {
return std::numeric_limits<float>::min();
}
DefaultTileProvider TemporalTileProvider::createTileProvider(
std::string_view timekey) const
{
ZoneScoped
std::string value;
switch (_mode) {
case Mode::Prototype: {
static const std::vector<std::string> IgnoredTokens = {
// From: http://www.gdal.org/frmt_wms.html
"${x}", "${y}", "${z}", "${version}" "${format}", "${layer}"
};
value = _prototyped.prototype;
while (true) {
const size_t pos = value.find(TimePlaceholder);
if (pos == std::string::npos) {
break;
}
const size_t numChars = std::string_view(TimePlaceholder).size();
value = value.replace(pos, numChars, timekey);
}
value = FileSys.expandPathTokens(std::move(value), IgnoredTokens).string();
break;
}
case Mode::Folder: {
value = std::string(timekey);
break;
}
}
ghoul::Dictionary dict = _initDict;
dict.setValue("FilePath", value);
return DefaultTileProvider(dict);
}
DefaultTileProvider* TemporalTileProvider::retrieveTileProvider(const Time& t) {
ZoneScoped
const double time = t.j2000Seconds();
if (const auto it = _tileProviderMap.find(time); it != _tileProviderMap.end()) {
return &it->second;
}
std::string_view timeStr = [this, time]() {
switch (_mode) {
case Mode::Prototype:
return timeStringify(_prototyped.timeFormat, Time(time));
case Mode::Folder: {
// Yes this will have to be done twice since we do the check previously
// but it is only happening when the images change, so I think that should
// be fine
auto it = std::lower_bound(
_folder.files.cbegin(),
_folder.files.cend(),
time,
[](const std::pair<double, std::string>& p, double time) {
return p.first < time;
}
);
return std::string_view(it->second);
}
default: throw ghoul::MissingCaseException();
};
}();
DefaultTileProvider tileProvider = createTileProvider(timeStr);
tileProvider.initialize();
auto it = _tileProviderMap.insert({ time, std::move(tileProvider) });
return &it.first->second;
}
template <>
TileProvider*
TemporalTileProvider::tileProvider<TemporalTileProvider::Mode::Folder, false>(
const Time& time)
{
// Find the most current image that matches the current time. We can't pass the `time`
// variable into the retrieveTileProvider function as it would generate a new
// non-existing TileProvider for every new frame
using It = std::vector<std::pair<double, std::string>>::const_iterator;
It it = std::lower_bound(
_folder.files.begin(),
_folder.files.end(),
time.j2000Seconds(),
[](const std::pair<double, std::string>& p, double t) {
return p.first < t;
}
);
if (it != _folder.files.begin()) {
it -= 1;
}
double t = it->first;
return retrieveTileProvider(Time(t));
}
template <>
TileProvider*
TemporalTileProvider::tileProvider<TemporalTileProvider::Mode::Folder, true>(
const Time& time)
{
using It = std::vector<std::pair<double, std::string>>::const_iterator;
It next = std::lower_bound(
_folder.files.begin(),
_folder.files.end(),
time.j2000Seconds(),
[](const std::pair<double, std::string>& p, double t) {
return p.first < t;
}
);
It curr = next != _folder.files.begin() ? next - 1 : next;
It nextNext = next != _folder.files.end() ? next + 1 : curr;
It prev = curr != _folder.files.begin() ? curr - 1 : curr;
_interpolateTileProvider->t1 = retrieveTileProvider(Time(curr->first));
_interpolateTileProvider->t2 = retrieveTileProvider(Time(next->first));
_interpolateTileProvider->future = retrieveTileProvider(Time(nextNext->first));
_interpolateTileProvider->before = retrieveTileProvider(Time(prev->first));
_interpolateTileProvider->factor = static_cast<float>(
(time.j2000Seconds() - curr->first) /
(next->first - curr->first)
);
if (_interpolateTileProvider->factor > 1.f) {
_interpolateTileProvider->factor = 1.f;
}
return _interpolateTileProvider.get();
}
template <>
TileProvider*
TemporalTileProvider::tileProvider<TemporalTileProvider::Mode::Prototype, false>(
const Time& time)
{
Time tCopy(time);
if (_prototyped.timeQuantizer.quantize(tCopy, true)) {
return retrieveTileProvider(tCopy);
}
else {
return nullptr;
}
}
template <>
TileProvider*
TemporalTileProvider::tileProvider<TemporalTileProvider::Mode::Prototype, true>(
const Time& time)
{
Time tCopy(time);
if (!_prototyped.timeQuantizer.quantize(tCopy, true)) {
return nullptr;
}
Time nextTile = tCopy;
Time nextNextTile = tCopy;
Time prevTile = tCopy;
Time secondToLast = Time(_prototyped.endTimeJ2000);
Time secondToFirst = Time(_prototyped.startTimeJ2000);
_interpolateTileProvider->t1 = retrieveTileProvider(tCopy);
// if the images are for each hour
if (_prototyped.temporalResolution == "1h") {
constexpr const int Hour = 60 * 60;
// the second tile to interpolate between
nextTile.advanceTime(Hour);
// the tile after the second tile
nextNextTile.advanceTime(2 * Hour);
// the tile before the first tile
prevTile.advanceTime(-Hour + 1);
// to make sure that an image outside the dataset is not searched for both
// ends of the dataset are calculated
secondToLast.advanceTime(-Hour);
secondToFirst.advanceTime(Hour);
}
// if the images are for each month
if (_prototyped.temporalResolution == "1M") {
constexpr const int Day = 24 * 60 * 60;
// the second tile to interpolate between
nextTile.advanceTime(32 * Day);
// the tile after the second tile
nextNextTile.advanceTime(64 * Day);
// the tile before the first tile
prevTile.advanceTime(-2 * Day);
// to make sure that an image outside the dataset is not searched for both
// ends of the dataset are calculated
secondToLast.advanceTime(-2 * Day);
secondToFirst.advanceTime(32 * Day);
// since months vary in length the time is set to the first of each month
auto setToFirstOfMonth = [](Time& t) {
std::string timeString = std::string(t.ISO8601());
timeString[8] = '0';
timeString[9] = '1';
t.setTime(timeString);
};
setToFirstOfMonth(nextTile);
setToFirstOfMonth(nextNextTile);
setToFirstOfMonth(prevTile);
setToFirstOfMonth(secondToLast);
setToFirstOfMonth(secondToFirst);
}
// the necessary tile providers are loaded if they exist within the timespan
if (secondToLast.j2000Seconds() > time.j2000Seconds() &&
secondToFirst.j2000Seconds() < time.j2000Seconds())
{
_interpolateTileProvider->t2 = retrieveTileProvider(nextTile);
_interpolateTileProvider->future = retrieveTileProvider(nextNextTile);
_interpolateTileProvider->before = retrieveTileProvider(prevTile);
}
else if (secondToLast.j2000Seconds() < time.j2000Seconds() &&
_prototyped.endTimeJ2000 > time.j2000Seconds())
{
_interpolateTileProvider->t2 = retrieveTileProvider(nextTile);
_interpolateTileProvider->future = retrieveTileProvider(tCopy);
_interpolateTileProvider->before = retrieveTileProvider(prevTile);
}
else if (secondToFirst.j2000Seconds() > time.j2000Seconds() &&
_prototyped.startTimeJ2000 < time.j2000Seconds())
{
_interpolateTileProvider->t2 = retrieveTileProvider(nextTile);
_interpolateTileProvider->future = retrieveTileProvider(nextNextTile);
_interpolateTileProvider->before = retrieveTileProvider(tCopy);
}
else {
_interpolateTileProvider->t2 = retrieveTileProvider(tCopy);
_interpolateTileProvider->future = retrieveTileProvider(tCopy);
_interpolateTileProvider->before = retrieveTileProvider(tCopy);
}
_interpolateTileProvider->factor = static_cast<float>(
(time.j2000Seconds() - tCopy.j2000Seconds()) /
(nextTile.j2000Seconds() - tCopy.j2000Seconds())
);
if (_interpolateTileProvider->factor > 1.f) {
_interpolateTileProvider->factor = 1.f;
}
return _interpolateTileProvider.get();
}
TileProvider* TemporalTileProvider::tileProvider(const Time& time) {
if (_isInterpolating) {
switch (_mode) {
case Mode::Folder:
return tileProvider<Mode::Folder, true>(time);
case Mode::Prototype:
return tileProvider<Mode::Prototype, true>(time);
default: throw ghoul::MissingCaseException();
}
}
else {
switch (_mode) {
case Mode::Folder:
return tileProvider<Mode::Folder, false>(time);
case Mode::Prototype:
return tileProvider<Mode::Prototype, false>(time);
default: throw ghoul::MissingCaseException();
}
}
}
TemporalTileProvider::InterpolateTileProvider::InterpolateTileProvider(
const ghoul::Dictionary&)
{
ZoneScoped
glGenFramebuffers(1, &fbo);
glGenVertexArrays(1, &vaoQuad);
glGenBuffers(1, &vboQuad);
glBindVertexArray(vaoQuad);
glBindBuffer(GL_ARRAY_BUFFER, vboQuad);
// Quad for fullscreen with vertex (xy) and texture coordinates (uv)
const GLfloat vertexData[] = {
// x y u v
-1.f, -1.f, 0.f, 0.f,
1.f, 1.f, 1.f, 1.f,
-1.f, 1.f, 0.f, 1.f,
-1.f, -1.f, 0.f, 0.f,
1.f, -1.f, 1.f, 0.f,
1.f, 1.f, 1.f, 1.f
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
// vertex coordinates at location 0
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(0);
// texture coords at location 1
glVertexAttribPointer(
1,
2,
GL_FLOAT,
GL_FALSE,
4 * sizeof(GLfloat),
reinterpret_cast<void*>(2 * sizeof(GLfloat))
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
shaderProgram = global::renderEngine->buildRenderProgram(
"InterpolatingProgram",
absPath("${MODULE_GLOBEBROWSING}/shaders/interpolate_vs.glsl"),
absPath("${MODULE_GLOBEBROWSING}/shaders/interpolate_fs.glsl")
);
}
TemporalTileProvider::InterpolateTileProvider::~InterpolateTileProvider() {
glDeleteFramebuffers(1, &fbo);
glDeleteBuffers(1, &vboQuad);
glDeleteVertexArrays(1, &vaoQuad);
}
Tile TemporalTileProvider::InterpolateTileProvider::tile(const TileIndex& tileIndex) {
ZoneScoped
TracyGpuZone("tile");
// prev and next are the two tiles to interpolate between
Tile prev = t1->tile(tileIndex);
Tile next = t2->tile(tileIndex);
// the tile before and the tile after the interpolation interval are loaded so the
// interpolation goes smoother
Tile prevprev = before->tile(tileIndex);
Tile nextnext = future->tile(tileIndex);
cache::ProviderTileKey key = { tileIndex, uniqueIdentifier };
if (!prev.texture || !next.texture) {
return Tile{ nullptr, std::nullopt, Tile::Status::Unavailable };
}
// The data for initializing the texture
TileTextureInitData initData(
prev.texture->dimensions().x,
prev.texture->dimensions().y,
prev.texture->dataType(),
prev.texture->format(),
TileTextureInitData::PadTiles::No,
TileTextureInitData::ShouldAllocateDataOnCPU::No
);
// Check if a tile exists for the given key in the tileCache
// Initializing the tile that will contian the interpolated texture
Tile ourTile;
// The texture that will contain the interpolated image
ghoul::opengl::Texture* writeTexture;
cache::MemoryAwareTileCache* tileCache =
global::moduleEngine->module<GlobeBrowsingModule>()->tileCache();
if (tileCache->exist(key)) {
ourTile = tileCache->get(key);
writeTexture = ourTile.texture;
}
else {
// Create a texture with the initialization data
writeTexture = tileCache->texture(initData);
ourTile = Tile{ writeTexture, std::nullopt, Tile::Status::OK };
tileCache->put(key, initData.hashKey, ourTile);
}
// Saves current state
GLint currentFBO;
GLint viewport[4];
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFBO);
global::renderEngine->openglStateCache().viewport(viewport);
// Bind render texture to FBO
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *writeTexture, 0);
glDisable(GL_BLEND);
GLenum textureBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, textureBuffers);
// Setup our own viewport settings
GLsizei w = static_cast<GLsizei>(writeTexture->width());
GLsizei h = static_cast<GLsizei>(writeTexture->height());
glViewport(0, 0, w, h);
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
GLint id;
glGetIntegerv(GL_CURRENT_PROGRAM, &id);
// Activate shader and bind uniforms
shaderProgram->activate();
shaderProgram->setUniform("blendFactor", factor);
// The texture that will give the color for the interpolated texture
ghoul::opengl::TextureUnit colormapUnit;
colormapUnit.activate();
colormap->bind();
shaderProgram->setUniform("colormapTexture", colormapUnit);
ghoul::opengl::TextureUnit prevUnit;
prevUnit.activate();
prev.texture->bind();
shaderProgram->setUniform("prevTexture", prevUnit);
ghoul::opengl::TextureUnit nextUnit;
nextUnit.activate();
next.texture->bind();
shaderProgram->setUniform("nextTexture", nextUnit);
// Render to the texture
glBindVertexArray(vaoQuad);
glDrawArrays(GL_TRIANGLES, 0, 6); // 2 triangles
// Deactivate shader program (when rendering is completed)
shaderProgram->deactivate();
glUseProgram(id);
// Restores system state
glBindFramebuffer(GL_FRAMEBUFFER, currentFBO);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
// Restores OpenGL Rendering State
global::renderEngine->openglStateCache().resetColorState();
global::renderEngine->openglStateCache().resetBlendState();
global::renderEngine->openglStateCache().resetDepthState();
global::renderEngine->openglStateCache().resetPolygonAndClippingState();
global::renderEngine->openglStateCache().resetViewportState();
return ourTile;
}
Tile::Status TemporalTileProvider::InterpolateTileProvider::tileStatus(
const TileIndex& index)
{
return std::min(t1->tileStatus(index), t2->tileStatus(index));
}
TileDepthTransform TemporalTileProvider::InterpolateTileProvider::depthTransform() {
return t1->depthTransform();
}
void TemporalTileProvider::InterpolateTileProvider::update() {
t1->update();
t2->update();
before->update();
future->update();
}
void TemporalTileProvider::InterpolateTileProvider::reset() {
t1->reset();
t2->reset();
before->reset();
future->reset();
}
int TemporalTileProvider::InterpolateTileProvider::maxLevel() {
return glm::min(t1->maxLevel(), t2->maxLevel());
}
float TemporalTileProvider::InterpolateTileProvider::noDataValueAsFloat() {
return std::numeric_limits<float>::min();
}
} // namespace openspace::globebrowsing
@@ -0,0 +1,130 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TEMPORALTILEPROVIDER___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TEMPORALTILEPROVIDER___H__
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
#include <modules/globebrowsing/src/tileprovider/defaulttileprovider.h>
#include <modules/globebrowsing/src/tileprovider/singleimagetileprovider.h>
namespace openspace::globebrowsing {
/**
* Provide <code>Tile</code>s from web map services that have temporal resolution.
*
* TemporalTileProviders are instantiated using a ghoul::Dictionary, and must define a
* filepath to a Openspace Temporal dataset description file. This is an xml-file that
* defines the same meta data as the GDAL wms description
* (http://www.gdal.org/frmt_wms.html), but augmented with some extra tags describing the
* temporal properties of the dataset. See
* <code>TemporalTileProvider::TemporalXMLTags</code>
*/
class TemporalTileProvider : public TileProvider {
public:
TemporalTileProvider(const ghoul::Dictionary& dictionary);
Tile tile(const TileIndex& tileIndex) override final;
Tile::Status tileStatus(const TileIndex& index) override final;
TileDepthTransform depthTransform() override final;
void update() override final;
void reset() override final;
int maxLevel() override final;
float noDataValueAsFloat() override final;
private:
enum class Mode {
Prototype,
Folder
};
struct InterpolateTileProvider : public TileProvider {
InterpolateTileProvider(const ghoul::Dictionary&);
virtual ~InterpolateTileProvider();
Tile tile(const TileIndex& tileIndex) override final;
Tile::Status tileStatus(const TileIndex& index) override final;
TileDepthTransform depthTransform() override final;
void update() override final;
void reset() override final;
int maxLevel() override final;
float noDataValueAsFloat() override final;
TileProvider* before = nullptr;
TileProvider* t1 = nullptr;
TileProvider* t2 = nullptr;
TileProvider* future = nullptr;
float factor = 1.f;
GLuint vaoQuad = 0;
GLuint vboQuad = 0;
GLuint fbo = 0;
std::unique_ptr<ghoul::opengl::ProgramObject> shaderProgram;
std::unique_ptr<ghoul::opengl::Texture> colormap;
};
DefaultTileProvider createTileProvider(std::string_view timekey) const;
DefaultTileProvider* retrieveTileProvider(const Time& t);
template <Mode mode, bool interpolation>
TileProvider* tileProvider(const Time& time);
TileProvider* tileProvider(const Time& time);
Mode _mode;
struct {
double startTimeJ2000 = 0.0;
double endTimeJ2000 = 0.0;
std::string temporalResolution;
std::string timeFormat;
TimeQuantizer timeQuantizer;
std::string prototype;
} _prototyped;
struct {
std::filesystem::path folder;
std::string format;
std::vector<std::pair<double, std::string>> files;
} _folder;
ghoul::Dictionary _initDict;
properties::BoolProperty _useFixedTime;
properties::StringProperty _fixedTime;
bool _fixedTimeDirty = true;
TileProvider* _currentTileProvider = nullptr;
std::unordered_map<double, DefaultTileProvider> _tileProviderMap;
bool _isInterpolating = false;
std::string _colormap;
std::unique_ptr<InterpolateTileProvider> _interpolateTileProvider;
};
} // namespace openspace::globebrowsing
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TEMPORALTILEPROVIDER___H__
@@ -0,0 +1,109 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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/texttileprovider.h>
#include <modules/globebrowsing/globebrowsingmodule.h>
#include <modules/globebrowsing/src/memoryawaretilecache.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/rendering/renderengine.h>
#include <ghoul/font/fontmanager.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/opengl/openglstatecache.h>
namespace openspace::globebrowsing {
TextTileProvider::TextTileProvider(TileTextureInitData initData_, size_t fontSize_)
: initData(std::move(initData_))
, fontSize(fontSize_)
{
ZoneScoped
tileCache = global::moduleEngine->module<GlobeBrowsingModule>()->tileCache();
}
TextTileProvider::~TextTileProvider() {}
void TextTileProvider::internalInitialize() {
ZoneScoped
font = global::fontManager->font("Mono", static_cast<float>(fontSize));
fontRenderer = ghoul::fontrendering::FontRenderer::createDefault();
fontRenderer->setFramebufferSize(glm::vec2(initData.dimensions));
glGenFramebuffers(1, &fbo);
}
void TextTileProvider::internalDeinitialize() {
glDeleteFramebuffers(1, &fbo);
}
Tile TextTileProvider::renderTile(const TileIndex& tileIndex, const std::string& text,
const glm::vec2& position, const glm::vec4& color)
{
ZoneScoped
TracyGpuZone("tile")
cache::ProviderTileKey key = { tileIndex, uniqueIdentifier };
Tile tile = tileCache->get(key);
if (!tile.texture) {
ghoul::opengl::Texture* texture = tileCache->texture(initData);
// Keep track of defaultFBO and viewport to be able to reset state when done
GLint defaultFBO = global::renderEngine->openglStateCache().defaultFramebuffer();
// Render to texture
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
*texture,
0
);
GLsizei w = static_cast<GLsizei>(texture->width());
GLsizei h = static_cast<GLsizei>(texture->height());
glViewport(0, 0, w, h);
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
fontRenderer->render(*font, position, text, color);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
global::renderEngine->openglStateCache().resetViewportState();
tile = Tile{ texture, std::nullopt, Tile::Status::OK };
tileCache->put(key, initData.hashKey, tile);
}
return tile;
}
void TextTileProvider::reset() {
ZoneScoped
tileCache->clear();
}
} // namespace openspace::globebrowsing
@@ -0,0 +1,60 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TEXTTILEPROVIDER___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TEXTTILEPROVIDER___H__
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
namespace openspace::globebrowsing {
class TextTileProvider : public TileProvider {
public:
TextTileProvider(TileTextureInitData initData, size_t fontSize = 48);
virtual ~TextTileProvider();
void reset() override;
protected:
Tile renderTile(const TileIndex& tileIndex, const std::string& text,
const glm::vec2& position, const glm::vec4& color);
const TileTextureInitData initData;
std::unique_ptr<ghoul::fontrendering::FontRenderer> fontRenderer;
std::shared_ptr<ghoul::fontrendering::Font> font;
size_t fontSize = 0;
GLuint fbo = 0;
cache::MemoryAwareTileCache* tileCache;
private:
void internalInitialize() override final;
void internalDeinitialize() override final;
};
} // namespace openspace::globebrowsing
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TEXTTILEPROVIDER___H__
@@ -0,0 +1,65 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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/tileindextileprovider.h>
namespace openspace::globebrowsing {
TileIndexTileProvider::TileIndexTileProvider(const ghoul::Dictionary&)
: TextTileProvider(tileTextureInitData(layergroupid::GroupID::ColorLayers, false))
{}
Tile TileIndexTileProvider::tile(const TileIndex& tileIndex) {
ZoneScoped
std::string text = fmt::format(
"level: {}\nx: {}\ny: {}", tileIndex.level, tileIndex.x, tileIndex.y
);
glm::vec2 textPosition = glm::vec2(
initData.dimensions.x / 4 -
(initData.dimensions.x / 32) * log10(1 << tileIndex.level),
initData.dimensions.y / 2 + fontSize
);
return TextTileProvider::renderTile(tileIndex, text, textPosition, glm::vec4(1.f));
}
Tile::Status TileIndexTileProvider::tileStatus(const TileIndex&) {
return Tile::Status::OK;
}
TileDepthTransform TileIndexTileProvider::depthTransform() {
return { 0.f, 1.f };
}
void TileIndexTileProvider::update() {}
int TileIndexTileProvider::maxLevel() {
return 1337; // unlimited
}
float TileIndexTileProvider::noDataValueAsFloat() {
return std::numeric_limits<float>::min();
}
} // namespace openspace::globebrowsing
@@ -22,14 +22,25 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "catch2/catch.hpp"
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEINDEXTILEPROVIDER___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEINDEXTILEPROVIDER___H__
#include <modules/globebrowsing/src/tileprovider.h>
#include <openspace/util/time.h>
#include <glm/glm.hpp>
#include <modules/globebrowsing/src/tileprovider/texttileprovider.h>
namespace {
constexpr const char* fileName = "data/scene/debugglobe/map_service_configs/"
"VIIRS_SNPP_CorrectedReflectance_TrueColor_temporal.xml";
} // namespace
namespace openspace::globebrowsing {
class TileIndexTileProvider : public TextTileProvider {
public:
TileIndexTileProvider(const ghoul::Dictionary& dictionary);
Tile tile(const TileIndex& tileIndex) override final;
Tile::Status tileStatus(const TileIndex& index) override final;
TileDepthTransform depthTransform() override final;
void update() override final;
int maxLevel() override final;
float noDataValueAsFloat() override final;
};
} // namespace openspace::globebrowsing
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEINDEXTILEPROVIDER___H__
@@ -0,0 +1,238 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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/tileprovider.h>
#include <modules/globebrowsing/globebrowsingmodule.h>
#include <modules/globebrowsing/src/asynctiledataprovider.h>
#include <modules/globebrowsing/src/geodeticpatch.h>
#include <modules/globebrowsing/src/layermanager.h>
#include <modules/globebrowsing/src/memoryawaretilecache.h>
#include <modules/globebrowsing/src/rawtiledatareader.h>
#include <modules/globebrowsing/src/tileprovider/defaulttileprovider.h>
#include <modules/globebrowsing/src/tileprovider/imagesequencetileprovider.h>
#include <modules/globebrowsing/src/tileprovider/singleimagetileprovider.h>
#include <modules/globebrowsing/src/tileprovider/sizereferencetileprovider.h>
#include <modules/globebrowsing/src/tileprovider/temporaltileprovider.h>
#include <modules/globebrowsing/src/tileprovider/tileindextileprovider.h>
#include <modules/globebrowsing/src/tileprovider/tileproviderbyindex.h>
#include <modules/globebrowsing/src/tileprovider/tileproviderbylevel.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/util/factorymanager.h>
#include <openspace/util/memorymanager.h>
#include <openspace/util/spicemanager.h>
#include <openspace/util/timemanager.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/font/fontmanager.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/profiling.h>
#include <ghoul/opengl/openglstatecache.h>
#include <ghoul/opengl/textureunit.h>
#include <filesystem>
#include <fstream>
#include "cpl_minixml.h"
namespace openspace::globebrowsing {
namespace {
std::unique_ptr<ghoul::opengl::Texture> DefaultTileTexture;
Tile DefaultTile = Tile { nullptr, std::nullopt, Tile::Status::Unavailable };
constexpr const char* KeyFilePath = "FilePath";
} // namespace
unsigned int TileProvider::NumTileProviders = 0;
std::unique_ptr<TileProvider> TileProvider::createFromDictionary(
layergroupid::TypeID layerTypeID,
const ghoul::Dictionary& dictionary)
{
ZoneScoped
const char* type = layergroupid::LAYER_TYPE_NAMES[static_cast<int>(layerTypeID)];
auto factory = FactoryManager::ref().factory<TileProvider>();
TileProvider* result = factory->create(type, dictionary);
return std::unique_ptr<TileProvider>(result);
}
void TileProvider::initializeDefaultTile() {
ZoneScoped
ghoul_assert(!DefaultTile.texture, "Default tile should not have been created");
using namespace ghoul::opengl;
// Create pixel data
TileTextureInitData initData(
8,
8,
GL_UNSIGNED_BYTE,
Texture::Format::RGBA,
TileTextureInitData::PadTiles::No,
TileTextureInitData::ShouldAllocateDataOnCPU::Yes
);
char* pixels = new char[initData.totalNumBytes];
memset(pixels, 0, initData.totalNumBytes * sizeof(char));
// Create ghoul texture
DefaultTileTexture = std::make_unique<Texture>(initData.dimensions, GL_TEXTURE_2D);
DefaultTileTexture->setDataOwnership(Texture::TakeOwnership::Yes);
DefaultTileTexture->setPixelData(pixels);
DefaultTileTexture->uploadTexture();
DefaultTileTexture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
// Create tile
DefaultTile = Tile{ DefaultTileTexture.get(), std::nullopt, Tile::Status::OK };
}
void TileProvider::deinitializeDefaultTile() {
DefaultTileTexture = nullptr;
}
TileProvider::TileProvider() : properties::PropertyOwner({ "tileProvider" }) {}
void TileProvider::initialize() {
ZoneScoped
ghoul_assert(!isInitialized, "TileProvider can only be initialized once.");
if (TileProvider::NumTileProviders >
static_cast<unsigned int>(std::numeric_limits<uint16_t>::max()) - 1)
{
LERRORC(
"TileProvider",
"Number of tile providers exceeds 65535. Something will break soon"
);
TileProvider::NumTileProviders = 0;
}
uniqueIdentifier = static_cast<uint16_t>(TileProvider::NumTileProviders++);
if (TileProvider::NumTileProviders == std::numeric_limits<unsigned int>::max()) {
--TileProvider::NumTileProviders;
return;
}
internalInitialize();
isInitialized = true;
}
void TileProvider::deinitialize() {
ZoneScoped
internalDeinitialize();
}
void TileProvider::internalInitialize() {}
void TileProvider::internalDeinitialize() {}
ChunkTile TileProvider::chunkTile(TileIndex tileIndex, int parents, int maxParents) {
ZoneScoped
ghoul_assert(isInitialized, "TileProvider was not initialized.");
auto ascendToParent = [](TileIndex& ti, TileUvTransform& uv) {
uv.uvOffset *= 0.5;
uv.uvScale *= 0.5;
uv.uvOffset += ti.positionRelativeParent();
ti.x /= 2;
ti.y /= 2;
ti.level--;
};
TileUvTransform uvTransform = { glm::vec2(0.f, 0.f), glm::vec2(1.f, 1.f) };
// Step 1. Traverse 0 or more parents up the chunkTree as requested by the caller
for (int i = 0; i < parents && tileIndex.level > 1; i++) {
ascendToParent(tileIndex, uvTransform);
}
maxParents -= parents;
// Step 2. Traverse 0 or more parents up the chunkTree to make sure we're inside
// the range of defined data.
int maximumLevel = maxLevel();
while (tileIndex.level > maximumLevel) {
ascendToParent(tileIndex, uvTransform);
maxParents--;
}
if (maxParents < 0) {
return ChunkTile { Tile(), uvTransform, TileDepthTransform() };
}
// Step 3. Traverse 0 or more parents up the chunkTree until we find a chunk that
// has a loaded tile ready to use.
while (tileIndex.level > 1) {
Tile t = tile(tileIndex);
if (t.status != Tile::Status::OK) {
if (--maxParents < 0) {
return ChunkTile { Tile(), uvTransform, TileDepthTransform() };
}
ascendToParent(tileIndex, uvTransform);
}
else {
return ChunkTile { std::move(t), uvTransform, TileDepthTransform() };
}
}
return ChunkTile { Tile(), uvTransform, TileDepthTransform() };
}
ChunkTilePile TileProvider::chunkTilePile(TileIndex tileIndex, int pileSize) {
ZoneScoped
ghoul_assert(isInitialized, "TileProvider was not initialized.");
ghoul_assert(pileSize >= 0, "pileSize must be positive");
ChunkTilePile chunkTilePile;
std::fill(chunkTilePile.begin(), chunkTilePile.end(), std::nullopt);
for (int i = 0; i < pileSize; ++i) {
chunkTilePile[i] = chunkTile(tileIndex, i);
if (chunkTilePile[i]->tile.status == Tile::Status::Unavailable) {
if (i == 0) {
// First iteration
chunkTilePile[i]->tile = DefaultTile;
chunkTilePile[i]->uvTransform.uvOffset = { 0.f, 0.f };
chunkTilePile[i]->uvTransform.uvScale = { 1.f, 1.f };
}
else {
// We are iterating through the array one-by-one, so we are guaranteed
// that for tile 'i', tile 'i-1' already was initializated
chunkTilePile[i]->tile = chunkTilePile[i - 1]->tile;
chunkTilePile[i]->uvTransform.uvOffset =
chunkTilePile[i - 1]->uvTransform.uvOffset;
chunkTilePile[i]->uvTransform.uvScale =
chunkTilePile[i - 1]->uvTransform.uvScale;
}
}
}
return chunkTilePile;
}
} // namespace openspace::globebrowsing
@@ -0,0 +1,145 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEPROVIDER___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEPROVIDER___H__
#include <openspace/properties/propertyowner.h>
#include <modules/globebrowsing/src/basictypes.h>
#include <modules/globebrowsing/src/ellipsoid.h>
#include <modules/globebrowsing/src/layergroupid.h>
#include <modules/globebrowsing/src/tileindex.h>
#include <modules/globebrowsing/src/tiletextureinitdata.h>
#include <modules/globebrowsing/src/timequantizer.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/intproperty.h>
#include <unordered_map>
#include <ghoul/opengl/programobject.h>
struct CPLXMLNode;
namespace ghoul::fontrendering {
class Font;
class FontRenderer;
} // namespace ghoul::fontrendering
namespace openspace { class PixelBuffer; }
namespace openspace::globebrowsing {
class AsyncTileDataProvider;
struct RawTile;
struct TileIndex;
namespace cache { class MemoryAwareTileCache; }
} // namespace openspace::globebrowsing
namespace openspace::globebrowsing {
enum class Type {
DefaultTileProvider = 0,
SingleImageTileProvider,
ImageSequenceTileProvider,
SizeReferenceTileProvider,
TemporalTileProvider,
TileIndexTileProvider,
ByIndexTileProvider,
ByLevelTileProvider,
InterpolateTileProvider
};
struct TileProvider : public properties::PropertyOwner {
static unsigned int NumTileProviders;
static std::unique_ptr<TileProvider> createFromDictionary(
layergroupid::TypeID layerTypeID, const ghoul::Dictionary& dictionary);
static void initializeDefaultTile();
static void deinitializeDefaultTile();
TileProvider();
virtual ~TileProvider() = default;
void initialize();
void deinitialize();
virtual Tile tile(const TileIndex& tileIndex) = 0;
/**
* Returns the status of a <code>Tile</code>. The <code>Tile::Status</code>
* corresponds the <code>Tile</code> that would be returned if the function
* <code>tile</code> would be invoked with the same <code>TileIndex</code> argument at
* this point in time.
*/
virtual Tile::Status tileStatus(const TileIndex& index) = 0;
/**
* Get the associated depth transform for this TileProvider. This is necessary for
* TileProviders serving height map data, in order to correcly map pixel values to
* meters.
*/
virtual TileDepthTransform depthTransform() = 0;
/**
* This method should be called once per frame. Here, TileProviders are given the
* opportunity to update their internal state.
*/
virtual void update() = 0;
/**
* Provides a uniform way of all TileProviders to reload or restore all of its
* internal state. This is mainly useful for debugging purposes.
*/
virtual void reset() = 0;
/**
* \return The maximum level as defined by <code>TileIndex</code> that this
* TileProvider is able provide.
*/
virtual int maxLevel() = 0;
/**
* \return the no data value for the dataset. Default is the minimum float value.
*/
virtual float noDataValueAsFloat() = 0;
ChunkTile chunkTile(TileIndex tileIndex, int parents = 0, int maxParents = 1337);
ChunkTilePile chunkTilePile(TileIndex tileIndex, int pileSize);
std::string name;
uint16_t uniqueIdentifier = 0;
bool isInitialized = false;
private:
virtual void internalInitialize();
virtual void internalDeinitialize();
};
} // namespace openspace::globebrowsing
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEPROVIDER___H__
@@ -0,0 +1,140 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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/tileproviderbyindex.h>
#include <openspace/documentation/documentation.h>
namespace {
constexpr const char* KeyDefaultProvider = "DefaultProvider";
constexpr const char* KeyProviders = "IndexTileProviders";
constexpr const char* KeyTileIndex = "TileIndex";
constexpr const char* KeyTileProvider = "TileProvider";
struct [[codegen::Dictionary(TileProviderByIndex)]] Parameters {
ghoul::Dictionary defaultProvider;
struct IndexProvider {
struct Index {
int x [[codegen::greaterequal(0)]];
int y [[codegen::greaterequal(0)]];
int level [[codegen::inrange(0, 255)]];
};
Index tileIndex;
ghoul::Dictionary tileProvider;
};
std::vector<IndexProvider> indexTileProviders;
};
#include "tileproviderbyindex_codegen.cpp"
} // namespace
namespace openspace::globebrowsing {
TileProviderByIndex::TileProviderByIndex(const ghoul::Dictionary& dictionary) {
ZoneScoped
const Parameters p = codegen::bake<Parameters>(dictionary);
layergroupid::TypeID typeID = layergroupid::TypeID::DefaultTileLayer;
if (p.defaultProvider.hasValue<std::string>("Type")) {
std::string type = p.defaultProvider.value<std::string>("Type");
typeID = ghoul::from_string<layergroupid::TypeID>(type);
if (typeID == layergroupid::TypeID::Unknown) {
throw ghoul::RuntimeError("Unknown layer type: " + type);
}
}
_defaultTileProvider = createFromDictionary(typeID, p.defaultProvider);
for (const Parameters::IndexProvider& ip : p.indexTileProviders) {
const TileIndex tileIndex(
ip.tileIndex.x,
ip.tileIndex.y,
static_cast<uint8_t>(ip.tileIndex.level)
);
layergroupid::TypeID providerTypeID = layergroupid::TypeID::DefaultTileLayer;
if (ip.tileProvider.hasValue<std::string>("Type")) {
std::string type = ip.tileProvider.value<std::string>("Type");
providerTypeID = ghoul::from_string<layergroupid::TypeID>(type);
if (providerTypeID == layergroupid::TypeID::Unknown) {
throw ghoul::RuntimeError("Unknown layer type: " + type);
}
}
std::unique_ptr<TileProvider> stp = createFromDictionary(
providerTypeID,
ip.tileProvider
);
TileIndex::TileHashKey key = tileIndex.hashKey();
_providers.insert(std::make_pair(key, std::move(stp)));
}
}
Tile TileProviderByIndex::tile(const TileIndex& tileIndex) {
ZoneScoped
const auto it = _providers.find(tileIndex.hashKey());
const bool hasProvider = it != _providers.end();
return hasProvider ? it->second->tile(tileIndex) : Tile();
}
Tile::Status TileProviderByIndex::tileStatus(const TileIndex& index) {
const auto it = _providers.find(index.hashKey());
const bool hasProvider = it != _providers.end();
return hasProvider ? it->second->tileStatus(index) : Tile::Status::Unavailable;
}
TileDepthTransform TileProviderByIndex::depthTransform() {
return _defaultTileProvider->depthTransform();
}
void TileProviderByIndex::update() {
using K = TileIndex::TileHashKey;
using V = std::unique_ptr<TileProvider>;
for (std::pair<const K, V>& it : _providers) {
it.second->update();
}
_defaultTileProvider->update();
}
void TileProviderByIndex::reset() {
using K = TileIndex::TileHashKey;
using V = std::unique_ptr<TileProvider>;
for (std::pair<const K, V>& it : _providers) {
it.second->reset();
}
_defaultTileProvider->reset();
}
int TileProviderByIndex::maxLevel() {
return _defaultTileProvider->maxLevel();
}
float TileProviderByIndex::noDataValueAsFloat() {
return std::numeric_limits<float>::min();
}
} // namespace openspace::globebrowsing
@@ -0,0 +1,51 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEPROVIDERBYINDEX___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEPROVIDERBYINDEX___H__
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
namespace openspace::globebrowsing {
class TileProviderByIndex : public TileProvider {
public:
TileProviderByIndex(const ghoul::Dictionary& dictionary);
Tile tile(const TileIndex& tileIndex) override final;
Tile::Status tileStatus(const TileIndex& index) override final;
TileDepthTransform depthTransform() override final;
void update() override final;
void reset() override final;
int maxLevel() override final;
float noDataValueAsFloat() override final;
private:
std::unordered_map<TileIndex::TileHashKey, std::unique_ptr<TileProvider>> _providers;
std::unique_ptr<TileProvider> _defaultTileProvider;
};
} // namespace openspace::globebrowsing
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEPROVIDERBYINDEX___H__
@@ -0,0 +1,161 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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/tileproviderbylevel.h>
#include <openspace/documentation/documentation.h>
namespace {
struct [[codegen::Dictionary(TileProviderByLevel)]] Parameters {
int layerGroupID;
struct Providers {
int maxLevel [[codegen::greaterequal(0)]];
ghoul::Dictionary tileProvider;
};
std::vector<Providers> levelTileProviders;
};
#include "tileproviderbylevel_codegen.cpp"
} // namespace
namespace openspace::globebrowsing {
TileProviderByLevel::TileProviderByLevel(const ghoul::Dictionary& dictionary) {
ZoneScoped
const Parameters p = codegen::bake<Parameters>(dictionary);
layergroupid::GroupID layerGroup = static_cast<layergroupid::GroupID>(p.layerGroupID);
for (Parameters::Providers p : p.levelTileProviders) {
p.tileProvider.setValue("LayerGroupID", static_cast<int>(layerGroup));
layergroupid::TypeID typeID = layergroupid::TypeID::DefaultTileLayer;
if (p.tileProvider.hasValue<std::string>("Type")) {
std::string type = p.tileProvider.value<std::string>("Type");
typeID = ghoul::from_string<layergroupid::TypeID>(type);
if (typeID == layergroupid::TypeID::Unknown) {
throw ghoul::RuntimeError("Unknown layer type: " + type);
}
}
std::unique_ptr<TileProvider> tp = createFromDictionary(typeID, p.tileProvider);
std::string provId = p.tileProvider.value<std::string>("Identifier");
tp->setIdentifier(provId);
std::string providerName = p.tileProvider.value<std::string>("Name");
tp->setGuiName(providerName);
addPropertySubOwner(tp.get());
_levelTileProviders.push_back(std::move(tp));
// Ensure we can represent the max level
if (static_cast<int>(_providerIndices.size()) < p.maxLevel) {
_providerIndices.resize(p.maxLevel + 1, -1);
}
// map this level to the tile provider index
_providerIndices[p.maxLevel] = static_cast<int>(_levelTileProviders.size()) - 1;
}
// Fill in the gaps (value -1 ) in provider indices, from back to end
for (int i = static_cast<int>(_providerIndices.size()) - 2; i >= 0; --i) {
if (_providerIndices[i] == -1) {
_providerIndices[i] = _providerIndices[i + 1];
}
}
}
void TileProviderByLevel::internalInitialize() {
for (const std::unique_ptr<TileProvider>& prov : _levelTileProviders) {
prov->initialize();
}
}
void TileProviderByLevel::internalDeinitialize() {
for (const std::unique_ptr<TileProvider>& prov : _levelTileProviders) {
prov->deinitialize();
}
}
Tile TileProviderByLevel::tile(const TileIndex& tileIndex) {
ZoneScoped
TileProvider* provider = levelProvider(tileIndex.level);
if (provider) {
return provider->tile(tileIndex);
}
else {
return Tile();
}
}
Tile::Status TileProviderByLevel::tileStatus(const TileIndex& index) {
TileProvider* provider = levelProvider(index.level);
return provider ? provider->tileStatus(index) : Tile::Status::Unavailable;
}
TileProvider* TileProviderByLevel::levelProvider(int level) const {
ZoneScoped
if (!_levelTileProviders.empty()) {
int clampedLevel = glm::clamp(
level,
0,
static_cast<int>(_providerIndices.size() - 1)
);
int idx = _providerIndices[clampedLevel];
return _levelTileProviders[idx].get();
}
else {
return nullptr;
}
}
TileDepthTransform TileProviderByLevel::depthTransform() {
return { 0.f, 1.f };
}
void TileProviderByLevel::update() {
for (const std::unique_ptr<TileProvider>& provider : _levelTileProviders) {
provider->update();
}
}
void TileProviderByLevel::reset() {
for (const std::unique_ptr<TileProvider>& provider : _levelTileProviders) {
provider->reset();
}
}
int TileProviderByLevel::maxLevel() {
return static_cast<int>(_providerIndices.size() - 1);
}
float TileProviderByLevel::noDataValueAsFloat() {
return std::numeric_limits<float>::min();
}
} // namespace openspace::globebrowsing
@@ -0,0 +1,55 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEPROVIDERBYLEVEL___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEPROVIDERBYLEVEL___H__
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
namespace openspace::globebrowsing {
class TileProviderByLevel : public TileProvider {
public:
TileProviderByLevel(const ghoul::Dictionary& dictionary);
Tile tile(const TileIndex& tileIndex) override final;
Tile::Status tileStatus(const TileIndex& index) override final;
TileDepthTransform depthTransform() override final;
void update() override final;
void reset() override final;
int maxLevel() override final;
float noDataValueAsFloat() override final;
private:
std::vector<int> _providerIndices;
std::vector<std::unique_ptr<TileProvider>> _levelTileProviders;
void internalInitialize() override final;
void internalDeinitialize() override final;
TileProvider* levelProvider(int level) const;
};
} // namespace openspace::globebrowsing
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__TILEPROVIDERBYLEVEL___H__
-1
View File
@@ -40,7 +40,6 @@ add_executable(
test_rawvolumeio.cpp
test_scriptscheduler.cpp
test_spicemanager.cpp
test_temporaltileprovider.cpp
test_timequantizer.cpp
test_timeline.cpp