mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-07 03:49:43 -05:00
Merge branch 'feature/globebrowsing' of github.com:OpenSpace/OpenSpace-Development into feature/globebrowsing
This commit is contained in:
@@ -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>
|
||||
+1
-1
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user