Merge branch 'feature/globebrowsing' of github.com:OpenSpace/OpenSpace-Development into feature/globebrowsing

This commit is contained in:
Kalle Bladin
2016-05-24 22:55:34 -04:00
21 changed files with 801 additions and 634 deletions
+18 -6
View File
@@ -8,20 +8,32 @@ return {
Radii = {6378137.0, 6378137.0, 6356752.314245}, -- Earth's radii
Textures = {
ColorTextures = {
--[[
{
Name = "ESRI Imagery World 2D",
FilePath = "map_service_configs/ESRI_Imagery_World_2D.wms",
},
--]]
{
Name = "MODIS_Terra_CorrectedReflectance_TrueColor",
FilePath = "map_service_configs/MODIS_Terra_CorrectedReflectance_TrueColor.xml",
},
--[[
{
Name = "Coastlines",
FilePath = "map_service_configs/Coastlines.xml",
},
{
Name = "VIIRS_SNPP_CorrectedReflectance_TrueColor",
FilePath = "map_service_configs/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml"
},
{
Name = "ESRI Imagery World 2D",
FilePath = "map_service_configs/ESRI_Imagery_World_2D.wms",
},
{
Name = "MODIS_Terra_CorrectedReflectance_TrueColor",
FilePath = "map_service_configs/MODIS_Terra_CorrectedReflectance_TrueColor.xml",
},
--]]
},
HeightMaps = {
{
@@ -12,4 +12,5 @@
<BlockSizeX>512</BlockSizeX>
<BlockSizeY>512</BlockSizeY>
<BandsCount>3</BandsCount>
<MaxConnections>5</MaxConnections>
</GDAL_WMS>
@@ -7,7 +7,7 @@
<UpperLeftY>90</UpperLeftY>
<LowerRightX>396.0</LowerRightX>
<LowerRightY>-198</LowerRightY>
<TileLevel>5</TileLevel>
<TileLevel>8</TileLevel>
<TileCountX>2</TileCountX>
<TileCountY>1</TileCountY>
<YOrigin>top</YOrigin>
@@ -0,0 +1,7 @@
<GDAL_WMS>
<Service name="VirtualEarth">
<ServerUrl>http://a${server_num}.ortho.tiles.virtualearth.net/tiles/a${quadkey}.jpeg?g=90</ServerUrl>
</Service>
<MaxConnections>4</MaxConnections>
<Cache/>
</GDAL_WMS>
@@ -0,0 +1,17 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<TileLevel>15</TileLevel>
<TileCountX>2</TileCountX>
<TileCountY>1</TileCountY>
<YOrigin>top</YOrigin>
</DataWindow>
<Projection>EPSG:4326</Projection>
<BlockSizeX>512</BlockSizeX>
<BlockSizeY>512</BlockSizeY>
<BandsCount>3</BandsCount>
</GDAL_WMS>
+2 -2
View File
@@ -52,7 +52,7 @@ set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/other/texturetileset.h
${CMAKE_CURRENT_SOURCE_DIR}/other/patchcoverageprovider.h
${CMAKE_CURRENT_SOURCE_DIR}/other/tileprovider.h
${CMAKE_CURRENT_SOURCE_DIR}/other/gdaldataconverter.h
${CMAKE_CURRENT_SOURCE_DIR}/other/texturedataprovider.h
${CMAKE_CURRENT_SOURCE_DIR}/other/lrucache.h
${CMAKE_CURRENT_SOURCE_DIR}/other/concurrentjobmanager.h
${CMAKE_CURRENT_SOURCE_DIR}/other/threadpool.h
@@ -89,7 +89,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/other/texturetileset.cpp
${CMAKE_CURRENT_SOURCE_DIR}/other/patchcoverageprovider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/other/tileprovider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/other/gdaldataconverter.inl
${CMAKE_CURRENT_SOURCE_DIR}/other/texturedataprovider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/other/lrucache.inl
${CMAKE_CURRENT_SOURCE_DIR}/other/concurrentjobmanager.inl
${CMAKE_CURRENT_SOURCE_DIR}/other/threadpool.cpp
@@ -69,6 +69,11 @@ namespace openspace {
return ChunkIndex(newX, newY, level);
}
int ChunkIndex::manhattan(const ChunkIndex& other) const {
ghoul_assert(level == other.level, "makes no sense if not on same level");
return std::abs(x - other.x) + std::abs(y - other.y);
}
HashKey ChunkIndex::hashKey() const {
return x ^ (y << 16) ^ (level << 24);
}
@@ -89,6 +89,8 @@ struct ChunkIndex {
*/
ChunkIndex getRelatedTile(int deltaX, int deltaY) const;
int manhattan(const ChunkIndex& other) const;
HashKey hashKey() const;
bool operator==(const ChunkIndex& other) const;
@@ -41,6 +41,7 @@
#include <modules/globebrowsing/geodetics/ellipsoid.h>
#include <modules/globebrowsing/other/tileprovidermanager.h>
#include <modules/globebrowsing/other/threadpool.h>
namespace ghoul {
namespace opengl {
@@ -31,6 +31,9 @@ namespace {
namespace openspace {
ThreadPool TileProviderManager::tileRequestThreadPool(1);
TileProviderManager::TileProviderManager()
{
}
@@ -26,19 +26,22 @@
#define __TILE_PROVIDER_MANAGER_H__
#include "modules/globebrowsing/other/tileprovider.h"
#include <modules/globebrowsing/other/threadpool.h>
#include <memory>
#include <vector>
#include <string>
namespace openspace {
class TileProviderManager
{
class TileProviderManager {
public:
TileProviderManager();
~TileProviderManager();
static ThreadPool tileRequestThreadPool;
void addHeightMap(std::string name, std::shared_ptr<TileProvider> tileProvider);
void addColorTexture(std::string name, std::shared_ptr<TileProvider> tileProvider);
/*
@@ -47,6 +50,7 @@ namespace openspace {
*/
const std::vector<std::shared_ptr<TileProvider> >& heightMapProviders();
const std::vector<std::shared_ptr<TileProvider> >& colorTextureProviders();
private:
std::vector<std::shared_ptr<TileProvider> > _heightMapProviders;
std::vector<std::shared_ptr<TileProvider> > _colorTextureProviders;
@@ -30,9 +30,9 @@
#include <ostream>
#include <thread>
#include <queue>
#include <atomic>
#include <modules/globebrowsing/other/concurrentqueue.h>
#include <modules/globebrowsing/other/threadpool.h>
#include <ghoul/misc/assert.h>
@@ -64,8 +64,7 @@ namespace openspace {
template<typename P>
class ConcurrentJobManager{
public:
ConcurrentJobManager()
: _hasWorkingThread(false)
ConcurrentJobManager(ThreadPool& pool) : threadPool(pool)
{
}
@@ -76,17 +75,14 @@ namespace openspace {
void enqueueJob(std::shared_ptr<Job<P>> job) {
_incomingJobs.push(job);
if (!_hasWorkingThread) {
_hasWorkingThread = true; // Can only be set to true by the main thread
executeJobsInSeparateThread();
}
threadPool.enqueue([this, job]() {
job->execute();
_finishedJobs.push(job);
});
}
void clearEnqueuedJobs() {
while (_incomingJobs.size()) {
_incomingJobs.pop();
}
threadPool.clearTasks();
}
std::shared_ptr<Job<P>> popFinishedJob() {
@@ -102,33 +98,8 @@ namespace openspace {
private:
void executeJobsInSeparateThread() {
// Create new thread and run workerThreadMainTask on that thread
std::thread t(&ConcurrentJobManager::workerThreadMainTask, this);
t.detach();
}
void workerThreadMainTask() {
while (_incomingJobs.size() > 0) {
auto job = _incomingJobs.pop();
job->execute();
_finishedJobs.push(job);
}
_hasWorkingThread = false; // Can only be set to false by worker thread
}
ConcurrentQueue<std::shared_ptr<Job<P>>> _incomingJobs;
ConcurrentQueue<std::shared_ptr<Job<P>>> _finishedJobs;
// Using this atomic bool is probably not optimal - Should probably
// use a conditional variable instead
std::atomic<bool> _hasWorkingThread;
std::atomic<int> _numActiveThreads;
ThreadPool& threadPool;
};
@@ -1,101 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* 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 __GDALDATACONVERTER_H__
#define __GDALDATACONVERTER_H__
//#include <modules/globebrowsing/other/tileprovider.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/opengl/texture.h>
#include <modules/globebrowsing/geodetics/geodetic2.h>
#include "gdal_priv.h"
#include <memory>
namespace openspace {
using namespace ghoul::opengl;
struct UninitializedTextureTile {
struct TextureFormat
{
Texture::Format ghoulFormat;
GLuint glFormat;
};
UninitializedTextureTile(
void* data,
glm::uvec3 dims,
TextureFormat format,
GLuint glType,
const ChunkIndex& chunkIndex)
: imageData(data)
, dimensions(dims)
, texFormat(format)
, glType(glType)
, chunkIndex(chunkIndex)
{
}
void* imageData;
glm::uvec3 dimensions;
TextureFormat texFormat;
GLuint glType;
const ChunkIndex chunkIndex;
};
template<class T>
class GdalDataConverter
{
public:
GdalDataConverter();
~GdalDataConverter();
std::shared_ptr<UninitializedTextureTile> getUninitializedTextureTile(
GDALDataset * dataSet,
ChunkIndex chunkIndex,
int tileLevelDifference);
UninitializedTextureTile::TextureFormat getTextureFormat(
int rasterCount,
GDALDataType gdalType);
GLuint getGlDataTypeFromGdalDataType(GDALDataType gdalType);
glm::uvec2 geodeticToPixel(GDALDataset* dataSet, const Geodetic2& geo);
};
} // namespace openspace
#include <modules/globebrowsing/other/gdaldataconverter.inl>
#endif // __GDALDATACONVERTER_H__
@@ -1,357 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* 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/other/gdaldataconverter.h>
#include <modules/globebrowsing/other/tileprovider.h>
#include <modules/globebrowsing/geodetics/angle.h>
namespace openspace {
template<class T>
GdalDataConverter<T>::GdalDataConverter()
{
}
template<class T>
GdalDataConverter<T>::~GdalDataConverter()
{
}
template<class T>
std::shared_ptr<UninitializedTextureTile> GdalDataConverter<T>::getUninitializedTextureTile(
GDALDataset* dataSet,
ChunkIndex chunkIndex,
int tileLevelDifference)
{
int nRasters = dataSet->GetRasterCount();
ghoul_assert(nRasters > 0, "Bad dataset. Contains no rasterband.");
ghoul_assert(chunkIndex.level > 0, "Level of chunk index must be bigger than 0.");
GDALRasterBand* firstBand = dataSet->GetRasterBand(1);
// Assume all raster bands have the same data type
GDALDataType gdalType = firstBand->GetRasterDataType();
// Level = overviewCount - overview (default, levels may be overridden)
int numOverviews = firstBand->GetOverviewCount();
// Generate a patch from the chunkIndex, extract the bounds which
// are used to calculated where in the GDAL data set to read data.
// pixelStart0 and pixelEnd0 defines the interval in the pixel space
// at overview 0
GeodeticPatch patch = GeodeticPatch(chunkIndex);
glm::uvec2 pixelStart0 = geodeticToPixel(dataSet, patch.northWestCorner());
glm::uvec2 pixelEnd0 = geodeticToPixel(dataSet, patch.southEastCorner());
glm::uvec2 numPixels0 = pixelEnd0 - pixelStart0;
// Calculate a suitable overview to choose from the GDAL dataset
int minNumPixels0 = glm::min(numPixels0.x, numPixels0.y);
int sizeLevel0 = firstBand->GetOverview(numOverviews - 1)->GetXSize();
int ov = log2(minNumPixels0) - log2(sizeLevel0 + 1) - tileLevelDifference;
ov = glm::clamp(ov, 0, numOverviews - 1);
// Convert the interval [pixelStart0, pixelEnd0] to pixel space at
// the calculated suitable overview, ov. using a >> b = a / 2^b
int toShift = ov + 1;
glm::uvec2 pixelStart(pixelStart0.x >> toShift, pixelStart0.y >> toShift);
glm::uvec2 pixelEnd(pixelEnd0.x >> toShift, pixelEnd0.y >> toShift);
glm::uvec2 numPixels = pixelEnd - pixelStart;
// When GDAL reads rasterbands of small size, the image data gets screwed up.
// This is not a solution to the problem, but makes it look a little better
if (numPixels.x < 32 || numPixels.y < 32) {
numPixels = glm::uvec2(32, 32);
}
// GDAL reads image data top to bottom
T* imageData = new T[numPixels.x * numPixels.y * nRasters];
// Read the data (each rasterband is a separate channel)
for (size_t i = 0; i < nRasters; i++) {
GDALRasterBand* rasterBand = dataSet->GetRasterBand(i + 1)->GetOverview(ov);
int xSize = rasterBand->GetXSize();
int ySize = rasterBand->GetYSize();
CPLErr err = rasterBand->RasterIO(
GF_Read,
pixelStart.x, // Begin read x
pixelStart.y, // Begin read y
numPixels.x, // width to read x
numPixels.y, // width to read y
imageData + i, // Where to put data
numPixels.x, // width to write x in destination
numPixels.y, // width to write y in destination
gdalType, // Type
sizeof(T) * nRasters, // Pixel spacing
0); // Line spacing
if (err != CE_None) {
;//LERROR("There was a IO error (" << err << ") for: " << dataSet->GetDescription());
}
}
// GDAL reads image data top to bottom. We want the opposite.
T* imageDataYflipped = new T[numPixels.x * numPixels.y * nRasters];
for (size_t y = 0; y < numPixels.y; y++) {
for (size_t x = 0; x < numPixels.x * nRasters; x++) {
imageDataYflipped[x + y * numPixels.x * nRasters] =
imageData[x + (numPixels.y - 1 - y) * numPixels.x * nRasters];
}
}
delete[] imageData;
glm::uvec3 dims(numPixels.x, numPixels.y, 1);
UninitializedTextureTile::TextureFormat textureFormat =
getTextureFormat(nRasters, gdalType);
GLuint glType = getGlDataTypeFromGdalDataType(gdalType);
UninitializedTextureTile* uninitedTexPtr = new UninitializedTextureTile(
imageDataYflipped,
dims,
textureFormat,
glType,
chunkIndex);
std::shared_ptr<UninitializedTextureTile> uninitedTex =
std::shared_ptr<UninitializedTextureTile>(uninitedTexPtr);
return uninitedTex;
}
template<class T>
glm::uvec2 GdalDataConverter<T>::geodeticToPixel(GDALDataset* dataSet, const Geodetic2& geo) {
double padfTransform[6];
CPLErr err = dataSet->GetGeoTransform(padfTransform);
ghoul_assert(err != CE_Failure, "Failed to get transform");
Scalar Y = Angle<Scalar>::fromRadians(geo.lat).asDegrees();
Scalar X = Angle<Scalar>::fromRadians(geo.lon).asDegrees();
// convert from pixel and line to geodetic coordinates
// Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
// Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
// <=>
double* a = &(padfTransform[0]);
double* b = &(padfTransform[3]);
// Xp = a[0] + P*a[1] + L*a[2];
// Yp = b[0] + P*b[1] + L*b[2];
// <=>
double divisor = (a[2]*b[1] - a[1]*b[2]);
ghoul_assert(divisor != 0.0, "Division by zero!");
//ghoul_assert(a[2] != 0.0, "a2 must not be zero!");
double P = (a[0]*b[2] - a[2]*b[0] + a[2]*Y - b[2]*X) / divisor;
double L = (-a[0]*b[1] + a[1]*b[0] - a[1]*Y + b[1]*X) / divisor;
// ref: https://www.wolframalpha.com/input/?i=X+%3D+a0+%2B+a1P+%2B+a2L,+Y+%3D+b0+%2B+b1P+%2B+b2L,+solve+for+P+and+L
double Xp = a[0] + P*a[1] + L*a[2];
double Yp = b[0] + P*b[1] + L*b[2];
ghoul_assert(abs(X - Xp) < 1e-10, "inverse should yield X as before");
ghoul_assert(abs(Y - Yp) < 1e-10, "inverse should yield Y as before");
return glm::uvec2(glm::round(P), glm::round(L));
}
template<class T>
UninitializedTextureTile::TextureFormat GdalDataConverter<T>::getTextureFormat(
int rasterCount,
GDALDataType gdalType)
{
UninitializedTextureTile::TextureFormat format;
switch (rasterCount)
{
case 1: // Red
format.ghoulFormat = Texture::Format::Red;
switch (gdalType)
{
case GDT_Byte:
format.glFormat = GL_R8;
break;
case GDT_UInt16:
format.glFormat = GL_R16;
break;
case GDT_Int16:
format.glFormat = GL_R16;
break;
case GDT_UInt32:
format.glFormat = GL_R32UI;
break;
case GDT_Int32:
format.glFormat = GL_R32I;
break;
case GDT_Float32:
format.glFormat = GL_R32F;
break;
/*
case GDT_Float64:
format.glFormat = GL_RED; // No representation of 64 bit float?
break;
*/
default:
;//LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
case 2:
format.ghoulFormat = Texture::Format::RG;
switch (gdalType)
{
case GDT_Byte:
format.glFormat = GL_RG8;
break;
case GDT_UInt16:
format.glFormat = GL_RG16;
break;
case GDT_Int16:
format.glFormat = GL_RG16;
break;
case GDT_UInt32:
format.glFormat = GL_RG32UI;
break;
case GDT_Int32:
format.glFormat = GL_RG32I;
break;
case GDT_Float32:
format.glFormat = GL_RG32F;
break;
/*
case GDT_Float64:
format.glFormat = GL_RED; // No representation of 64 bit float?
break;
*/
default:
;//LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
case 3:
format.ghoulFormat = Texture::Format::RGB;
switch (gdalType)
{
case GDT_Byte:
format.glFormat = GL_RGB8;
break;
case GDT_UInt16:
format.glFormat = GL_RGB16;
break;
case GDT_Int16:
format.glFormat = GL_RGB16;
break;
case GDT_UInt32:
format.glFormat = GL_RGB32UI;
break;
case GDT_Int32:
format.glFormat = GL_RGB32I;
break;
case GDT_Float32:
format.glFormat = GL_RGB32F;
break;
/*
case GDT_Float64:
format.glFormat = GL_RED; // No representation of 64 bit float?
break;
*/
default:
;//LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
case 4:
format.ghoulFormat = Texture::Format::RGBA;
switch (gdalType)
{
case GDT_Byte:
format.glFormat = GL_RGBA8;
break;
case GDT_UInt16:
format.glFormat = GL_RGBA16;
break;
case GDT_Int16:
format.glFormat = GL_RGBA16;
break;
case GDT_UInt32:
format.glFormat = GL_RGBA32UI;
break;
case GDT_Int32:
format.glFormat = GL_RGBA32I;
break;
case GDT_Float32:
format.glFormat = GL_RGBA32F;
break;
/*
case GDT_Float64:
format.glFormat = GL_RED; // No representation of 64 bit float?
break;
*/
default:
;//LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
default:
;//LERROR("Unknown number of channels for OpenGL texture: " << rasterCount);
break;
}
return format;
}
template<class T>
GLuint GdalDataConverter<T>::getGlDataTypeFromGdalDataType(GDALDataType gdalType)
{
switch (gdalType)
{
case GDT_Byte:
return GL_UNSIGNED_BYTE;
break;
case GDT_UInt16:
return GL_UNSIGNED_SHORT;
break;
case GDT_Int16:
return GL_SHORT;
break;
case GDT_UInt32:
return GL_UNSIGNED_INT;
break;
case GDT_Int32:
return GL_INT;
break;
case GDT_Float32:
return GL_FLOAT;
break;
case GDT_Float64:
return GL_DOUBLE;
break;
default:
//LERROR("GDAL data type unknown to OpenGL: " << gdalType);
return GL_UNSIGNED_BYTE;
}
}
} // namespace openspace
@@ -0,0 +1,404 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* 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 <ghoul/logging/logmanager.h>
#include <modules/globebrowsing/other/texturedataprovider.h>
#include <modules/globebrowsing/other/tileprovider.h>
#include <modules/globebrowsing/geodetics/angle.h>
namespace {
const std::string _loggerCat = "TextureDataProvider";
}
namespace openspace {
TextureDataProvider::TextureDataProvider() {
}
TextureDataProvider::~TextureDataProvider() {
}
std::shared_ptr<TileIOResult> TextureDataProvider::getTextureData(GDALDataset* dataSet,
ChunkIndex chunkIndex, int tileLevelDifference)
{
GdalDataRegion region(dataSet, chunkIndex, tileLevelDifference);
DataLayout dataLayout(dataSet, region);
char* imageData = new char[dataLayout.totalNumBytes];
CPLErr worstError = CPLErr::CE_None;
// Read the data (each rasterband is a separate channel)
for (size_t i = 0; i < region.numRasters; i++) {
GDALRasterBand* rasterBand = dataSet->GetRasterBand(i + 1)->GetOverview(region.overview);
char* dataDestination = imageData + (i * dataLayout.bytesPerDatum);
CPLErr err = rasterBand->RasterIO(
GF_Read,
region.pixelStart.x, // Begin read x
region.pixelStart.y, // Begin read y
region.numPixels.x, // width to read x
region.numPixels.y, // width to read y
dataDestination, // Where to put data
region.numPixels.x, // width to write x in destination
region.numPixels.y, // width to write y in destination
dataLayout.gdalType, // Type
dataLayout.bytesPerPixel, // Pixel spacing
dataLayout.bytesPerLine); // Line spacing
// CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4
worstError = std::max(worstError, err);
}
std::shared_ptr<RawTileData> tileData = nullptr;
tileData = createRawTileData(region, dataLayout, imageData);
std::shared_ptr<TileIOResult> result(new TileIOResult);
result->error = worstError;
result->rawTileData = tileData;
return result;
}
/*
void TextureDataProvider::asyncRequest(GDALDataset * dataSet, ChunkIndex chunkIndex, int tileLevelDifference) {
GdalDataRegion region(dataSet, chunkIndex, tileLevelDifference);
DataLayout dataLayout(dataSet, region);
char* imageData = new char[dataLayout.totalNumBytes];
int* rasterBandSelection = nullptr; // default to { 1, 2, ... , region.numRasters }
GDALAsyncReader * asyncReader = dataSet->BeginAsyncReader(
region.pixelStart.x, // nXOff
region.pixelStart.y, // nYOff
region.numPixels.x, // nXSize
region.numPixels.y, // nYSize
imageData, // pBuf
region.numPixels.x, // nBufXSize
region.numPixels.y, // nBufYSize
dataLayout.gdalType, // eBufType
region.numRasters, // nBandCount
rasterBandSelection, // panBandMap
dataLayout.bytesPerDatum, // nPixelSpace
dataLayout.bytesPerLine, // nLineSpace
dataLayout.bytesPerPixel, // nBandSpace
nullptr // papszOptions
);
ghoul_assert(asyncReader != nullptr, "Async reader is null");
GdalAsyncRequest request = { dataSet, asyncReader, region, dataLayout, imageData };
asyncRequests.insert(request);
}
void TextureDataProvider::updateAsyncRequests() {
double updateWaitTime = -1.0;
int nBufXOff, nBufYOff, nBufXSize, nBufYSize;
auto it = asyncRequests.begin();
auto end = asyncRequests.end();
while (it != end) {
GDALAsyncStatusType status = it->asyncReader->GetNextUpdatedRegion(
updateWaitTime, &nBufXOff, &nBufYOff, &nBufXSize, &nBufYSize);
if (status == GDALAsyncStatusType::GARIO_ERROR) {
LERROR("Async IO error for chunk " << it->region.chunkIndex);
it->dataSet->EndAsyncReader(it->asyncReader);
it = asyncRequests.erase(it);
}
else if (status == GDALAsyncStatusType::GARIO_COMPLETE) {
auto rawTileData = createRawTileData(it->region, it->dataLayout, it->imageData);
loadedTextureTiles.push(rawTileData);
it->dataSet->EndAsyncReader(it->asyncReader);
it = asyncRequests.erase(it);
}
else {
it++;
}
}
}
bool TextureDataProvider::hasTextureTileData() const {
return loadedTextureTiles.size() > 0;
}
std::shared_ptr<RawTileData> TextureDataProvider::nextTextureTile() {
auto tile = loadedTextureTiles.front();
loadedTextureTiles.pop();
return tile;
}
*/
std::shared_ptr<RawTileData> TextureDataProvider::createRawTileData(const GdalDataRegion& region,
const DataLayout& dataLayout, const char* imageData)
{
//if(cplError == CPLErr::CE_Fatal)
// GDAL reads image data top to bottom. We want the opposite.
char* imageDataYflipped = new char[dataLayout.totalNumBytes];
for (size_t y = 0; y < region.numPixels.y; y++) {
for (size_t x = 0; x < dataLayout.bytesPerLine; x++) {
imageDataYflipped[x + y * dataLayout.bytesPerLine] =
imageData[x + (region.numPixels.y - 1 - y) * dataLayout.bytesPerLine];
}
}
delete[] imageData;
glm::uvec3 dims(region.numPixels.x, region.numPixels.y, 1);
RawTileData::TextureFormat textureFormat = getTextureFormat(region.numRasters, dataLayout.gdalType);
GLuint glType = getOpenGLDataType(dataLayout.gdalType);
RawTileData* textureDataPtr = new RawTileData(imageDataYflipped, dims,
textureFormat, glType, region.chunkIndex);
std::shared_ptr<RawTileData> textureData =
std::shared_ptr<RawTileData>(textureDataPtr);
return textureData;
}
size_t TextureDataProvider::numberOfBytes(GDALDataType gdalType) {
switch (gdalType) {
case GDT_Byte: return sizeof(GLubyte);
case GDT_UInt16: return sizeof(GLushort);
case GDT_Int16: return sizeof(GLshort);
case GDT_UInt32: return sizeof(GLuint);
case GDT_Int32: return sizeof(GLint);
case GDT_Float32: return sizeof(GLfloat);
case GDT_Float64: return sizeof(GLdouble);
default:
//LERROR("Unknown data type");
return -1;
}
}
glm::uvec2 TextureDataProvider::geodeticToPixel(GDALDataset* dataSet, const Geodetic2& geo) {
double padfTransform[6];
CPLErr err = dataSet->GetGeoTransform(padfTransform);
ghoul_assert(err != CE_Failure, "Failed to get transform");
Scalar Y = Angle<Scalar>::fromRadians(geo.lat).asDegrees();
Scalar X = Angle<Scalar>::fromRadians(geo.lon).asDegrees();
// convert from pixel and line to geodetic coordinates
// Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
// Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
// <=>
double* a = &(padfTransform[0]);
double* b = &(padfTransform[3]);
// Xp = a[0] + P*a[1] + L*a[2];
// Yp = b[0] + P*b[1] + L*b[2];
// <=>
double divisor = (a[2]*b[1] - a[1]*b[2]);
ghoul_assert(divisor != 0.0, "Division by zero!");
//ghoul_assert(a[2] != 0.0, "a2 must not be zero!");
double P = (a[0]*b[2] - a[2]*b[0] + a[2]*Y - b[2]*X) / divisor;
double L = (-a[0]*b[1] + a[1]*b[0] - a[1]*Y + b[1]*X) / divisor;
// ref: https://www.wolframalpha.com/input/?i=X+%3D+a0+%2B+a1P+%2B+a2L,+Y+%3D+b0+%2B+b1P+%2B+b2L,+solve+for+P+and+L
double Xp = a[0] + P*a[1] + L*a[2];
double Yp = b[0] + P*b[1] + L*b[2];
ghoul_assert(abs(X - Xp) < 1e-10, "inverse should yield X as before");
ghoul_assert(abs(Y - Yp) < 1e-10, "inverse should yield Y as before");
return glm::uvec2(glm::round(P), glm::round(L));
}
RawTileData::TextureFormat TextureDataProvider::getTextureFormat(
int rasterCount, GDALDataType gdalType)
{
RawTileData::TextureFormat format;
switch (rasterCount) {
case 1: // Red
format.ghoulFormat = Texture::Format::Red;
switch (gdalType) {
case GDT_Byte: format.glFormat = GL_R8; break;
case GDT_UInt16: format.glFormat = GL_R16; break;
case GDT_Int16: format.glFormat = GL_R16; break;
case GDT_UInt32: format.glFormat = GL_R32UI; break;
case GDT_Int32: format.glFormat = GL_R32I; break;
case GDT_Float32: format.glFormat = GL_R32F; break;
//case GDT_Float64: format.glFormat = GL_RED; break; // No representation of 64 bit float?
default: ;//LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
case 2:
format.ghoulFormat = Texture::Format::RG;
switch (gdalType) {
case GDT_Byte: format.glFormat = GL_RG8; break;
case GDT_UInt16: format.glFormat = GL_RG16; break;
case GDT_Int16: format.glFormat = GL_RG16; break;
case GDT_UInt32: format.glFormat = GL_RG32UI; break;
case GDT_Int32: format.glFormat = GL_RG32I; break;
case GDT_Float32: format.glFormat = GL_RG32F; break;
case GDT_Float64: format.glFormat = GL_RED; break; // No representation of 64 bit float?
default: ;//LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
case 3:
format.ghoulFormat = Texture::Format::RGB;
switch (gdalType) {
case GDT_Byte: format.glFormat = GL_RGB8; break;
case GDT_UInt16: format.glFormat = GL_RGB16; break;
case GDT_Int16: format.glFormat = GL_RGB16; break;
case GDT_UInt32: format.glFormat = GL_RGB32UI; break;
case GDT_Int32: format.glFormat = GL_RGB32I; break;
case GDT_Float32: format.glFormat = GL_RGB32F; break;
// case GDT_Float64: format.glFormat = GL_RED; break;// No representation of 64 bit float?
default: ;//LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
case 4:
format.ghoulFormat = Texture::Format::RGBA;
switch (gdalType) {
case GDT_Byte: format.glFormat = GL_RGBA8; break;
case GDT_UInt16: format.glFormat = GL_RGBA16; break;
case GDT_Int16: format.glFormat = GL_RGBA16; break;
case GDT_UInt32: format.glFormat = GL_RGBA32UI; break;
case GDT_Int32: format.glFormat = GL_RGBA32I; break;
case GDT_Float32: format.glFormat = GL_RGBA32F; break;
case GDT_Float64: format.glFormat = GL_RED; break; // No representation of 64 bit float?
default: ;//LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
break;
default:
//LERROR("Unknown number of channels for OpenGL texture: " << rasterCount);
break;
}
return format;
}
GLuint TextureDataProvider::getOpenGLDataType(GDALDataType gdalType) {
switch (gdalType) {
case GDT_Byte: return GL_UNSIGNED_BYTE;
case GDT_UInt16: return GL_UNSIGNED_SHORT;
case GDT_Int16: return GL_SHORT;
case GDT_UInt32: return GL_UNSIGNED_INT;
case GDT_Int32: return GL_INT;
case GDT_Float32: return GL_FLOAT;
case GDT_Float64: return GL_DOUBLE;
default:
//LERROR("GDAL data type unknown to OpenGL: " << gdalType);
return GL_UNSIGNED_BYTE;
}
}
TextureDataProvider::GdalDataRegion::GdalDataRegion(GDALDataset * dataSet,
const ChunkIndex& chunkIndex, int tileLevelDifference)
: chunkIndex(chunkIndex)
{
GDALRasterBand* firstBand = dataSet->GetRasterBand(1);
// Assume all raster bands have the same data type
// Level = overviewCount - overview (default, levels may be overridden)
int numOverviews = firstBand->GetOverviewCount();
// Generate a patch from the chunkIndex, extract the bounds which
// are used to calculated where in the GDAL data set to read data.
// pixelStart0 and pixelEnd0 defines the interval in the pixel space
// at overview 0
GeodeticPatch patch = GeodeticPatch(chunkIndex);
glm::uvec2 pixelStart0 = geodeticToPixel(dataSet, patch.northWestCorner());
glm::uvec2 pixelEnd0 = geodeticToPixel(dataSet, patch.southEastCorner());
glm::uvec2 numPixels0 = pixelEnd0 - pixelStart0;
// Calculate a suitable overview to choose from the GDAL dataset
int minNumPixels0 = glm::min(numPixels0.x, numPixels0.y);
int sizeLevel0 = firstBand->GetOverview(numOverviews - 1)->GetXSize();
int ov = std::log2(minNumPixels0) - std::log2(sizeLevel0 + 1) - tileLevelDifference;
ov = glm::clamp(ov, 0, numOverviews - 1);
// Convert the interval [pixelStart0, pixelEnd0] to pixel space at
// the calculated suitable overview, ov. using a >> b = a / 2^b
int toShift = ov + 1;
// Set member variables
overview = ov;
numRasters = dataSet->GetRasterCount();
ghoul_assert(numRasters > 0, "Bad dataset. Contains no rasterband.");
pixelStart = glm::uvec2(pixelStart0.x >> toShift, pixelStart0.y >> toShift);
pixelEnd = glm::uvec2(pixelEnd0.x >> toShift, pixelEnd0.y >> toShift);
numPixels = pixelEnd - pixelStart;
}
TextureDataProvider::DataLayout::DataLayout(GDALDataset* dataSet, const GdalDataRegion& region) {
// Assume all raster bands have the same data type
gdalType = dataSet->GetRasterBand(1)->GetRasterDataType();
bytesPerDatum = numberOfBytes(gdalType);
bytesPerPixel = bytesPerDatum * region.numRasters;
bytesPerLine = bytesPerPixel * region.numPixels.x;
totalNumBytes = bytesPerLine * region.numPixels.y;
}
} // namespace openspace
@@ -0,0 +1,198 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* 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 __TEXTURE_DATA_PROVIDER_H__
#define __TEXTURE_DATA_PROVIDER_H__
//#include <modules/globebrowsing/other/tileprovider.h>
#include <ghoul/opengl/texture.h>
#include <modules/globebrowsing/geodetics/geodetic2.h>
#include <modules/globebrowsing/other/threadpool.h>
#include "gdal_priv.h"
#include <memory>
#include <set>
#include <queue>
namespace openspace {
using namespace ghoul::opengl;
struct RawTileData {
struct TextureFormat {
Texture::Format ghoulFormat;
GLuint glFormat;
};
RawTileData(void* data, glm::uvec3 dims, TextureFormat format,
GLuint glType, const ChunkIndex& chunkIndex)
: imageData(data)
, dimensions(dims)
, texFormat(format)
, glType(glType)
, chunkIndex(chunkIndex)
{
}
void* imageData;
glm::uvec3 dimensions;
TextureFormat texFormat;
GLuint glType;
ChunkIndex chunkIndex;
};
struct TileIOResult {
CPLErr error;
std::shared_ptr<RawTileData> rawTileData;
};
class TextureDataProvider {
public:
TextureDataProvider();
~TextureDataProvider();
std::shared_ptr<TileIOResult> getTextureData(
GDALDataset * dataSet, ChunkIndex chunkIndex, int tileLevelDifference);
/*
void asyncRequest(GDALDataset * dataSet, ChunkIndex chunkIndex, int tileLevelDifference);
void updateAsyncRequests();
bool hasTextureTileData() const;
std::shared_ptr<RawTileData> nextTextureTile();
*/
private:
//////////////////////////////////////////////////////////////////////////////////
// HELPER STRUCTS //
//////////////////////////////////////////////////////////////////////////////////
struct GdalDataRegion {
GdalDataRegion(GDALDataset* dataSet, const ChunkIndex& chunkIndex,
int tileLevelDifference);
const ChunkIndex chunkIndex;
glm::uvec2 pixelStart;
glm::uvec2 pixelEnd;
glm::uvec2 numPixels;
size_t numRasters;
int overview;
};
struct DataLayout {
DataLayout(GDALDataset* dataSet, const GdalDataRegion& region);
GDALDataType gdalType;
size_t bytesPerDatum;
size_t bytesPerPixel;
size_t bytesPerLine;
size_t totalNumBytes;
};
struct GdalAsyncRequest {
GDALDataset* dataSet;
GDALAsyncReader* asyncReader;
const GdalDataRegion region;
const DataLayout dataLayout;
const char* imageData;
};
struct GdalAsyncRequestCompare {
bool operator() (const GdalAsyncRequest& lhs, const GdalAsyncRequest& rhs) const {
return lhs.region.chunkIndex.hashKey() < rhs.region.chunkIndex.hashKey();
}
};
//////////////////////////////////////////////////////////////////////////////////
// HELPER FUNCTIONS //
//////////////////////////////////////////////////////////////////////////////////
static glm::uvec2 geodeticToPixel(GDALDataset* dataSet, const Geodetic2& geo);
static GLuint getOpenGLDataType(GDALDataType gdalType);
static RawTileData::TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType);
static size_t numberOfBytes(GDALDataType gdalType);
static std::shared_ptr<RawTileData> createRawTileData(const GdalDataRegion& region,
const DataLayout& dataLayout, const char* imageData);
//////////////////////////////////////////////////////////////////////////////////
// MEMBER VARIABLES //
//////////////////////////////////////////////////////////////////////////////////
std::queue<std::shared_ptr<RawTileData>> loadedTextureTiles;
std::set<GdalAsyncRequest, GdalAsyncRequestCompare> asyncRequests;
};
} // namespace openspace
#endif // __TEXTURE_DATA_PROVIDER_H__
@@ -25,7 +25,7 @@
#include <modules/globebrowsing/other/texturetileset.h>
#include <modules/globebrowsing/geodetics/ellipsoid.h>
#include <modules/globebrowsing/other/gdaldataconverter.h>
#include <modules/globebrowsing/other/texturedataprovider.h>
#include <ghoul/opengl/texturemanager.h>
#include <ghoul/io/texture/texturereader.h>
@@ -67,7 +67,7 @@ namespace openspace {
poDataset = (GDALDataset *)GDALOpen(testFile.c_str(), GA_ReadOnly);
assert(poDataset != nullptr, "Unable to read dataset" << testFile);
GdalDataConverter conv;
TextureDataProvider conv;
GeodeticTileIndex ti(0, 0, 0);
+8 -2
View File
@@ -29,7 +29,6 @@
#include <ostream>
#include <thread>
#include <queue>
#include <atomic>
#include <modules/globebrowsing/other/concurrentqueue.h>
#include <modules/globebrowsing/other/threadpool.h>
@@ -113,8 +112,15 @@ namespace openspace {
} // release lock
// wake up one thread
std::cout << "Notify one thread" << std::endl;
condition.notify_one();
}
void ThreadPool::clearTasks() {
{ // acquire lock
std::unique_lock<std::mutex> lock(queue_mutex);
tasks.clear();
} // release lock
}
} // namespace openspace
+1 -1
View File
@@ -30,7 +30,6 @@
#include <ostream>
#include <thread>
#include <queue>
#include <atomic>
#include <modules/globebrowsing/other/concurrentqueue.h>
@@ -59,6 +58,7 @@ namespace openspace {
~ThreadPool();
void enqueue(std::function<void()> f);
void clearTasks();
private:
friend class Worker;
+73 -101
View File
@@ -24,6 +24,7 @@
#include <modules/globebrowsing/geodetics/geodetic2.h>
#include <modules/globebrowsing/other/tileprovider.h>
#include <modules/globebrowsing/other/tileprovidermanager.h>
#include <openspace/engine/downloadmanager.h>
@@ -43,8 +44,28 @@ namespace {
namespace openspace {
TileDepthTransform::TileDepthTransform() { }
TileDepthTransform::TileDepthTransform(GDALDataset* dataset) {
GDALRasterBand* firstBand = dataset->GetRasterBand(1);
GDALDataType gdalType = firstBand->GetRasterDataType();
double maximumValue = (gdalType == GDT_Float32 || gdalType == GDT_Float64) ?
1.0 : firstBand->GetMaximum();
depthOffset = firstBand->GetOffset();
depthScale = firstBand->GetScale() * maximumValue;
}
bool TileProvider::hasInitializedGDAL = false;
TileProvider::TileProvider(
const std::string& filePath,
int tileCacheSize,
@@ -54,6 +75,7 @@ namespace openspace {
, _tileCache(tileCacheSize) // setting cache size
, _framesSinceLastRequestFlush(0)
, _framesUntilRequestFlush(framesUntilRequestFlush)
, _tileLoadManager(TileProviderManager::tileRequestThreadPool)
{
// Set a temporary texture
std::string fileName = "textures/earth_bluemarble.jpg";
@@ -69,24 +91,14 @@ namespace openspace {
_defaultTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
_defaultTexture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToBorder);
}
int downloadApplicationVersion = 1;
if (!DownloadManager::isInitialized()) {
DownloadManager::initialize(
"../tmp_openspace_downloads/",
downloadApplicationVersion);
}
if (!hasInitializedGDAL) {
GDALAllRegister();
//CPLSetConfigOption("GDAL_CACHEMAX", "0");
hasInitializedGDAL = true;
}
std::string absFilePath = absPath(filePath);
_gdalDataSet = (GDALDataset *)GDALOpen(absFilePath.c_str(), GA_ReadOnly);
//auto desc = _gdalDataSet->GetDescription();
_gdalDataSet = (GDALDataset *)GDALOpen(absPath(filePath).c_str(), GA_ReadOnly);
ghoul_assert(_gdalDataSet != nullptr, "Failed to load dataset: " << filePath);
GDALRasterBand* firstBand = _gdalDataSet->GetRasterBand(1);
@@ -95,12 +107,7 @@ namespace openspace {
_tileLevelDifference = log2(minimumPixelSize) - log2(sizeLevel0);
GDALDataType gdalType = firstBand->GetRasterDataType();
double maximumValue = (gdalType == GDT_Float32 || gdalType == GDT_Float64) ?
1.0 : firstBand->GetMaximum();
_depthTransform.depthOffset = firstBand->GetOffset();
_depthTransform.depthScale = firstBand->GetScale() * maximumValue;
_depthTransform = TileDepthTransform(_gdalDataSet);
}
TileProvider::~TileProvider(){
@@ -110,6 +117,7 @@ namespace openspace {
void TileProvider::prerender() {
//_rawTextureTileDataProvider.updateAsyncRequests();
initTexturesFromLoadedData();
if (_framesSinceLastRequestFlush++ > _framesUntilRequestFlush) {
@@ -119,13 +127,15 @@ namespace openspace {
void TileProvider::initTexturesFromLoadedData() {
while (_tileLoadManager.numFinishedJobs() > 0) {
auto finishedJob = _tileLoadManager.popFinishedJob();
std::shared_ptr<UninitializedTextureTile> uninitedTex =
finishedJob->product();
HashKey key = uninitedTex->chunkIndex.hashKey();
std::shared_ptr<Texture> texture = initializeTexture(uninitedTex);
_tileCache.put(key, texture);
std::shared_ptr<TileIOResult> tileIOResult= _tileLoadManager.popFinishedJob()->product();
initializeAndAddToCache(tileIOResult);
}
/*
while (_rawTextureTileDataProvider.hasTextureTileData()) {
auto rawTextureTile = _rawTextureTileDataProvider.nextTextureTile();
initializeAndAddToCache(rawTextureTile);
}
*/
}
void TileProvider::clearRequestQueue() {
@@ -154,8 +164,9 @@ namespace openspace {
TileUvTransform& uvTransform)
{
HashKey key = chunkIndex.hashKey();
if (_tileCache.exist(key)) {
return { _tileCache.get(key), uvTransform };
if (_tileCache.exist(key) && _tileCache.get(key).ioError == CPLErr::CE_None) {
std::shared_ptr<Texture> texture = _tileCache.get(key).texture;
return { texture, uvTransform };
}
else if (chunkIndex.level <= 1) {
return { getDefaultTexture(), uvTransform };
@@ -194,7 +205,7 @@ namespace openspace {
std::shared_ptr<Texture> TileProvider::getOrStartFetchingTile(ChunkIndex chunkIndex) {
HashKey hashkey = chunkIndex.hashKey();
if (_tileCache.exist(hashkey)) {
return _tileCache.get(hashkey);
return _tileCache.get(hashkey).texture;
}
else {
enqueueTileRequest(chunkIndex);
@@ -204,17 +215,23 @@ namespace openspace {
bool TileProvider::enqueueTileRequest(const ChunkIndex& chunkIndex) {
HashKey key = chunkIndex.hashKey();
bool tileHasBeenQueued = _queuedTileRequests.find(key) != _queuedTileRequests.end();
if (!tileHasBeenQueued) {
// enque load job
std::shared_ptr<TextureTileLoadJob> job = std::shared_ptr<TextureTileLoadJob>(
new TextureTileLoadJob(this, chunkIndex));
_tileLoadManager.enqueueJob(job);
_queuedTileRequests.insert(key);
auto it = _queuedTileRequests.begin();
auto end = _queuedTileRequests.end();
for (; it != end; it++) {
const ChunkIndex& otherChunk = it->second;
if (chunkIndex.level == otherChunk.level &&
chunkIndex.manhattan(otherChunk) < 1) {
return false;
}
}
return !tileHasBeenQueued;
std::shared_ptr<TextureTileLoadJob> job = std::shared_ptr<TextureTileLoadJob>(
new TextureTileLoadJob(this, chunkIndex));
_tileLoadManager.enqueueJob(job);
_queuedTileRequests[key] = chunkIndex;
return true;
}
@@ -228,80 +245,35 @@ namespace openspace {
}
std::shared_ptr<UninitializedTextureTile> TileProvider::getUninitializedTextureTile(
std::shared_ptr<TileIOResult> TileProvider::syncDownloadData(
const ChunkIndex& chunkIndex) {
// We assume here that all rasterbands have the same data type
GDALDataType gdalType = _gdalDataSet->GetRasterBand(1)->GetRasterDataType();
switch (gdalType)
{
case GDT_Byte:
return _uByteConverter.getUninitializedTextureTile(
_gdalDataSet,
chunkIndex,
_tileLevelDifference);
break;
case GDT_UInt16:
return _uShortConverter.getUninitializedTextureTile(
_gdalDataSet,
chunkIndex,
_tileLevelDifference);
break;
case GDT_Int16:
return _shortConverter.getUninitializedTextureTile(
_gdalDataSet,
chunkIndex,
_tileLevelDifference);
break;
case GDT_UInt32:
return _uIntConverter.getUninitializedTextureTile(
_gdalDataSet,
chunkIndex,
_tileLevelDifference);
break;
case GDT_Int32:
return _intConverter.getUninitializedTextureTile(
_gdalDataSet,
chunkIndex,
_tileLevelDifference);
break;
case GDT_Float32:
return _floatConverter.getUninitializedTextureTile(
_gdalDataSet,
chunkIndex,
_tileLevelDifference);
std::shared_ptr<TileIOResult> res = _rawTextureTileDataProvider.getTextureData(
_gdalDataSet, chunkIndex, _tileLevelDifference);
break;
case GDT_Float64:
return _doubleConverter.getUninitializedTextureTile(
_gdalDataSet,
chunkIndex,
_tileLevelDifference);
break;
default:
LERROR("GDAL data type unknown to OpenGL: " << gdalType);
}
return nullptr;
return res;
}
std::shared_ptr<Texture> TileProvider::initializeTexture(
std::shared_ptr<UninitializedTextureTile> uninitedTexture) {
Texture* tex = new Texture(
uninitedTexture->imageData,
uninitedTexture->dimensions,
uninitedTexture->texFormat.ghoulFormat,
uninitedTexture->texFormat.glFormat,
uninitedTexture->glType,
void TileProvider::initializeAndAddToCache(std::shared_ptr<TileIOResult> tileIOResult) {
std::shared_ptr<RawTileData> tileData = tileIOResult->rawTileData;
HashKey key = tileData->chunkIndex.hashKey();
Texture* texturePtr = new Texture(
tileData->imageData,
tileData->dimensions,
tileData->texFormat.ghoulFormat,
tileData->texFormat.glFormat,
tileData->glType,
Texture::FilterMode::Linear,
Texture::WrappingMode::ClampToEdge);
// The texture should take ownership of the data
std::shared_ptr<Texture> texture = std::shared_ptr<Texture>(tex);
std::shared_ptr<Texture> texture = std::shared_ptr<Texture>(texturePtr);
texture->uploadTexture();
return texture;
MetaTexture metaTexture = { texture, tileIOResult->error };
_tileCache.put(key, metaTexture);
}
+44 -22
View File
@@ -38,7 +38,7 @@
#include <modules/globebrowsing/geodetics/geodetic2.h>
#include <modules/globebrowsing/other/lrucache.h>
#include <modules/globebrowsing/other/concurrentjobmanager.h>
#include <modules/globebrowsing/other/gdaldataconverter.h>
#include <modules/globebrowsing/other/texturedataprovider.h>
//////////////////////////////////////////////////////////////////////////////////////////
// TILE PROVIDER //
@@ -46,24 +46,38 @@
namespace openspace {
using namespace ghoul::opengl;
struct TileDepthTransform
{
struct TileDepthTransform {
TileDepthTransform();
TileDepthTransform(GDALDataset* dataset);
float depthScale;
float depthOffset;
};
struct TileUvTransform
{
glm::vec2 uvOffset;
glm::vec2 uvScale;
};
struct Tile {
std::shared_ptr<Texture> texture;
TileUvTransform uvTransform;
};
struct MetaTexture {
std::shared_ptr<Texture> texture;
CPLErr ioError;
};
/**
Provides tiles through GDAL datasets which can be defined with xml files
for example for wms.
@@ -82,6 +96,9 @@ namespace openspace {
void prerender();
static ThreadPool threadPool;
private:
friend class TextureTileLoadJob;
@@ -99,14 +116,14 @@ namespace openspace {
/**
Fetches all the needeed texture data from the GDAL dataset.
*/
std::shared_ptr<UninitializedTextureTile> getUninitializedTextureTile(
std::shared_ptr<TileIOResult> syncDownloadData(
const ChunkIndex& chunkIndex);
/**
Creates an OpenGL texture and pushes the data to the GPU.
*/
std::shared_ptr<Texture> initializeTexture(
std::shared_ptr<UninitializedTextureTile> uninitedTexture);
void initializeAndAddToCache(
std::shared_ptr<TileIOResult> uninitedTexture);
bool enqueueTileRequest(const ChunkIndex& ci);
@@ -117,12 +134,13 @@ namespace openspace {
//////////////////////////////////////////////////////////////////////////////////
// Member variables //
//////////////////////////////////////////////////////////////////////////////////
LRUCache<HashKey, std::shared_ptr<Texture>> _tileCache;
std::set<HashKey> _queuedTileRequests;
LRUCache<HashKey, MetaTexture> _tileCache;
std::unordered_map<HashKey, ChunkIndex> _queuedTileRequests;
int _framesSinceLastRequestFlush;
int _framesUntilRequestFlush;
@@ -132,29 +150,34 @@ namespace openspace {
static bool hasInitializedGDAL;
GDALDataset* _gdalDataSet;
// Converters are needed for all different data types since they are templated.
GdalDataConverter<GLubyte> _uByteConverter;
GdalDataConverter<GLushort> _uShortConverter;
GdalDataConverter<GLshort> _shortConverter;
GdalDataConverter<GLuint> _uIntConverter;
GdalDataConverter<GLint> _intConverter;
GdalDataConverter<GLfloat> _floatConverter;
GdalDataConverter<GLdouble> _doubleConverter;
TextureDataProvider _rawTextureTileDataProvider;
ConcurrentJobManager<UninitializedTextureTile> _tileLoadManager;
ConcurrentJobManager<TileIOResult> _tileLoadManager;
std::shared_ptr<Texture> _defaultTexture;
int _tileLevelDifference;
TileDepthTransform _depthTransform;
};
} // namespace openspace
namespace openspace {
using namespace ghoul::opengl;
struct TextureTileLoadJob : public Job<UninitializedTextureTile> {
struct TextureTileLoadJob : public Job<TileIOResult> {
TextureTileLoadJob(TileProvider * tileProvider, const ChunkIndex& chunkIndex)
: _tileProvider(tileProvider)
, _chunkIndex(chunkIndex) {
@@ -164,11 +187,10 @@ namespace openspace {
virtual ~TextureTileLoadJob() { }
virtual void execute() {
_uninitedTexture = _tileProvider->getUninitializedTextureTile(_chunkIndex);
_uninitedTexture = _tileProvider->syncDownloadData(_chunkIndex);
}
virtual std::shared_ptr<UninitializedTextureTile> product() {
virtual std::shared_ptr<TileIOResult> product() {
return _uninitedTexture;
}
@@ -176,7 +198,7 @@ namespace openspace {
private:
ChunkIndex _chunkIndex;
TileProvider * _tileProvider;
std::shared_ptr<UninitializedTextureTile> _uninitedTexture;
std::shared_ptr<TileIOResult> _uninitedTexture;
};
}