mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-07 20:09:58 -05:00
Feature/tileinterpolation (#1769)
* Interpolation of tiles added to tileprovider, with additional new shaders to make this work. * Asset file for testing interpolation Co-authored-by: tobiasp93 <tobias.pettersson@liu.se> Co-authored-by: Alexander Bock <alexander.bock@liu.se>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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 "fragment.glsl"
|
||||
|
||||
uniform sampler2D prevTexture;
|
||||
uniform sampler2D nextTexture;
|
||||
uniform sampler2D colormapTexture;
|
||||
uniform float blendFactor;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
Fragment getFragment() {
|
||||
vec4 texel0 = texture2D(prevTexture, texCoord);
|
||||
vec4 texel1 = texture2D(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);
|
||||
}
|
||||
else {
|
||||
vec2 position = vec2(mixedTexture.r , 0.5);
|
||||
frag.color = texture2D(colormapTexture, position);
|
||||
}
|
||||
|
||||
frag.color.a = mixedTexture.a;
|
||||
return frag;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
layout (location = 0) in vec2 in_position;
|
||||
layout (location = 1) in vec2 in_texCoords;
|
||||
|
||||
out vec2 texCoord;
|
||||
|
||||
void main() {
|
||||
texCoord = in_texCoords;
|
||||
gl_Position = vec4(in_position, 0.0, 1.0);
|
||||
}
|
||||
@@ -34,8 +34,9 @@
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/util/factorymanager.h>
|
||||
#include <openspace/util/timemanager.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>
|
||||
@@ -44,6 +45,7 @@
|
||||
#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"
|
||||
@@ -142,7 +144,8 @@ namespace temporal {
|
||||
constexpr const char* TimeEnd = "OpenSpaceTimeEnd";
|
||||
constexpr const char* TimeResolution = "OpenSpaceTimeResolution";
|
||||
constexpr const char* TimeFormat = "OpenSpaceTimeIdFormat";
|
||||
|
||||
constexpr const char* TimeInterpolation = "OpenSpaceTimeInterpolation";
|
||||
constexpr const char* TransferFunction = "OpenSpaceTransferFunction";
|
||||
constexpr openspace::properties::Property::PropertyInfo FilePathInfo = {
|
||||
"FilePath",
|
||||
"File Path",
|
||||
@@ -291,10 +294,13 @@ TileProvider* levelProvider(TileProviderByLevel& t, int level) {
|
||||
//
|
||||
|
||||
// Buffer needs at least 22 characters space
|
||||
int timeStringify(TemporalTileProvider::TimeFormatType type, const Time& t, char* buffer)
|
||||
{
|
||||
std::string_view timeStringify(TemporalTileProvider::TimeFormatType type, const Time& t) {
|
||||
ZoneScoped
|
||||
|
||||
char* buffer = reinterpret_cast<char*>(
|
||||
global::memoryManager->TemporaryMemory.allocate(22)
|
||||
);
|
||||
|
||||
std::memset(buffer, 0, 22);
|
||||
const double time = t.j2000Seconds();
|
||||
|
||||
@@ -304,32 +310,32 @@ int timeStringify(TemporalTileProvider::TimeFormatType type, const Time& t, char
|
||||
constexpr const char Format[] = "YYYY-MM-DD";
|
||||
constexpr const int Size = sizeof(Format);
|
||||
SpiceManager::ref().dateFromEphemerisTime(time, buffer, Size, Format);
|
||||
return Size - 1;
|
||||
return std::string_view(buffer, Size - 1);
|
||||
}
|
||||
case TemporalTileProvider::TimeFormatType::YYYYMMDD_hhmmss: {
|
||||
constexpr const char Format[] = "YYYYMMDD_HRMNSC";
|
||||
constexpr const int Size = sizeof(Format);
|
||||
SpiceManager::ref().dateFromEphemerisTime(time, buffer, Size, Format);
|
||||
return Size - 1;
|
||||
return std::string_view(buffer, Size - 1);
|
||||
}
|
||||
case TemporalTileProvider::TimeFormatType::YYYYMMDD_hhmm: {
|
||||
constexpr const char Format[] = "YYYYMMDD_HRMN";
|
||||
constexpr const int Size = sizeof(Format);
|
||||
SpiceManager::ref().dateFromEphemerisTime(time, buffer, Size, Format);
|
||||
return Size - 1;
|
||||
return std::string_view(buffer, Size - 1);
|
||||
}
|
||||
case TemporalTileProvider::TimeFormatType::YYYY_MM_DDThhColonmmColonssZ:
|
||||
{
|
||||
constexpr const char Format[] = "YYYY-MM-DDTHR:MN:SCZ";
|
||||
constexpr const int Size = sizeof(Format);
|
||||
SpiceManager::ref().dateFromEphemerisTime(time, buffer, Size, Format);
|
||||
return Size - 1;
|
||||
return std::string_view(buffer, Size - 1);
|
||||
}
|
||||
case TemporalTileProvider::TimeFormatType::YYYY_MM_DDThh_mm_ssZ: {
|
||||
constexpr const char Format[] = "YYYY-MM-DDTHR_MN_SCZ";
|
||||
constexpr const int Size = sizeof(Format);
|
||||
SpiceManager::ref().dateFromEphemerisTime(time, buffer, Size, Format);
|
||||
return Size - 1;
|
||||
return std::string_view(buffer, Size - 1);
|
||||
}
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
@@ -387,30 +393,137 @@ TileProvider* getTileProvider(TemporalTileProvider& t, std::string_view timekey)
|
||||
TileProvider* getTileProvider(TemporalTileProvider& t, const Time& time) {
|
||||
ZoneScoped
|
||||
|
||||
if (t.useFixedTime && !t.fixedTime.value().empty()) {
|
||||
try {
|
||||
return getTileProvider(t, t.fixedTime.value());
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC("TemporalTileProvider", e.message);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Time tCopy(time);
|
||||
if (t.timeQuantizer.quantize(tCopy, true)) {
|
||||
char Buffer[22];
|
||||
const int size = timeStringify(t.timeFormat, tCopy, Buffer);
|
||||
if (!t.interpolation) {
|
||||
if (t.useFixedTime && !t.fixedTime.value().empty()) {
|
||||
try {
|
||||
return getTileProvider(t, std::string_view(Buffer, size));
|
||||
return getTileProvider(t, t.fixedTime.value());
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC("TemporalTileProvider", e.message);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Time tCopy(time);
|
||||
if (t.timeQuantizer.quantize(tCopy, true)) {
|
||||
std::string_view timeStr = timeStringify(t.timeFormat, tCopy);
|
||||
try {
|
||||
return getTileProvider(t, timeStr);
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC("TemporalTileProvider", e.message);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Time tCopy(time);
|
||||
if (!t.timeQuantizer.quantize(tCopy, true)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Time simulationTime(time);
|
||||
Time nextTile;
|
||||
Time nextNextTile;
|
||||
Time prevTile;
|
||||
Time secondToLast;
|
||||
Time secondToFirst;
|
||||
|
||||
std::string_view tCopyStr = timeStringify(t.timeFormat, tCopy);
|
||||
try {
|
||||
t.interpolateTileProvider->t1 = getTileProvider(t, tCopyStr);
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC("TemporalTileProvider", e.message);
|
||||
return nullptr;
|
||||
}
|
||||
// if the images are for each hour
|
||||
if (t.myResolution == "1h") {
|
||||
// the second tile to interpolate between
|
||||
nextTile.setTime(tCopy.j2000Seconds() + 60 * 60);
|
||||
// the tile after the second tile
|
||||
nextNextTile.setTime(tCopy.j2000Seconds() + 120 * 60);
|
||||
// the tile before the first tile
|
||||
prevTile.setTime(tCopy.j2000Seconds() - 60 * 60 + 1);
|
||||
// to make sure that an image outside the dataset is not searched for both ends of
|
||||
// the dataset are calculated
|
||||
secondToLast.setTime(t.endTimeJ2000 - 60 * 60);
|
||||
secondToFirst.setTime(t.startTimeJ2000 + 60 * 60);
|
||||
}
|
||||
// if the images are for each month
|
||||
if (t.myResolution == "1M") {
|
||||
// the second tile to interpolate between
|
||||
nextTile.setTime(tCopy.j2000Seconds() + 32 * 60 * 60 * 24);
|
||||
// the tile after the second tile
|
||||
nextNextTile.setTime(tCopy.j2000Seconds() + 64 * 60 * 60 * 24);
|
||||
// the tile before the first tile
|
||||
prevTile.setTime(tCopy.j2000Seconds() - 2 * 60 * 60 * 24);
|
||||
// to make sure that an image outside the dataset is not searched for both ends of
|
||||
// the dataset are calculated
|
||||
secondToLast.setTime(t.endTimeJ2000 - 2 * 60 * 60 * 24);
|
||||
secondToFirst.setTime(t.startTimeJ2000 + 32 * 60 * 60 * 24);
|
||||
|
||||
// since months vary in length the time strings are set to the first of each month
|
||||
auto setToFirstOfMonth = [](Time& time) {
|
||||
std::string timeString = std::string(time.ISO8601());
|
||||
timeString[8] = '0';
|
||||
timeString[9] = '1';
|
||||
time.setTime(timeString);
|
||||
};
|
||||
|
||||
setToFirstOfMonth(nextTile);
|
||||
setToFirstOfMonth(nextNextTile);
|
||||
setToFirstOfMonth(prevTile);
|
||||
setToFirstOfMonth(secondToLast);
|
||||
setToFirstOfMonth(secondToFirst);
|
||||
}
|
||||
|
||||
std::string_view nextTileStr = timeStringify(t.timeFormat, nextTile);
|
||||
std::string_view nextNextTileStr = timeStringify(t.timeFormat, nextNextTile);
|
||||
std::string_view prevTileStr = timeStringify(t.timeFormat, prevTile);
|
||||
try {
|
||||
// the necessary tile providers are loaded if they exist within the
|
||||
// dataset's timespan
|
||||
if (secondToLast.j2000Seconds() > simulationTime.j2000Seconds() &&
|
||||
secondToFirst.j2000Seconds() < simulationTime.j2000Seconds())
|
||||
{
|
||||
t.interpolateTileProvider->t2 = getTileProvider(t, nextTileStr);
|
||||
t.interpolateTileProvider->future = getTileProvider(t, nextNextTileStr);
|
||||
t.interpolateTileProvider->before = getTileProvider(t, prevTileStr);
|
||||
}
|
||||
else if (secondToLast.j2000Seconds() < simulationTime.j2000Seconds() &&
|
||||
t.endTimeJ2000 > simulationTime.j2000Seconds())
|
||||
{
|
||||
t.interpolateTileProvider->t2 = getTileProvider(t, nextTileStr);
|
||||
t.interpolateTileProvider->future = getTileProvider(t, tCopyStr);
|
||||
t.interpolateTileProvider->before = getTileProvider(t, prevTileStr);
|
||||
}
|
||||
else if (secondToFirst.j2000Seconds() > simulationTime.j2000Seconds() &&
|
||||
t.startTimeJ2000 < simulationTime.j2000Seconds())
|
||||
{
|
||||
t.interpolateTileProvider->t2 = getTileProvider(t, nextTileStr);
|
||||
t.interpolateTileProvider->future = getTileProvider(t, nextNextTileStr);
|
||||
t.interpolateTileProvider->before = getTileProvider(t, tCopyStr);
|
||||
}
|
||||
else {
|
||||
t.interpolateTileProvider->t2 = getTileProvider(t, tCopyStr);
|
||||
t.interpolateTileProvider->future = getTileProvider(t, tCopyStr);
|
||||
t.interpolateTileProvider->before = getTileProvider(t, tCopyStr);
|
||||
}
|
||||
t.interpolateTileProvider->factor =
|
||||
(simulationTime.j2000Seconds() - tCopy.j2000Seconds()) /
|
||||
(nextTile.j2000Seconds() - tCopy.j2000Seconds());
|
||||
|
||||
if (t.interpolateTileProvider->factor > 1) {
|
||||
t.interpolateTileProvider->factor = 1;
|
||||
}
|
||||
return t.interpolateTileProvider.get();
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC("TemporalTileProvider", e.message);
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ensureUpdated(TemporalTileProvider& t) {
|
||||
@@ -422,10 +535,10 @@ void ensureUpdated(TemporalTileProvider& t) {
|
||||
}
|
||||
|
||||
std::string xmlValue(TemporalTileProvider& t, CPLXMLNode* node, const std::string& key,
|
||||
const std::string& defaultVal)
|
||||
const std::string& defaultVal, bool isOptional = false)
|
||||
{
|
||||
CPLXMLNode* n = CPLSearchXMLNode(node, key.c_str());
|
||||
if (!n) {
|
||||
if (!n && !isOptional) {
|
||||
throw ghoul::RuntimeError(
|
||||
fmt::format("Unable to parse file {}. {} missing", t.filePath.value(), key)
|
||||
);
|
||||
@@ -449,10 +562,20 @@ std::string consumeTemporalMetaData(TemporalTileProvider& t, const std::string&
|
||||
temporal::TimeFormat,
|
||||
"YYYY-MM-DDThh:mm:ssZ"
|
||||
);
|
||||
std::string timeInterpolation = xmlValue(
|
||||
t,
|
||||
node,
|
||||
temporal::TimeInterpolation,
|
||||
"none",
|
||||
true
|
||||
);
|
||||
t.colormap = xmlValue(t, node, temporal::TransferFunction, "none", true);
|
||||
|
||||
Time start;
|
||||
start.setTime(std::move(timeStart));
|
||||
Time end(Time::now());
|
||||
Time start = Time(timeStart);
|
||||
Time end = Time::now();
|
||||
Time endOfInterval = Time(timeEnd);
|
||||
t.startTimeJ2000 = start.j2000Seconds();
|
||||
t.endTimeJ2000 = endOfInterval.j2000Seconds();
|
||||
if (timeEnd == "Yesterday") {
|
||||
end.advanceTime(-60.0 * 60.0 * 24.0); // Go back one day
|
||||
}
|
||||
@@ -466,6 +589,7 @@ std::string consumeTemporalMetaData(TemporalTileProvider& t, const std::string&
|
||||
std::string(end.ISO8601())
|
||||
);
|
||||
t.timeQuantizer.setResolution(timeResolution);
|
||||
t.myResolution = timeResolution;
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
@@ -474,6 +598,7 @@ std::string consumeTemporalMetaData(TemporalTileProvider& t, const std::string&
|
||||
));
|
||||
}
|
||||
t.timeFormat = ghoul::from_string<TemporalTileProvider::TimeFormatType>(timeIdFormat);
|
||||
t.interpolation = (timeInterpolation == "linear");
|
||||
|
||||
CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "GDAL_WMS");
|
||||
if (gdalNode) {
|
||||
@@ -492,10 +617,10 @@ std::string consumeTemporalMetaData(TemporalTileProvider& t, const std::string&
|
||||
}
|
||||
}
|
||||
|
||||
bool readFilePath(TemporalTileProvider& t) {
|
||||
void readFilePath(TemporalTileProvider& t) {
|
||||
ZoneScoped
|
||||
|
||||
std::ifstream in(t.filePath.value().c_str());
|
||||
std::ifstream in(t.filePath.value());
|
||||
std::string xml;
|
||||
if (in.is_open()) {
|
||||
// read file
|
||||
@@ -516,7 +641,6 @@ bool readFilePath(TemporalTileProvider& t) {
|
||||
}
|
||||
|
||||
t.gdalXmlTemplate = consumeTemporalMetaData(t, xml);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -874,11 +998,21 @@ TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary)
|
||||
}
|
||||
addProperty(fixedTime);
|
||||
|
||||
successfulInitialization = readFilePath(*this);
|
||||
readFilePath(*this);
|
||||
successfulInitialization = true;
|
||||
|
||||
if (!successfulInitialization) {
|
||||
LERRORC("TemporalTileProvider", "Unable to read file " + filePath.value());
|
||||
}
|
||||
if (interpolation) {
|
||||
interpolateTileProvider = std::make_unique<InterpolateTileProvider>(dictionary);
|
||||
interpolateTileProvider->colormap = colormap;
|
||||
initialize(*interpolateTileProvider);
|
||||
ghoul::Dictionary dict;
|
||||
dict.setValue("FilePath", colormap);
|
||||
interpolateTileProvider->singleImageProvider =
|
||||
std::make_unique<SingleImageProvider>(dict);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -933,6 +1067,8 @@ bool initialize(TileProvider& tp) {
|
||||
}
|
||||
return success;
|
||||
}
|
||||
case Type::InterpolateTileProvider:
|
||||
break;
|
||||
case Type::TemporalTileProvider:
|
||||
break;
|
||||
default:
|
||||
@@ -975,6 +1111,8 @@ bool deinitialize(TileProvider& tp) {
|
||||
}
|
||||
return success;
|
||||
}
|
||||
case Type::InterpolateTileProvider:
|
||||
break;
|
||||
case Type::TemporalTileProvider:
|
||||
break;
|
||||
default:
|
||||
@@ -984,8 +1122,175 @@ bool deinitialize(TileProvider& tp) {
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// InterpolateTileProvider
|
||||
//
|
||||
InterpolateTileProvider::InterpolateTileProvider(const ghoul::Dictionary&) {
|
||||
ZoneScoped
|
||||
|
||||
type = Type::InterpolateTileProvider;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glGenVertexArrays(1, &vaoQuad);
|
||||
glGenBuffers(1, &vboQuad);
|
||||
glBindVertexArray(vaoQuad);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboQuad);
|
||||
tileCache = global::moduleEngine->module<GlobeBrowsingModule>()->tileCache();
|
||||
// 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*>(sizeof(GLfloat) * 2)
|
||||
);
|
||||
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")
|
||||
);
|
||||
}
|
||||
|
||||
InterpolateTileProvider::~InterpolateTileProvider() {
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
glDeleteBuffers(1, &vboQuad);
|
||||
glDeleteVertexArrays(1, &vaoQuad);
|
||||
}
|
||||
|
||||
Tile InterpolateTileProvider::calculateTile(const TileIndex& tileIndex) {
|
||||
ZoneScoped
|
||||
TracyGpuZone("tile");
|
||||
|
||||
// prev and next are the two tiles to interpolate between
|
||||
Tile prev = tile(*t1, tileIndex);
|
||||
Tile next = tile(*t2, tileIndex);
|
||||
// the tile before and the tile after the interpolation interval are loaded so the
|
||||
// interpolation goes smoother
|
||||
Tile prevprev = tile(*before, tileIndex);
|
||||
Tile nextnext = tile(*future, tileIndex);
|
||||
cache::ProviderTileKey key = { tileIndex, uniqueIdentifier };
|
||||
|
||||
if (!prev.texture || !next.texture) {
|
||||
return Tile{ nullptr, std::nullopt, Tile::Status::Unavailable };
|
||||
}
|
||||
|
||||
// There is a previous and next texture to interpolate between so do the interpolation
|
||||
|
||||
// The texture that will give the color for the interpolated texture
|
||||
ghoul::opengl::Texture* colormapTexture = singleImageProvider->tile.texture;
|
||||
long long hkey = cache::ProviderTileHasher()(key);
|
||||
// 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;
|
||||
if (tileCache->exist(key)) {
|
||||
// Get the tile from the tilecache
|
||||
ourTile = tileCache->get(key);
|
||||
// Use the texture from the tileCache
|
||||
writeTexture = ourTile.texture;
|
||||
}
|
||||
else {
|
||||
// Create a texture with the initialization data
|
||||
writeTexture = tileCache->texture(initData);
|
||||
// Create a tile with the texture
|
||||
ourTile = Tile{ writeTexture, std::nullopt, Tile::Status::OK };
|
||||
// Add it to the tilecache
|
||||
tileCache->put(key, initData.hashKey, ourTile);
|
||||
}
|
||||
|
||||
// Saves current state
|
||||
GLint currentFBO;
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFBO);
|
||||
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);
|
||||
// Check that our framebuffer is ok
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
LERRORC("TileProvider", "Incomplete framebuffer");
|
||||
}
|
||||
// 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);
|
||||
|
||||
ghoul::opengl::TextureUnit colormapUnit;
|
||||
colormapUnit.activate();
|
||||
colormapTexture->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 tile(TileProvider& tp, const TileIndex& tileIndex) {
|
||||
@@ -1091,6 +1396,13 @@ Tile tile(TileProvider& tp, const TileIndex& tileIndex) {
|
||||
return Tile();
|
||||
}
|
||||
}
|
||||
case Type::InterpolateTileProvider: {
|
||||
|
||||
ZoneScopedN("Type::InterpolateTileProvider")
|
||||
InterpolateTileProvider& t = static_cast<InterpolateTileProvider&>(tp);
|
||||
return t.calculateTile(tileIndex);
|
||||
break;
|
||||
}
|
||||
case Type::TemporalTileProvider: {
|
||||
ZoneScopedN("Type::TemporalTileProvider")
|
||||
TemporalTileProvider& t = static_cast<TemporalTileProvider&>(tp);
|
||||
@@ -1152,6 +1464,17 @@ Tile::Status tileStatus(TileProvider& tp, const TileIndex& index) {
|
||||
TileProvider* provider = levelProvider(t, index.level);
|
||||
return provider ? tileStatus(*provider, index) : Tile::Status::Unavailable;
|
||||
}
|
||||
case Type::InterpolateTileProvider: {
|
||||
InterpolateTileProvider& t = static_cast<InterpolateTileProvider&>(tp);
|
||||
Tile::Status t1Stat = tileStatus(*t.t1, index);
|
||||
Tile::Status t2Stat = tileStatus(*t.t2, index);
|
||||
if (t1Stat <= t2Stat) {
|
||||
return t1Stat;
|
||||
}
|
||||
else {
|
||||
return t2Stat;
|
||||
}
|
||||
}
|
||||
case Type::TemporalTileProvider: {
|
||||
TemporalTileProvider& t = static_cast<TemporalTileProvider&>(tp);
|
||||
if (t.successfulInitialization) {
|
||||
@@ -1197,6 +1520,10 @@ TileDepthTransform depthTransform(TileProvider& tp) {
|
||||
}
|
||||
case Type::ByLevelTileProvider:
|
||||
return { 0.f, 1.f };
|
||||
case Type::InterpolateTileProvider: {
|
||||
InterpolateTileProvider& t = static_cast<InterpolateTileProvider&>(tp);
|
||||
return depthTransform(*t.t1);
|
||||
}
|
||||
case Type::TemporalTileProvider: {
|
||||
TemporalTileProvider& t = static_cast<TemporalTileProvider&>(tp);
|
||||
if (t.successfulInitialization) {
|
||||
@@ -1265,6 +1592,14 @@ int update(TileProvider& tp) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::InterpolateTileProvider: {
|
||||
InterpolateTileProvider& t = static_cast<InterpolateTileProvider&>(tp);
|
||||
update(*t.t1);
|
||||
update(*t.t2);
|
||||
update(*t.before);
|
||||
update(*t.future);
|
||||
break;
|
||||
}
|
||||
case Type::TemporalTileProvider: {
|
||||
TemporalTileProvider& t = static_cast<TemporalTileProvider&>(tp);
|
||||
if (t.successfulInitialization) {
|
||||
@@ -1356,6 +1691,14 @@ void reset(TileProvider& tp) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::InterpolateTileProvider: {
|
||||
InterpolateTileProvider& t = static_cast<InterpolateTileProvider&>(tp);
|
||||
reset(*t.t1);
|
||||
reset(*t.t2);
|
||||
reset(*t.before);
|
||||
reset(*t.future);
|
||||
break;
|
||||
}
|
||||
case Type::TemporalTileProvider: {
|
||||
TemporalTileProvider& t = static_cast<TemporalTileProvider&>(tp);
|
||||
if (t.successfulInitialization) {
|
||||
@@ -1402,6 +1745,10 @@ int maxLevel(TileProvider& tp) {
|
||||
TileProviderByLevel& t = static_cast<TileProviderByLevel&>(tp);
|
||||
return static_cast<int>(t.providerIndices.size() - 1);
|
||||
}
|
||||
case Type::InterpolateTileProvider: {
|
||||
InterpolateTileProvider& t = static_cast<InterpolateTileProvider&>(tp);
|
||||
return glm::min(maxLevel(*t.t1), maxLevel(*t.t2));
|
||||
}
|
||||
case Type::TemporalTileProvider: {
|
||||
TemporalTileProvider& t = static_cast<TemporalTileProvider&>(tp);
|
||||
if (t.successfulInitialization) {
|
||||
@@ -1443,6 +1790,8 @@ float noDataValueAsFloat(TileProvider& tp) {
|
||||
return std::numeric_limits<float>::min();
|
||||
case Type::ByLevelTileProvider:
|
||||
return std::numeric_limits<float>::min();
|
||||
case Type::InterpolateTileProvider:
|
||||
return std::numeric_limits<float>::min();
|
||||
case Type::TemporalTileProvider:
|
||||
return std::numeric_limits<float>::min();
|
||||
default:
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#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 {
|
||||
@@ -63,7 +63,8 @@ enum class Type {
|
||||
TemporalTileProvider,
|
||||
TileIndexTileProvider,
|
||||
ByIndexTileProvider,
|
||||
ByLevelTileProvider
|
||||
ByLevelTileProvider,
|
||||
InterpolateTileProvider
|
||||
};
|
||||
|
||||
|
||||
@@ -104,6 +105,25 @@ struct SingleImageProvider : public TileProvider {
|
||||
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);
|
||||
|
||||
@@ -181,12 +201,18 @@ struct TemporalTileProvider : public TileProvider {
|
||||
|
||||
std::unordered_map<TimeKey, std::unique_ptr<TileProvider>> tileProviderMap;
|
||||
|
||||
TileProvider* currentTileProvider = nullptr;
|
||||
bool interpolation = false;
|
||||
|
||||
TileProvider* currentTileProvider = nullptr;
|
||||
double startTimeJ2000;
|
||||
double endTimeJ2000;
|
||||
TimeFormatType timeFormat;
|
||||
TimeQuantizer timeQuantizer;
|
||||
std::string colormap;
|
||||
|
||||
std::string myResolution;
|
||||
bool successfulInitialization = false;
|
||||
std::unique_ptr<InterpolateTileProvider> interpolateTileProvider;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user