mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-22 12:59:07 -06:00
Started with code cleanup of Globebrowsing
This commit is contained in:
@@ -53,7 +53,6 @@ set(HEADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbylevel.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbyindex.h
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tilepile.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tile.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/chunktile.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileindex.h
|
||||
@@ -106,9 +105,7 @@ set(SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/temporaltileprovider.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbylevel.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbyindex.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tilepile.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tile.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/chunktile.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileindex.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileselector.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tile/tilediskcache.cpp
|
||||
@@ -126,6 +123,7 @@ set(SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/other/lrucache.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/other/concurrentjobmanager.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/other/statscollector.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/other/statscollector.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/other/threadpool.cpp
|
||||
)
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
|
||||
@@ -22,193 +22,190 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
|
||||
#include <modules/globebrowsing/chunk/chunk.h>
|
||||
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
|
||||
#include <modules/globebrowsing/rendering/layermanager.h>
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
#include <modules/globebrowsing/tile/tileselector.h>
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "Chunk";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
const float Chunk::DEFAULT_HEIGHT = 0.0f;
|
||||
const float Chunk::DEFAULT_HEIGHT = 0.0f;
|
||||
|
||||
Chunk::Chunk(
|
||||
const RenderableGlobe& owner,
|
||||
const TileIndex& tileIndex,
|
||||
bool initVisible)
|
||||
: _owner(owner)
|
||||
, _surfacePatch(tileIndex)
|
||||
, _tileIndex(tileIndex)
|
||||
, _isVisible(initVisible)
|
||||
{ }
|
||||
Chunk::Chunk(const RenderableGlobe& owner, const TileIndex& tileIndex, bool initVisible)
|
||||
: _owner(owner)
|
||||
, _surfacePatch(tileIndex)
|
||||
, _tileIndex(tileIndex)
|
||||
, _isVisible(initVisible)
|
||||
{}
|
||||
|
||||
const GeodeticPatch& Chunk::surfacePatch() const {
|
||||
return _surfacePatch;
|
||||
const GeodeticPatch& Chunk::surfacePatch() const {
|
||||
return _surfacePatch;
|
||||
}
|
||||
|
||||
const RenderableGlobe& Chunk::owner() const {
|
||||
return _owner;
|
||||
}
|
||||
|
||||
const TileIndex Chunk::tileIndex() const {
|
||||
return _tileIndex;
|
||||
}
|
||||
|
||||
bool Chunk::isVisible() const {
|
||||
return _isVisible;
|
||||
}
|
||||
|
||||
Chunk::Status Chunk::update(const RenderData& data) {
|
||||
auto savedCamera = _owner.savedCamera();
|
||||
const Camera& camRef = savedCamera != nullptr ? *savedCamera : data.camera;
|
||||
RenderData myRenderData = { camRef, data.position, data.doPerformanceMeasurement };
|
||||
|
||||
_isVisible = true;
|
||||
if (_owner.chunkedLodGlobe()->testIfCullable(*this, myRenderData)) {
|
||||
_isVisible = false;
|
||||
return Status::WANT_MERGE;
|
||||
}
|
||||
|
||||
const RenderableGlobe& Chunk::owner() const {
|
||||
return _owner;
|
||||
int desiredLevel = _owner.chunkedLodGlobe()->getDesiredLevel(*this, myRenderData);
|
||||
|
||||
if (desiredLevel < _tileIndex.level) {
|
||||
return Status::WANT_MERGE;
|
||||
}
|
||||
|
||||
const TileIndex Chunk::tileIndex() const {
|
||||
return _tileIndex;
|
||||
else if (_tileIndex.level < desiredLevel) {
|
||||
return Status::WANT_SPLIT;
|
||||
}
|
||||
|
||||
bool Chunk::isVisible() const {
|
||||
return _isVisible;
|
||||
else {
|
||||
return Status::DO_NOTHING;
|
||||
}
|
||||
}
|
||||
|
||||
Chunk::Status Chunk::update(const RenderData& data) {
|
||||
auto savedCamera = _owner.savedCamera();
|
||||
const Camera& camRef =
|
||||
savedCamera != nullptr ? *savedCamera : data.camera;
|
||||
RenderData myRenderData =
|
||||
{ camRef, data.position, data.doPerformanceMeasurement };
|
||||
Chunk::BoundingHeights Chunk::getBoundingHeights() const {
|
||||
BoundingHeights boundingHeights;
|
||||
boundingHeights.max = 0;
|
||||
boundingHeights.min = 0;
|
||||
boundingHeights.available = false;
|
||||
|
||||
|
||||
_isVisible = true;
|
||||
if (_owner.chunkedLodGlobe()->testIfCullable(*this, myRenderData)) {
|
||||
_isVisible = false;
|
||||
return Status::WANT_MERGE;
|
||||
}
|
||||
|
||||
int desiredLevel = _owner.chunkedLodGlobe()->getDesiredLevel(*this, myRenderData);
|
||||
|
||||
if (desiredLevel < _tileIndex.level) return Status::WANT_MERGE;
|
||||
else if (_tileIndex.level < desiredLevel) return Status::WANT_SPLIT;
|
||||
else return Status::DO_NOTHING;
|
||||
}
|
||||
|
||||
Chunk::BoundingHeights Chunk::getBoundingHeights() const {
|
||||
BoundingHeights boundingHeights;
|
||||
boundingHeights.max = 0;
|
||||
boundingHeights.min = 0;
|
||||
boundingHeights.available = false;
|
||||
|
||||
// In the future, this should be abstracted away and more easily queryable.
|
||||
// One must also handle how to sample pick one out of multiplte heightmaps
|
||||
auto layerManager = owner().chunkedLodGlobe()->layerManager();
|
||||
// In the future, this should be abstracted away and more easily queryable.
|
||||
// One must also handle how to sample pick one out of multiplte heightmaps
|
||||
auto layerManager = owner().chunkedLodGlobe()->layerManager();
|
||||
|
||||
// The raster of a height map is the first one. We assume that the height map is
|
||||
// a single raster image. If it is not we will just use the first raster
|
||||
// (that is channel 0).
|
||||
size_t HEIGHT_CHANNEL = 0;
|
||||
const LayerGroup& heightmaps =
|
||||
layerManager->layerGroup(LayerManager::HeightLayers);
|
||||
std::vector<ChunkTile> chunkTiles =
|
||||
TileSelector::getTilesSortedByHighestResolution(heightmaps, _tileIndex);
|
||||
bool lastHadMissingData = true;
|
||||
for (auto chunkTile : chunkTiles) {
|
||||
bool goodTile = chunkTile.tile.status == Tile::Status::OK;
|
||||
bool hastileMetaData = chunkTile.tile.metaData != nullptr;
|
||||
// The raster of a height map is the first one. We assume that the height map is
|
||||
// a single raster image. If it is not we will just use the first raster
|
||||
// (that is channel 0).
|
||||
size_t HEIGHT_CHANNEL = 0;
|
||||
const LayerGroup& heightmaps = layerManager->layerGroup(LayerManager::HeightLayers);
|
||||
std::vector<ChunkTile> chunkTiles = TileSelector::getTilesSortedByHighestResolution(
|
||||
heightmaps, _tileIndex
|
||||
);
|
||||
|
||||
if (goodTile && hastileMetaData) {
|
||||
auto tileMetaData = chunkTile.tile.metaData;
|
||||
bool lastHadMissingData = true;
|
||||
for (auto chunkTile : chunkTiles) {
|
||||
bool goodTile = chunkTile.tile.status == Tile::Status::OK;
|
||||
bool hastileMetaData = chunkTile.tile.metaData != nullptr;
|
||||
|
||||
if (!boundingHeights.available) {
|
||||
if (tileMetaData->hasMissingData[HEIGHT_CHANNEL]) {
|
||||
boundingHeights.min = std::min(
|
||||
DEFAULT_HEIGHT, tileMetaData->minValues[HEIGHT_CHANNEL]);
|
||||
boundingHeights.max = std::max(
|
||||
DEFAULT_HEIGHT, tileMetaData->maxValues[HEIGHT_CHANNEL]);
|
||||
}
|
||||
else {
|
||||
boundingHeights.min = tileMetaData->minValues[HEIGHT_CHANNEL];
|
||||
boundingHeights.max = tileMetaData->maxValues[HEIGHT_CHANNEL];
|
||||
}
|
||||
boundingHeights.available = true;
|
||||
if (goodTile && hastileMetaData) {
|
||||
auto tileMetaData = chunkTile.tile.metaData;
|
||||
|
||||
if (!boundingHeights.available) {
|
||||
if (tileMetaData->hasMissingData[HEIGHT_CHANNEL]) {
|
||||
boundingHeights.min = std::min(
|
||||
DEFAULT_HEIGHT,
|
||||
tileMetaData->minValues[HEIGHT_CHANNEL]
|
||||
);
|
||||
boundingHeights.max = std::max(
|
||||
DEFAULT_HEIGHT,
|
||||
tileMetaData->maxValues[HEIGHT_CHANNEL]
|
||||
);
|
||||
}
|
||||
else {
|
||||
boundingHeights.min = std::min(
|
||||
boundingHeights.min, tileMetaData->minValues[HEIGHT_CHANNEL]);
|
||||
boundingHeights.max = std::max(
|
||||
boundingHeights.max, tileMetaData->maxValues[HEIGHT_CHANNEL]);
|
||||
boundingHeights.min = tileMetaData->minValues[HEIGHT_CHANNEL];
|
||||
boundingHeights.max = tileMetaData->maxValues[HEIGHT_CHANNEL];
|
||||
}
|
||||
lastHadMissingData = tileMetaData->hasMissingData[HEIGHT_CHANNEL];
|
||||
boundingHeights.available = true;
|
||||
}
|
||||
|
||||
// Allow for early termination
|
||||
if (!lastHadMissingData) {
|
||||
break;
|
||||
else {
|
||||
boundingHeights.min = std::min(
|
||||
boundingHeights.min,
|
||||
tileMetaData->minValues[HEIGHT_CHANNEL]
|
||||
);
|
||||
boundingHeights.max = std::max(
|
||||
boundingHeights.max,
|
||||
tileMetaData->maxValues[HEIGHT_CHANNEL]
|
||||
);
|
||||
}
|
||||
lastHadMissingData = tileMetaData->hasMissingData[HEIGHT_CHANNEL];
|
||||
}
|
||||
|
||||
// Allow for early termination
|
||||
if (!lastHadMissingData) {
|
||||
break;
|
||||
}
|
||||
|
||||
return boundingHeights;
|
||||
}
|
||||
|
||||
std::vector<glm::dvec4> Chunk::getBoundingPolyhedronCorners() const {
|
||||
const Ellipsoid& ellipsoid = owner().ellipsoid();
|
||||
const GeodeticPatch& patch = surfacePatch();
|
||||
|
||||
BoundingHeights boundingHeight = getBoundingHeights();
|
||||
|
||||
// assume worst case
|
||||
double patchCenterRadius = ellipsoid.maximumRadius();
|
||||
|
||||
double maxCenterRadius = patchCenterRadius + boundingHeight.max;
|
||||
Geodetic2 halfSize = patch.halfSize();
|
||||
|
||||
// As the patch is curved, the maximum height offsets at the corners must be long
|
||||
// enough to cover large enough to cover a boundingHeight.max at the center of the
|
||||
// patch.
|
||||
// Approximating scaleToCoverCenter by assuming the latitude and longitude angles
|
||||
// of "halfSize" are equal to the angles they create from the center of the
|
||||
// globe to the patch corners. This is true for the longitude direction when
|
||||
// the ellipsoid can be approximated as a sphere and for the latitude for patches
|
||||
// close to the equator. Close to the pole this will lead to a bigger than needed
|
||||
// value for scaleToCoverCenter. However, this is a simple calculation and a good
|
||||
// Approximation.
|
||||
double y1 = tan(halfSize.lat);
|
||||
double y2 = tan(halfSize.lon);
|
||||
double scaleToCoverCenter = sqrt(1 + pow(y1, 2) + pow(y2, 2));
|
||||
|
||||
double maxCornerHeight = maxCenterRadius * scaleToCoverCenter - patchCenterRadius;
|
||||
return boundingHeights;
|
||||
}
|
||||
|
||||
bool chunkIsNorthOfEquator = patch.isNorthern();
|
||||
std::vector<glm::dvec4> Chunk::getBoundingPolyhedronCorners() const {
|
||||
const Ellipsoid& ellipsoid = owner().ellipsoid();
|
||||
const GeodeticPatch& patch = surfacePatch();
|
||||
|
||||
// The minimum height offset, however, we can simply
|
||||
double minCornerHeight = boundingHeight.min;
|
||||
std::vector<glm::dvec4> corners(8);
|
||||
BoundingHeights boundingHeight = getBoundingHeights();
|
||||
|
||||
// assume worst case
|
||||
double patchCenterRadius = ellipsoid.maximumRadius();
|
||||
|
||||
double maxCenterRadius = patchCenterRadius + boundingHeight.max;
|
||||
Geodetic2 halfSize = patch.halfSize();
|
||||
|
||||
// As the patch is curved, the maximum height offsets at the corners must be long
|
||||
// enough to cover large enough to cover a boundingHeight.max at the center of the
|
||||
// patch.
|
||||
// Approximating scaleToCoverCenter by assuming the latitude and longitude angles
|
||||
// of "halfSize" are equal to the angles they create from the center of the
|
||||
// globe to the patch corners. This is true for the longitude direction when
|
||||
// the ellipsoid can be approximated as a sphere and for the latitude for patches
|
||||
// close to the equator. Close to the pole this will lead to a bigger than needed
|
||||
// value for scaleToCoverCenter. However, this is a simple calculation and a good
|
||||
// Approximation.
|
||||
double y1 = tan(halfSize.lat);
|
||||
double y2 = tan(halfSize.lon);
|
||||
double scaleToCoverCenter = sqrt(1 + pow(y1, 2) + pow(y2, 2));
|
||||
|
||||
Scalar latCloseToEquator = patch.edgeLatitudeNearestEquator();
|
||||
Geodetic3 p1Geodetic = { { latCloseToEquator, patch.minLon() }, maxCornerHeight };
|
||||
Geodetic3 p2Geodetic = { { latCloseToEquator, patch.maxLon() }, maxCornerHeight };
|
||||
|
||||
glm::vec3 p1 = ellipsoid.cartesianPosition(p1Geodetic);
|
||||
glm::vec3 p2 = ellipsoid.cartesianPosition(p2Geodetic);
|
||||
glm::vec3 p = 0.5f * (p1 + p2);
|
||||
Geodetic2 pGeodetic = ellipsoid.cartesianToGeodetic2(p);
|
||||
Scalar latDiff = latCloseToEquator - pGeodetic.lat;
|
||||
double maxCornerHeight = maxCenterRadius * scaleToCoverCenter - patchCenterRadius;
|
||||
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
Quad q = (Quad)(i % 4);
|
||||
double cornerHeight = i < 4 ? minCornerHeight : maxCornerHeight;
|
||||
Geodetic3 cornerGeodetic = { patch.getCorner(q), cornerHeight };
|
||||
bool chunkIsNorthOfEquator = patch.isNorthern();
|
||||
|
||||
// The minimum height offset, however, we can simply
|
||||
double minCornerHeight = boundingHeight.min;
|
||||
std::vector<glm::dvec4> corners(8);
|
||||
|
||||
double latCloseToEquator = patch.edgeLatitudeNearestEquator();
|
||||
Geodetic3 p1Geodetic = { { latCloseToEquator, patch.minLon() }, maxCornerHeight };
|
||||
Geodetic3 p2Geodetic = { { latCloseToEquator, patch.maxLon() }, maxCornerHeight };
|
||||
|
||||
glm::vec3 p1 = ellipsoid.cartesianPosition(p1Geodetic);
|
||||
glm::vec3 p2 = ellipsoid.cartesianPosition(p2Geodetic);
|
||||
glm::vec3 p = 0.5f * (p1 + p2);
|
||||
Geodetic2 pGeodetic = ellipsoid.cartesianToGeodetic2(p);
|
||||
double latDiff = latCloseToEquator - pGeodetic.lat;
|
||||
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
Quad q = (Quad)(i % 4);
|
||||
double cornerHeight = i < 4 ? minCornerHeight : maxCornerHeight;
|
||||
Geodetic3 cornerGeodetic = { patch.getCorner(q), cornerHeight };
|
||||
|
||||
bool cornerIsNorthern = !((i / 2) % 2);
|
||||
bool cornerCloseToEquator = chunkIsNorthOfEquator ^ cornerIsNorthern;
|
||||
if (cornerCloseToEquator) {
|
||||
cornerGeodetic.geodetic2.lat += latDiff;
|
||||
}
|
||||
|
||||
corners[i] = dvec4(ellipsoid.cartesianPosition(cornerGeodetic), 1);
|
||||
bool cornerIsNorthern = !((i / 2) % 2);
|
||||
bool cornerCloseToEquator = chunkIsNorthOfEquator ^ cornerIsNorthern;
|
||||
if (cornerCloseToEquator) {
|
||||
cornerGeodetic.geodetic2.lat += latDiff;
|
||||
}
|
||||
return corners;
|
||||
|
||||
corners[i] = glm::dvec4(ellipsoid.cartesianPosition(cornerGeodetic), 1);
|
||||
}
|
||||
return corners;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -22,93 +22,86 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __CHUNK_H__
|
||||
#define __CHUNK_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_H__
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
#include <modules/globebrowsing/chunk/culling.h>
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
#include <modules/globebrowsing/chunk/chunklevelevaluator.h>
|
||||
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/geometry/angle.h>
|
||||
|
||||
|
||||
namespace openspace {
|
||||
|
||||
struct RenderData;
|
||||
|
||||
namespace globebrowsing {
|
||||
|
||||
class RenderableGlobe;
|
||||
class GeodeticPatch;
|
||||
class RenderableGlobe;
|
||||
struct TileIndex;
|
||||
|
||||
class Chunk {
|
||||
public:
|
||||
const static float DEFAULT_HEIGHT;
|
||||
class Chunk {
|
||||
public:
|
||||
const static float DEFAULT_HEIGHT;
|
||||
|
||||
struct BoundingHeights {
|
||||
float min, max;
|
||||
bool available;
|
||||
};
|
||||
|
||||
enum class Status {
|
||||
DO_NOTHING,
|
||||
WANT_MERGE,
|
||||
WANT_SPLIT,
|
||||
};
|
||||
|
||||
Chunk(
|
||||
const RenderableGlobe& owner,
|
||||
const TileIndex& tileIndex,
|
||||
bool initVisible = true);
|
||||
|
||||
/**
|
||||
* Updates the Chunk internally and returns the Status of the Chunk.
|
||||
*
|
||||
* Tests if the Chunk is cullable and gets the desired level of the Chunk. If the
|
||||
* Chunk is cullable it will be set to invisible and return Status::WANT_MERGE.
|
||||
* If the desired level is smaller than the current level of the chunk it will
|
||||
* return Status::WANT_MERGE, if it is larger it will return Status::WANT_SPLIT,
|
||||
* otherwise Status::DO_NOTHING.
|
||||
*
|
||||
* \returns The Status of the chunk.
|
||||
*/
|
||||
Status update(const RenderData& data);
|
||||
|
||||
/**
|
||||
* Returns a convex polyhedron of eight vertices tightly bounding the volume of
|
||||
* the Chunk.
|
||||
*/
|
||||
std::vector<glm::dvec4> getBoundingPolyhedronCorners() const;
|
||||
|
||||
const GeodeticPatch& surfacePatch() const;
|
||||
const RenderableGlobe& owner() const;
|
||||
const TileIndex tileIndex() const;
|
||||
bool isVisible() const;
|
||||
|
||||
/**
|
||||
* Returns BoundingHeights that fits the Chunk as tightly as possible.
|
||||
*
|
||||
* If the Chunk uses more than one HightLayer, the BoundingHeights will be set
|
||||
* to cover all HightLayers. If the Chunk has a higher level than its highest
|
||||
* resolution HightLayer Tile, it will base its BoundingHeights on that Tile.
|
||||
* This means that high level Chunks can have BoundingHeights that are not
|
||||
* tightly fitting.
|
||||
*/
|
||||
BoundingHeights getBoundingHeights() const;
|
||||
|
||||
private:
|
||||
const RenderableGlobe& _owner;
|
||||
const TileIndex _tileIndex;
|
||||
bool _isVisible;
|
||||
const GeodeticPatch _surfacePatch;
|
||||
struct BoundingHeights {
|
||||
float min, max;
|
||||
bool available;
|
||||
};
|
||||
|
||||
enum class Status {
|
||||
DO_NOTHING,
|
||||
WANT_MERGE,
|
||||
WANT_SPLIT,
|
||||
};
|
||||
|
||||
Chunk(const RenderableGlobe& owner, const TileIndex& tileIndex,
|
||||
bool initVisible = true);
|
||||
|
||||
/**
|
||||
* Updates the Chunk internally and returns the Status of the Chunk.
|
||||
*
|
||||
* Tests if the Chunk is cullable and gets the desired level of the Chunk. If the
|
||||
* Chunk is cullable it will be set to invisible and return Status::WANT_MERGE.
|
||||
* If the desired level is smaller than the current level of the chunk it will
|
||||
* return Status::WANT_MERGE, if it is larger it will return Status::WANT_SPLIT,
|
||||
* otherwise Status::DO_NOTHING.
|
||||
*
|
||||
* \returns The Status of the chunk.
|
||||
*/
|
||||
Status update(const RenderData& data);
|
||||
|
||||
/**
|
||||
* Returns a convex polyhedron of eight vertices tightly bounding the volume of
|
||||
* the Chunk.
|
||||
*/
|
||||
std::vector<glm::dvec4> getBoundingPolyhedronCorners() const;
|
||||
|
||||
const GeodeticPatch& surfacePatch() const;
|
||||
const RenderableGlobe& owner() const;
|
||||
const TileIndex tileIndex() const;
|
||||
bool isVisible() const;
|
||||
|
||||
/**
|
||||
* Returns BoundingHeights that fits the Chunk as tightly as possible.
|
||||
*
|
||||
* If the Chunk uses more than one HightLayer, the BoundingHeights will be set
|
||||
* to cover all HightLayers. If the Chunk has a higher level than its highest
|
||||
* resolution HightLayer Tile, it will base its BoundingHeights on that Tile.
|
||||
* This means that high level Chunks can have BoundingHeights that are not
|
||||
* tightly fitting.
|
||||
*/
|
||||
BoundingHeights getBoundingHeights() const;
|
||||
|
||||
private:
|
||||
const RenderableGlobe& _owner;
|
||||
const TileIndex _tileIndex;
|
||||
bool _isVisible;
|
||||
const GeodeticPatch _surfacePatch;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
|
||||
#endif // __CHUNK_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_H__
|
||||
|
||||
@@ -22,179 +22,166 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
|
||||
#include <modules/globebrowsing/chunk/chunklevelevaluator.h>
|
||||
|
||||
#include <modules/globebrowsing/chunk/chunk.h>
|
||||
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
#include <modules/globebrowsing/rendering/layermanager.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/rendering/layermanager.h>
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "ChunkLevelEvaluator";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
int EvaluateChunkLevelByDistance::getDesiredLevel(
|
||||
const Chunk& chunk,
|
||||
const RenderData& data) const {
|
||||
// Calculations are done in the reference frame of the globe
|
||||
// (model space). Hence, the camera position needs to be transformed
|
||||
// with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
const RenderableGlobe& globe = chunk.owner();
|
||||
const Ellipsoid& ellipsoid = globe.ellipsoid();
|
||||
int EvaluateChunkLevelByDistance::getDesiredLevel(const Chunk& chunk,
|
||||
const RenderData& data) const
|
||||
{
|
||||
// Calculations are done in the reference frame of the globe
|
||||
// (model space). Hence, the camera position needs to be transformed
|
||||
// with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
const RenderableGlobe& globe = chunk.owner();
|
||||
const Ellipsoid& ellipsoid = globe.ellipsoid();
|
||||
|
||||
Vec3 cameraPosition =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
|
||||
glm::dvec3 cameraPosition =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
|
||||
|
||||
Geodetic2 pointOnPatch = chunk.surfacePatch().closestPoint(
|
||||
ellipsoid.cartesianToGeodetic2(cameraPosition));
|
||||
Vec3 patchNormal = ellipsoid.geodeticSurfaceNormal(pointOnPatch);
|
||||
Vec3 patchPosition = ellipsoid.cartesianSurfacePosition(pointOnPatch);
|
||||
Geodetic2 pointOnPatch = chunk.surfacePatch().closestPoint(
|
||||
ellipsoid.cartesianToGeodetic2(cameraPosition)
|
||||
);
|
||||
glm::dvec3 patchNormal = ellipsoid.geodeticSurfaceNormal(pointOnPatch);
|
||||
glm::dvec3 patchPosition = ellipsoid.cartesianSurfacePosition(pointOnPatch);
|
||||
|
||||
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
|
||||
Scalar heightToChunk = heights.min;
|
||||
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
|
||||
double heightToChunk = heights.min;
|
||||
|
||||
// Offset position according to height
|
||||
patchPosition += patchNormal * heightToChunk;
|
||||
// Offset position according to height
|
||||
patchPosition += patchNormal * heightToChunk;
|
||||
|
||||
Vec3 cameraToChunk = patchPosition - cameraPosition;
|
||||
glm::dvec3 cameraToChunk = patchPosition - cameraPosition;
|
||||
|
||||
// Calculate desired level based on distance
|
||||
Scalar distanceToPatch = glm::length(cameraToChunk);
|
||||
Scalar distance = distanceToPatch;
|
||||
// Calculate desired level based on distance
|
||||
double distanceToPatch = glm::length(cameraToChunk);
|
||||
double distance = distanceToPatch;
|
||||
|
||||
Scalar scaleFactor =
|
||||
globe.generalProperties().lodScaleFactor * ellipsoid.minimumRadius();
|
||||
Scalar projectedScaleFactor = scaleFactor / distance;
|
||||
int desiredLevel = ceil(log2(projectedScaleFactor));
|
||||
return desiredLevel;
|
||||
}
|
||||
double scaleFactor =
|
||||
globe.generalProperties().lodScaleFactor * ellipsoid.minimumRadius();
|
||||
double projectedScaleFactor = scaleFactor / distance;
|
||||
int desiredLevel = ceil(log2(projectedScaleFactor));
|
||||
return desiredLevel;
|
||||
}
|
||||
|
||||
int EvaluateChunkLevelByProjectedArea::getDesiredLevel(
|
||||
const Chunk& chunk,
|
||||
const RenderData& data) const {
|
||||
// Calculations are done in the reference frame of the globe
|
||||
// (model space). Hence, the camera position needs to be transformed
|
||||
// with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
int EvaluateChunkLevelByProjectedArea::getDesiredLevel(const Chunk& chunk,
|
||||
const RenderData& data) const
|
||||
{
|
||||
// Calculations are done in the reference frame of the globe
|
||||
// (model space). Hence, the camera position needs to be transformed
|
||||
// with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
|
||||
const RenderableGlobe& globe = chunk.owner();
|
||||
const Ellipsoid& ellipsoid = globe.ellipsoid();
|
||||
glm::dvec4 cameraPositionModelSpace = glm::dvec4(data.camera.positionVec3(), 1);
|
||||
Vec3 cameraPosition =
|
||||
glm::dvec3(inverseModelTransform * cameraPositionModelSpace);
|
||||
Vec3 cameraToEllipsoidCenter = -cameraPosition;
|
||||
const RenderableGlobe& globe = chunk.owner();
|
||||
const Ellipsoid& ellipsoid = globe.ellipsoid();
|
||||
glm::dvec4 cameraPositionModelSpace = glm::dvec4(data.camera.positionVec3(), 1);
|
||||
glm::dvec3 cameraPosition =
|
||||
glm::dvec3(inverseModelTransform * cameraPositionModelSpace);
|
||||
glm::dvec3 cameraToEllipsoidCenter = -cameraPosition;
|
||||
|
||||
Geodetic2 cameraGeodeticPos = ellipsoid.cartesianToGeodetic2(cameraPosition);
|
||||
Geodetic2 cameraGeodeticPos = ellipsoid.cartesianToGeodetic2(cameraPosition);
|
||||
|
||||
// Approach:
|
||||
// The projected area of the chunk will be calculated based on a small area that
|
||||
// is close to the camera, and the scaled up to represent the full area.
|
||||
// The advantage of doing this is that it will better handle the cases where the
|
||||
// full patch is very curved (e.g. stretches from latitude 0 to 90 deg).
|
||||
// Approach:
|
||||
// The projected area of the chunk will be calculated based on a small area that
|
||||
// is close to the camera, and the scaled up to represent the full area.
|
||||
// The advantage of doing this is that it will better handle the cases where the
|
||||
// full patch is very curved (e.g. stretches from latitude 0 to 90 deg).
|
||||
|
||||
const Geodetic2 center = chunk.surfacePatch().center();
|
||||
const Geodetic2 closestCorner =
|
||||
chunk.surfacePatch().closestCorner(cameraGeodeticPos);
|
||||
const Geodetic2 center = chunk.surfacePatch().center();
|
||||
const Geodetic2 closestCorner = chunk.surfacePatch().closestCorner(cameraGeodeticPos);
|
||||
|
||||
// Camera
|
||||
// |
|
||||
// V
|
||||
//
|
||||
// oo
|
||||
// [ ]<
|
||||
// *geodetic space*
|
||||
//
|
||||
// closestCorner
|
||||
// +-----------------+ <-- north east corner
|
||||
// | |
|
||||
// | center |
|
||||
// | |
|
||||
// +-----------------+ <-- south east corner
|
||||
// Camera
|
||||
// |
|
||||
// V
|
||||
//
|
||||
// oo
|
||||
// [ ]<
|
||||
// *geodetic space*
|
||||
//
|
||||
// closestCorner
|
||||
// +-----------------+ <-- north east corner
|
||||
// | |
|
||||
// | center |
|
||||
// | |
|
||||
// +-----------------+ <-- south east corner
|
||||
|
||||
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
|
||||
const Geodetic3 c = { center, heights.min };
|
||||
const Geodetic3 c1 = { Geodetic2(center.lat, closestCorner.lon), heights.min };
|
||||
const Geodetic3 c2 = { Geodetic2(closestCorner.lat, center.lon), heights.min };
|
||||
Chunk::BoundingHeights heights = chunk.getBoundingHeights();
|
||||
const Geodetic3 c = { center, heights.min };
|
||||
const Geodetic3 c1 = { Geodetic2(center.lat, closestCorner.lon), heights.min };
|
||||
const Geodetic3 c2 = { Geodetic2(closestCorner.lat, center.lon), heights.min };
|
||||
|
||||
// Camera
|
||||
// |
|
||||
// V
|
||||
//
|
||||
// oo
|
||||
// [ ]<
|
||||
// *geodetic space*
|
||||
//
|
||||
// +--------c2-------+ <-- north east corner
|
||||
// | |
|
||||
// c1 c |
|
||||
// | |
|
||||
// +-----------------+ <-- south east corner
|
||||
// Camera
|
||||
// |
|
||||
// V
|
||||
//
|
||||
// oo
|
||||
// [ ]<
|
||||
// *geodetic space*
|
||||
//
|
||||
// +--------c2-------+ <-- north east corner
|
||||
// | |
|
||||
// c1 c |
|
||||
// | |
|
||||
// +-----------------+ <-- south east corner
|
||||
|
||||
|
||||
// Go from geodetic to cartesian space
|
||||
Vec3 A = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c);
|
||||
Vec3 B = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c1);
|
||||
Vec3 C = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c2);
|
||||
// Go from geodetic to cartesian space
|
||||
glm::dvec3 A = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c);
|
||||
glm::dvec3 B = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c1);
|
||||
glm::dvec3 C = cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c2);
|
||||
|
||||
// Project onto unit sphere
|
||||
A = glm::normalize(A);
|
||||
B = glm::normalize(B);
|
||||
C = glm::normalize(C);
|
||||
// Project onto unit sphere
|
||||
A = glm::normalize(A);
|
||||
B = glm::normalize(B);
|
||||
C = glm::normalize(C);
|
||||
|
||||
// Camera *cartesian space*
|
||||
// | +--------+---+
|
||||
// V __--'' __--'' /
|
||||
// C-------A--------- +
|
||||
// oo / / /
|
||||
//[ ]< +-------B----------+
|
||||
//
|
||||
// Camera *cartesian space*
|
||||
// | +--------+---+
|
||||
// V __--'' __--'' /
|
||||
// C-------A--------- +
|
||||
// oo / / /
|
||||
//[ ]< +-------B----------+
|
||||
//
|
||||
|
||||
// If the geodetic patch is small (i.e. has small width), that means the patch in
|
||||
// cartesian space will be almost flat, and in turn, the triangle ABC will roughly
|
||||
// correspond to 1/8 of the full area
|
||||
const Vec3 AB = B - A;
|
||||
const Vec3 AC = C - A;
|
||||
double areaABC = 0.5 * glm::length(glm::cross(AC, AB));
|
||||
double projectedChunkAreaApprox = 8 * areaABC;
|
||||
// If the geodetic patch is small (i.e. has small width), that means the patch in
|
||||
// cartesian space will be almost flat, and in turn, the triangle ABC will roughly
|
||||
// correspond to 1/8 of the full area
|
||||
const glm::dvec3 AB = B - A;
|
||||
const glm::dvec3 AC = C - A;
|
||||
double areaABC = 0.5 * glm::length(glm::cross(AC, AB));
|
||||
double projectedChunkAreaApprox = 8 * areaABC;
|
||||
|
||||
double scaledArea =
|
||||
globe.generalProperties().lodScaleFactor * projectedChunkAreaApprox;
|
||||
return chunk.tileIndex().level + round(scaledArea - 1);
|
||||
}
|
||||
double scaledArea =
|
||||
globe.generalProperties().lodScaleFactor * projectedChunkAreaApprox;
|
||||
return chunk.tileIndex().level + round(scaledArea - 1);
|
||||
}
|
||||
|
||||
int EvaluateChunkLevelByAvailableTileData::getDesiredLevel(
|
||||
const Chunk& chunk,
|
||||
const RenderData& data) const {
|
||||
auto layerManager = chunk.owner().chunkedLodGlobe()->layerManager();
|
||||
auto heightLayers = layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
|
||||
int currLevel = chunk.tileIndex().level;
|
||||
int EvaluateChunkLevelByAvailableTileData::getDesiredLevel(const Chunk& chunk,
|
||||
const RenderData& data) const
|
||||
{
|
||||
auto layerManager = chunk.owner().chunkedLodGlobe()->layerManager();
|
||||
auto heightLayers = layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
|
||||
int currLevel = chunk.tileIndex().level;
|
||||
|
||||
for (size_t i = 0; i < LayerManager::NUM_LAYER_GROUPS; i++) {
|
||||
for (auto& layer : layerManager->layerGroup(i).activeLayers()) {
|
||||
Tile::Status tileStatus =
|
||||
layer->tileProvider()->getTileStatus(chunk.tileIndex());
|
||||
if (tileStatus == Tile::Status::OK) {
|
||||
return UNKNOWN_DESIRED_LEVEL;
|
||||
}
|
||||
for (size_t i = 0; i < LayerManager::NUM_LAYER_GROUPS; ++i) {
|
||||
for (auto& layer : layerManager->layerGroup(i).activeLayers()) {
|
||||
Tile::Status tileStatus =
|
||||
layer->tileProvider()->getTileStatus(chunk.tileIndex());
|
||||
if (tileStatus == Tile::Status::OK) {
|
||||
return UNKNOWN_DESIRED_LEVEL;
|
||||
}
|
||||
}
|
||||
|
||||
return currLevel - 1;
|
||||
}
|
||||
|
||||
return currLevel - 1;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -22,61 +22,61 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __CHUNK_LEVEL_EVALUATOR_H__
|
||||
#define __CHUNK_LEVEL_EVALUATOR_H__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
#include <modules/globebrowsing/chunk/chunk.h>
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKLEVELEVALUATOR_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKLEVELEVALUATOR_H__
|
||||
|
||||
namespace openspace {
|
||||
|
||||
struct RenderData;
|
||||
|
||||
namespace globebrowsing {
|
||||
/**
|
||||
* Abstract class defining an interface for accessing a desired level of a Chunk.
|
||||
* The desired level can be used in the process of determining whether a Chunk should
|
||||
* want to split, merge or do nothing.
|
||||
*/
|
||||
class ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const = 0;
|
||||
static const int UNKNOWN_DESIRED_LEVEL = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate the Chunk level depending on the distance from the Camera to the Chunk.
|
||||
* This evaluation method aims to keep the screen size (horizontal length and not
|
||||
* area) of all chunks constant.
|
||||
*/
|
||||
class EvaluateChunkLevelByDistance : public ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
|
||||
};
|
||||
class Chunk;
|
||||
|
||||
/**
|
||||
* Evaluate the chunk level using the area of the non-heightmapped Chunk projected
|
||||
* on a sphere with the center in the position of the camera. A Chunk near the
|
||||
* horizon will have a small projected area and hence a lower desired level. This
|
||||
* evaluation is more forgiving than EvaluateChunkLevelByDistance, meaning it results
|
||||
* in lower desired levels.
|
||||
*/
|
||||
class EvaluateChunkLevelByProjectedArea : public ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
|
||||
};
|
||||
/**
|
||||
* Abstract class defining an interface for accessing a desired level of a Chunk.
|
||||
* The desired level can be used in the process of determining whether a Chunk should
|
||||
* want to split, merge or do nothing.
|
||||
*/
|
||||
class ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const = 0;
|
||||
static const int UNKNOWN_DESIRED_LEVEL = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate the Chunk level depending on the distance from the Camera to the Chunk.
|
||||
* This evaluation method aims to keep the screen size (horizontal length and not
|
||||
* area) of all chunks constant.
|
||||
*/
|
||||
class EvaluateChunkLevelByDistance : public ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate the chunk level using the area of the non-heightmapped Chunk projected
|
||||
* on a sphere with the center in the position of the camera. A Chunk near the
|
||||
* horizon will have a small projected area and hence a lower desired level. This
|
||||
* evaluation is more forgiving than EvaluateChunkLevelByDistance, meaning it results
|
||||
* in lower desired levels.
|
||||
*/
|
||||
class EvaluateChunkLevelByProjectedArea : public ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* If this chunk has available tile data for any LayerGroup on any of its active
|
||||
* Layers it will return an UNKNOWN_DESIRED_LEVEL. If no data is available it will
|
||||
* evaluate to a level that is <code>current level -1</code>.
|
||||
*/
|
||||
class EvaluateChunkLevelByAvailableTileData : public ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* If this chunk has available tile data for any LayerGroup on any of its active
|
||||
* Layers it will return an UNKNOWN_DESIRED_LEVEL. If no data is available it will
|
||||
* evaluate to a level that is <code>current level -1</code>.
|
||||
*/
|
||||
class EvaluateChunkLevelByAvailableTileData : public ChunkLevelEvaluator {
|
||||
public:
|
||||
virtual int getDesiredLevel(const Chunk& chunk, const RenderData& data) const;
|
||||
};
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __CHUNK_LEVEL_EVALUATOR_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKLEVELEVALUATOR_H__
|
||||
|
||||
@@ -22,20 +22,12 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <queue>
|
||||
#include <modules/globebrowsing/chunk/chunknode.h>
|
||||
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
|
||||
#include <modules/globebrowsing/chunk/chunknode.h>
|
||||
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
|
||||
#include <modules/globebrowsing/chunk/culling.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "ChunkNode";
|
||||
}
|
||||
#include <stack>
|
||||
#include <queue>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
@@ -43,13 +35,10 @@ namespace globebrowsing {
|
||||
int ChunkNode::chunkNodeCount = 0;
|
||||
|
||||
ChunkNode::ChunkNode(const Chunk& chunk, ChunkNode* parent)
|
||||
: _chunk(chunk)
|
||||
, _parent(parent)
|
||||
: _chunk(chunk)
|
||||
, _parent(parent)
|
||||
, _children({ nullptr, nullptr, nullptr, nullptr })
|
||||
{
|
||||
_children[0] = nullptr;
|
||||
_children[1] = nullptr;
|
||||
_children[2] = nullptr;
|
||||
_children[3] = nullptr;
|
||||
chunkNodeCount++;
|
||||
}
|
||||
|
||||
@@ -121,8 +110,8 @@ void ChunkNode::breadthFirst(const std::function<void(const ChunkNode&)>& f) con
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkNode::reverseBreadthFirst(
|
||||
const std::function<void(const ChunkNode&)>& f) const {
|
||||
void ChunkNode::reverseBreadthFirst(const std::function<void(const ChunkNode&)>& f) const
|
||||
{
|
||||
std::stack<const ChunkNode*> S;
|
||||
std::queue<const ChunkNode*> Q;
|
||||
|
||||
@@ -137,9 +126,12 @@ void ChunkNode::reverseBreadthFirst(
|
||||
|
||||
// Add children to queue, if any
|
||||
if (!node->isLeaf()) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
Q.push(node->_children[i].get());
|
||||
for (const auto& c : node->_children) {
|
||||
Q.push(c.get());
|
||||
}
|
||||
//for (int i = 0; i < 4; ++i) {
|
||||
// Q.push(node->_children[i].get());
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,23 +142,21 @@ void ChunkNode::reverseBreadthFirst(
|
||||
}
|
||||
}
|
||||
|
||||
#define CHUNK_NODE_FIND(node, p) \
|
||||
while (!node->isLeaf()) { \
|
||||
const Geodetic2 center = node->_chunk.surfacePatch().center();\
|
||||
int index = 0;\
|
||||
if (center.lon < p.lon) {\
|
||||
++index;\
|
||||
}\
|
||||
if (p.lat < center.lat) {\
|
||||
++index;\
|
||||
++index;\
|
||||
}\
|
||||
node = &(node->getChild((Quad)index));\
|
||||
}
|
||||
|
||||
const ChunkNode& ChunkNode::find(const Geodetic2& location) const {
|
||||
const ChunkNode* node = this;
|
||||
CHUNK_NODE_FIND(node, location);
|
||||
|
||||
while (!node->isLeaf()) {
|
||||
const Geodetic2 center = node->_chunk.surfacePatch().center();
|
||||
int index = 0;
|
||||
if (center.lon < location.lon) {
|
||||
++index;
|
||||
}
|
||||
if (location.lat < center.lat) {
|
||||
++index;
|
||||
++index;
|
||||
}
|
||||
node = &(node->getChild((Quad)index));
|
||||
}
|
||||
return *node;
|
||||
}
|
||||
|
||||
@@ -176,21 +166,21 @@ const ChunkNode& ChunkNode::getChild(Quad quad) const {
|
||||
|
||||
void ChunkNode::split(int depth) {
|
||||
if (depth > 0 && isLeaf()) {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
for (size_t i = 0; i < _children.size(); i++) {
|
||||
Chunk chunk(_chunk.owner(), _chunk.tileIndex().child((Quad)i));
|
||||
_children[i] = std::make_unique<ChunkNode>(chunk, this);
|
||||
}
|
||||
}
|
||||
|
||||
if (depth - 1 > 0) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int i = 0; i < _children.size(); ++i) {
|
||||
_children[i]->split(depth - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkNode::merge() {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int i = 0; i < _children.size(); ++i) {
|
||||
if (_children[i] != nullptr) {
|
||||
_children[i]->merge();
|
||||
}
|
||||
|
||||
@@ -22,20 +22,14 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __QUADTREE_H__
|
||||
#define __QUADTREE_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKNODE_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKNODE_H__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <functional>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
#include <modules/globebrowsing/chunk/chunk.h>
|
||||
#include <modules/globebrowsing/rendering/chunkrenderer.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
@@ -63,9 +57,9 @@ public:
|
||||
bool isRoot() const;
|
||||
bool isLeaf() const;
|
||||
|
||||
void depthFirst( const std::function<void(const ChunkNode&)>& f) const;
|
||||
void breadthFirst( const std::function<void(const ChunkNode&)>& f) const;
|
||||
void reverseBreadthFirst( const std::function<void(const ChunkNode&)>& f) const;
|
||||
void depthFirst(const std::function<void(const ChunkNode&)>& f) const;
|
||||
void breadthFirst(const std::function<void(const ChunkNode&)>& f) const;
|
||||
void reverseBreadthFirst(const std::function<void(const ChunkNode&)>& f) const;
|
||||
|
||||
const ChunkNode& find(const Geodetic2& location) const;
|
||||
const ChunkNode& getChild(Quad quad) const;
|
||||
@@ -84,7 +78,7 @@ public:
|
||||
|
||||
private:
|
||||
ChunkNode* _parent;
|
||||
std::unique_ptr<ChunkNode> _children[4];
|
||||
std::array<std::unique_ptr<ChunkNode>, 4> _children;
|
||||
|
||||
Chunk _chunk;
|
||||
};
|
||||
@@ -92,4 +86,4 @@ private:
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __QUADTREE_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKNODE_H__
|
||||
@@ -1,157 +1,125 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/chunk/culling.h>
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
|
||||
#include <modules/globebrowsing/chunk/chunk.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/ellipsoid.h>
|
||||
#include <modules/globebrowsing/geometry/convexhull.h>
|
||||
|
||||
#include <modules/globebrowsing/meshes/trianglesoup.h>
|
||||
|
||||
#include <modules/debugging/rendering/debugrenderer.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "FrustrumCuller";
|
||||
}
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// FRUSTUM CULLER //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
FrustumCuller::FrustumCuller(const AABB3 viewFrustum)
|
||||
: _viewFrustum(viewFrustum){
|
||||
FrustumCuller::FrustumCuller(const AABB3 viewFrustum) : _viewFrustum(viewFrustum) {}
|
||||
|
||||
}
|
||||
bool FrustumCuller::isCullable(const Chunk& chunk, const RenderData& data) {
|
||||
// Calculate the MVP matrix
|
||||
glm::dmat4 modelTransform = chunk.owner().modelTransform();
|
||||
glm::dmat4 viewTransform = glm::dmat4(data.camera.combinedViewMatrix());
|
||||
glm::dmat4 modelViewProjectionTransform = glm::dmat4(data.camera.projectionMatrix())
|
||||
* viewTransform * modelTransform;
|
||||
|
||||
FrustumCuller::~FrustumCuller() {
|
||||
|
||||
}
|
||||
|
||||
bool FrustumCuller::isCullable(const Chunk& chunk, const RenderData& data) {
|
||||
// Calculate the MVP matrix
|
||||
dmat4 modelTransform = chunk.owner().modelTransform();
|
||||
dmat4 viewTransform = dmat4(data.camera.combinedViewMatrix());
|
||||
dmat4 modelViewProjectionTransform = dmat4(data.camera.projectionMatrix())
|
||||
* viewTransform * modelTransform;
|
||||
|
||||
const std::vector<glm::dvec4>& corners = chunk.getBoundingPolyhedronCorners();
|
||||
const std::vector<glm::dvec4>& corners = chunk.getBoundingPolyhedronCorners();
|
||||
|
||||
// Create a bounding box that fits the patch corners
|
||||
AABB3 bounds; // in screen space
|
||||
std::vector<vec4> clippingSpaceCorners(8);
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
dvec4 cornerClippingSpace = modelViewProjectionTransform * corners[i];
|
||||
clippingSpaceCorners[i] = cornerClippingSpace;
|
||||
// Create a bounding box that fits the patch corners
|
||||
AABB3 bounds; // in screen space
|
||||
std::vector<glm::vec4> clippingSpaceCorners(8);
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
glm::dvec4 cornerClippingSpace = modelViewProjectionTransform * corners[i];
|
||||
clippingSpaceCorners[i] = cornerClippingSpace;
|
||||
|
||||
dvec3 cornerNDC =
|
||||
(1.0f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace;
|
||||
bounds.expand(cornerNDC);
|
||||
glm::dvec3 cornerNDC =
|
||||
(1.0f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace;
|
||||
bounds.expand(cornerNDC);
|
||||
}
|
||||
|
||||
return !_viewFrustum.intersects(bounds);
|
||||
}
|
||||
|
||||
bool HorizonCuller::isCullable(const Chunk& chunk, const RenderData& data) {
|
||||
// Calculations are done in the reference frame of the globe. Hence, the camera
|
||||
// position needs to be transformed with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
|
||||
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
|
||||
const GeodeticPatch& patch = chunk.surfacePatch();
|
||||
float maxHeight = chunk.getBoundingHeights().max;
|
||||
glm::dvec3 globePosition = glm::dvec3(0,0,0); // In model space it is 0
|
||||
double minimumGlobeRadius = ellipsoid.minimumRadius();
|
||||
|
||||
glm::dvec3 cameraPosition =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
|
||||
|
||||
glm::dvec3 globeToCamera = cameraPosition;
|
||||
|
||||
Geodetic2 cameraPositionOnGlobe =
|
||||
ellipsoid.cartesianToGeodetic2(globeToCamera);
|
||||
Geodetic2 closestPatchPoint = patch.closestPoint(cameraPositionOnGlobe);
|
||||
glm::dvec3 objectPosition = ellipsoid.cartesianSurfacePosition(closestPatchPoint);
|
||||
|
||||
// objectPosition is closest in latlon space but not guaranteed to be closest in
|
||||
// castesian coordinates. Therefore we compare it to the corners and pick the
|
||||
// real closest point,
|
||||
glm::dvec3 corners[4];
|
||||
corners[0] = ellipsoid.cartesianSurfacePosition(
|
||||
chunk.surfacePatch().getCorner(NORTH_WEST));
|
||||
corners[1] = ellipsoid.cartesianSurfacePosition(
|
||||
chunk.surfacePatch().getCorner(NORTH_EAST));
|
||||
corners[2] = ellipsoid.cartesianSurfacePosition(
|
||||
chunk.surfacePatch().getCorner(SOUTH_WEST));
|
||||
corners[3] = ellipsoid.cartesianSurfacePosition(
|
||||
chunk.surfacePatch().getCorner(SOUTH_EAST));
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
float distance = glm::length(cameraPosition - corners[i]);
|
||||
if (distance < glm::length(cameraPosition - objectPosition)) {
|
||||
objectPosition = corners[i];
|
||||
}
|
||||
}
|
||||
|
||||
return !_viewFrustum.intersects(bounds);
|
||||
}
|
||||
return isCullable(cameraPosition, globePosition, objectPosition,
|
||||
maxHeight, minimumGlobeRadius);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// HORIZON CULLER //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
HorizonCuller::HorizonCuller() {
|
||||
|
||||
}
|
||||
|
||||
HorizonCuller::~HorizonCuller() {
|
||||
|
||||
}
|
||||
|
||||
bool HorizonCuller::isCullable(const Chunk& chunk, const RenderData& data) {
|
||||
// Calculations are done in the reference frame of the globe. Hence, the camera
|
||||
// position needs to be transformed with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
|
||||
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
|
||||
const GeodeticPatch& patch = chunk.surfacePatch();
|
||||
float maxHeight = chunk.getBoundingHeights().max;
|
||||
Vec3 globePosition = glm::dvec3(0,0,0); // In model space it is 0
|
||||
Scalar minimumGlobeRadius = ellipsoid.minimumRadius();
|
||||
|
||||
Vec3 cameraPosition =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
|
||||
|
||||
Vec3 globeToCamera = cameraPosition;
|
||||
|
||||
Geodetic2 cameraPositionOnGlobe =
|
||||
ellipsoid.cartesianToGeodetic2(globeToCamera);
|
||||
Geodetic2 closestPatchPoint = patch.closestPoint(cameraPositionOnGlobe);
|
||||
Vec3 objectPosition = ellipsoid.cartesianSurfacePosition(closestPatchPoint);
|
||||
|
||||
// objectPosition is closest in latlon space but not guaranteed to be closest in
|
||||
// castesian coordinates. Therefore we compare it to the corners and pick the
|
||||
// real closest point,
|
||||
glm::dvec3 corners[4];
|
||||
corners[0] = ellipsoid.cartesianSurfacePosition(
|
||||
chunk.surfacePatch().getCorner(NORTH_WEST));
|
||||
corners[1] = ellipsoid.cartesianSurfacePosition(
|
||||
chunk.surfacePatch().getCorner(NORTH_EAST));
|
||||
corners[2] = ellipsoid.cartesianSurfacePosition(
|
||||
chunk.surfacePatch().getCorner(SOUTH_WEST));
|
||||
corners[3] = ellipsoid.cartesianSurfacePosition(
|
||||
chunk.surfacePatch().getCorner(SOUTH_EAST));
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
float distance = glm::length(cameraPosition - corners[i]);
|
||||
if (distance < glm::length(cameraPosition - objectPosition)) {
|
||||
objectPosition = corners[i];
|
||||
}
|
||||
}
|
||||
|
||||
return isCullable(cameraPosition, globePosition, objectPosition,
|
||||
maxHeight, minimumGlobeRadius);
|
||||
}
|
||||
|
||||
bool HorizonCuller::isCullable(
|
||||
const Vec3& cameraPosition,
|
||||
const Vec3& globePosition,
|
||||
const Vec3& objectPosition,
|
||||
Scalar objectBoundingSphereRadius,
|
||||
Scalar minimumGlobeRadius)
|
||||
{
|
||||
Scalar distanceToHorizon =
|
||||
sqrt(pow(length(cameraPosition - globePosition), 2) -
|
||||
pow(minimumGlobeRadius, 2));
|
||||
Scalar minimumAllowedDistanceToObjectFromHorizon = sqrt(
|
||||
pow(length(objectPosition - globePosition), 2) -
|
||||
pow(minimumGlobeRadius - objectBoundingSphereRadius, 2));
|
||||
// Minimum allowed for the object to be occluded
|
||||
Scalar minimumAllowedDistanceToObjectSquared =
|
||||
pow(distanceToHorizon + minimumAllowedDistanceToObjectFromHorizon, 2)
|
||||
+ pow(objectBoundingSphereRadius, 2);
|
||||
Scalar distanceToObjectSquared = pow(length(objectPosition - cameraPosition), 2);
|
||||
return distanceToObjectSquared > minimumAllowedDistanceToObjectSquared;
|
||||
}
|
||||
bool HorizonCuller::isCullable(const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& globePosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
double objectBoundingSphereRadius,
|
||||
double minimumGlobeRadius)
|
||||
{
|
||||
double distanceToHorizon =
|
||||
sqrt(pow(length(cameraPosition - globePosition), 2) -
|
||||
pow(minimumGlobeRadius, 2));
|
||||
double minimumAllowedDistanceToObjectFromHorizon = sqrt(
|
||||
pow(length(objectPosition - globePosition), 2) -
|
||||
pow(minimumGlobeRadius - objectBoundingSphereRadius, 2));
|
||||
// Minimum allowed for the object to be occluded
|
||||
double minimumAllowedDistanceToObjectSquared =
|
||||
pow(distanceToHorizon + minimumAllowedDistanceToObjectFromHorizon, 2)
|
||||
+ pow(objectBoundingSphereRadius, 2);
|
||||
double distanceToObjectSquared = pow(length(objectPosition - cameraPosition), 2);
|
||||
return distanceToObjectSquared > minimumAllowedDistanceToObjectSquared;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,58 +1,49 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __CULLING_H__
|
||||
#define __CULLING_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CULLING_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_CULLING_H__
|
||||
|
||||
#include <memory>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
// open space includes
|
||||
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/geometry/ellipsoid.h>
|
||||
#include <modules/globebrowsing/geometry/aabb.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
struct RenderData;
|
||||
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace glm;
|
||||
class Chunk;
|
||||
|
||||
class Chunk;
|
||||
|
||||
class ChunkCuller {
|
||||
public:
|
||||
virtual void update() { }
|
||||
|
||||
/**
|
||||
* Determine if the Chunk is cullable. That is return true if removing the
|
||||
* Chunk 'culling it' will not have any result on the final rendering. Culling
|
||||
* it will make the rendering faster.
|
||||
*/
|
||||
virtual bool isCullable(const Chunk& chunk, const RenderData& renderData) = 0;
|
||||
};
|
||||
class ChunkCuller {
|
||||
public:
|
||||
/**
|
||||
* Determine if the Chunk is cullable. That is return true if removing the
|
||||
* Chunk 'culling it' will not have any result on the final rendering. Culling
|
||||
* it will make the rendering faster.
|
||||
*/
|
||||
virtual bool isCullable(const Chunk& chunk, const RenderData& renderData) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Culls all chunks that are completely outside the view frustum.
|
||||
@@ -61,41 +52,37 @@ namespace globebrowsing {
|
||||
* screen space. This is calculated from a bounding polyhedron bounding the
|
||||
* Chunk. Hence the culling will not be 'perfect' but fast and good enough for
|
||||
* culling chunks outside the frustum with some margin.
|
||||
*/
|
||||
class FrustumCuller : public ChunkCuller {
|
||||
public:
|
||||
/**
|
||||
* \param viewFrustum is the view space in normalized device coordinates space.
|
||||
Hence it is an axis aligned bounding box and not a real frustum.
|
||||
*/
|
||||
FrustumCuller(const AABB3 viewFrustum);
|
||||
~FrustumCuller();
|
||||
|
||||
virtual bool isCullable(const Chunk& chunk, const RenderData& renderData);
|
||||
|
||||
private:
|
||||
const AABB3 _viewFrustum;
|
||||
};
|
||||
|
||||
*/
|
||||
class FrustumCuller : public ChunkCuller {
|
||||
public:
|
||||
/**
|
||||
* In this implementation of the horizon culling, the closer the ellipsoid is to a
|
||||
* sphere, the better this will make the culling. Using the minimum radius to
|
||||
* be safe. This means that if the ellipsoid has high difference between radii,
|
||||
* splitting might accur even though it may not be needed.
|
||||
*/
|
||||
class HorizonCuller : public ChunkCuller {
|
||||
public:
|
||||
HorizonCuller();
|
||||
~HorizonCuller();
|
||||
* \param viewFrustum is the view space in normalized device coordinates space.
|
||||
* Hence it is an axis aligned bounding box and not a real frustum.
|
||||
*/
|
||||
FrustumCuller(const AABB3 viewFrustum);
|
||||
|
||||
virtual bool isCullable(const Chunk& chunk, const RenderData& renderData);
|
||||
bool isCullable(const Chunk& chunk, const RenderData& renderData) override;
|
||||
|
||||
bool isCullable(const Vec3& cameraPosition, const Vec3& globePosition,
|
||||
const Vec3& objectPosition, Scalar objectBoundingSphereRadius,
|
||||
Scalar minimumGlobeRadius);
|
||||
};
|
||||
private:
|
||||
const AABB3 _viewFrustum;
|
||||
};
|
||||
|
||||
/**
|
||||
* In this implementation of the horizon culling, the closer the ellipsoid is to a
|
||||
* sphere, the better this will make the culling. Using the minimum radius to
|
||||
* be safe. This means that if the ellipsoid has high difference between radii,
|
||||
* splitting might accur even though it may not be needed.
|
||||
*/
|
||||
class HorizonCuller : public ChunkCuller {
|
||||
public:
|
||||
bool isCullable(const Chunk& chunk, const RenderData& renderData) override;
|
||||
|
||||
bool isCullable(const glm::dvec3& cameraPosition, const glm::dvec3& globePosition,
|
||||
const glm::dvec3& objectPosition, double objectBoundingSphereRadius,
|
||||
double minimumGlobeRadius);
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __CULLING_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CULLING_H__
|
||||
|
||||
@@ -1,163 +1,189 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/geometry/aabb.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "AABB";
|
||||
}
|
||||
#include <limits>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
AABB1::AABB1() : min(1e35), max(-1e35) { }
|
||||
AABB1::AABB1(float min, float max) : min(min), max(max) { }
|
||||
AABB1::AABB1()
|
||||
: AABB1(std::numeric_limits<float>::max(), -std::numeric_limits<float>::max())
|
||||
{}
|
||||
|
||||
void AABB1::expand(float p) {
|
||||
min = glm::min(min, p);
|
||||
max = glm::max(max, p);
|
||||
}
|
||||
AABB1::AABB1(float min, float max)
|
||||
: min(min)
|
||||
, max(max)
|
||||
{}
|
||||
|
||||
float AABB1::center() const {
|
||||
return 0.5f * (min + max);
|
||||
}
|
||||
void AABB1::expand(float p) {
|
||||
min = glm::min(min, p);
|
||||
max = glm::max(max, p);
|
||||
}
|
||||
|
||||
float AABB1::size() const {
|
||||
return max - min;
|
||||
}
|
||||
float AABB1::center() const {
|
||||
return 0.5f * (min + max);
|
||||
}
|
||||
|
||||
bool AABB1::contains(float p) const {
|
||||
return (min <= p) && (p <= max);
|
||||
}
|
||||
float AABB1::size() const {
|
||||
return max - min;
|
||||
}
|
||||
|
||||
bool AABB1::contains(const AABB1& o) const {
|
||||
return (min <= o.min) && (o.max <= max);
|
||||
}
|
||||
bool AABB1::contains(float p) const {
|
||||
return (min <= p) && (p <= max);
|
||||
}
|
||||
|
||||
bool AABB1::intersects(const AABB1& o) const {
|
||||
return (min <= o.max) && (o.min <= max);
|
||||
}
|
||||
bool AABB1::contains(const AABB1& o) const {
|
||||
return (min <= o.min) && (o.max <= max);
|
||||
}
|
||||
|
||||
AABBSpatialRelation AABB1::relationTo(const AABB1& o) const {
|
||||
if (intersects(o)) {
|
||||
if (contains(o)) return AABBSpatialRelation::Containing;
|
||||
if (o.contains(*this)) return AABBSpatialRelation::Contained;
|
||||
return AABBSpatialRelation::Intersecting;
|
||||
bool AABB1::intersects(const AABB1& o) const {
|
||||
return (min <= o.max) && (o.min <= max);
|
||||
}
|
||||
|
||||
AABBSpatialRelation AABB1::relationTo(const AABB1& o) const {
|
||||
if (intersects(o)) {
|
||||
if (contains(o)) {
|
||||
return AABBSpatialRelation::Containing;
|
||||
}
|
||||
return AABBSpatialRelation::None;
|
||||
}
|
||||
|
||||
AABB2::AABB2() : min(1e35), max(-1e35) { }
|
||||
AABB2::AABB2(const vec2& min, const vec2& max) : min(min), max(max) { }
|
||||
|
||||
void AABB2::expand(const vec2& p) {
|
||||
min.x = glm::min(min.x, p.x);
|
||||
min.y = glm::min(min.y, p.y);
|
||||
max.x = glm::max(max.x, p.x);
|
||||
max.y = glm::max(max.y, p.y);
|
||||
}
|
||||
|
||||
vec2 AABB2::center() const {
|
||||
return 0.5f * (min + max);
|
||||
}
|
||||
|
||||
vec2 AABB2::size() const {
|
||||
return max - min;
|
||||
}
|
||||
|
||||
bool AABB2::contains(const vec2& p) const {
|
||||
return (min.x <= p.x) && (p.x <= max.x)
|
||||
&& (min.y <= p.y) && (p.y <= max.y);
|
||||
}
|
||||
|
||||
bool AABB2::contains(const AABB2& o) const {
|
||||
return (min.x <= o.min.x) && (o.max.x <= max.x)
|
||||
&& (min.y <= o.min.y) && (o.max.y <= max.y);
|
||||
}
|
||||
|
||||
bool AABB2::intersects(const AABB2& o) const {
|
||||
return (min.x <= o.max.x) && (o.min.x <= max.x)
|
||||
&& (min.y <= o.max.y) && (o.min.y <= max.y);
|
||||
}
|
||||
|
||||
AABBSpatialRelation AABB2::relationTo(const AABB2& o) const {
|
||||
if (intersects(o)) {
|
||||
if (contains(o)) return AABBSpatialRelation::Containing;
|
||||
if (o.contains(*this)) return AABBSpatialRelation::Contained;
|
||||
return AABBSpatialRelation::Intersecting;
|
||||
if (o.contains(*this)) {
|
||||
return AABBSpatialRelation::Contained;
|
||||
}
|
||||
return AABBSpatialRelation::None;
|
||||
return AABBSpatialRelation::Intersecting;
|
||||
}
|
||||
return AABBSpatialRelation::None;
|
||||
}
|
||||
|
||||
AABB3::AABB3() : min(1e35), max(-1e35) { }
|
||||
AABB3::AABB3(const vec3& min, const vec3& max) : min(min), max(max) { }
|
||||
AABB2::AABB2()
|
||||
: AABB2(
|
||||
glm::vec2(std::numeric_limits<float>::max()),
|
||||
glm::vec2(-std::numeric_limits<float>::max())
|
||||
)
|
||||
{}
|
||||
|
||||
void AABB3::expand(const vec3 p) {
|
||||
min.x = glm::min(min.x, p.x);
|
||||
min.y = glm::min(min.y, p.y);
|
||||
min.z = glm::min(min.z, p.z);
|
||||
max.x = glm::max(max.x, p.x);
|
||||
max.y = glm::max(max.y, p.y);
|
||||
max.z = glm::max(max.z, p.z);
|
||||
}
|
||||
AABB2::AABB2(const glm::vec2& min, const glm::vec2& max)
|
||||
: min(min)
|
||||
, max(max)
|
||||
{}
|
||||
|
||||
vec3 AABB3::center() const {
|
||||
return 0.5f * (min + max);
|
||||
}
|
||||
void AABB2::expand(const glm::vec2& p) {
|
||||
min = glm::min(min, p);
|
||||
max = glm::max(max, p);
|
||||
}
|
||||
|
||||
vec3 AABB3::size() const {
|
||||
return max - min;
|
||||
}
|
||||
glm::vec2 AABB2::center() const {
|
||||
return 0.5f * (min + max);
|
||||
}
|
||||
|
||||
bool AABB3::contains(const vec3& p) const {
|
||||
return (min.x <= p.x) && (p.x <= max.x)
|
||||
&& (min.y <= p.y) && (p.y <= max.y)
|
||||
&& (min.z <= p.z) && (p.z <= max.z);
|
||||
}
|
||||
glm::vec2 AABB2::size() const {
|
||||
return max - min;
|
||||
}
|
||||
|
||||
bool AABB3::contains(const AABB3& o) const {
|
||||
return (min.x <= o.min.x) && (o.max.x <= max.x)
|
||||
&& (min.y <= o.min.y) && (o.max.y <= max.y)
|
||||
&& (min.z <= o.min.z) && (o.max.z <= max.z);
|
||||
}
|
||||
bool AABB2::contains(const glm::vec2& p) const {
|
||||
return (min.x <= p.x) && (p.x <= max.x)
|
||||
&& (min.y <= p.y) && (p.y <= max.y);
|
||||
}
|
||||
|
||||
bool AABB3::intersects(const AABB3& o) const {
|
||||
return (min.x <= o.max.x) && (o.min.x <= max.x)
|
||||
&& (min.y <= o.max.y) && (o.min.y <= max.y)
|
||||
&& (min.z <= o.max.z) && (o.min.z <= max.z);
|
||||
}
|
||||
bool AABB2::contains(const AABB2& o) const {
|
||||
return (min.x <= o.min.x) && (o.max.x <= max.x)
|
||||
&& (min.y <= o.min.y) && (o.max.y <= max.y);
|
||||
}
|
||||
|
||||
AABBSpatialRelation AABB3::relationTo(const AABB3& o) const {
|
||||
if (intersects(o)) {
|
||||
if (contains(o)) return AABBSpatialRelation::Containing;
|
||||
if (o.contains(*this)) return AABBSpatialRelation::Contained;
|
||||
return AABBSpatialRelation::Intersecting;
|
||||
bool AABB2::intersects(const AABB2& o) const {
|
||||
return (min.x <= o.max.x) && (o.min.x <= max.x)
|
||||
&& (min.y <= o.max.y) && (o.min.y <= max.y);
|
||||
}
|
||||
|
||||
AABBSpatialRelation AABB2::relationTo(const AABB2& o) const {
|
||||
if (intersects(o)) {
|
||||
if (contains(o)) {
|
||||
return AABBSpatialRelation::Containing;
|
||||
}
|
||||
return AABBSpatialRelation::None;
|
||||
if (o.contains(*this)) {
|
||||
return AABBSpatialRelation::Contained;
|
||||
}
|
||||
return AABBSpatialRelation::Intersecting;
|
||||
}
|
||||
return AABBSpatialRelation::None;
|
||||
}
|
||||
|
||||
AABB3::AABB3()
|
||||
: AABB3(
|
||||
glm::vec3(std::numeric_limits<float>::max()),
|
||||
glm::vec3(-std::numeric_limits<float>::max())
|
||||
)
|
||||
{}
|
||||
|
||||
AABB3::AABB3(const glm::vec3& min, const glm::vec3& max)
|
||||
: min(min),
|
||||
max(max)
|
||||
{}
|
||||
|
||||
void AABB3::expand(const glm::vec3 p) {
|
||||
min = glm::min(min, p);
|
||||
max = glm::max(max, p);
|
||||
}
|
||||
|
||||
glm::vec3 AABB3::center() const {
|
||||
return 0.5f * (min + max);
|
||||
}
|
||||
|
||||
glm::vec3 AABB3::size() const {
|
||||
return max - min;
|
||||
}
|
||||
|
||||
bool AABB3::contains(const glm::vec3& p) const {
|
||||
return (min.x <= p.x) && (p.x <= max.x)
|
||||
&& (min.y <= p.y) && (p.y <= max.y)
|
||||
&& (min.z <= p.z) && (p.z <= max.z);
|
||||
}
|
||||
|
||||
bool AABB3::contains(const AABB3& o) const {
|
||||
return (min.x <= o.min.x) && (o.max.x <= max.x)
|
||||
&& (min.y <= o.min.y) && (o.max.y <= max.y)
|
||||
&& (min.z <= o.min.z) && (o.max.z <= max.z);
|
||||
}
|
||||
|
||||
bool AABB3::intersects(const AABB3& o) const {
|
||||
return (min.x <= o.max.x) && (o.min.x <= max.x)
|
||||
&& (min.y <= o.max.y) && (o.min.y <= max.y)
|
||||
&& (min.z <= o.max.z) && (o.min.z <= max.z);
|
||||
}
|
||||
|
||||
AABBSpatialRelation AABB3::relationTo(const AABB3& o) const {
|
||||
if (intersects(o)) {
|
||||
if (contains(o)) {
|
||||
return AABBSpatialRelation::Containing;
|
||||
}
|
||||
if (o.contains(*this)) {
|
||||
return AABBSpatialRelation::Contained;
|
||||
}
|
||||
return AABBSpatialRelation::Intersecting;
|
||||
}
|
||||
return AABBSpatialRelation::None;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,94 +1,91 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __AABB_H__
|
||||
#define __AABB_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_AABB_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_AABB_H__
|
||||
|
||||
#include <memory>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace glm;
|
||||
enum class AABBSpatialRelation {
|
||||
None,
|
||||
Intersecting,
|
||||
Contained,
|
||||
Containing
|
||||
};
|
||||
|
||||
enum class AABBSpatialRelation {
|
||||
None,
|
||||
Intersecting,
|
||||
Contained,
|
||||
Containing
|
||||
};
|
||||
struct AABB1 {
|
||||
AABB1();
|
||||
AABB1(float min, float max);
|
||||
|
||||
struct AABB1 {
|
||||
AABB1();
|
||||
AABB1(float min, float max);
|
||||
void expand(float p);
|
||||
float center() const;
|
||||
float size() const;
|
||||
bool contains(float p) const;
|
||||
bool contains(const AABB1& o) const;
|
||||
bool intersects(const AABB1& o) const;
|
||||
AABBSpatialRelation relationTo(const AABB1& o) const;
|
||||
|
||||
void expand(float p);
|
||||
float center() const;
|
||||
float size() const;
|
||||
bool contains(float p) const;
|
||||
bool contains(const AABB1& o) const;
|
||||
bool intersects(const AABB1& o) const;
|
||||
AABBSpatialRelation relationTo(const AABB1& o) const;
|
||||
float min;
|
||||
float max;
|
||||
};
|
||||
|
||||
float min;
|
||||
float max;
|
||||
};
|
||||
struct AABB2 {
|
||||
AABB2();
|
||||
AABB2(const glm::vec2& min, const glm::vec2& max);
|
||||
|
||||
struct AABB2 {
|
||||
AABB2();
|
||||
AABB2(const vec2& min, const vec2& max);
|
||||
void expand(const glm::vec2& p);
|
||||
glm::vec2 center() const;
|
||||
glm::vec2 size() const;
|
||||
bool contains(const glm::vec2& p) const;
|
||||
bool contains(const AABB2& o) const;
|
||||
bool intersects(const AABB2& o) const;
|
||||
AABBSpatialRelation relationTo(const AABB2& o) const;
|
||||
|
||||
void expand(const vec2& p);
|
||||
vec2 center() const;
|
||||
vec2 size() const;
|
||||
bool contains(const vec2& p) const;
|
||||
bool contains(const AABB2& o) const;
|
||||
bool intersects(const AABB2& o) const;
|
||||
AABBSpatialRelation relationTo(const AABB2& o) const;
|
||||
glm::vec2 min;
|
||||
glm::vec2 max;
|
||||
};
|
||||
|
||||
vec2 min;
|
||||
vec2 max;
|
||||
};
|
||||
struct AABB3 {
|
||||
AABB3();
|
||||
AABB3(const glm::vec3& min, const glm::vec3& max);
|
||||
|
||||
struct AABB3 {
|
||||
AABB3();
|
||||
AABB3(const vec3& min, const vec3& max);
|
||||
void expand(const glm::vec3 p);
|
||||
glm::vec3 center() const;
|
||||
glm::vec3 size() const;
|
||||
bool contains(const glm::vec3& p) const;
|
||||
bool contains(const AABB3& o) const;
|
||||
bool intersects(const AABB3& o) const;
|
||||
AABBSpatialRelation relationTo(const AABB3& o) const;
|
||||
|
||||
void expand(const vec3 p);
|
||||
vec3 center() const;
|
||||
vec3 size() const;
|
||||
bool contains(const vec3& p) const;
|
||||
bool contains(const AABB3& o) const;
|
||||
bool intersects(const AABB3& o) const;
|
||||
AABBSpatialRelation relationTo(const AABB3& o) const;
|
||||
|
||||
vec3 min;
|
||||
vec3 max;
|
||||
};
|
||||
glm::vec3 min;
|
||||
glm::vec3 max;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __AABB_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_AABB_H__
|
||||
|
||||
@@ -1,178 +1,170 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/geometry/convexhull.h>
|
||||
|
||||
#include <string>
|
||||
#include <stack>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "ConvexHull";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
Point2 ConvexHull2::p0(0,0);
|
||||
glm::vec2 ConvexHull2::p0(0,0);
|
||||
|
||||
ConvexHull2::ConvexHull2(){ }
|
||||
ConvexHull2 ConvexHull2::grahamScan_NOT_THREAD_SAFE(std::vector<glm::vec2>& points,
|
||||
int yMinIndex)
|
||||
{
|
||||
ConvexHull2 hull;
|
||||
|
||||
ConvexHull2 ConvexHull2::grahamScan_NOT_THREAD_SAFE(std::vector<Point2>& points, int yMinIndex){
|
||||
ConvexHull2 hull;
|
||||
|
||||
if (yMinIndex == -1){
|
||||
yMinIndex = 0;
|
||||
float ymin = points[0].y;
|
||||
for (int i = 1; i < points.size(); i++) {
|
||||
float y = points[i].y;
|
||||
// Pick the bottom-most or chose the left most point in case of tie
|
||||
if ((y < ymin) || (ymin == y && points[i].x < points[yMinIndex].x)) {
|
||||
ymin = points[i].y;
|
||||
yMinIndex = i;
|
||||
}
|
||||
if (yMinIndex == -1) {
|
||||
yMinIndex = 0;
|
||||
float ymin = points[0].y;
|
||||
for (int i = 1; i < points.size(); i++) {
|
||||
float y = points[i].y;
|
||||
// Pick the bottom-most or chose the left most point in case of tie
|
||||
if ((y < ymin) || (ymin == y && points[i].x < points[yMinIndex].x)) {
|
||||
ymin = points[i].y;
|
||||
yMinIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Place the bottom-most point at first position
|
||||
swap(points[0], points[yMinIndex]);
|
||||
// Place the bottom-most point at first position
|
||||
swap(points[0], points[yMinIndex]);
|
||||
|
||||
// Sort n-1 points with respect to the first point. A point p1 comes
|
||||
// before p2 in sorted ouput if p2 has larger polar angle (in
|
||||
// counterclockwise direction) than p1
|
||||
hull.p0 = points[0];
|
||||
// Sort n-1 points with respect to the first point. A point p1 comes
|
||||
// before p2 in sorted ouput if p2 has larger polar angle (in
|
||||
// counterclockwise direction) than p1
|
||||
hull.p0 = points[0];
|
||||
|
||||
qsort(&(points.data()[1]), points.size()-1, sizeof(Point2), &(hull.compare));
|
||||
// Replace with std::sort
|
||||
qsort(&(points.data()[1]), points.size()-1, sizeof(glm::vec2), &(hull.compare));
|
||||
|
||||
|
||||
// Create an empty stack and push first three points to it.
|
||||
std::stack<glm::vec2> S;
|
||||
S.push(points[0]);
|
||||
S.push(points[1]);
|
||||
S.push(points[2]);
|
||||
|
||||
// Create an empty stack and push first three points to it.
|
||||
std::stack<Point2> S;
|
||||
S.push(points[0]);
|
||||
S.push(points[1]);
|
||||
S.push(points[2]);
|
||||
|
||||
// Process remaining n-3 points
|
||||
for (int i = 3; i < points.size(); i++)
|
||||
{
|
||||
// Keep removing top while the angle formed by points next-to-top,
|
||||
// top, and points[i] makes a non-left turn
|
||||
while (orientation(oneBelowTop(S), S.top(), points[i]) == 1)
|
||||
S.pop();
|
||||
S.push(points[i]);
|
||||
}
|
||||
|
||||
// Now stack has the output points, print contents of stack
|
||||
while (!S.empty())
|
||||
{
|
||||
Point2 p = S.top();
|
||||
hull._points.push_back(p);
|
||||
// Process remaining n-3 points
|
||||
for (int i = 3; i < points.size(); i++) {
|
||||
// Keep removing top while the angle formed by points next-to-top,
|
||||
// top, and points[i] makes a non-left turn
|
||||
while (orientation(oneBelowTop(S), S.top(), points[i]) == 1)
|
||||
S.pop();
|
||||
}
|
||||
|
||||
return hull;
|
||||
S.push(points[i]);
|
||||
}
|
||||
|
||||
bool ConvexHull2::intersects(const ConvexHull2& other) const {
|
||||
// uses Separating Axis Theorem
|
||||
// ref: http://stackoverflow.com/questions/753140/how-do-i-determine-if-two-convex-polygons-intersect
|
||||
return this->hasPerpendicularLineWhereProjectedPointsOverlap(other) ||
|
||||
other.hasPerpendicularLineWhereProjectedPointsOverlap(*this);
|
||||
// Now stack has the output points, print contents of stack
|
||||
while (!S.empty()) {
|
||||
glm::vec2 p = S.top();
|
||||
hull._points.push_back(p);
|
||||
S.pop();
|
||||
}
|
||||
|
||||
return hull;
|
||||
}
|
||||
|
||||
bool ConvexHull2::hasPerpendicularLineWhereProjectedPointsOverlap(const ConvexHull2& other) const {
|
||||
for (size_t i = 1; i < _points.size(); i++) {
|
||||
glm::vec2 dividingAxis = _points[i] - _points[i - 1];
|
||||
// project all points onto the vector perpendicular to the dividing axis
|
||||
glm::vec2 projAxis(glm::normalize(glm::vec2(-dividingAxis.y, dividingAxis.x)));
|
||||
const AABB1& myBounds = projectedRegion(projAxis);
|
||||
const AABB1& otherBounds = other.projectedRegion(projAxis);
|
||||
if (!myBounds.intersects(otherBounds)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ConvexHull2::intersects(const ConvexHull2& other) const {
|
||||
// uses Separating Axis Theorem
|
||||
// ref: http://stackoverflow.com/questions/753140/how-do-i-determine-if-two-convex-polygons-intersect
|
||||
return this->hasPerpendicularLineWhereProjectedPointsOverlap(other) ||
|
||||
other.hasPerpendicularLineWhereProjectedPointsOverlap(*this);
|
||||
}
|
||||
|
||||
// test line defined by last-to-first point
|
||||
glm::vec2 dividingAxis = _points[0] - _points.back();
|
||||
|
||||
bool ConvexHull2::hasPerpendicularLineWhereProjectedPointsOverlap(const ConvexHull2& other) const {
|
||||
for (size_t i = 1; i < _points.size(); i++) {
|
||||
glm::vec2 dividingAxis = _points[i] - _points[i - 1];
|
||||
// project all points onto the vector perpendicular to the dividing axis
|
||||
glm::vec2 projAxis(glm::normalize(glm::vec2(-dividingAxis.y, dividingAxis.x)));
|
||||
const AABB1& myBounds = projectedRegion(projAxis);
|
||||
const AABB1& otherBounds = other.projectedRegion(projAxis);
|
||||
if (!myBounds.intersects(otherBounds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AABB1 ConvexHull2::projectedRegion(glm::vec2 direction) const {
|
||||
AABB1 projectedRegion;
|
||||
for (size_t i = 0; i < _points.size(); i++) {
|
||||
projectedRegion.expand(glm::dot(_points[i], direction));
|
||||
}
|
||||
return projectedRegion;
|
||||
// test line defined by last-to-first point
|
||||
glm::vec2 dividingAxis = _points[0] - _points.back();
|
||||
glm::vec2 projAxis(glm::normalize(glm::vec2(-dividingAxis.y, dividingAxis.x)));
|
||||
const AABB1& myBounds = projectedRegion(projAxis);
|
||||
const AABB1& otherBounds = other.projectedRegion(projAxis);
|
||||
if (!myBounds.intersects(otherBounds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Point2 ConvexHull2::oneBelowTop(std::stack<Point2>& S) {
|
||||
Point2 p = S.top();
|
||||
S.pop();
|
||||
Point2 res = S.top();
|
||||
S.push(p);
|
||||
return res;
|
||||
return true;
|
||||
}
|
||||
|
||||
AABB1 ConvexHull2::projectedRegion(glm::vec2 direction) const {
|
||||
AABB1 projectedRegion;
|
||||
for (const glm::vec2& p : _points) {
|
||||
projectedRegion.expand(glm::dot(p, direction));
|
||||
}
|
||||
//for (size_t i = 0; i < _points.size(); i++) {
|
||||
// projectedRegion.expand(glm::dot(_points[i], direction));
|
||||
//}
|
||||
return projectedRegion;
|
||||
}
|
||||
|
||||
glm::vec2 ConvexHull2::oneBelowTop(std::stack<glm::vec2>& S) {
|
||||
glm::vec2 p = S.top();
|
||||
S.pop();
|
||||
glm::vec2 res = S.top();
|
||||
S.push(p);
|
||||
return res;
|
||||
}
|
||||
|
||||
void ConvexHull2::swap(glm::vec2& p1, glm::vec2& p2) {
|
||||
glm::vec2 temp = p1;
|
||||
p1 = p2;
|
||||
p2 = temp;
|
||||
}
|
||||
|
||||
const std::vector<glm::vec2> ConvexHull2::points() const {
|
||||
return _points;
|
||||
}
|
||||
|
||||
int ConvexHull2::orientation(const glm::vec2& p, const glm::vec2& q, const glm::vec2& r) {
|
||||
float val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
||||
return (val == 0) ? 0 : (val > 0) ? 1 : 2;
|
||||
}
|
||||
|
||||
float ConvexHull2::dist(const glm::vec2& p1, const glm::vec2& p2) {
|
||||
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
|
||||
}
|
||||
|
||||
int ConvexHull2::compare(const void *vp1, const void *vp2) {
|
||||
glm::vec2* p1 = (glm::vec2 *)vp1;
|
||||
glm::vec2* p2 = (glm::vec2 *)vp2;
|
||||
|
||||
// Find orientation
|
||||
int o = orientation(p0, *p1, *p2);
|
||||
if (o == 0) {
|
||||
return (dist(p0, *p2) >= dist(p0, *p1)) ? -1 : 1;
|
||||
}
|
||||
|
||||
void ConvexHull2::swap(Point2& p1, Point2& p2) {
|
||||
Point2 temp = p1;
|
||||
p1 = p2;
|
||||
p2 = temp;
|
||||
}
|
||||
return (o == 2) ? -1 : 1;
|
||||
}
|
||||
|
||||
const std::vector<Point2> ConvexHull2::points() const {
|
||||
return _points;
|
||||
}
|
||||
|
||||
|
||||
int ConvexHull2::orientation(const Point2& p, const Point2& q, const Point2& r) {
|
||||
float val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
||||
return (val == 0) ? 0 : (val > 0) ? 1 : 2;
|
||||
}
|
||||
|
||||
float ConvexHull2::dist(const Point2& p1, const Point2& p2) {
|
||||
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
|
||||
}
|
||||
|
||||
int ConvexHull2::compare(const void *vp1, const void *vp2) {
|
||||
Point2 *p1 = (Point2 *)vp1;
|
||||
Point2 *p2 = (Point2 *)vp2;
|
||||
|
||||
// Find orientation
|
||||
int o = orientation(p0, *p1, *p2);
|
||||
if (o == 0)
|
||||
return (dist(p0, *p2) >= dist(p0, *p1)) ? -1 : 1;
|
||||
|
||||
return (o == 2) ? -1 : 1;
|
||||
}
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
@@ -1,78 +1,72 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __CONVEX_HULL_H__
|
||||
#define __CONVEX_HULL_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CONVEX_HULL_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_CONVEX_HULL_H__
|
||||
|
||||
#include <modules/globebrowsing/geometry/aabb.h>
|
||||
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
#include <memory>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace glm;
|
||||
// Implementation based on
|
||||
// http://www.sanfoundry.com/cpp-program-implement-graham-scan-algorithm-find-convex-hull/
|
||||
|
||||
class ConvexHull2 {
|
||||
public:
|
||||
static ConvexHull2 grahamScan_NOT_THREAD_SAFE(std::vector<glm::vec2>& points,
|
||||
int yMinIndex = -1);
|
||||
|
||||
const std::vector<glm::vec2> points() const;
|
||||
|
||||
bool intersects(const ConvexHull2& o) const;
|
||||
|
||||
AABB1 projectedRegion(glm::vec2 direction) const;
|
||||
|
||||
// Implementation based on
|
||||
// http://www.sanfoundry.com/cpp-program-implement-graham-scan-algorithm-find-convex-hull/
|
||||
private:
|
||||
bool hasPerpendicularLineWhereProjectedPointsOverlap(const ConvexHull2& other) const;
|
||||
|
||||
typedef glm::vec2 Point2;
|
||||
static int compare(const void* vp1, const void* vp2);
|
||||
|
||||
class ConvexHull2 {
|
||||
public:
|
||||
ConvexHull2();
|
||||
static glm::vec2 oneBelowTop(std::stack<glm::vec2>&);
|
||||
static void swap(glm::vec2& p1, glm::vec2& p2);
|
||||
|
||||
static ConvexHull2 grahamScan_NOT_THREAD_SAFE(std::vector<Point2>& points, int yMinIndex = -1);
|
||||
// returns 0 = colinear, 1 = clockwise, 2 = counterclockwise
|
||||
static int orientation(const glm::vec2& p, const glm::vec2& q, const glm::vec2& r);
|
||||
static float dist(const glm::vec2& p1, const glm::vec2& p2);
|
||||
|
||||
const std::vector<Point2> points() const;
|
||||
|
||||
bool intersects(const ConvexHull2& o) const;
|
||||
|
||||
AABB1 projectedRegion(glm::vec2 direction) const;
|
||||
|
||||
private:
|
||||
bool hasPerpendicularLineWhereProjectedPointsOverlap(const ConvexHull2& other) const;
|
||||
|
||||
static int compare(const void *vp1, const void *vp2);
|
||||
|
||||
static Point2 oneBelowTop(std::stack<Point2>&);
|
||||
static void swap(Point2& p1, Point2& p2);
|
||||
|
||||
// returns 0 = colinear, 1 = clockwise, 2 = counterclockwise
|
||||
static int orientation(const Point2& p, const Point2& q, const Point2& r);
|
||||
static float dist(const Point2& p1, const Point2& p2);
|
||||
|
||||
private:
|
||||
static Point2 p0;
|
||||
std::vector<Point2> _points;
|
||||
};
|
||||
private:
|
||||
static glm::vec2 p0;
|
||||
std::vector<glm::vec2> _points;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __CONVEX_HULL_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CONVEX_HULL_H__
|
||||
|
||||
@@ -24,167 +24,150 @@
|
||||
|
||||
#include <modules/globebrowsing/geometry/ellipsoid.h>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "Ellipsoid";
|
||||
}
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
Ellipsoid::Ellipsoid() : Ellipsoid(1,1,1) {
|
||||
Ellipsoid::Ellipsoid(glm::dvec3 radii) : _radii(radii) {
|
||||
updateInternalCache();
|
||||
}
|
||||
|
||||
}
|
||||
void Ellipsoid::updateInternalCache() {
|
||||
_cached._radiiSquared = glm::dvec3(
|
||||
(_radii.x * _radii.x),
|
||||
(_radii.y * _radii.y),
|
||||
(_radii.z * _radii.z));
|
||||
|
||||
Ellipsoid::Ellipsoid(Vec3 radii) : _radii(radii) {
|
||||
updateInternalCache();
|
||||
}
|
||||
|
||||
Ellipsoid::Ellipsoid(Scalar x, Scalar y, Scalar z) : _radii(x, y, z) {
|
||||
updateInternalCache();
|
||||
}
|
||||
|
||||
Ellipsoid::~Ellipsoid(){
|
||||
|
||||
}
|
||||
|
||||
void Ellipsoid::updateInternalCache() {
|
||||
_cached._radiiSquared = Vec3(
|
||||
(_radii.x * _radii.x),
|
||||
(_radii.y * _radii.y),
|
||||
(_radii.z * _radii.z));
|
||||
|
||||
_cached._oneOverRadiiSquared = Vec3(1) / _cached._radiiSquared;
|
||||
_cached._radiiToTheFourth = _cached._radiiSquared * _cached._radiiSquared;
|
||||
_cached._oneOverRadiiSquared = glm::dvec3(1) / _cached._radiiSquared;
|
||||
_cached._radiiToTheFourth = _cached._radiiSquared * _cached._radiiSquared;
|
||||
|
||||
std::vector<Scalar> radii = { _radii.x, _radii.y, _radii.z };
|
||||
std::sort(radii.begin(), radii.end());
|
||||
_cached._minimumRadius = radii[0];
|
||||
_cached._medianRadius = radii[1];
|
||||
_cached._maximumRadius = radii[2];
|
||||
}
|
||||
std::vector<double> radii = { _radii.x, _radii.y, _radii.z };
|
||||
std::sort(radii.begin(), radii.end());
|
||||
_cached._minimumRadius = radii[0];
|
||||
_cached._medianRadius = radii[1];
|
||||
_cached._maximumRadius = radii[2];
|
||||
}
|
||||
|
||||
Vec3 Ellipsoid::geocentricSurfaceProjection(const Vec3& p) const {
|
||||
Scalar beta = 1.0 / sqrt(dot(p * p, _cached._oneOverRadiiSquared));
|
||||
return beta * p;
|
||||
}
|
||||
glm::dvec3 Ellipsoid::geocentricSurfaceProjection(const glm::dvec3& p) const {
|
||||
double beta = 1.0 / sqrt(dot(p * p, _cached._oneOverRadiiSquared));
|
||||
return beta * p;
|
||||
}
|
||||
|
||||
Vec3 Ellipsoid::geodeticSurfaceProjection(const Vec3& p) const {
|
||||
Scalar beta = 1.0 / sqrt(dot(p * p, _cached._oneOverRadiiSquared));
|
||||
Scalar n = glm::length(beta * p * _cached._oneOverRadiiSquared);
|
||||
Scalar alpha = (1.0 - beta) * (glm::length(p) / n);
|
||||
glm::dvec3 Ellipsoid::geodeticSurfaceProjection(const glm::dvec3& p) const {
|
||||
double beta = 1.0 / sqrt(dot(p * p, _cached._oneOverRadiiSquared));
|
||||
double n = glm::length(beta * p * _cached._oneOverRadiiSquared);
|
||||
double alpha = (1.0 - beta) * (glm::length(p) / n);
|
||||
|
||||
Vec3 p2 = p * p;
|
||||
Vec3 d, d2, d3;
|
||||
glm::dvec3 p2 = p * p;
|
||||
glm::dvec3 d, d2, d3;
|
||||
|
||||
Scalar s = 0.0;
|
||||
Scalar dSdA = 1.0;
|
||||
double s = 0.0;
|
||||
double dSdA = 1.0;
|
||||
|
||||
Scalar epsilon = 1e-10;
|
||||
do {
|
||||
alpha -= (s / dSdA);
|
||||
double epsilon = 1e-10;
|
||||
do {
|
||||
alpha -= (s / dSdA);
|
||||
|
||||
d = Vec3(1.0) + alpha * _cached._oneOverRadiiSquared;
|
||||
d2 = d * d;
|
||||
d3 = d * d2;
|
||||
d = glm::dvec3(1.0) + alpha * _cached._oneOverRadiiSquared;
|
||||
d2 = d * d;
|
||||
d3 = d * d2;
|
||||
|
||||
s = glm::dot(p2 / (_cached._radiiSquared * d2), Vec3(1.0)) - 1.0;
|
||||
s = glm::dot(p2 / (_cached._radiiSquared * d2), glm::dvec3(1.0)) - 1.0;
|
||||
|
||||
dSdA = -2.0 * glm::dot(p2 / (_cached._radiiToTheFourth * d3), Vec3(1.0));
|
||||
}
|
||||
while (abs(s) > epsilon);
|
||||
return p / d;
|
||||
dSdA = -2.0 * glm::dot(p2 / (_cached._radiiToTheFourth * d3), glm::dvec3(1.0));
|
||||
}
|
||||
while (abs(s) > epsilon);
|
||||
return p / d;
|
||||
}
|
||||
|
||||
Vec3 Ellipsoid::geodeticSurfaceNormalForGeocentricallyProjectedPoint(const Vec3& p) const {
|
||||
Vec3 normal = p * _cached._oneOverRadiiSquared;
|
||||
return glm::normalize(normal);
|
||||
}
|
||||
glm::dvec3 Ellipsoid::geodeticSurfaceNormalForGeocentricallyProjectedPoint(const glm::dvec3& p) const {
|
||||
glm::dvec3 normal = p * _cached._oneOverRadiiSquared;
|
||||
return glm::normalize(normal);
|
||||
}
|
||||
|
||||
Vec3 Ellipsoid::geodeticSurfaceNormal(Geodetic2 geodetic2) const {
|
||||
Scalar cosLat = glm::cos(geodetic2.lat);
|
||||
//geodetic2.lon = geodetic2.lon > M_PI ? geodetic2.lon - M_PI * 2 : geodetic2.lon;
|
||||
return Vec3(
|
||||
cosLat * cos(geodetic2.lon),
|
||||
cosLat * sin(geodetic2.lon),
|
||||
sin(geodetic2.lat));
|
||||
}
|
||||
glm::dvec3 Ellipsoid::geodeticSurfaceNormal(Geodetic2 geodetic2) const {
|
||||
double cosLat = glm::cos(geodetic2.lat);
|
||||
//geodetic2.lon = geodetic2.lon > M_PI ? geodetic2.lon - M_PI * 2 : geodetic2.lon;
|
||||
return glm::dvec3(
|
||||
cosLat * cos(geodetic2.lon),
|
||||
cosLat * sin(geodetic2.lon),
|
||||
sin(geodetic2.lat));
|
||||
}
|
||||
|
||||
const Vec3& Ellipsoid::radii() const {
|
||||
return _radii;
|
||||
}
|
||||
const glm::dvec3& Ellipsoid::radii() const {
|
||||
return _radii;
|
||||
}
|
||||
|
||||
|
||||
const Vec3& Ellipsoid::radiiSquared() const {
|
||||
return _cached._radiiSquared;
|
||||
}
|
||||
const glm::dvec3& Ellipsoid::radiiSquared() const {
|
||||
return _cached._radiiSquared;
|
||||
}
|
||||
|
||||
const Vec3& Ellipsoid::oneOverRadiiSquared() const {
|
||||
return _cached._oneOverRadiiSquared;
|
||||
}
|
||||
const glm::dvec3& Ellipsoid::oneOverRadiiSquared() const {
|
||||
return _cached._oneOverRadiiSquared;
|
||||
}
|
||||
|
||||
const Vec3& Ellipsoid::radiiToTheFourth() const {
|
||||
return _cached._radiiToTheFourth;
|
||||
}
|
||||
const glm::dvec3& Ellipsoid::radiiToTheFourth() const {
|
||||
return _cached._radiiToTheFourth;
|
||||
}
|
||||
|
||||
Scalar Ellipsoid::minimumRadius() const {
|
||||
return _cached._minimumRadius;
|
||||
}
|
||||
double Ellipsoid::minimumRadius() const {
|
||||
return _cached._minimumRadius;
|
||||
}
|
||||
|
||||
Scalar Ellipsoid::maximumRadius() const {
|
||||
return _cached._maximumRadius;
|
||||
}
|
||||
double Ellipsoid::maximumRadius() const {
|
||||
return _cached._maximumRadius;
|
||||
}
|
||||
|
||||
Scalar Ellipsoid::averageRadius() const {
|
||||
return (_radii.x + _radii.y + _radii.z) / 3.0;
|
||||
}
|
||||
double Ellipsoid::averageRadius() const {
|
||||
return (_radii.x + _radii.y + _radii.z) / 3.0;
|
||||
}
|
||||
|
||||
Scalar Ellipsoid::longitudalDistance(Scalar lat, Scalar lon1, Scalar lon2) const {
|
||||
Vec2 ellipseRadii = glm::cos(lat) * Vec2(_radii);
|
||||
// Approximating with the ellipse mean radius
|
||||
Scalar meanRadius = 0.5 * (ellipseRadii.x + ellipseRadii.y);
|
||||
return meanRadius * std::abs(lon2 - lon1);
|
||||
}
|
||||
double Ellipsoid::longitudalDistance(double lat, double lon1, double lon2) const {
|
||||
glm::dvec2 ellipseRadii = glm::cos(lat) * glm::dvec2(_radii);
|
||||
// Approximating with the ellipse mean radius
|
||||
double meanRadius = 0.5 * (ellipseRadii.x + ellipseRadii.y);
|
||||
return meanRadius * std::abs(lon2 - lon1);
|
||||
}
|
||||
|
||||
Scalar Ellipsoid::greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) const{
|
||||
// https://en.wikipedia.org/wiki/Meridian_arc
|
||||
// https://en.wikipedia.org/wiki/Great-circle_distance#Vector_version
|
||||
double Ellipsoid::greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) const{
|
||||
// https://en.wikipedia.org/wiki/Meridian_arc
|
||||
// https://en.wikipedia.org/wiki/Great-circle_distance#Vector_version
|
||||
|
||||
Vec3 n1 = geodeticSurfaceNormal(p1);
|
||||
Vec3 n2 = geodeticSurfaceNormal(p2);
|
||||
Scalar centralAngle = glm::atan(glm::length(glm::cross(n1, n2)) / glm::dot(n1, n2));
|
||||
glm::dvec3 n1 = geodeticSurfaceNormal(p1);
|
||||
glm::dvec3 n2 = geodeticSurfaceNormal(p2);
|
||||
double centralAngle = glm::atan(glm::length(glm::cross(n1, n2)) / glm::dot(n1, n2));
|
||||
|
||||
Geodetic2 pMid = (p1 + p2) / 2;
|
||||
Vec3 centralNormal = cartesianSurfacePosition(pMid);
|
||||
Geodetic2 pMid = (p1 + p2) / 2;
|
||||
glm::dvec3 centralNormal = cartesianSurfacePosition(pMid);
|
||||
|
||||
return centralAngle * glm::length(centralNormal);
|
||||
}
|
||||
return centralAngle * glm::length(centralNormal);
|
||||
}
|
||||
|
||||
Geodetic2 Ellipsoid::cartesianToGeodetic2(const Vec3& p) const
|
||||
{
|
||||
Vec3 normal = geodeticSurfaceNormalForGeocentricallyProjectedPoint(p);
|
||||
return Geodetic2(
|
||||
asin(normal.z / length(normal)), // Latitude
|
||||
atan2(normal.y, normal.x)); // Longitude
|
||||
}
|
||||
Geodetic2 Ellipsoid::cartesianToGeodetic2(const glm::dvec3& p) const
|
||||
{
|
||||
glm::dvec3 normal = geodeticSurfaceNormalForGeocentricallyProjectedPoint(p);
|
||||
return Geodetic2(
|
||||
asin(normal.z / length(normal)), // Latitude
|
||||
atan2(normal.y, normal.x)); // Longitude
|
||||
}
|
||||
|
||||
Vec3 Ellipsoid::cartesianSurfacePosition(const Geodetic2& geodetic2) const
|
||||
{
|
||||
// Position on surface : height = 0
|
||||
return cartesianPosition(Geodetic3({ geodetic2, 0 }));
|
||||
}
|
||||
glm::dvec3 Ellipsoid::cartesianSurfacePosition(const Geodetic2& geodetic2) const
|
||||
{
|
||||
// Position on surface : height = 0
|
||||
return cartesianPosition(Geodetic3({ geodetic2, 0 }));
|
||||
}
|
||||
|
||||
Vec3 Ellipsoid::cartesianPosition(const Geodetic3& geodetic3) const
|
||||
{
|
||||
Vec3 normal = geodeticSurfaceNormal(geodetic3.geodetic2);
|
||||
Vec3 k = _cached._radiiSquared * normal;
|
||||
Scalar gamma = sqrt(dot(k, normal));
|
||||
Vec3 rSurface = k / gamma;
|
||||
return rSurface + geodetic3.height * normal;
|
||||
}
|
||||
glm::dvec3 Ellipsoid::cartesianPosition(const Geodetic3& geodetic3) const
|
||||
{
|
||||
glm::dvec3 normal = geodeticSurfaceNormal(geodetic3.geodetic2);
|
||||
glm::dvec3 k = _cached._radiiSquared * normal;
|
||||
double gamma = sqrt(dot(k, normal));
|
||||
glm::dvec3 rSurface = k / gamma;
|
||||
return rSurface + geodetic3.height * normal;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -22,92 +22,83 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __ELLIPSOID_H__
|
||||
#define __ELLIPSOID_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_ELLIPSOID_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_ELLIPSOID_H__
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
|
||||
#include <ghoul/glm.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
/**
|
||||
This class is based largely on the Ellipsoid class defined in the book
|
||||
"3D Engine Design for Virtual Globes". Most planets or planetary objects are better
|
||||
described using ellipsoids than spheres. All inputs and outputs to this class is
|
||||
based on the WGS84 standard coordinate system where the x-axis points towards geographic
|
||||
(lat = 0, lon = 0), the y-axis points towards (lat = 0, lon = 90deg) and the
|
||||
z-axis points towards the north pole. For other globes than earth of course the radii
|
||||
can differ.
|
||||
*/
|
||||
/**
|
||||
* This class is based largely on the Ellipsoid class defined in the book
|
||||
* "3D Engine Design for Virtual Globes". Most planets or planetary objects are better
|
||||
* described using ellipsoids than spheres. All inputs and outputs to this class is
|
||||
* based on the WGS84 standard coordinate system where the x-axis points towards geographic
|
||||
* (lat = 0, lon = 0), the y-axis points towards (lat = 0, lon = 90deg) and the
|
||||
* z-axis points towards the north pole. For other globes than earth of course the radii
|
||||
* can differ.
|
||||
*/
|
||||
class Ellipsoid {
|
||||
public:
|
||||
|
||||
Ellipsoid();
|
||||
/**
|
||||
* \param radii defines three radii for the Ellipsoid
|
||||
*/
|
||||
Ellipsoid(glm::dvec3 radii = glm::dvec3(1.0, 1.0, 1.0));
|
||||
|
||||
/**
|
||||
\param radii defines three radii for the Ellipsoid
|
||||
*/
|
||||
Ellipsoid(Vec3 radii);
|
||||
* Scales a point along the geocentric normal and places it on the surface of the
|
||||
* Ellipsoid.
|
||||
* \param p is a point in the cartesian coordinate system to be placed on the surface
|
||||
* of the Ellipsoid
|
||||
*/
|
||||
glm::dvec3 geocentricSurfaceProjection(const glm::dvec3& p) const;
|
||||
|
||||
/**
|
||||
\param x defines the radius in x direction.
|
||||
\param y defines the radius in y direction.
|
||||
\param z defines the radius in z direction.
|
||||
*/
|
||||
Ellipsoid(Scalar x, Scalar y, Scalar z);
|
||||
~Ellipsoid();
|
||||
* Scales a point along the geodetic normal and places it on the surface of the
|
||||
* Ellipsoid.
|
||||
* \param p is a point in the cartesian coordinate system to be placed on the surface
|
||||
* of the Ellipsoid
|
||||
*/
|
||||
glm::dvec3 geodeticSurfaceProjection(const glm::dvec3& p) const;
|
||||
|
||||
/**
|
||||
Scales a point along the geocentric normal and places it on the surface of the
|
||||
Ellipsoid.
|
||||
\param p is a point in the cartesian coordinate system to be placed on the surface
|
||||
of the Ellipsoid
|
||||
*/
|
||||
Vec3 geocentricSurfaceProjection(const Vec3& p) const;
|
||||
|
||||
/**
|
||||
Scales a point along the geodetic normal and places it on the surface of the
|
||||
Ellipsoid.
|
||||
\param p is a point in the cartesian coordinate system to be placed on the surface
|
||||
of the Ellipsoid
|
||||
*/
|
||||
Vec3 geodeticSurfaceProjection(const Vec3& p) const;
|
||||
|
||||
Vec3 geodeticSurfaceNormalForGeocentricallyProjectedPoint(const Vec3& p) const;
|
||||
Vec3 geodeticSurfaceNormal(Geodetic2 geodetic2) const;
|
||||
glm::dvec3 geodeticSurfaceNormalForGeocentricallyProjectedPoint(const glm::dvec3& p) const;
|
||||
glm::dvec3 geodeticSurfaceNormal(Geodetic2 geodetic2) const;
|
||||
|
||||
const Vec3& radii() const;
|
||||
const Vec3& radiiSquared() const;
|
||||
const Vec3& oneOverRadiiSquared() const;
|
||||
const Vec3& radiiToTheFourth() const;
|
||||
const glm::dvec3& radii() const;
|
||||
const glm::dvec3& radiiSquared() const;
|
||||
const glm::dvec3& oneOverRadiiSquared() const;
|
||||
const glm::dvec3& radiiToTheFourth() const;
|
||||
|
||||
Scalar minimumRadius() const;
|
||||
Scalar maximumRadius() const;
|
||||
Scalar averageRadius() const;
|
||||
double minimumRadius() const;
|
||||
double maximumRadius() const;
|
||||
double averageRadius() const;
|
||||
|
||||
Scalar longitudalDistance(Scalar lat, Scalar lon1, Scalar lon2) const;
|
||||
Scalar greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) const;
|
||||
double longitudalDistance(double lat, double lon1, double lon2) const;
|
||||
double greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) const;
|
||||
|
||||
Geodetic2 cartesianToGeodetic2(const Vec3& p) const;
|
||||
Vec3 cartesianSurfacePosition(const Geodetic2& geodetic2) const;
|
||||
Vec3 cartesianPosition(const Geodetic3& geodetic3) const;
|
||||
Geodetic2 cartesianToGeodetic2(const glm::dvec3& p) const;
|
||||
glm::dvec3 cartesianSurfacePosition(const Geodetic2& geodetic2) const;
|
||||
glm::dvec3 cartesianPosition(const Geodetic3& geodetic3) const;
|
||||
|
||||
private:
|
||||
struct EllipsoidCache {
|
||||
Vec3 _radiiSquared;
|
||||
Vec3 _oneOverRadiiSquared;
|
||||
Vec3 _radiiToTheFourth;
|
||||
Scalar _minimumRadius;
|
||||
Scalar _maximumRadius;
|
||||
Scalar _medianRadius;
|
||||
glm::dvec3 _radiiSquared;
|
||||
glm::dvec3 _oneOverRadiiSquared;
|
||||
glm::dvec3 _radiiToTheFourth;
|
||||
double _minimumRadius;
|
||||
double _maximumRadius;
|
||||
double _medianRadius;
|
||||
} _cached;
|
||||
|
||||
void updateInternalCache();
|
||||
|
||||
Vec3 _radii;
|
||||
glm::dvec3 _radii;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __ELLIPSOID_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_ELLIPSOID_H__
|
||||
|
||||
@@ -23,277 +23,252 @@
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/angle.h>
|
||||
#include <modules/globebrowsing/geometry/ellipsoid.h>
|
||||
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "Geodetic2";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// GEODETIC2 //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
Geodetic2::Geodetic2(double latitude, double longitude)
|
||||
: lat(latitude)
|
||||
, lon(longitude)
|
||||
{}
|
||||
|
||||
Geodetic2::Geodetic2()
|
||||
: lat(0)
|
||||
, lon(0)
|
||||
{}
|
||||
Geodetic2::Geodetic2(const Geodetic2& p)
|
||||
: Geodetic2(p.lat, p.lon)
|
||||
{}
|
||||
|
||||
Geodetic2::Geodetic2(Scalar latitude, Scalar longitude)
|
||||
: lat(latitude)
|
||||
, lon(longitude)
|
||||
{}
|
||||
glm::dvec2 Geodetic2::toLonLatVec2() const {
|
||||
return glm::dvec2(lon, lat);
|
||||
}
|
||||
|
||||
Geodetic2::Geodetic2(const Geodetic2& p)
|
||||
: Geodetic2(p.lat, p.lon)
|
||||
{}
|
||||
bool Geodetic2::operator==(const Geodetic2& other) const {
|
||||
return lat == other.lat && lon == other.lon;
|
||||
}
|
||||
|
||||
Vec2 Geodetic2::toLonLatVec2() const {
|
||||
return Vec2(lon, lat);
|
||||
}
|
||||
Geodetic2 Geodetic2::operator+(const Geodetic2& other) const {
|
||||
return Geodetic2(lat + other.lat, lon + other.lon);
|
||||
}
|
||||
|
||||
bool Geodetic2::operator==(const Geodetic2& other) const {
|
||||
return lat == other.lat && lon == other.lon;
|
||||
}
|
||||
Geodetic2 Geodetic2::operator-(const Geodetic2& other) const {
|
||||
return Geodetic2(lat - other.lat, lon - other.lon);
|
||||
}
|
||||
|
||||
Geodetic2 Geodetic2::operator+(const Geodetic2& other) const {
|
||||
return Geodetic2(lat + other.lat, lon + other.lon);
|
||||
}
|
||||
Geodetic2 Geodetic2::operator*(double scalar) const {
|
||||
return Geodetic2(lat * scalar, lon * scalar);
|
||||
}
|
||||
|
||||
Geodetic2 Geodetic2::operator-(const Geodetic2& other) const {
|
||||
return Geodetic2(lat - other.lat, lon - other.lon);
|
||||
}
|
||||
Geodetic2 Geodetic2::operator/(double scalar) const {
|
||||
return Geodetic2(lat / scalar, lon / scalar);
|
||||
}
|
||||
|
||||
Geodetic2 Geodetic2::operator*(Scalar scalar) const {
|
||||
return Geodetic2(lat * scalar, lon * scalar);
|
||||
}
|
||||
GeodeticPatch::GeodeticPatch(double centerLat, double centerLon, double halfSizeLat,
|
||||
double halfSizeLon)
|
||||
: _center(Geodetic2(centerLat, centerLon))
|
||||
, _halfSize(Geodetic2(halfSizeLat, halfSizeLon))
|
||||
{}
|
||||
|
||||
Geodetic2 Geodetic2::operator/(Scalar scalar) const {
|
||||
return Geodetic2(lat / scalar, lon / scalar);
|
||||
}
|
||||
GeodeticPatch::GeodeticPatch(const Geodetic2& center, const Geodetic2& halfSize)
|
||||
: _center(center)
|
||||
, _halfSize(halfSize)
|
||||
{}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// GEODETICPATCH //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
GeodeticPatch::GeodeticPatch(const GeodeticPatch& patch)
|
||||
: _center(patch._center)
|
||||
, _halfSize(patch._halfSize)
|
||||
{}
|
||||
|
||||
GeodeticPatch::GeodeticPatch(
|
||||
Scalar centerLat,
|
||||
Scalar centerLon,
|
||||
Scalar halfSizeLat,
|
||||
Scalar halfSizeLon)
|
||||
: _center(Geodetic2(centerLat, centerLon))
|
||||
, _halfSize(Geodetic2(halfSizeLat, halfSizeLon))
|
||||
{}
|
||||
GeodeticPatch::GeodeticPatch(const TileIndex& tileIndex) {
|
||||
double deltaLat = (2 * glm::pi<double>()) / ((double)(1 << tileIndex.level));
|
||||
double deltaLon = (2 * glm::pi<double>()) / ((double)(1 << tileIndex.level));
|
||||
Geodetic2 nwCorner(glm::pi<double>() / 2 - deltaLat * tileIndex.y, -glm::pi<double>() + deltaLon * tileIndex.x);
|
||||
_halfSize = Geodetic2(deltaLat / 2, deltaLon / 2);
|
||||
_center = Geodetic2(nwCorner.lat - _halfSize.lat, nwCorner.lon + _halfSize.lon);
|
||||
}
|
||||
|
||||
GeodeticPatch::GeodeticPatch(
|
||||
const Geodetic2& center,
|
||||
const Geodetic2& halfSize)
|
||||
: _center(center)
|
||||
, _halfSize(halfSize)
|
||||
{}
|
||||
void GeodeticPatch::setCenter(const Geodetic2& center) {
|
||||
_center = center;
|
||||
}
|
||||
|
||||
GeodeticPatch::GeodeticPatch(const GeodeticPatch& patch)
|
||||
: _center(patch._center)
|
||||
, _halfSize(patch._halfSize)
|
||||
{}
|
||||
void GeodeticPatch::setHalfSize(const Geodetic2& halfSize) {
|
||||
_halfSize = halfSize;
|
||||
}
|
||||
|
||||
GeodeticPatch::GeodeticPatch(const TileIndex& tileIndex) {
|
||||
Scalar deltaLat = (2 * M_PI) / ((double)(1 << tileIndex.level));
|
||||
Scalar deltaLon = (2 * M_PI) / ((double)(1 << tileIndex.level));
|
||||
Geodetic2 nwCorner(M_PI / 2 - deltaLat * tileIndex.y, -M_PI + deltaLon * tileIndex.x);
|
||||
_halfSize = Geodetic2(deltaLat / 2, deltaLon / 2);
|
||||
_center = Geodetic2(nwCorner.lat - _halfSize.lat, nwCorner.lon + _halfSize.lon);
|
||||
}
|
||||
double GeodeticPatch::maximumTileLevel() const {
|
||||
// Numerator is just pi, not 2*pi, since we are dealing with HALF sizes
|
||||
return log2(glm::pi<double>() / glm::min(_halfSize.lat, _halfSize.lon));
|
||||
}
|
||||
|
||||
void GeodeticPatch::setCenter(const Geodetic2& center) {
|
||||
_center = center;
|
||||
}
|
||||
double GeodeticPatch::minimumTileLevel() const {
|
||||
// Numerator is just pi, not 2*pi, since we are dealing with HALF sizes
|
||||
return log2(glm::pi<double>() / glm::max(_halfSize.lat, _halfSize.lon));
|
||||
}
|
||||
|
||||
void GeodeticPatch::setHalfSize(const Geodetic2& halfSize) {
|
||||
_halfSize = halfSize;
|
||||
}
|
||||
const Geodetic2& GeodeticPatch::center() const {
|
||||
return _center;
|
||||
}
|
||||
|
||||
Scalar GeodeticPatch::maximumTileLevel() const {
|
||||
// Numerator is just pi, not 2*pi, since we are dealing with HALF sizes
|
||||
return log2(M_PI / glm::min(_halfSize.lat, _halfSize.lon));
|
||||
}
|
||||
const Geodetic2& GeodeticPatch::halfSize() const {
|
||||
return _halfSize;
|
||||
}
|
||||
|
||||
Scalar GeodeticPatch::minimumTileLevel() const {
|
||||
// Numerator is just pi, not 2*pi, since we are dealing with HALF sizes
|
||||
return log2(M_PI / glm::max(_halfSize.lat, _halfSize.lon));
|
||||
}
|
||||
Geodetic2 GeodeticPatch::size() const {
|
||||
return Geodetic2(2 * _halfSize.lat, 2 * _halfSize.lon);
|
||||
}
|
||||
|
||||
const Geodetic2& GeodeticPatch::center() const {
|
||||
return _center;
|
||||
}
|
||||
|
||||
const Geodetic2& GeodeticPatch::halfSize() const {
|
||||
return _halfSize;
|
||||
}
|
||||
|
||||
Geodetic2 GeodeticPatch::size() const {
|
||||
return Geodetic2(2 * _halfSize.lat, 2 * _halfSize.lon);
|
||||
}
|
||||
|
||||
Geodetic2 GeodeticPatch::getCorner(Quad q) const {
|
||||
switch (q) {
|
||||
Geodetic2 GeodeticPatch::getCorner(Quad q) const {
|
||||
switch (q) {
|
||||
case NORTH_WEST: return Geodetic2(maxLat(), minLon());// northWestCorner();
|
||||
case NORTH_EAST: return Geodetic2(maxLat(), maxLon());// northEastCorner();
|
||||
case SOUTH_WEST: return Geodetic2(minLat(), minLon());// southWestCorner();
|
||||
case SOUTH_EAST: return Geodetic2(minLat(), maxLon());// southEastCorner();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Geodetic2 GeodeticPatch::getSize() const {
|
||||
return _halfSize * 2;
|
||||
}
|
||||
Geodetic2 GeodeticPatch::getSize() const {
|
||||
return _halfSize * 2;
|
||||
}
|
||||
|
||||
double GeodeticPatch::minLat() const {
|
||||
return _center.lat - _halfSize.lat;
|
||||
}
|
||||
|
||||
Scalar GeodeticPatch::minLat() const {
|
||||
return _center.lat - _halfSize.lat;
|
||||
}
|
||||
double GeodeticPatch::maxLat() const {
|
||||
return _center.lat + _halfSize.lat;
|
||||
}
|
||||
|
||||
Scalar GeodeticPatch::maxLat() const {
|
||||
return _center.lat + _halfSize.lat;
|
||||
}
|
||||
double GeodeticPatch::minLon() const {
|
||||
return _center.lon - _halfSize.lon;
|
||||
}
|
||||
|
||||
Scalar GeodeticPatch::minLon() const {
|
||||
return _center.lon - _halfSize.lon;
|
||||
}
|
||||
|
||||
Scalar GeodeticPatch::maxLon() const {
|
||||
return _center.lon + _halfSize.lon;
|
||||
}
|
||||
double GeodeticPatch::maxLon() const {
|
||||
return _center.lon + _halfSize.lon;
|
||||
}
|
||||
|
||||
bool GeodeticPatch::contains(const Geodetic2& p) const {
|
||||
Geodetic2 diff = _center - p;
|
||||
return glm::abs(diff.lat) <= _halfSize.lat && glm::abs(diff.lon) <= _halfSize.lon;
|
||||
}
|
||||
bool GeodeticPatch::contains(const Geodetic2& p) const {
|
||||
Geodetic2 diff = _center - p;
|
||||
return glm::abs(diff.lat) <= _halfSize.lat && glm::abs(diff.lon) <= _halfSize.lon;
|
||||
}
|
||||
|
||||
Scalar GeodeticPatch::edgeLatitudeNearestEquator() const {
|
||||
return _center.lat + _halfSize.lat * (isNorthern() ? -1 : 1);
|
||||
}
|
||||
double GeodeticPatch::edgeLatitudeNearestEquator() const {
|
||||
return _center.lat + _halfSize.lat * (isNorthern() ? -1 : 1);
|
||||
}
|
||||
|
||||
Scalar GeodeticPatch::isNorthern() const {
|
||||
return _center.lat > 0.0;
|
||||
}
|
||||
double GeodeticPatch::isNorthern() const {
|
||||
return _center.lat > 0.0;
|
||||
}
|
||||
|
||||
Geodetic2 GeodeticPatch::clamp(const Geodetic2& p) const {
|
||||
using Ang = Angle<Scalar>;
|
||||
Geodetic2 GeodeticPatch::clamp(const Geodetic2& p) const {
|
||||
using Ang = Angle<double>;
|
||||
|
||||
// Convert to Angles for normalization
|
||||
Ang centerLat = Ang::fromRadians(_center.lat);
|
||||
Ang centerLon = Ang::fromRadians(_center.lon);
|
||||
Ang pointLat = Ang::fromRadians(p.lat);
|
||||
Ang pointLon = Ang::fromRadians(p.lon);
|
||||
// Convert to Angles for normalization
|
||||
Ang centerLat = Ang::fromRadians(_center.lat);
|
||||
Ang centerLon = Ang::fromRadians(_center.lon);
|
||||
Ang pointLat = Ang::fromRadians(p.lat);
|
||||
Ang pointLon = Ang::fromRadians(p.lon);
|
||||
|
||||
// Normalize w.r.t. the center in order for the clamping to done correctly
|
||||
//
|
||||
// Example:
|
||||
// centerLat = 0 deg, halfSize.lat = 10 deg, pointLat = 330 deg
|
||||
// --> Just clamping pointLat would be clamp(330, -10, 10) = 10 // WRONG!
|
||||
// Instead, if we first normalize 330 deg around 0, we get -30 deg
|
||||
// --> clamp(-30, -10, 10) = -10 // CORRECT!
|
||||
pointLat.normalizeAround(centerLat);
|
||||
pointLon.normalizeAround(centerLon);
|
||||
// Normalize w.r.t. the center in order for the clamping to done correctly
|
||||
//
|
||||
// Example:
|
||||
// centerLat = 0 deg, halfSize.lat = 10 deg, pointLat = 330 deg
|
||||
// --> Just clamping pointLat would be clamp(330, -10, 10) = 10 // WRONG!
|
||||
// Instead, if we first normalize 330 deg around 0, we get -30 deg
|
||||
// --> clamp(-30, -10, 10) = -10 // CORRECT!
|
||||
pointLat.normalizeAround(centerLat);
|
||||
pointLon.normalizeAround(centerLon);
|
||||
|
||||
return Geodetic2(
|
||||
glm::clamp(pointLat.asRadians(), minLat(), maxLat()),
|
||||
glm::clamp(pointLon.asRadians(), minLon(), maxLon())
|
||||
);
|
||||
}
|
||||
return Geodetic2(
|
||||
glm::clamp(pointLat.asRadians(), minLat(), maxLat()),
|
||||
glm::clamp(pointLon.asRadians(), minLon(), maxLon())
|
||||
);
|
||||
}
|
||||
|
||||
Geodetic2 GeodeticPatch::closestCorner(const Geodetic2& p) const {
|
||||
using Ang = Angle<Scalar>;
|
||||
Geodetic2 GeodeticPatch::closestCorner(const Geodetic2& p) const {
|
||||
using Ang = Angle<double>;
|
||||
|
||||
// LatLon vector from patch center to the point
|
||||
Geodetic2 centerToPoint = p - _center;
|
||||
// LatLon vector from patch center to the point
|
||||
Geodetic2 centerToPoint = p - _center;
|
||||
|
||||
// Normalize the difference angles to be centered around 0.
|
||||
Ang latDiff = Ang::fromRadians(centerToPoint.lat).normalizeAround(Ang::ZERO);
|
||||
Ang lonDiff = Ang::fromRadians(centerToPoint.lon).normalizeAround(Ang::ZERO);
|
||||
// Normalize the difference angles to be centered around 0.
|
||||
Ang latDiff = Ang::fromRadians(centerToPoint.lat).normalizeAround(Ang::ZERO);
|
||||
Ang lonDiff = Ang::fromRadians(centerToPoint.lon).normalizeAround(Ang::ZERO);
|
||||
|
||||
// If latDiff > 0
|
||||
// --> point p is north of the patch center
|
||||
// --> the closest corner to the point must be a northern one
|
||||
// --> set the corner's latitude coordinate to center.lat + halfSize.lat
|
||||
// else
|
||||
// --> set corner's latidude coordinate to center.lat - halfSize.lat
|
||||
Scalar cornerLat = _center.lat + _halfSize.lat * (latDiff > Ang::ZERO ? 1 : -1);
|
||||
// If latDiff > 0
|
||||
// --> point p is north of the patch center
|
||||
// --> the closest corner to the point must be a northern one
|
||||
// --> set the corner's latitude coordinate to center.lat + halfSize.lat
|
||||
// else
|
||||
// --> set corner's latidude coordinate to center.lat - halfSize.lat
|
||||
double cornerLat = _center.lat + _halfSize.lat * (latDiff > Ang::ZERO ? 1 : -1);
|
||||
|
||||
// We then assigned the corner's longitude coordinate in a similar fashion
|
||||
Scalar cornerLon = _center.lon + _halfSize.lon * (lonDiff > Ang::ZERO ? 1 : -1);
|
||||
// We then assigned the corner's longitude coordinate in a similar fashion
|
||||
double cornerLon = _center.lon + _halfSize.lon * (lonDiff > Ang::ZERO ? 1 : -1);
|
||||
|
||||
return Geodetic2(cornerLat, cornerLon);
|
||||
}
|
||||
return Geodetic2(cornerLat, cornerLon);
|
||||
}
|
||||
|
||||
Geodetic2 GeodeticPatch::closestPoint(const Geodetic2& p) const {
|
||||
// This method finds the closest point on the patch, to the provided
|
||||
// point p. As we are deali ng with latitude-longitude patches, distance in this
|
||||
// context refers to great-circle distance.
|
||||
// (https://en.wikipedia.org/wiki/Great-circle_distance)
|
||||
//
|
||||
// This uses a simple clamping approach to find the closest point on the
|
||||
// patch. A naive castesian clamp is not sufficient for this purpose,
|
||||
// as illustrated with an example below.
|
||||
Geodetic2 GeodeticPatch::closestPoint(const Geodetic2& p) const {
|
||||
// This method finds the closest point on the patch, to the provided
|
||||
// point p. As we are deali ng with latitude-longitude patches, distance in this
|
||||
// context refers to great-circle distance.
|
||||
// (https://en.wikipedia.org/wiki/Great-circle_distance)
|
||||
//
|
||||
// This uses a simple clamping approach to find the closest point on the
|
||||
// patch. A naive castesian clamp is not sufficient for this purpose,
|
||||
// as illustrated with an example below.
|
||||
|
||||
// Example: (degrees are used for latidude, longitude)
|
||||
// patchCenter = (0,0), patchHalfSize = (45,45), point = (5, 170)
|
||||
// Note, the point and the patch are on opposite sides of the sphere
|
||||
//
|
||||
// cartesian clamp:
|
||||
// --> clampedPointLat = clamp(5, -45, 45) = 5
|
||||
// --> clampedPointLon = clamp(170, -45, 45) = 45
|
||||
// --> result: (5, 45)
|
||||
// --> closest point is actually (45, 45)
|
||||
// --> The error is significant
|
||||
//
|
||||
// This method simply adds an extra clamp on the latitude in these cases. In the
|
||||
// above example, that would be the following:
|
||||
// --> clampedPointLat = clamp(180 - 5, -45, 45) = 45
|
||||
//
|
||||
// Just doing this actually makes points returned from this methods being the
|
||||
// true closest point, great-circle distance-wise.
|
||||
// Example: (degrees are used for latidude, longitude)
|
||||
// patchCenter = (0,0), patchHalfSize = (45,45), point = (5, 170)
|
||||
// Note, the point and the patch are on opposite sides of the sphere
|
||||
//
|
||||
// cartesian clamp:
|
||||
// --> clampedPointLat = clamp(5, -45, 45) = 5
|
||||
// --> clampedPointLon = clamp(170, -45, 45) = 45
|
||||
// --> result: (5, 45)
|
||||
// --> closest point is actually (45, 45)
|
||||
// --> The error is significant
|
||||
//
|
||||
// This method simply adds an extra clamp on the latitude in these cases. In the
|
||||
// above example, that would be the following:
|
||||
// --> clampedPointLat = clamp(180 - 5, -45, 45) = 45
|
||||
//
|
||||
// Just doing this actually makes points returned from this methods being the
|
||||
// true closest point, great-circle distance-wise.
|
||||
|
||||
|
||||
using Ang = Angle<Scalar>;
|
||||
using Ang = Angle<double>;
|
||||
|
||||
// Convert to Angles for normalization
|
||||
Ang centerLat = Ang::fromRadians(_center.lat);
|
||||
Ang centerLon = Ang::fromRadians(_center.lon);
|
||||
Ang pointLat = Ang::fromRadians(p.lat);
|
||||
Ang pointLon = Ang::fromRadians(p.lon);
|
||||
// Convert to Angles for normalization
|
||||
Ang centerLat = Ang::fromRadians(_center.lat);
|
||||
Ang centerLon = Ang::fromRadians(_center.lon);
|
||||
Ang pointLat = Ang::fromRadians(p.lat);
|
||||
Ang pointLon = Ang::fromRadians(p.lon);
|
||||
|
||||
// Normalize point with respect to center. This is done because the point
|
||||
// will later be clamped. See LatLonPatch::clamp(const LatLon&) for explanation
|
||||
pointLat.normalizeAround(centerLat);
|
||||
pointLon.normalizeAround(centerLon);
|
||||
// Normalize point with respect to center. This is done because the point
|
||||
// will later be clamped. See LatLonPatch::clamp(const LatLon&) for explanation
|
||||
pointLat.normalizeAround(centerLat);
|
||||
pointLon.normalizeAround(centerLon);
|
||||
|
||||
// Calculate the longitud difference between center and point. We normalize around
|
||||
// zero because we want the "shortest distance" difference, i.e the difference
|
||||
// should be in the interval [-180 deg, 180 deg]
|
||||
Ang centerToPointLon = (centerLon - pointLon).normalizeAround(Ang::ZERO);
|
||||
// Calculate the longitud difference between center and point. We normalize around
|
||||
// zero because we want the "shortest distance" difference, i.e the difference
|
||||
// should be in the interval [-180 deg, 180 deg]
|
||||
Ang centerToPointLon = (centerLon - pointLon).normalizeAround(Ang::ZERO);
|
||||
|
||||
// Calculate the longitudinal distance to the closest patch edge
|
||||
Ang longitudeDistanceToClosestPatchEdge = centerToPointLon.abs() - Ang::fromRadians(_halfSize.lon);
|
||||
// Calculate the longitudinal distance to the closest patch edge
|
||||
Ang longitudeDistanceToClosestPatchEdge = centerToPointLon.abs() - Ang::fromRadians(_halfSize.lon);
|
||||
|
||||
// If the longitude distance to the closest patch edge is larger than 90 deg
|
||||
// the latitude will have to be clamped to its closest corner, as explained in
|
||||
// the example above.
|
||||
Scalar clampedLat = longitudeDistanceToClosestPatchEdge > Ang::QUARTER ?
|
||||
clampedLat = glm::clamp((Ang::HALF - pointLat).normalizeAround(centerLat).asRadians(), minLat(), maxLat()) :
|
||||
clampedLat = glm::clamp(pointLat.asRadians(), minLat(), maxLat());
|
||||
// If the longitude distance to the closest patch edge is larger than 90 deg
|
||||
// the latitude will have to be clamped to its closest corner, as explained in
|
||||
// the example above.
|
||||
double clampedLat = longitudeDistanceToClosestPatchEdge > Ang::QUARTER ?
|
||||
clampedLat = glm::clamp((Ang::HALF - pointLat).normalizeAround(centerLat).asRadians(), minLat(), maxLat()) :
|
||||
clampedLat = glm::clamp(pointLat.asRadians(), minLat(), maxLat());
|
||||
|
||||
// Longitude is just clamped normally
|
||||
Scalar clampedLon = glm::clamp(pointLon.asRadians(), minLon(), maxLon());
|
||||
// Longitude is just clamped normally
|
||||
double clampedLon = glm::clamp(pointLon.asRadians(), minLon(), maxLon());
|
||||
|
||||
return Geodetic2(clampedLat, clampedLon);
|
||||
}
|
||||
return Geodetic2(clampedLat, clampedLon);
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -22,69 +22,51 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __GEODETIC2_H__
|
||||
#define __GEODETIC2_H__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_GEODETIC2_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_GEODETIC2_H__
|
||||
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
// Using double precision
|
||||
typedef double Scalar;
|
||||
typedef glm::dvec2 Vec2;
|
||||
typedef glm::dvec3 Vec3;
|
||||
#include <ghoul/glm.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
// Forward declaration
|
||||
class Ellipsoid;
|
||||
|
||||
struct Geodetic2 {
|
||||
Geodetic2();
|
||||
Geodetic2(Scalar latitude, Scalar longitude);
|
||||
Geodetic2(double latitude = 0.0, double longitude = 0.0);
|
||||
Geodetic2(const Geodetic2& src);
|
||||
|
||||
//static Geodetic2 fromCartesian(const Vec3& v);
|
||||
//Vec3 asUnitCartesian() const;
|
||||
|
||||
Vec2 toLonLatVec2() const;
|
||||
glm::dvec2 toLonLatVec2() const;
|
||||
|
||||
bool operator==(const Geodetic2& other) const;
|
||||
bool operator!=(const Geodetic2& other) const { return !(*this == (other)); }
|
||||
|
||||
Geodetic2 operator+(const Geodetic2& other) const;
|
||||
Geodetic2 operator-(const Geodetic2& other) const;
|
||||
Geodetic2 operator*(Scalar scalar) const;
|
||||
Geodetic2 operator/(Scalar scalar) const;
|
||||
Geodetic2 operator*(double scalar) const;
|
||||
Geodetic2 operator/(double scalar) const;
|
||||
|
||||
Scalar lat;
|
||||
Scalar lon;
|
||||
double lat;
|
||||
double lon;
|
||||
};
|
||||
|
||||
struct Geodetic3 {
|
||||
Geodetic2 geodetic2;
|
||||
Scalar height;
|
||||
double height;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// GEODETICPATCH //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
class GeodeticPatch {
|
||||
public:
|
||||
GeodeticPatch(
|
||||
Scalar centerLat,
|
||||
Scalar centerLon,
|
||||
Scalar halfSizeLat,
|
||||
Scalar halfSizeLon);
|
||||
double centerLat,
|
||||
double centerLon,
|
||||
double halfSizeLat,
|
||||
double halfSizeLon);
|
||||
|
||||
GeodeticPatch(
|
||||
const Geodetic2& center,
|
||||
@@ -100,20 +82,20 @@ public:
|
||||
/**
|
||||
returns the latitude boundary which is closest to the equator
|
||||
*/
|
||||
Scalar edgeLatitudeNearestEquator() const;
|
||||
double edgeLatitudeNearestEquator() const;
|
||||
|
||||
/**
|
||||
Returns true if the center above the equator
|
||||
*/
|
||||
Scalar isNorthern() const;
|
||||
double isNorthern() const;
|
||||
|
||||
Geodetic2 getCorner(Quad q) const;
|
||||
Geodetic2 getSize() const;
|
||||
|
||||
Scalar minLat() const;
|
||||
Scalar maxLat() const;
|
||||
Scalar minLon() const;
|
||||
Scalar maxLon() const;
|
||||
double minLat() const;
|
||||
double maxLat() const;
|
||||
double minLon() const;
|
||||
double maxLon() const;
|
||||
|
||||
/**
|
||||
* returns true if the specified coordinate is contained within the patch
|
||||
@@ -140,12 +122,12 @@ public:
|
||||
/**
|
||||
* Returns the minimum tile level of the patch (based on largest side)
|
||||
*/
|
||||
Scalar minimumTileLevel() const;
|
||||
double minimumTileLevel() const;
|
||||
|
||||
/**
|
||||
* Returns the maximum level of the patch (based on smallest side)
|
||||
*/
|
||||
Scalar maximumTileLevel() const;
|
||||
double maximumTileLevel() const;
|
||||
|
||||
const Geodetic2& center() const;
|
||||
const Geodetic2& halfSize() const;
|
||||
@@ -159,4 +141,4 @@ private:
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __GEODETIC2_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_GEODETIC2_H__
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
#include <modules/globebrowsing/other/distanceswitch.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/cachingtileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/singleimageprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/temporaltileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/texttileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileproviderbylevel.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileproviderbyindex.h>
|
||||
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/util/factorymanager.h>
|
||||
@@ -33,44 +40,31 @@
|
||||
#include <ghoul/misc/templatefactory.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/cachingtileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/singleimageprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/temporaltileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/texttileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileproviderbylevel.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileproviderbyindex.h>
|
||||
|
||||
|
||||
namespace openspace {
|
||||
|
||||
GlobeBrowsingModule::GlobeBrowsingModule()
|
||||
: OpenSpaceModule("GlobeBrowsing")
|
||||
{}
|
||||
GlobeBrowsingModule::GlobeBrowsingModule() : OpenSpaceModule("GlobeBrowsing") {}
|
||||
|
||||
void GlobeBrowsingModule::internalInitialize() {
|
||||
using namespace globebrowsing;
|
||||
|
||||
auto fRenderable = FactoryManager::ref().factory<Renderable>();
|
||||
ghoul_assert(fRenderable, "Renderable factory was not created");
|
||||
fRenderable->registerClass<globebrowsing::RenderableGlobe>("RenderableGlobe");
|
||||
|
||||
void addFactory(std::unique_ptr<ghoul::TemplateFactoryBase> factory);
|
||||
|
||||
// add Tile Provider factory
|
||||
FactoryManager::ref().addFactory(
|
||||
std::make_unique<ghoul::TemplateFactory<globebrowsing::TileProvider>>());
|
||||
auto fTileProvider = std::make_unique<ghoul::TemplateFactory<TileProvider>>();
|
||||
|
||||
auto fTileProvider =
|
||||
FactoryManager::ref().factory<globebrowsing::TileProvider>();
|
||||
fTileProvider->registerClass<globebrowsing::CachingTileProvider>("LRUCaching");
|
||||
fTileProvider->registerClass<globebrowsing::SingleImageProvider>("SingleImage");
|
||||
fTileProvider->registerClass<globebrowsing::TemporalTileProvider>("Temporal");
|
||||
fTileProvider->registerClass<globebrowsing::TileIndexTileProvider>("TileIndex");
|
||||
fTileProvider->registerClass<globebrowsing::SizeReferenceTileProvider>("SizeReference");
|
||||
fTileProvider->registerClass<CachingTileProvider>("LRUCaching");
|
||||
fTileProvider->registerClass<SingleImageProvider>("SingleImage");
|
||||
fTileProvider->registerClass<TemporalTileProvider>("Temporal");
|
||||
fTileProvider->registerClass<TileIndexTileProvider>("TileIndex");
|
||||
fTileProvider->registerClass<SizeReferenceTileProvider>("SizeReference");
|
||||
|
||||
// Combining Tile Providers
|
||||
fTileProvider->registerClass<globebrowsing::TileProviderByLevel>("ByLevel");
|
||||
fTileProvider->registerClass<globebrowsing::TileProviderByIndex>("ByIndex");
|
||||
fTileProvider->registerClass<TileProviderByLevel>("ByLevel");
|
||||
fTileProvider->registerClass<TileProviderByIndex>("ByIndex");
|
||||
|
||||
FactoryManager::ref().addFactory(std::move(fTileProvider));
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,351 +1,321 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
* *
|
||||
* 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/globes/chunkedlodglobe.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/chunk/chunk.h>
|
||||
#include <modules/globebrowsing/chunk/chunklevelevaluator.h>
|
||||
#include <modules/globebrowsing/chunk/chunknode.h>
|
||||
#include <modules/globebrowsing/chunk/culling.h>
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
#include <modules/globebrowsing/meshes/skirtedgrid.h>
|
||||
#include <modules/globebrowsing/chunk/culling.h>
|
||||
#include <modules/globebrowsing/chunk/chunklevelevaluator.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/rendering/chunkrenderer.h>
|
||||
#include <modules/globebrowsing/rendering/layermanager.h>
|
||||
#include <modules/debugging/rendering/debugrenderer.h>
|
||||
|
||||
// open space includes
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/util/spicemanager.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
// ghoul includes
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
// open space includes
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
|
||||
#include <modules/globebrowsing/chunk/chunknode.h>
|
||||
#include <modules/globebrowsing/rendering/chunkrenderer.h>
|
||||
|
||||
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "ChunkedLodGlobe";
|
||||
}
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
const TileIndex ChunkedLodGlobe::LEFT_HEMISPHERE_INDEX =
|
||||
TileIndex(0, 0, 1);
|
||||
const TileIndex ChunkedLodGlobe::RIGHT_HEMISPHERE_INDEX =
|
||||
TileIndex(1, 0, 1);
|
||||
const GeodeticPatch ChunkedLodGlobe::COVERAGE =
|
||||
GeodeticPatch(0, 0, 90, 180);
|
||||
const TileIndex ChunkedLodGlobe::LEFT_HEMISPHERE_INDEX = TileIndex(0, 0, 1);
|
||||
const TileIndex ChunkedLodGlobe::RIGHT_HEMISPHERE_INDEX = TileIndex(1, 0, 1);
|
||||
const GeodeticPatch ChunkedLodGlobe::COVERAGE = GeodeticPatch(0, 0, 90, 180);
|
||||
|
||||
ChunkedLodGlobe::ChunkedLodGlobe(
|
||||
const RenderableGlobe& owner,
|
||||
size_t segmentsPerPatch,
|
||||
std::shared_ptr<LayerManager> layerManager)
|
||||
: _owner(owner)
|
||||
, _leftRoot(std::make_unique<ChunkNode>(
|
||||
Chunk(owner, LEFT_HEMISPHERE_INDEX)))
|
||||
, _rightRoot(std::make_unique<ChunkNode>(
|
||||
Chunk(owner, RIGHT_HEMISPHERE_INDEX)))
|
||||
, minSplitDepth(2)
|
||||
, maxSplitDepth(22)
|
||||
, _layerManager(layerManager)
|
||||
, stats(StatsCollector(absPath("test_stats"), 1,
|
||||
StatsCollector::Enabled::No)) {
|
||||
auto geometry = std::make_shared<SkirtedGrid>(
|
||||
(unsigned int) segmentsPerPatch,
|
||||
(unsigned int) segmentsPerPatch,
|
||||
TriangleSoup::Positions::No,
|
||||
TriangleSoup::TextureCoordinates::Yes,
|
||||
TriangleSoup::Normals::No);
|
||||
ChunkedLodGlobe::ChunkedLodGlobe(const RenderableGlobe& owner, size_t segmentsPerPatch,
|
||||
std::shared_ptr<LayerManager> layerManager)
|
||||
: _owner(owner)
|
||||
, _leftRoot(std::make_unique<ChunkNode>(Chunk(owner, LEFT_HEMISPHERE_INDEX)))
|
||||
, _rightRoot(std::make_unique<ChunkNode>(Chunk(owner, RIGHT_HEMISPHERE_INDEX)))
|
||||
, minSplitDepth(2)
|
||||
, maxSplitDepth(22)
|
||||
, _layerManager(layerManager)
|
||||
, stats(StatsCollector(absPath("test_stats"), 1, StatsCollector::Enabled::No))
|
||||
{
|
||||
auto geometry = std::make_shared<SkirtedGrid>(
|
||||
static_cast<unsigned int>(segmentsPerPatch),
|
||||
static_cast<unsigned int>(segmentsPerPatch),
|
||||
TriangleSoup::Positions::No,
|
||||
TriangleSoup::TextureCoordinates::Yes,
|
||||
TriangleSoup::Normals::No
|
||||
);
|
||||
|
||||
_chunkCullers.push_back(std::make_unique<HorizonCuller>());
|
||||
_chunkCullers.push_back(std::make_unique<FrustumCuller>(
|
||||
AABB3(vec3(-1, -1, 0), vec3(1, 1, 1e35))));
|
||||
_chunkCullers.push_back(std::make_unique<HorizonCuller>());
|
||||
_chunkCullers.push_back(std::make_unique<FrustumCuller>(
|
||||
AABB3(glm::vec3(-1, -1, 0), glm::vec3(1, 1, 1e35)))
|
||||
);
|
||||
|
||||
_chunkEvaluatorByAvailableTiles =
|
||||
std::make_unique<EvaluateChunkLevelByAvailableTileData>();
|
||||
_chunkEvaluatorByProjectedArea =
|
||||
std::make_unique<EvaluateChunkLevelByProjectedArea>();
|
||||
_chunkEvaluatorByDistance =
|
||||
std::make_unique<EvaluateChunkLevelByDistance>();
|
||||
_chunkEvaluatorByAvailableTiles =
|
||||
std::make_unique<EvaluateChunkLevelByAvailableTileData>();
|
||||
_chunkEvaluatorByProjectedArea =
|
||||
std::make_unique<EvaluateChunkLevelByProjectedArea>();
|
||||
_chunkEvaluatorByDistance =
|
||||
std::make_unique<EvaluateChunkLevelByDistance>();
|
||||
|
||||
_renderer = std::make_unique<ChunkRenderer>(geometry, layerManager);
|
||||
}
|
||||
_renderer = std::make_unique<ChunkRenderer>(geometry, layerManager);
|
||||
}
|
||||
|
||||
ChunkedLodGlobe::~ChunkedLodGlobe() {
|
||||
bool ChunkedLodGlobe::initialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
bool ChunkedLodGlobe::deinitialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChunkedLodGlobe::initialize() {
|
||||
return isReady();
|
||||
}
|
||||
bool ChunkedLodGlobe::isReady() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChunkedLodGlobe::deinitialize() {
|
||||
std::shared_ptr<LayerManager> ChunkedLodGlobe::layerManager() const {
|
||||
return _layerManager;
|
||||
}
|
||||
|
||||
bool ChunkedLodGlobe::testIfCullable(const Chunk& chunk,
|
||||
const RenderData& renderData) const
|
||||
{
|
||||
if (_owner.debugProperties().performHorizonCulling &&
|
||||
_chunkCullers[0]->isCullable(chunk, renderData)) {
|
||||
return true;
|
||||
}
|
||||
if (_owner.debugProperties().performFrustumCulling &&
|
||||
_chunkCullers[1]->isCullable(chunk, renderData)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChunkedLodGlobe::isReady() const {
|
||||
bool ready = true;
|
||||
return ready;
|
||||
const ChunkNode& ChunkedLodGlobe::findChunkNode(const Geodetic2& p) const {
|
||||
ghoul_assert(COVERAGE.contains(p),
|
||||
"Point must be in lat [-90, 90] and lon [-180, 180]");
|
||||
|
||||
return p.lon < COVERAGE.center().lon ? _leftRoot->find(p) : _rightRoot->find(p);
|
||||
}
|
||||
|
||||
int ChunkedLodGlobe::getDesiredLevel(
|
||||
const Chunk& chunk, const RenderData& renderData) const {
|
||||
int desiredLevel = 0;
|
||||
if (_owner.debugProperties().levelByProjectedAreaElseDistance) {
|
||||
desiredLevel = _chunkEvaluatorByProjectedArea->getDesiredLevel(chunk, renderData);
|
||||
}
|
||||
else {
|
||||
desiredLevel = _chunkEvaluatorByDistance->getDesiredLevel(chunk, renderData);
|
||||
}
|
||||
|
||||
std::shared_ptr<LayerManager> ChunkedLodGlobe::layerManager() const {
|
||||
return _layerManager;
|
||||
int desiredLevelByAvailableData = _chunkEvaluatorByAvailableTiles->getDesiredLevel(
|
||||
chunk, renderData
|
||||
);
|
||||
if (desiredLevelByAvailableData != ChunkLevelEvaluator::UNKNOWN_DESIRED_LEVEL) {
|
||||
desiredLevel = glm::min(desiredLevel, desiredLevelByAvailableData);
|
||||
}
|
||||
|
||||
bool ChunkedLodGlobe::testIfCullable(
|
||||
const Chunk& chunk, const RenderData& renderData) const {
|
||||
if (_owner.debugProperties().performHorizonCulling &&
|
||||
_chunkCullers[0]->isCullable(chunk, renderData)) {
|
||||
return true;
|
||||
}
|
||||
if (_owner.debugProperties().performFrustumCulling &&
|
||||
_chunkCullers[1]->isCullable(chunk, renderData)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const ChunkNode& ChunkedLodGlobe::findChunkNode(const Geodetic2 p) const {
|
||||
ghoul_assert(COVERAGE.contains(p),
|
||||
"Point must be in lat [-90, 90] and lon [-180, 180]");
|
||||
return
|
||||
p.lon < COVERAGE.center().lon ?
|
||||
_leftRoot->find(p) :
|
||||
_rightRoot->find(p);
|
||||
}
|
||||
|
||||
int ChunkedLodGlobe::getDesiredLevel(
|
||||
const Chunk& chunk, const RenderData& renderData) const {
|
||||
int desiredLevel = 0;
|
||||
if (_owner.debugProperties().levelByProjectedAreaElseDistance) {
|
||||
desiredLevel = _chunkEvaluatorByProjectedArea->getDesiredLevel(
|
||||
chunk, renderData);
|
||||
}
|
||||
else {
|
||||
desiredLevel = _chunkEvaluatorByDistance->getDesiredLevel(
|
||||
chunk, renderData);
|
||||
}
|
||||
|
||||
int desiredLevelByAvailableData =
|
||||
_chunkEvaluatorByAvailableTiles->getDesiredLevel(chunk, renderData);
|
||||
if (desiredLevelByAvailableData !=
|
||||
ChunkLevelEvaluator::UNKNOWN_DESIRED_LEVEL) {
|
||||
desiredLevel = min(desiredLevel, desiredLevelByAvailableData);
|
||||
}
|
||||
|
||||
desiredLevel = glm::clamp(desiredLevel, minSplitDepth, maxSplitDepth);
|
||||
return desiredLevel;
|
||||
}
|
||||
desiredLevel = glm::clamp(desiredLevel, minSplitDepth, maxSplitDepth);
|
||||
return desiredLevel;
|
||||
}
|
||||
|
||||
float ChunkedLodGlobe::getHeight(glm::dvec3 position) const {
|
||||
float height = 0;
|
||||
float ChunkedLodGlobe::getHeight(glm::dvec3 position) const {
|
||||
float height = 0;
|
||||
|
||||
// Get the uv coordinates to sample from
|
||||
Geodetic2 geodeticPosition = _owner.ellipsoid().cartesianToGeodetic2(position);
|
||||
int chunkLevel = findChunkNode(geodeticPosition).getChunk().tileIndex().level;
|
||||
// Get the uv coordinates to sample from
|
||||
Geodetic2 geodeticPosition = _owner.ellipsoid().cartesianToGeodetic2(position);
|
||||
int chunkLevel = findChunkNode(geodeticPosition).getChunk().tileIndex().level;
|
||||
|
||||
TileIndex tileIndex = TileIndex(geodeticPosition, chunkLevel);
|
||||
GeodeticPatch patch = GeodeticPatch(tileIndex);
|
||||
TileIndex tileIndex = TileIndex(geodeticPosition, chunkLevel);
|
||||
GeodeticPatch patch = GeodeticPatch(tileIndex);
|
||||
|
||||
Geodetic2 geoDiffPatch =
|
||||
patch.getCorner(Quad::NORTH_EAST) -
|
||||
patch.getCorner(Quad::SOUTH_WEST);
|
||||
Geodetic2 geoDiffPoint = geodeticPosition - patch.getCorner(Quad::SOUTH_WEST);
|
||||
glm::vec2 patchUV = glm::vec2(
|
||||
geoDiffPoint.lon / geoDiffPatch.lon, geoDiffPoint.lat / geoDiffPatch.lat);
|
||||
Geodetic2 geoDiffPatch =
|
||||
patch.getCorner(Quad::NORTH_EAST) - patch.getCorner(Quad::SOUTH_WEST);
|
||||
|
||||
// Get the tile providers for the height maps
|
||||
const auto& heightMapLayers = _layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
|
||||
Geodetic2 geoDiffPoint = geodeticPosition - patch.getCorner(Quad::SOUTH_WEST);
|
||||
glm::vec2 patchUV = glm::vec2(
|
||||
geoDiffPoint.lon / geoDiffPatch.lon,
|
||||
geoDiffPoint.lat / geoDiffPatch.lat
|
||||
);
|
||||
|
||||
// Get the tile providers for the height maps
|
||||
const auto& heightMapLayers = _layerManager->layerGroup(LayerManager::HeightLayers).activeLayers();
|
||||
|
||||
for (const auto& layer : heightMapLayers) {
|
||||
TileProvider* tileProvider = layer->tileProvider();
|
||||
// Transform the uv coordinates to the current tile texture
|
||||
ChunkTile chunkTile = tileProvider->getChunkTile(tileIndex);
|
||||
const auto& tile = chunkTile.tile;
|
||||
const auto& uvTransform = chunkTile.uvTransform;
|
||||
const auto& depthTransform = tileProvider->depthTransform();
|
||||
if (tile.status != Tile::Status::OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
glm::vec2 transformedUv = Tile::TileUvToTextureSamplePosition(
|
||||
uvTransform,
|
||||
patchUV,
|
||||
glm::uvec2(tile.texture->dimensions()));
|
||||
|
||||
// Sample and do linear interpolation
|
||||
// (could possibly be moved as a function in ghoul texture)
|
||||
// Suggestion: a function in ghoul::opengl::Texture that takes uv coordinates
|
||||
// in range [0,1] and uses the set interpolation method and clamping.
|
||||
|
||||
glm::uvec3 dimensions = tile.texture->dimensions();
|
||||
|
||||
glm::vec2 samplePos = transformedUv * glm::vec2(dimensions);
|
||||
glm::uvec2 samplePos00 = samplePos;
|
||||
samplePos00 = glm::clamp(
|
||||
samplePos00, glm::uvec2(0, 0), glm::uvec2(dimensions) - glm::uvec2(1));
|
||||
glm::vec2 samplePosFract = samplePos - glm::vec2(samplePos00);
|
||||
|
||||
glm::uvec2 samplePos10 = glm::min(
|
||||
samplePos00 + glm::uvec2(1, 0), glm::uvec2(dimensions) - glm::uvec2(1));
|
||||
glm::uvec2 samplePos01 = glm::min(
|
||||
samplePos00 + glm::uvec2(0, 1), glm::uvec2(dimensions) - glm::uvec2(1));
|
||||
glm::uvec2 samplePos11 = glm::min(
|
||||
samplePos00 + glm::uvec2(1, 1), glm::uvec2(dimensions) - glm::uvec2(1));
|
||||
|
||||
float sample00 = tile.texture->texelAsFloat(samplePos00).x;
|
||||
float sample10 = tile.texture->texelAsFloat(samplePos10).x;
|
||||
float sample01 = tile.texture->texelAsFloat(samplePos01).x;
|
||||
float sample11 = tile.texture->texelAsFloat(samplePos11).x;
|
||||
|
||||
// In case the texture has NaN or no data values don't use this height map.
|
||||
bool anySampleIsNaN =
|
||||
isnan(sample00) ||
|
||||
isnan(sample01) ||
|
||||
isnan(sample10) ||
|
||||
isnan(sample11);
|
||||
|
||||
bool anySampleIsNoData =
|
||||
sample00 == tileProvider->noDataValueAsFloat() ||
|
||||
sample01 == tileProvider->noDataValueAsFloat() ||
|
||||
sample10 == tileProvider->noDataValueAsFloat() ||
|
||||
sample11 == tileProvider->noDataValueAsFloat();
|
||||
|
||||
if (anySampleIsNaN || anySampleIsNoData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float sample0 = sample00 * (1.0 - samplePosFract.x) + sample10 * samplePosFract.x;
|
||||
float sample1 = sample01 * (1.0 - samplePosFract.x) + sample11 * samplePosFract.x;
|
||||
|
||||
float sample = sample0 * (1.0 - samplePosFract.y) + sample1 * samplePosFract.y;
|
||||
|
||||
// Perform depth transform to get the value in meters
|
||||
height = depthTransform.depthOffset + depthTransform.depthScale * sample;
|
||||
for (const auto& layer : heightMapLayers) {
|
||||
TileProvider* tileProvider = layer->tileProvider();
|
||||
// Transform the uv coordinates to the current tile texture
|
||||
ChunkTile chunkTile = tileProvider->getChunkTile(tileIndex);
|
||||
const auto& tile = chunkTile.tile;
|
||||
const auto& uvTransform = chunkTile.uvTransform;
|
||||
const auto& depthTransform = tileProvider->depthTransform();
|
||||
if (tile.status != Tile::Status::OK) {
|
||||
return 0;
|
||||
}
|
||||
// Return the result
|
||||
return height;
|
||||
}
|
||||
|
||||
void ChunkedLodGlobe::render(const RenderData& data) {
|
||||
|
||||
stats.startNewRecord();
|
||||
|
||||
auto duration = std::chrono::system_clock::now().time_since_epoch();
|
||||
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
duration).count();
|
||||
stats.i["time"] = millis;
|
||||
glm::vec2 transformedUv = Tile::TileUvToTextureSamplePosition(
|
||||
uvTransform,
|
||||
patchUV,
|
||||
glm::uvec2(tile.texture->dimensions())
|
||||
);
|
||||
|
||||
_leftRoot->updateChunkTree(data);
|
||||
_rightRoot->updateChunkTree(data);
|
||||
// Sample and do linear interpolation
|
||||
// (could possibly be moved as a function in ghoul texture)
|
||||
// Suggestion: a function in ghoul::opengl::Texture that takes uv coordinates
|
||||
// in range [0,1] and uses the set interpolation method and clamping.
|
||||
|
||||
// Calculate the MVP matrix
|
||||
dmat4 viewTransform = dmat4(data.camera.combinedViewMatrix());
|
||||
dmat4 vp = dmat4(data.camera.projectionMatrix()) * viewTransform;
|
||||
dmat4 mvp = vp * _owner.modelTransform();
|
||||
|
||||
// Render function
|
||||
auto renderJob = [this, &data, &mvp](const ChunkNode& chunkNode) {
|
||||
stats.i["chunks nodes"]++;
|
||||
const Chunk& chunk = chunkNode.getChunk();
|
||||
if (chunkNode.isLeaf()){
|
||||
stats.i["leafs chunk nodes"]++;
|
||||
if (chunk.isVisible()) {
|
||||
stats.i["rendered chunks"]++;
|
||||
double t0 = Time::now().j2000Seconds();
|
||||
_renderer->renderChunk(chunkNode.getChunk(), data);
|
||||
debugRenderChunk(chunk, mvp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_leftRoot->breadthFirst(renderJob);
|
||||
_rightRoot->breadthFirst(renderJob);
|
||||
|
||||
//_leftRoot->reverseBreadthFirst(renderJob);
|
||||
//_rightRoot->reverseBreadthFirst(renderJob);
|
||||
|
||||
auto duration2 = std::chrono::system_clock::now().time_since_epoch();
|
||||
auto millis2 = std::chrono::duration_cast<std::chrono::milliseconds>(duration2).count();
|
||||
stats.i["chunk globe render time"] = millis2 - millis;
|
||||
}
|
||||
|
||||
void ChunkedLodGlobe::debugRenderChunk(
|
||||
const Chunk& chunk, const glm::dmat4& mvp) const {
|
||||
if (_owner.debugProperties().showChunkBounds ||
|
||||
_owner.debugProperties().showChunkAABB) {
|
||||
const std::vector<glm::dvec4> modelSpaceCorners =
|
||||
chunk.getBoundingPolyhedronCorners();
|
||||
std::vector<glm::vec4> clippingSpaceCorners(8);
|
||||
AABB3 screenSpaceBounds;
|
||||
glm::uvec3 dimensions = tile.texture->dimensions();
|
||||
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
const vec4& clippingSpaceCorner = mvp * modelSpaceCorners[i];
|
||||
clippingSpaceCorners[i] = clippingSpaceCorner;
|
||||
glm::vec2 samplePos = transformedUv * glm::vec2(dimensions);
|
||||
glm::uvec2 samplePos00 = samplePos;
|
||||
samplePos00 = glm::clamp(
|
||||
samplePos00,
|
||||
glm::uvec2(0, 0),
|
||||
glm::uvec2(dimensions) - glm::uvec2(1)
|
||||
);
|
||||
glm::vec2 samplePosFract = samplePos - glm::vec2(samplePos00);
|
||||
|
||||
vec3 screenSpaceCorner =
|
||||
(1.0f / clippingSpaceCorner.w) * clippingSpaceCorner;
|
||||
screenSpaceBounds.expand(screenSpaceCorner);
|
||||
}
|
||||
glm::uvec2 samplePos10 = glm::min(
|
||||
samplePos00 + glm::uvec2(1, 0),
|
||||
glm::uvec2(dimensions) - glm::uvec2(1)
|
||||
);
|
||||
glm::uvec2 samplePos01 = glm::min(
|
||||
samplePos00 + glm::uvec2(0, 1),
|
||||
glm::uvec2(dimensions) - glm::uvec2(1)
|
||||
);
|
||||
glm::uvec2 samplePos11 = glm::min(
|
||||
samplePos00 + glm::uvec2(1, 1),
|
||||
glm::uvec2(dimensions) - glm::uvec2(1)
|
||||
);
|
||||
|
||||
unsigned int colorBits = 1 + chunk.tileIndex().level % 6;
|
||||
vec4 color = vec4(colorBits & 1, colorBits & 2, colorBits & 4, 0.3);
|
||||
float sample00 = tile.texture->texelAsFloat(samplePos00).x;
|
||||
float sample10 = tile.texture->texelAsFloat(samplePos10).x;
|
||||
float sample01 = tile.texture->texelAsFloat(samplePos01).x;
|
||||
float sample11 = tile.texture->texelAsFloat(samplePos11).x;
|
||||
|
||||
if (_owner.debugProperties().showChunkBounds) {
|
||||
DebugRenderer::ref().renderNiceBox(clippingSpaceCorners, color);
|
||||
}
|
||||
// In case the texture has NaN or no data values don't use this height map.
|
||||
bool anySampleIsNaN =
|
||||
isnan(sample00) ||
|
||||
isnan(sample01) ||
|
||||
isnan(sample10) ||
|
||||
isnan(sample11);
|
||||
|
||||
if (_owner.debugProperties().showChunkAABB) {
|
||||
auto& screenSpacePoints =
|
||||
DebugRenderer::ref().verticesFor(screenSpaceBounds);
|
||||
DebugRenderer::ref().renderNiceBox(screenSpacePoints, color);
|
||||
bool anySampleIsNoData =
|
||||
sample00 == tileProvider->noDataValueAsFloat() ||
|
||||
sample01 == tileProvider->noDataValueAsFloat() ||
|
||||
sample10 == tileProvider->noDataValueAsFloat() ||
|
||||
sample11 == tileProvider->noDataValueAsFloat();
|
||||
|
||||
if (anySampleIsNaN || anySampleIsNoData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float sample0 = sample00 * (1.0 - samplePosFract.x) + sample10 * samplePosFract.x;
|
||||
float sample1 = sample01 * (1.0 - samplePosFract.x) + sample11 * samplePosFract.x;
|
||||
|
||||
float sample = sample0 * (1.0 - samplePosFract.y) + sample1 * samplePosFract.y;
|
||||
|
||||
// Perform depth transform to get the value in meters
|
||||
height = depthTransform.depthOffset + depthTransform.depthScale * sample;
|
||||
}
|
||||
// Return the result
|
||||
return height;
|
||||
}
|
||||
|
||||
void ChunkedLodGlobe::render(const RenderData& data) {
|
||||
stats.startNewRecord();
|
||||
|
||||
auto duration = std::chrono::system_clock::now().time_since_epoch();
|
||||
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
|
||||
stats.i["time"] = millis;
|
||||
|
||||
_leftRoot->updateChunkTree(data);
|
||||
_rightRoot->updateChunkTree(data);
|
||||
|
||||
// Calculate the MVP matrix
|
||||
glm::dmat4 viewTransform = glm::dmat4(data.camera.combinedViewMatrix());
|
||||
glm::dmat4 vp = glm::dmat4(data.camera.projectionMatrix()) * viewTransform;
|
||||
glm::dmat4 mvp = vp * _owner.modelTransform();
|
||||
|
||||
// Render function
|
||||
auto renderJob = [this, &data, &mvp](const ChunkNode& chunkNode) {
|
||||
stats.i["chunks nodes"]++;
|
||||
const Chunk& chunk = chunkNode.getChunk();
|
||||
if (chunkNode.isLeaf()) {
|
||||
stats.i["leafs chunk nodes"]++;
|
||||
if (chunk.isVisible()) {
|
||||
stats.i["rendered chunks"]++;
|
||||
double t0 = Time::now().j2000Seconds();
|
||||
_renderer->renderChunk(chunkNode.getChunk(), data);
|
||||
debugRenderChunk(chunk, mvp);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void ChunkedLodGlobe::update(const UpdateData& data) {
|
||||
_renderer->update();
|
||||
_leftRoot->breadthFirst(renderJob);
|
||||
_rightRoot->breadthFirst(renderJob);
|
||||
|
||||
//_leftRoot->reverseBreadthFirst(renderJob);
|
||||
//_rightRoot->reverseBreadthFirst(renderJob);
|
||||
|
||||
auto duration2 = std::chrono::system_clock::now().time_since_epoch();
|
||||
auto millis2 = std::chrono::duration_cast<std::chrono::milliseconds>(duration2).count();
|
||||
stats.i["chunk globe render time"] = millis2 - millis;
|
||||
}
|
||||
|
||||
void ChunkedLodGlobe::debugRenderChunk(const Chunk& chunk, const glm::dmat4& mvp) const {
|
||||
if (_owner.debugProperties().showChunkBounds ||
|
||||
_owner.debugProperties().showChunkAABB)
|
||||
{
|
||||
const std::vector<glm::dvec4> modelSpaceCorners =
|
||||
chunk.getBoundingPolyhedronCorners();
|
||||
std::vector<glm::vec4> clippingSpaceCorners(8);
|
||||
AABB3 screenSpaceBounds;
|
||||
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
const glm::vec4& clippingSpaceCorner = mvp * modelSpaceCorners[i];
|
||||
clippingSpaceCorners[i] = clippingSpaceCorner;
|
||||
|
||||
glm::vec3 screenSpaceCorner =
|
||||
(1.0f / clippingSpaceCorner.w) * clippingSpaceCorner;
|
||||
screenSpaceBounds.expand(screenSpaceCorner);
|
||||
}
|
||||
|
||||
unsigned int colorBits = 1 + chunk.tileIndex().level % 6;
|
||||
glm::vec4 color = glm::vec4(colorBits & 1, colorBits & 2, colorBits & 4, 0.3);
|
||||
|
||||
if (_owner.debugProperties().showChunkBounds) {
|
||||
DebugRenderer::ref().renderNiceBox(clippingSpaceCorners, color);
|
||||
}
|
||||
|
||||
if (_owner.debugProperties().showChunkAABB) {
|
||||
auto& screenSpacePoints =
|
||||
DebugRenderer::ref().verticesFor(screenSpaceBounds);
|
||||
DebugRenderer::ref().renderNiceBox(screenSpacePoints, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkedLodGlobe::update(const UpdateData& data) {
|
||||
_renderer->update();
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,34 +1,33 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __CHUNKED_LOD_GLOBE__
|
||||
#define __CHUNKED_LOD_GLOBE__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKED_LOD_GLOBE_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKED_LOD_GLOBE_H__
|
||||
|
||||
#include <openspace/rendering/renderable.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/ellipsoid.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/other/statscollector.h>
|
||||
|
||||
#include <memory>
|
||||
@@ -36,107 +35,105 @@
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
class Chunk;
|
||||
class ChunkCuller;
|
||||
class ChunkLevelEvaluator;
|
||||
class ChunkNode;
|
||||
class ChunkRenderer;
|
||||
class LayerManager;
|
||||
class RenderableGlobe;
|
||||
class Chunk;
|
||||
class ChunkCuller;
|
||||
class ChunkLevelEvaluator;
|
||||
class ChunkNode;
|
||||
class ChunkRenderer;
|
||||
class Geodetic2;
|
||||
class LayerManager;
|
||||
class RenderableGlobe;
|
||||
|
||||
class ChunkedLodGlobe : public Renderable {
|
||||
public:
|
||||
ChunkedLodGlobe(
|
||||
const RenderableGlobe& owner,
|
||||
size_t segmentsPerPatch,
|
||||
std::shared_ptr<LayerManager> layerManager);
|
||||
virtual ~ChunkedLodGlobe();
|
||||
class ChunkedLodGlobe : public Renderable {
|
||||
public:
|
||||
ChunkedLodGlobe(const RenderableGlobe& owner, size_t segmentsPerPatch,
|
||||
std::shared_ptr<LayerManager> layerManager);
|
||||
|
||||
bool initialize() override;
|
||||
bool deinitialize() override;
|
||||
bool isReady() const override;
|
||||
bool initialize() override;
|
||||
bool deinitialize() override;
|
||||
bool isReady() const override;
|
||||
|
||||
void render(const RenderData& data) override;
|
||||
void update(const UpdateData& data) override;
|
||||
void render(const RenderData& data) override;
|
||||
void update(const UpdateData& data) override;
|
||||
|
||||
/**
|
||||
* Traverse the chunk tree and find the highest level chunk node.
|
||||
*
|
||||
* \param location is given in geodetic coordinates and must be in the range
|
||||
* latitude [-90. 90] and longitude [-180, 180]. In other words, it must be a
|
||||
* position defined on the globe in georeferenced coordinates.
|
||||
*/
|
||||
const ChunkNode& findChunkNode(const Geodetic2 location) const;
|
||||
/**
|
||||
* Traverse the chunk tree and find the highest level chunk node.
|
||||
*
|
||||
* \param location is given in geodetic coordinates and must be in the range
|
||||
* latitude [-90. 90] and longitude [-180, 180]. In other words, it must be a
|
||||
* position defined on the globe in georeferenced coordinates.
|
||||
*/
|
||||
const ChunkNode& findChunkNode(const Geodetic2& location) const;
|
||||
|
||||
/**
|
||||
* Test if a specific chunk can saefely be culled without affecting the rendered
|
||||
* image.
|
||||
*
|
||||
* Goes through all available <code>ChunkCuller</code>s and check if any of them
|
||||
* allows culling of the <code>Chunk</code>s in question.
|
||||
*/
|
||||
bool testIfCullable(const Chunk& chunk, const RenderData& renderData) const;
|
||||
/**
|
||||
* Test if a specific chunk can saefely be culled without affecting the rendered
|
||||
* image.
|
||||
*
|
||||
* Goes through all available <code>ChunkCuller</code>s and check if any of them
|
||||
* allows culling of the <code>Chunk</code>s in question.
|
||||
*/
|
||||
bool testIfCullable(const Chunk& chunk, const RenderData& renderData) const;
|
||||
|
||||
/**
|
||||
* Gets the desired level which can be used to determine if a chunk should split
|
||||
* or merge.
|
||||
*
|
||||
* Using <code>ChunkLevelEvaluator</code>s, the desired level can be higher or
|
||||
* lower than the current level of the <code>Chunks</code>s
|
||||
* <code>TileIndex</code>. If the desired level is higher than that of the
|
||||
* <code>Chunk</code>, it wants to split. If it is lower, it wants to merge with
|
||||
* its siblings.
|
||||
*/
|
||||
int getDesiredLevel(const Chunk& chunk, const RenderData& renderData) const;
|
||||
/**
|
||||
* Gets the desired level which can be used to determine if a chunk should split
|
||||
* or merge.
|
||||
*
|
||||
* Using <code>ChunkLevelEvaluator</code>s, the desired level can be higher or
|
||||
* lower than the current level of the <code>Chunks</code>s
|
||||
* <code>TileIndex</code>. If the desired level is higher than that of the
|
||||
* <code>Chunk</code>, it wants to split. If it is lower, it wants to merge with
|
||||
* its siblings.
|
||||
*/
|
||||
int getDesiredLevel(const Chunk& chunk, const RenderData& renderData) const;
|
||||
|
||||
/**
|
||||
* Calculates the height from the surface of the reference ellipsoid to the
|
||||
* heigh mapped surface.
|
||||
*
|
||||
* The height can be negative if the height map contains negative values.
|
||||
*
|
||||
* \param <code>position</code> is the position of a point that gets geodetically
|
||||
* projected on the reference ellipsoid. <code>position</code> must be in
|
||||
* cartesian model space.
|
||||
* \returns the height from the reference ellipsoid to the globe surface.
|
||||
*/
|
||||
float getHeight(glm::dvec3 position) const;
|
||||
/**
|
||||
* Calculates the height from the surface of the reference ellipsoid to the
|
||||
* heigh mapped surface.
|
||||
*
|
||||
* The height can be negative if the height map contains negative values.
|
||||
*
|
||||
* \param <code>position</code> is the position of a point that gets geodetically
|
||||
* projected on the reference ellipsoid. <code>position</code> must be in
|
||||
* cartesian model space.
|
||||
* \returns the height from the reference ellipsoid to the globe surface.
|
||||
*/
|
||||
float getHeight(glm::dvec3 position) const;
|
||||
|
||||
const int minSplitDepth;
|
||||
const int maxSplitDepth;
|
||||
const int minSplitDepth;
|
||||
const int maxSplitDepth;
|
||||
|
||||
std::shared_ptr<LayerManager> layerManager() const;
|
||||
std::shared_ptr<LayerManager> layerManager() const;
|
||||
|
||||
StatsCollector stats;
|
||||
StatsCollector stats;
|
||||
|
||||
private:
|
||||
void debugRenderChunk(const Chunk& chunk, const glm::dmat4& data) const;
|
||||
private:
|
||||
void debugRenderChunk(const Chunk& chunk, const glm::dmat4& data) const;
|
||||
|
||||
static const GeodeticPatch COVERAGE;
|
||||
static const TileIndex LEFT_HEMISPHERE_INDEX;
|
||||
static const TileIndex RIGHT_HEMISPHERE_INDEX;
|
||||
static const GeodeticPatch COVERAGE;
|
||||
static const TileIndex LEFT_HEMISPHERE_INDEX;
|
||||
static const TileIndex RIGHT_HEMISPHERE_INDEX;
|
||||
|
||||
// Covers all negative longitudes
|
||||
std::unique_ptr<ChunkNode> _leftRoot;
|
||||
// Covers all negative longitudes
|
||||
std::unique_ptr<ChunkNode> _leftRoot;
|
||||
|
||||
// Covers all positive longitudes
|
||||
std::unique_ptr<ChunkNode> _rightRoot;
|
||||
// Covers all positive longitudes
|
||||
std::unique_ptr<ChunkNode> _rightRoot;
|
||||
|
||||
// the patch used for actual rendering
|
||||
std::unique_ptr<ChunkRenderer> _renderer;
|
||||
// the patch used for actual rendering
|
||||
std::unique_ptr<ChunkRenderer> _renderer;
|
||||
|
||||
std::vector<std::unique_ptr<ChunkCuller>> _chunkCullers;
|
||||
std::vector<std::unique_ptr<ChunkCuller>> _chunkCullers;
|
||||
|
||||
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByAvailableTiles;
|
||||
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByProjectedArea;
|
||||
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByDistance;
|
||||
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByAvailableTiles;
|
||||
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByProjectedArea;
|
||||
std::unique_ptr<ChunkLevelEvaluator> _chunkEvaluatorByDistance;
|
||||
|
||||
std::shared_ptr<LayerManager> _layerManager;
|
||||
std::shared_ptr<LayerManager> _layerManager;
|
||||
|
||||
const RenderableGlobe& _owner;
|
||||
};
|
||||
const RenderableGlobe& _owner;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __CHUNKED_LOD_GLOBE__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKED_LOD_GLOBE_H__
|
||||
|
||||
@@ -1,147 +1,123 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/globes/pointglobe.h>
|
||||
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
|
||||
// open space includes
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/util/spicemanager.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
|
||||
// ghoul includes
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "PointGlobe";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
PointGlobe::PointGlobe(const RenderableGlobe& owner)
|
||||
: _owner(owner) {
|
||||
PointGlobe::PointGlobe(const RenderableGlobe& owner)
|
||||
: _owner(owner)
|
||||
{}
|
||||
|
||||
}
|
||||
PointGlobe::~PointGlobe() {
|
||||
glDeleteBuffers(1, &_vertexBufferID);
|
||||
glDeleteVertexArrays(1, &_vaoID);
|
||||
}
|
||||
|
||||
PointGlobe::~PointGlobe() {
|
||||
glDeleteBuffers(1, &_vertexBufferID);
|
||||
glDeleteVertexArrays(1, &_vaoID);
|
||||
}
|
||||
bool PointGlobe::initialize() {
|
||||
_programObject = OsEng.renderEngine().buildRenderProgram(
|
||||
"PointGlobe",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/pointglobe_vs.glsl",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/pointglobe_fs.glsl");
|
||||
|
||||
bool PointGlobe::initialize() {
|
||||
_programObject = OsEng.renderEngine().buildRenderProgram(
|
||||
"PointGlobe",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/pointglobe_vs.glsl",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/pointglobe_fs.glsl");
|
||||
glGenVertexArrays(1, &_vaoID);
|
||||
glGenBuffers(1, &_vertexBufferID);
|
||||
|
||||
// Create VAO
|
||||
glGenVertexArrays(1, &_vaoID);
|
||||
glBindVertexArray(_vaoID);
|
||||
|
||||
// Create VBOs
|
||||
glGenBuffers(1, &_vertexBufferID);
|
||||
if (_vertexBufferID == 0) {
|
||||
LERROR("Could not create vertex buffer");
|
||||
return false;
|
||||
}
|
||||
// Vertex data is only one point in the origin
|
||||
glm::vec3 data = glm::vec3(0,0,0);
|
||||
|
||||
// First VAO setup
|
||||
glBindVertexArray(_vaoID);
|
||||
// Vertex buffer
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID);
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
sizeof(glm::vec3),
|
||||
&data,
|
||||
GL_STATIC_DRAW
|
||||
);
|
||||
|
||||
// Vertex data is only one point in the origin
|
||||
glm::vec3 data = glm::vec3(0,0,0);
|
||||
// Position at location 0
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), 0);
|
||||
|
||||
// Vertex buffer
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID);
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
sizeof(glm::vec3),
|
||||
&data,
|
||||
GL_STATIC_DRAW);
|
||||
glBindVertexArray(0);
|
||||
|
||||
// Position at location 0
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), 0);
|
||||
return isReady();
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
bool PointGlobe::deinitialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isReady();
|
||||
}
|
||||
|
||||
bool PointGlobe::deinitialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PointGlobe::isReady() const {
|
||||
bool ready = true;
|
||||
return ready;
|
||||
}
|
||||
bool PointGlobe::isReady() const {
|
||||
return (_vaoID != 0) && (_vertexBufferID != 0);
|
||||
}
|
||||
|
||||
void PointGlobe::render(const RenderData& data) {
|
||||
_programObject->activate();
|
||||
void PointGlobe::render(const RenderData& data) {
|
||||
_programObject->activate();
|
||||
|
||||
// Calculate variables to be used as uniform variables in shader
|
||||
glm::dvec3 bodyPosition = data.modelTransform.translation;
|
||||
// Calculate variables to be used as uniform variables in shader
|
||||
glm::dvec3 bodyPosition = data.modelTransform.translation;
|
||||
|
||||
// Model transform and view transform needs to be in double precision
|
||||
glm::dmat4 modelTransform =
|
||||
glm::translate(glm::dmat4(1.0), bodyPosition) * // Translation
|
||||
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); // Scale
|
||||
glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform;
|
||||
glm::vec3 directionToSun = glm::normalize(glm::vec3(0) - glm::vec3(bodyPosition));
|
||||
glm::vec3 directionToSunViewSpace = glm::mat3(data.camera.combinedViewMatrix()) * directionToSun;
|
||||
// Model transform and view transform needs to be in double precision
|
||||
glm::dmat4 modelTransform =
|
||||
glm::translate(glm::dmat4(1.0), bodyPosition) * // Translation
|
||||
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); // Scale
|
||||
glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform;
|
||||
glm::vec3 directionToSun = glm::normalize(glm::vec3(0) - glm::vec3(bodyPosition));
|
||||
glm::vec3 directionToSunViewSpace = glm::mat3(data.camera.combinedViewMatrix()) * directionToSun;
|
||||
|
||||
int windowWidth = OsEng.windowWrapper().currentWindowSize().x;
|
||||
float avgRadius = _owner.ellipsoid().averageRadius();
|
||||
int windowWidth = OsEng.windowWrapper().currentWindowSize().x;
|
||||
float avgRadius = _owner.ellipsoid().averageRadius();
|
||||
|
||||
_programObject->setUniform("windowWidth", windowWidth);
|
||||
_programObject->setUniform("globeRadius", avgRadius);
|
||||
_programObject->setUniform("directionToSunViewSpace", directionToSunViewSpace);
|
||||
_programObject->setUniform("modelViewTransform", glm::mat4(modelViewTransform));
|
||||
_programObject->setUniform("projectionTransform", data.camera.projectionMatrix());
|
||||
_programObject->setUniform("windowWidth", windowWidth);
|
||||
_programObject->setUniform("globeRadius", avgRadius);
|
||||
_programObject->setUniform("directionToSunViewSpace", directionToSunViewSpace);
|
||||
_programObject->setUniform("modelViewTransform", glm::mat4(modelViewTransform));
|
||||
_programObject->setUniform("projectionTransform", data.camera.projectionMatrix());
|
||||
|
||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
|
||||
glBindVertexArray(_vaoID);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vertexBufferID);
|
||||
glDrawArrays(GL_POINTS, 0, 1);
|
||||
glBindVertexArray(0);
|
||||
glBindVertexArray(_vaoID);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vertexBufferID);
|
||||
glDrawArrays(GL_POINTS, 0, 1);
|
||||
glBindVertexArray(0);
|
||||
|
||||
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
|
||||
_programObject->deactivate();
|
||||
}
|
||||
_programObject->deactivate();
|
||||
}
|
||||
|
||||
void PointGlobe::update(const UpdateData& data) {
|
||||
|
||||
}
|
||||
void PointGlobe::update(const UpdateData& data) {}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,68 +1,62 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __POINT_GLOBE__
|
||||
#define __POINT_GLOBE__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_POINTGLOBE_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_POINTGLOBE_H__
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
|
||||
// open space includes
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/ellipsoid.h>
|
||||
namespace ghoul { namespace opengl {
|
||||
class ProgramObject;
|
||||
}}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace ghoul::opengl;
|
||||
class RenderableGlobe;
|
||||
class RenderableGlobe;
|
||||
|
||||
class PointGlobe : public Renderable {
|
||||
public:
|
||||
PointGlobe(const RenderableGlobe& owner);
|
||||
virtual ~PointGlobe();
|
||||
class PointGlobe : public Renderable {
|
||||
public:
|
||||
PointGlobe(const RenderableGlobe& owner);
|
||||
virtual ~PointGlobe();
|
||||
|
||||
bool initialize() override;
|
||||
bool deinitialize() override;
|
||||
bool isReady() const override;
|
||||
bool initialize() override;
|
||||
bool deinitialize() override;
|
||||
bool isReady() const override;
|
||||
|
||||
void render(const RenderData& data) override;
|
||||
void update(const UpdateData& data) override;
|
||||
void render(const RenderData& data) override;
|
||||
void update(const UpdateData& data) override;
|
||||
|
||||
private:
|
||||
const RenderableGlobe& _owner;
|
||||
std::unique_ptr<ProgramObject> _programObject;
|
||||
private:
|
||||
const RenderableGlobe& _owner;
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _programObject;
|
||||
|
||||
GLuint _vertexBufferID;
|
||||
GLuint _vaoID;
|
||||
};
|
||||
GLuint _vertexBufferID;
|
||||
GLuint _vaoID;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __POINT_GLOBE__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_POINTGLOBE_H__
|
||||
|
||||
@@ -1,272 +1,250 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
// globe browsing
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileselector.h>
|
||||
|
||||
#include <modules/globebrowsing/globes/pointglobe.h>
|
||||
|
||||
|
||||
#include <modules/debugging/rendering/debugrenderer.h>
|
||||
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
|
||||
#include <modules/globebrowsing/rendering/layermanager.h>
|
||||
|
||||
// open space includes
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/util/spicemanager.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
|
||||
#include <modules/debugging/rendering/debugrenderer.h>
|
||||
|
||||
// ghoul includes
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <ghoul/misc/threadpool.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "RenderableGlobe";
|
||||
|
||||
// Keys for the dictionary
|
||||
const std::string keyFrame = "Frame";
|
||||
const std::string keyRadii = "Radii";
|
||||
const std::string keyInteractionDepthBelowEllipsoid =
|
||||
"InteractionDepthBelowEllipsoid";
|
||||
const std::string keyCameraMinHeight = "CameraMinHeight";
|
||||
const std::string keySegmentsPerPatch = "SegmentsPerPatch";
|
||||
const std::string keyLayers = "Layers";
|
||||
const char* keyFrame = "Frame";
|
||||
const char* keyRadii = "Radii";
|
||||
const char* keyInteractionDepthBelowEllipsoid = "InteractionDepthBelowEllipsoid";
|
||||
const char* keyCameraMinHeight = "CameraMinHeight";
|
||||
const char* keySegmentsPerPatch = "SegmentsPerPatch";
|
||||
const char* keyLayers = "Layers";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
|
||||
using namespace properties;
|
||||
|
||||
namespace globebrowsing {
|
||||
|
||||
RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
: _generalProperties({
|
||||
properties::BoolProperty("enabled", "Enabled", true),
|
||||
properties::BoolProperty("performShading", "perform shading", true),
|
||||
properties::BoolProperty("atmosphere", "atmosphere", false),
|
||||
properties::FloatProperty("lodScaleFactor", "lodScaleFactor",10.0f, 1.0f, 50.0f),
|
||||
properties::FloatProperty("cameraMinHeight", "cameraMinHeight", 100.0f, 0.0f, 1000.0f)
|
||||
BoolProperty("enabled", "Enabled", true),
|
||||
BoolProperty("performShading", "perform shading", true),
|
||||
BoolProperty("atmosphere", "atmosphere", false),
|
||||
FloatProperty("lodScaleFactor", "lodScaleFactor",10.0f, 1.0f, 50.0f),
|
||||
FloatProperty("cameraMinHeight", "cameraMinHeight", 100.0f, 0.0f, 1000.0f)
|
||||
})
|
||||
, _debugProperties({
|
||||
properties::BoolProperty("saveOrThrowCamera", "save or throw camera", false),
|
||||
properties::BoolProperty("showChunkEdges", "show chunk edges", false),
|
||||
properties::BoolProperty("showChunkBounds", "show chunk bounds", false),
|
||||
properties::BoolProperty("showChunkAABB", "show chunk AABB", false),
|
||||
properties::BoolProperty("showHeightResolution", "show height resolution", false),
|
||||
properties::BoolProperty("showHeightIntensities", "show height intensities", false),
|
||||
properties::BoolProperty("performFrustumCulling", "perform frustum culling", true),
|
||||
properties::BoolProperty("performHorizonCulling", "perform horizon culling", true),
|
||||
properties::BoolProperty("levelByProjectedAreaElseDistance", "level by projected area (else distance)",false),
|
||||
properties::BoolProperty("resetTileProviders", "reset tile providers", false),
|
||||
properties::BoolProperty("toggleEnabledEveryFrame", "toggle enabled every frame", false),
|
||||
properties::BoolProperty("collectStats", "collect stats", false),
|
||||
properties::BoolProperty("onlyModelSpaceRendering", "Only Model Space Rendering", false)
|
||||
})
|
||||
|
||||
{
|
||||
setName("RenderableGlobe");
|
||||
BoolProperty("saveOrThrowCamera", "save or throw camera", false),
|
||||
BoolProperty("showChunkEdges", "show chunk edges", false),
|
||||
BoolProperty("showChunkBounds", "show chunk bounds", false),
|
||||
BoolProperty("showChunkAABB", "show chunk AABB", false),
|
||||
BoolProperty("showHeightResolution", "show height resolution", false),
|
||||
BoolProperty("showHeightIntensities", "show height intensities", false),
|
||||
BoolProperty("performFrustumCulling", "perform frustum culling", true),
|
||||
BoolProperty("performHorizonCulling", "perform horizon culling", true),
|
||||
BoolProperty("levelByProjectedAreaElseDistance", "level by projected area (else distance)",false),
|
||||
BoolProperty("resetTileProviders", "reset tile providers", false),
|
||||
BoolProperty("toggleEnabledEveryFrame", "toggle enabled every frame", false),
|
||||
BoolProperty("collectStats", "collect stats", false),
|
||||
BoolProperty("onlyModelSpaceRendering", "Only Model Space Rendering", false)
|
||||
})
|
||||
{
|
||||
setName("RenderableGlobe");
|
||||
|
||||
dictionary.getValue(keyFrame, _frame);
|
||||
dictionary.getValue(keyFrame, _frame);
|
||||
|
||||
// Read the radii in to its own dictionary
|
||||
Vec3 radii;
|
||||
dictionary.getValue(keyRadii, radii);
|
||||
_ellipsoid = Ellipsoid(radii);
|
||||
setBoundingSphere(pss(_ellipsoid.averageRadius(), 0.0));
|
||||
// Read the radii in to its own dictionary
|
||||
glm::dvec3 radii;
|
||||
dictionary.getValue(keyRadii, radii);
|
||||
_ellipsoid = Ellipsoid(radii);
|
||||
setBoundingSphere(pss(_ellipsoid.averageRadius(), 0.0));
|
||||
|
||||
// Ghoul can't read ints from lua dictionaries...
|
||||
double patchSegmentsd;
|
||||
dictionary.getValue(keySegmentsPerPatch, patchSegmentsd);
|
||||
int patchSegments = patchSegmentsd;
|
||||
// Ghoul can't read ints from lua dictionaries...
|
||||
double patchSegmentsd;
|
||||
dictionary.getValue(keySegmentsPerPatch, patchSegmentsd);
|
||||
int patchSegments = patchSegmentsd;
|
||||
|
||||
dictionary.getValue(keyInteractionDepthBelowEllipsoid,
|
||||
_interactionDepthBelowEllipsoid);
|
||||
float cameraMinHeight;
|
||||
dictionary.getValue(keyCameraMinHeight, cameraMinHeight);
|
||||
_generalProperties.cameraMinHeight.set(cameraMinHeight);
|
||||
dictionary.getValue(keyInteractionDepthBelowEllipsoid,
|
||||
_interactionDepthBelowEllipsoid);
|
||||
float cameraMinHeight;
|
||||
dictionary.getValue(keyCameraMinHeight, cameraMinHeight);
|
||||
_generalProperties.cameraMinHeight.set(cameraMinHeight);
|
||||
|
||||
// Init layer manager
|
||||
ghoul::Dictionary layersDictionary;
|
||||
if(!dictionary.getValue(keyLayers, layersDictionary))
|
||||
throw ghoul::RuntimeError(keyLayers + " must be specified specified!");
|
||||
// Init layer manager
|
||||
ghoul::Dictionary layersDictionary;
|
||||
if (!dictionary.getValue(keyLayers, layersDictionary))
|
||||
throw ghoul::RuntimeError(std::string(keyLayers) + " must be specified specified!");
|
||||
|
||||
_layerManager = std::make_shared<LayerManager>(layersDictionary);
|
||||
_layerManager = std::make_shared<LayerManager>(layersDictionary);
|
||||
|
||||
_chunkedLodGlobe = std::make_shared<ChunkedLodGlobe>(
|
||||
*this, patchSegments, _layerManager);
|
||||
_chunkedLodGlobe = std::make_shared<ChunkedLodGlobe>(
|
||||
*this, patchSegments, _layerManager);
|
||||
|
||||
// This distance will be enough to render the globe as one pixel if the field of
|
||||
// view is 'fov' radians and the screen resolution is 'res' pixels.
|
||||
double fov = 2 * M_PI / 6; // 60 degrees
|
||||
int res = 2880;
|
||||
double distance = res * _ellipsoid.maximumRadius() / tan(fov / 2);
|
||||
_distanceSwitch.addSwitchValue(_chunkedLodGlobe, distance);
|
||||
// This distance will be enough to render the globe as one pixel if the field of
|
||||
// view is 'fov' radians and the screen resolution is 'res' pixels.
|
||||
double fov = 2 * glm::pi<double>() / 6; // 60 degrees
|
||||
int res = 2880;
|
||||
double distance = res * _ellipsoid.maximumRadius() / tan(fov / 2);
|
||||
_distanceSwitch.addSwitchValue(_chunkedLodGlobe, distance);
|
||||
|
||||
_debugPropertyOwner.setName("Debug");
|
||||
_texturePropertyOwner.setName("Textures");
|
||||
_debugPropertyOwner.setName("Debug");
|
||||
_texturePropertyOwner.setName("Textures");
|
||||
|
||||
addProperty(_generalProperties.isEnabled);
|
||||
addProperty(_generalProperties.atmosphereEnabled);
|
||||
addProperty(_generalProperties.performShading);
|
||||
addProperty(_generalProperties.lodScaleFactor);
|
||||
addProperty(_generalProperties.cameraMinHeight);
|
||||
addProperty(_generalProperties.isEnabled);
|
||||
addProperty(_generalProperties.atmosphereEnabled);
|
||||
addProperty(_generalProperties.performShading);
|
||||
addProperty(_generalProperties.lodScaleFactor);
|
||||
addProperty(_generalProperties.cameraMinHeight);
|
||||
|
||||
_debugPropertyOwner.addProperty(_debugProperties.saveOrThrowCamera);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.showChunkEdges);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.showChunkBounds);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.showChunkAABB);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.showHeightResolution);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.showHeightIntensities);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.performFrustumCulling);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.performHorizonCulling);
|
||||
_debugPropertyOwner.addProperty(
|
||||
_debugProperties.levelByProjectedAreaElseDistance);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.resetTileProviders);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.toggleEnabledEveryFrame);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.collectStats);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.onlyModelSpaceRendering);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.saveOrThrowCamera);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.showChunkEdges);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.showChunkBounds);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.showChunkAABB);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.showHeightResolution);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.showHeightIntensities);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.performFrustumCulling);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.performHorizonCulling);
|
||||
_debugPropertyOwner.addProperty(
|
||||
_debugProperties.levelByProjectedAreaElseDistance
|
||||
);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.resetTileProviders);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.toggleEnabledEveryFrame);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.collectStats);
|
||||
_debugPropertyOwner.addProperty(_debugProperties.onlyModelSpaceRendering);
|
||||
|
||||
addPropertySubOwner(_debugPropertyOwner);
|
||||
addPropertySubOwner(_layerManager.get());
|
||||
addPropertySubOwner(_debugPropertyOwner);
|
||||
addPropertySubOwner(_layerManager.get());
|
||||
}
|
||||
|
||||
bool RenderableGlobe::initialize() {
|
||||
return _distanceSwitch.initialize();
|
||||
}
|
||||
|
||||
bool RenderableGlobe::deinitialize() {
|
||||
return _distanceSwitch.deinitialize();
|
||||
}
|
||||
|
||||
bool RenderableGlobe::isReady() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderableGlobe::render(const RenderData& data) {
|
||||
bool statsEnabled = _debugProperties.collectStats.value();
|
||||
_chunkedLodGlobe->stats.setEnabled(statsEnabled);
|
||||
|
||||
if (_debugProperties.toggleEnabledEveryFrame.value()) {
|
||||
_generalProperties.isEnabled.setValue(
|
||||
!_generalProperties.isEnabled.value()
|
||||
);
|
||||
}
|
||||
if (_generalProperties.isEnabled.value()) {
|
||||
if (_debugProperties.saveOrThrowCamera.value()) {
|
||||
_debugProperties.saveOrThrowCamera.setValue(false);
|
||||
|
||||
RenderableGlobe::~RenderableGlobe() {
|
||||
|
||||
}
|
||||
|
||||
bool RenderableGlobe::initialize() {
|
||||
return _distanceSwitch.initialize();
|
||||
}
|
||||
|
||||
bool RenderableGlobe::deinitialize() {
|
||||
return _distanceSwitch.deinitialize();
|
||||
}
|
||||
|
||||
bool RenderableGlobe::isReady() const {
|
||||
return _distanceSwitch.isReady();
|
||||
}
|
||||
|
||||
void RenderableGlobe::render(const RenderData& data) {
|
||||
bool statsEnabled = _debugProperties.collectStats.value();
|
||||
_chunkedLodGlobe->stats.setEnabled(statsEnabled);
|
||||
|
||||
if (_debugProperties.toggleEnabledEveryFrame.value()) {
|
||||
_generalProperties.isEnabled.setValue(
|
||||
!_generalProperties.isEnabled.value());
|
||||
}
|
||||
if (_generalProperties.isEnabled.value()) {
|
||||
if (_debugProperties.saveOrThrowCamera.value()) {
|
||||
_debugProperties.saveOrThrowCamera.setValue(false);
|
||||
|
||||
if (savedCamera() == nullptr) { // save camera
|
||||
LDEBUG("Saving snapshot of camera!");
|
||||
setSaveCamera(std::make_shared<Camera>(data.camera));
|
||||
}
|
||||
else { // throw camera
|
||||
LDEBUG("Throwing away saved camera!");
|
||||
setSaveCamera(nullptr);
|
||||
}
|
||||
if (savedCamera() == nullptr) { // save camera
|
||||
setSaveCamera(std::make_shared<Camera>(data.camera));
|
||||
}
|
||||
else { // throw camera
|
||||
setSaveCamera(nullptr);
|
||||
}
|
||||
_distanceSwitch.render(data);
|
||||
}
|
||||
if (_savedCamera != nullptr) {
|
||||
DebugRenderer::ref().renderCameraFrustum(data, *_savedCamera);
|
||||
}
|
||||
_distanceSwitch.render(data);
|
||||
}
|
||||
|
||||
void RenderableGlobe::update(const UpdateData& data) {
|
||||
_time = data.time;
|
||||
_distanceSwitch.update(data);
|
||||
|
||||
glm::dmat4 translation =
|
||||
glm::translate(glm::dmat4(1.0), data.modelTransform.translation);
|
||||
glm::dmat4 rotation = glm::dmat4(data.modelTransform.rotation);
|
||||
glm::dmat4 scaling =
|
||||
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale,
|
||||
data.modelTransform.scale, data.modelTransform.scale));
|
||||
|
||||
_cachedModelTransform = translation * rotation * scaling;
|
||||
_cachedInverseModelTransform = glm::inverse(_cachedModelTransform);
|
||||
|
||||
if (_debugProperties.resetTileProviders) {
|
||||
_layerManager->reset();
|
||||
_debugProperties.resetTileProviders = false;
|
||||
}
|
||||
_layerManager->update();
|
||||
_chunkedLodGlobe->update(data);
|
||||
if (_savedCamera != nullptr) {
|
||||
DebugRenderer::ref().renderCameraFrustum(data, *_savedCamera);
|
||||
}
|
||||
}
|
||||
|
||||
glm::dvec3 RenderableGlobe::projectOnEllipsoid(glm::dvec3 position) {
|
||||
return _ellipsoid.geodeticSurfaceProjection(position);
|
||||
}
|
||||
void RenderableGlobe::update(const UpdateData& data) {
|
||||
_time = data.time;
|
||||
_distanceSwitch.update(data);
|
||||
|
||||
float RenderableGlobe::getHeight(glm::dvec3 position) {
|
||||
if (_chunkedLodGlobe) {
|
||||
return _chunkedLodGlobe->getHeight(position);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
glm::dmat4 translation =
|
||||
glm::translate(glm::dmat4(1.0), data.modelTransform.translation);
|
||||
glm::dmat4 rotation = glm::dmat4(data.modelTransform.rotation);
|
||||
glm::dmat4 scaling =
|
||||
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale,
|
||||
data.modelTransform.scale, data.modelTransform.scale));
|
||||
|
||||
std::shared_ptr<ChunkedLodGlobe> RenderableGlobe::chunkedLodGlobe() const{
|
||||
return _chunkedLodGlobe;
|
||||
}
|
||||
_cachedModelTransform = translation * rotation * scaling;
|
||||
_cachedInverseModelTransform = glm::inverse(_cachedModelTransform);
|
||||
|
||||
const Ellipsoid& RenderableGlobe::ellipsoid() const{
|
||||
return _ellipsoid;
|
||||
if (_debugProperties.resetTileProviders) {
|
||||
_layerManager->reset();
|
||||
_debugProperties.resetTileProviders = false;
|
||||
}
|
||||
_layerManager->update();
|
||||
_chunkedLodGlobe->update(data);
|
||||
}
|
||||
|
||||
const glm::dmat4& RenderableGlobe::modelTransform() const{
|
||||
return _cachedModelTransform;
|
||||
}
|
||||
glm::dvec3 RenderableGlobe::projectOnEllipsoid(glm::dvec3 position) {
|
||||
return _ellipsoid.geodeticSurfaceProjection(position);
|
||||
}
|
||||
|
||||
const glm::dmat4& RenderableGlobe::inverseModelTransform() const{
|
||||
return _cachedInverseModelTransform;
|
||||
float RenderableGlobe::getHeight(glm::dvec3 position) {
|
||||
if (_chunkedLodGlobe) {
|
||||
return _chunkedLodGlobe->getHeight(position);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const RenderableGlobe::DebugProperties&
|
||||
RenderableGlobe::debugProperties() const{
|
||||
return _debugProperties;
|
||||
}
|
||||
std::shared_ptr<ChunkedLodGlobe> RenderableGlobe::chunkedLodGlobe() const{
|
||||
return _chunkedLodGlobe;
|
||||
}
|
||||
|
||||
const Ellipsoid& RenderableGlobe::ellipsoid() const{
|
||||
return _ellipsoid;
|
||||
}
|
||||
|
||||
const glm::dmat4& RenderableGlobe::modelTransform() const{
|
||||
return _cachedModelTransform;
|
||||
}
|
||||
|
||||
const glm::dmat4& RenderableGlobe::inverseModelTransform() const{
|
||||
return _cachedInverseModelTransform;
|
||||
}
|
||||
|
||||
const RenderableGlobe::DebugProperties&
|
||||
RenderableGlobe::debugProperties() const{
|
||||
return _debugProperties;
|
||||
}
|
||||
|
||||
const RenderableGlobe::GeneralProperties&
|
||||
RenderableGlobe::generalProperties() const{
|
||||
return _generalProperties;
|
||||
}
|
||||
const RenderableGlobe::GeneralProperties&
|
||||
RenderableGlobe::generalProperties() const{
|
||||
return _generalProperties;
|
||||
}
|
||||
|
||||
const std::shared_ptr<const Camera> RenderableGlobe::savedCamera() const {
|
||||
return _savedCamera;
|
||||
}
|
||||
const std::shared_ptr<const Camera> RenderableGlobe::savedCamera() const {
|
||||
return _savedCamera;
|
||||
}
|
||||
|
||||
double RenderableGlobe::interactionDepthBelowEllipsoid() {
|
||||
return _interactionDepthBelowEllipsoid;
|
||||
}
|
||||
double RenderableGlobe::interactionDepthBelowEllipsoid() {
|
||||
return _interactionDepthBelowEllipsoid;
|
||||
}
|
||||
|
||||
void RenderableGlobe::setSaveCamera(std::shared_ptr<Camera> camera) {
|
||||
_savedCamera = camera;
|
||||
}
|
||||
|
||||
void RenderableGlobe::setSaveCamera(std::shared_ptr<Camera> camera) {
|
||||
_savedCamera = camera;
|
||||
}
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
@@ -1,47 +1,36 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __RENDERABLEGLOBE_H__
|
||||
#define __RENDERABLEGLOBE_H__
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/threadpool.h>
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_RENDERABLEGLOBE_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_RENDERABLEGLOBE_H__
|
||||
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/optionproperty.h>
|
||||
#include <openspace/properties/selectionproperty.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/ellipsoid.h>
|
||||
#include <modules/globebrowsing/meshes/trianglesoup.h>
|
||||
#include <modules/globebrowsing/other/distanceswitch.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
@@ -55,13 +44,13 @@ class LayerManager;
|
||||
|
||||
* The renderable uses a <code>DistanceSwitch</code> to determine if the renderable
|
||||
* should be rendered.
|
||||
*/
|
||||
*/
|
||||
class RenderableGlobe : public Renderable {
|
||||
public:
|
||||
/**
|
||||
* These properties are specific for <code>ChunkedLodGlobe</code> and separated from
|
||||
* the general properties of <code>RenderableGlobe</code>.
|
||||
*/
|
||||
*/
|
||||
struct DebugProperties {
|
||||
properties::BoolProperty saveOrThrowCamera;
|
||||
properties::BoolProperty showChunkEdges;
|
||||
@@ -87,7 +76,7 @@ public:
|
||||
};
|
||||
|
||||
RenderableGlobe(const ghoul::Dictionary& dictionary);
|
||||
~RenderableGlobe();
|
||||
~RenderableGlobe() = default;
|
||||
|
||||
bool initialize() override;
|
||||
bool deinitialize() override;
|
||||
@@ -139,4 +128,4 @@ private:
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __RENDERABLEGLOBE_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_RENDERABLEGLOBE_H__
|
||||
|
||||
@@ -1,69 +1,60 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/meshes/basicgrid.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "BasicGrid";
|
||||
}
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
BasicGrid::BasicGrid(
|
||||
unsigned int xSegments,
|
||||
unsigned int ySegments,
|
||||
TriangleSoup::Positions usePositions,
|
||||
TriangleSoup::TextureCoordinates useTextureCoordinates,
|
||||
TriangleSoup::Normals useNormals)
|
||||
: Grid(
|
||||
xSegments,
|
||||
ySegments,
|
||||
usePositions,
|
||||
useTextureCoordinates,
|
||||
useNormals)
|
||||
BasicGrid::BasicGrid(unsigned int xSegments, unsigned int ySegments,
|
||||
TriangleSoup::Positions usePositions,
|
||||
TriangleSoup::TextureCoordinates useTextureCoordinates,
|
||||
TriangleSoup::Normals useNormals)
|
||||
: Grid(xSegments, ySegments, usePositions, useTextureCoordinates, useNormals)
|
||||
{
|
||||
_geometry = std::unique_ptr<TriangleSoup>(new TriangleSoup(
|
||||
_geometry = std::make_unique<TriangleSoup>(
|
||||
CreateElements(xSegments, ySegments),
|
||||
usePositions,
|
||||
useTextureCoordinates,
|
||||
useNormals));
|
||||
useNormals
|
||||
);
|
||||
|
||||
if (usePositions == TriangleSoup::Positions::Yes) {
|
||||
if (usePositions) {
|
||||
_geometry->setVertexPositions(CreatePositions(_xSegments, _ySegments));
|
||||
}
|
||||
if (useTextureCoordinates == TriangleSoup::TextureCoordinates::Yes) {
|
||||
_geometry->setVertexTextureCoordinates(CreateTextureCoordinates(_xSegments, _ySegments));
|
||||
if (useTextureCoordinates) {
|
||||
_geometry->setVertexTextureCoordinates(
|
||||
CreateTextureCoordinates(_xSegments, _ySegments)
|
||||
);
|
||||
}
|
||||
if (useNormals == TriangleSoup::Normals::Yes) {
|
||||
if (useNormals) {
|
||||
_geometry->setVertexNormals(CreateNormals(_xSegments, _ySegments));
|
||||
}
|
||||
}
|
||||
|
||||
BasicGrid::~BasicGrid()
|
||||
{}
|
||||
|
||||
int BasicGrid::xSegments() const {
|
||||
return _xSegments;
|
||||
}
|
||||
@@ -77,7 +68,7 @@ void BasicGrid::validate(int xSegments, int ySegments) {
|
||||
"Resolution must be at least 1x1. (" << xSegments << ", " << ySegments << ")");
|
||||
}
|
||||
|
||||
inline size_t BasicGrid::numElements(int xSegments, int ySegments){
|
||||
inline size_t BasicGrid::numElements(int xSegments, int ySegments) {
|
||||
return 3 * 2 * xSegments * ySegments;
|
||||
}
|
||||
|
||||
@@ -120,28 +111,29 @@ std::vector<GLuint> BasicGrid::CreateElements(int xSegments, int ySegments) {
|
||||
return elements;
|
||||
}
|
||||
|
||||
std::vector<glm::vec4> BasicGrid::CreatePositions(
|
||||
int xSegments,
|
||||
int ySegments)
|
||||
{
|
||||
std::vector<glm::vec4> BasicGrid::CreatePositions(int xSegments, int ySegments) {
|
||||
validate(xSegments, ySegments);
|
||||
std::vector<glm::vec4> positions;
|
||||
positions.reserve(numVertices(xSegments, ySegments));
|
||||
|
||||
// Copy from 2d texture coordinates and use as template to create positions
|
||||
std::vector<glm::vec2> templateTextureCoords = CreateTextureCoordinates(xSegments, ySegments);
|
||||
for (unsigned int i = 0; i < templateTextureCoords.size(); i++)
|
||||
{
|
||||
positions.push_back(glm::vec4(
|
||||
templateTextureCoords[i],
|
||||
0.0f,
|
||||
1.0f
|
||||
));
|
||||
std::vector<glm::vec2> templateTextureCoords = CreateTextureCoordinates(
|
||||
xSegments, ySegments
|
||||
);
|
||||
for (const glm::vec2& coords : templateTextureCoords) {
|
||||
positions.push_back(glm::vec4(coords, 0.f, 1.f));
|
||||
}
|
||||
//for (unsigned int i = 0; i < templateTextureCoords.size(); i++) {
|
||||
// positions.push_back(glm::vec4(
|
||||
// templateTextureCoords[i],
|
||||
// 0.0f,
|
||||
// 1.0f
|
||||
// ));
|
||||
//}
|
||||
return positions;
|
||||
}
|
||||
|
||||
std::vector<glm::vec2> BasicGrid::CreateTextureCoordinates(int xSegments, int ySegments){
|
||||
std::vector<glm::vec2> BasicGrid::CreateTextureCoordinates(int xSegments, int ySegments) {
|
||||
validate(xSegments, ySegments);
|
||||
std::vector<glm::vec2> textureCoordinates;
|
||||
textureCoordinates.reserve(numVertices(xSegments, ySegments));
|
||||
@@ -172,4 +164,4 @@ std::vector<glm::vec3> BasicGrid::CreateNormals(int xSegments, int ySegments) {
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
} // namespace openspace
|
||||
|
||||
@@ -22,39 +22,34 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
#ifndef __BASICGRIDGEOMETRY_H__
|
||||
#define __BASICGRIDGEOMETRY_H__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_BASICGRIDGEOMETRY_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_BASICGRIDGEOMETRY_H__
|
||||
|
||||
#include <modules/globebrowsing/meshes/grid.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
class BasicGrid : public Grid
|
||||
{
|
||||
class BasicGrid : public Grid {
|
||||
public:
|
||||
/**
|
||||
\param xSegments is the number of grid cells in the x direction.
|
||||
\param ySegments is the number of grid cells in the y direction.
|
||||
\param usePositions determines whether or not to upload any vertex position data
|
||||
to the GPU.
|
||||
\param useTextureCoordinates determines whether or not to upload any vertex texture
|
||||
coordinate data to the GPU.
|
||||
\param useNormals determines whether or not to upload any vertex normal data
|
||||
to the GPU.
|
||||
* \param xSegments is the number of grid cells in the x direction.
|
||||
* \param ySegments is the number of grid cells in the y direction.
|
||||
* \param usePositions determines whether or not to upload any vertex position data
|
||||
* to the GPU.
|
||||
* \param useTextureCoordinates determines whether or not to upload any vertex texture
|
||||
* coordinate data to the GPU.
|
||||
* \param useNormals determines whether or not to upload any vertex normal data
|
||||
* to the GPU.
|
||||
*/
|
||||
BasicGrid(
|
||||
unsigned int xSegments,
|
||||
unsigned int ySegments,
|
||||
TriangleSoup::Positions usePositions,
|
||||
TriangleSoup::TextureCoordinates useTextureCoordinates,
|
||||
TriangleSoup::Normals useNormals);
|
||||
~BasicGrid();
|
||||
BasicGrid(unsigned int xSegments, unsigned int ySegments,
|
||||
TriangleSoup::Positions usePositions,
|
||||
TriangleSoup::TextureCoordinates useTextureCoordinates,
|
||||
TriangleSoup::Normals useNormals);
|
||||
|
||||
virtual int xSegments() const;
|
||||
virtual int ySegments() const;
|
||||
@@ -74,4 +69,4 @@ private:
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __BASICGRIDGEOMETRY_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_BASICGRIDGEOMETRY_H__
|
||||
|
||||
@@ -1,53 +1,41 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/meshes/grid.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "Grid";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
Grid::Grid(
|
||||
int xSegments,
|
||||
int ySegments,
|
||||
TriangleSoup::Positions usePositions,
|
||||
TriangleSoup::TextureCoordinates useTextures,
|
||||
TriangleSoup::Normals useNormals)
|
||||
Grid::Grid(int xSegments, int ySegments, TriangleSoup::Positions usePositions,
|
||||
TriangleSoup::TextureCoordinates useTextures, TriangleSoup::Normals useNormals)
|
||||
: _xSegments(xSegments)
|
||||
, _ySegments(ySegments)
|
||||
{}
|
||||
|
||||
Grid::~Grid()
|
||||
{}
|
||||
|
||||
TriangleSoup& Grid::geometry()
|
||||
{
|
||||
TriangleSoup& Grid::geometry() {
|
||||
return *_geometry;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,100 +1,98 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __GRIDGEOMETRY_H__
|
||||
#define __GRIDGEOMETRY_H__
|
||||
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <glm/glm.hpp>
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_GRIDGEOMETRY_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_GRIDGEOMETRY_H__
|
||||
|
||||
#include <modules/globebrowsing/meshes/trianglesoup.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
/**
|
||||
* Abstract class defining an interface used for geometries with grid structures.
|
||||
* The class <code>Grid</code> should be extended for use of geometries with a 2D
|
||||
* structure where the number of segments in x and y direction represents the number
|
||||
* of vertices + 1 in each direction.
|
||||
*/
|
||||
class Grid
|
||||
{
|
||||
* Abstract class defining an interface used for geometries with grid structures.
|
||||
* The class <code>Grid</code> should be extended for use of geometries with a 2D
|
||||
* structure where the number of segments in x and y direction represents the number
|
||||
* of vertices + 1 in each direction.
|
||||
*/
|
||||
class Grid {
|
||||
public:
|
||||
Grid(
|
||||
int xSegments,
|
||||
int ySegments,
|
||||
Grid(int xSegments, int ySegments,
|
||||
TriangleSoup::Positions usePositions = TriangleSoup::Positions::No,
|
||||
TriangleSoup::TextureCoordinates useTextures =
|
||||
TriangleSoup::TextureCoordinates::No,
|
||||
TriangleSoup::TextureCoordinates::No,
|
||||
TriangleSoup::Normals useNormals = TriangleSoup::Normals::No);
|
||||
~Grid();
|
||||
|
||||
virtual ~Grid() = default;
|
||||
|
||||
TriangleSoup& geometry();
|
||||
|
||||
/**
|
||||
* Returns the number of grid cells in the x direction. Hence the number of vertices
|
||||
* in the x direction is xResolution + 1.
|
||||
*/
|
||||
* Returns the number of grid cells in the x direction. Hence the number of vertices
|
||||
* in the x direction is xResolution + 1.
|
||||
*/
|
||||
virtual int xSegments() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the number of grid cells in the y direction. Hence the number of vertices
|
||||
* in the y direction is xResolution + 1.
|
||||
*/
|
||||
* Returns the number of grid cells in the y direction. Hence the number of vertices
|
||||
* in the y direction is xResolution + 1.
|
||||
*/
|
||||
virtual int ySegments() const = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Should return the indices of vertices for a grid with size <code>xSegments</code> *
|
||||
* <code>ySegments</code>. Where the number of vertices in each direction is the number
|
||||
* of segments + 1.
|
||||
*/
|
||||
* Should return the indices of vertices for a grid with size <code>xSegments</code> *
|
||||
* <code>ySegments</code>. Where the number of vertices in each direction is the number
|
||||
* of segments + 1.
|
||||
*/
|
||||
virtual std::vector<GLuint> CreateElements(int xSegments, int ySegments) = 0;
|
||||
|
||||
/**
|
||||
* Should return the positions of vertices for a grid with size <code>xSegments</code>
|
||||
* * <code>ySegments</code>. Where the number of vertices in each direction is the
|
||||
* number of segments + 1.
|
||||
*/
|
||||
* Should return the positions of vertices for a grid with size <code>xSegments</code>
|
||||
* * <code>ySegments</code>. Where the number of vertices in each direction is the
|
||||
* number of segments + 1.
|
||||
*/
|
||||
virtual std::vector<glm::vec4> CreatePositions(int xSegments, int ySegments) = 0;
|
||||
|
||||
/**
|
||||
* Should return the texture coordinates of vertices for a grid with size
|
||||
* <code>xSegments</code> * <code>ySegments</code>. Where the number of vertices in
|
||||
* each direction is the number of segments + 1.
|
||||
*/
|
||||
* Should return the texture coordinates of vertices for a grid with size
|
||||
* <code>xSegments</code> * <code>ySegments</code>. Where the number of vertices in
|
||||
* each direction is the number of segments + 1.
|
||||
*/
|
||||
virtual std::vector<glm::vec2>
|
||||
CreateTextureCoordinates(int xSegments, int ySegments) = 0;
|
||||
|
||||
/**
|
||||
* Should return the normals of vertices for a grid with size <code>xSegments</code> *
|
||||
* <code>ySegments</code>. Where the number of vertices in each direction is the number
|
||||
* of segments + 1.
|
||||
*/
|
||||
* Should return the normals of vertices for a grid with size <code>xSegments</code> *
|
||||
* <code>ySegments</code>. Where the number of vertices in each direction is the number
|
||||
* of segments + 1.
|
||||
*/
|
||||
virtual std::vector<glm::vec3> CreateNormals(int xSegments, int ySegments) = 0;
|
||||
|
||||
std::unique_ptr<TriangleSoup> _geometry;
|
||||
@@ -106,4 +104,4 @@ protected:
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __GRIDGEOMETRY_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_GRIDGEOMETRY_H__
|
||||
|
||||
@@ -1,177 +1,180 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/meshes/skirtedgrid.h>
|
||||
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "SkirtedGrid";
|
||||
const char*_loggerCat = "SkirtedGrid";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
SkirtedGrid::SkirtedGrid(
|
||||
unsigned int xSegments,
|
||||
unsigned int ySegments,
|
||||
TriangleSoup::Positions usePositions,
|
||||
TriangleSoup::TextureCoordinates useTextureCoordinates,
|
||||
TriangleSoup::Normals useNormals)
|
||||
: Grid(
|
||||
xSegments,
|
||||
ySegments,
|
||||
usePositions,
|
||||
useTextureCoordinates,
|
||||
useNormals)
|
||||
{
|
||||
_geometry = std::unique_ptr<TriangleSoup>(new TriangleSoup(
|
||||
CreateElements(xSegments, ySegments),
|
||||
usePositions,
|
||||
useTextureCoordinates,
|
||||
useNormals));
|
||||
SkirtedGrid::SkirtedGrid(unsigned int xSegments, unsigned int ySegments,
|
||||
TriangleSoup::Positions usePositions,
|
||||
TriangleSoup::TextureCoordinates useTextureCoordinates,
|
||||
TriangleSoup::Normals useNormals)
|
||||
: Grid(xSegments, ySegments, usePositions, useTextureCoordinates, useNormals)
|
||||
{
|
||||
_geometry = std::make_unique<TriangleSoup>(
|
||||
CreateElements(xSegments, ySegments),
|
||||
usePositions,
|
||||
useTextureCoordinates,
|
||||
useNormals
|
||||
);
|
||||
|
||||
if (usePositions == TriangleSoup::Positions::Yes) {
|
||||
_geometry->setVertexPositions(CreatePositions(_xSegments, _ySegments));
|
||||
}
|
||||
if (useTextureCoordinates == TriangleSoup::TextureCoordinates::Yes) {
|
||||
_geometry->setVertexTextureCoordinates(CreateTextureCoordinates(_xSegments, _ySegments));
|
||||
}
|
||||
if (useNormals == TriangleSoup::Normals::Yes) {
|
||||
_geometry->setVertexNormals(CreateNormals(_xSegments, _ySegments));
|
||||
if (usePositions) {
|
||||
_geometry->setVertexPositions(CreatePositions(_xSegments, _ySegments));
|
||||
}
|
||||
if (useTextureCoordinates) {
|
||||
_geometry->setVertexTextureCoordinates(CreateTextureCoordinates(_xSegments, _ySegments));
|
||||
}
|
||||
if (useNormals) {
|
||||
_geometry->setVertexNormals(CreateNormals(_xSegments, _ySegments));
|
||||
}
|
||||
}
|
||||
|
||||
int SkirtedGrid::xSegments() const {
|
||||
return _xSegments;
|
||||
}
|
||||
|
||||
int SkirtedGrid::ySegments() const {
|
||||
return _ySegments;
|
||||
}
|
||||
|
||||
void SkirtedGrid::validate(int xSegments, int ySegments) {
|
||||
ghoul_assert(
|
||||
xSegments > 0 && ySegments > 0,
|
||||
"Resolution must be at least 1x1. (" + std::to_string(xSegments) + ", " + std::to_string(ySegments) + ")"
|
||||
);
|
||||
}
|
||||
|
||||
inline size_t SkirtedGrid::numElements(int xSegments, int ySegments) {
|
||||
return 3 * 2 * xSegments * ySegments;
|
||||
}
|
||||
|
||||
inline size_t SkirtedGrid::numVertices(int xSegments, int ySegments) {
|
||||
return (xSegments + 1) * (ySegments + 1);
|
||||
}
|
||||
|
||||
std::vector<GLuint> SkirtedGrid::CreateElements(int xSegments, int ySegments) {
|
||||
validate(xSegments, ySegments);
|
||||
|
||||
std::vector<GLuint> elements;
|
||||
elements.reserve(numElements(xSegments + 2, ySegments + 2));
|
||||
for (unsigned int y = 0; y < ySegments + 2; y++) {
|
||||
for (unsigned int x = 0; x < xSegments + 2; x++) {
|
||||
|
||||
// x v01---v11 x ..
|
||||
// | / |
|
||||
// x v00---v10 x ..
|
||||
//
|
||||
// x x x x ..
|
||||
// : : : :
|
||||
|
||||
GLuint v00 = (y + 0) * (xSegments + 2 + 1) + x + 0;
|
||||
GLuint v10 = (y + 0) * (xSegments + 2 + 1) + x + 1;
|
||||
GLuint v01 = (y + 1) * (xSegments + 2 + 1) + x + 0;
|
||||
GLuint v11 = (y + 1) * (xSegments + 2 + 1) + x + 1;
|
||||
|
||||
// add upper triangle
|
||||
elements.push_back(v00);
|
||||
elements.push_back(v10);
|
||||
elements.push_back(v11);
|
||||
|
||||
// add lower triangle
|
||||
elements.push_back(v00);
|
||||
elements.push_back(v11);
|
||||
elements.push_back(v01);
|
||||
}
|
||||
}
|
||||
|
||||
SkirtedGrid::~SkirtedGrid()
|
||||
{
|
||||
return elements;
|
||||
}
|
||||
|
||||
std::vector<glm::vec4> SkirtedGrid::CreatePositions(int xSegments, int ySegments) {
|
||||
validate(xSegments, ySegments);
|
||||
std::vector<glm::vec4> positions;
|
||||
positions.reserve(numVertices(xSegments, ySegments));
|
||||
|
||||
// Copy from 2d texture coordinates and use as template to create positions
|
||||
std::vector<glm::vec2> templateTextureCoords = CreateTextureCoordinates(
|
||||
xSegments, ySegments
|
||||
);
|
||||
for (const auto& c : templateTextureCoords) {
|
||||
positions.push_back(glm::vec4(c, 0.f, 1.f));
|
||||
}
|
||||
//for (unsigned int i = 0; i < templateTextureCoords.size(); i++) {
|
||||
// positions.push_back(glm::vec4(
|
||||
// templateTextureCoords[i],
|
||||
// 0.0f,
|
||||
// 1.0f
|
||||
// ));
|
||||
//}
|
||||
return positions;
|
||||
}
|
||||
|
||||
int SkirtedGrid::xSegments() const {
|
||||
return _xSegments;
|
||||
}
|
||||
std::vector<glm::vec2> SkirtedGrid::CreateTextureCoordinates(int xSegments, int ySegments)
|
||||
{
|
||||
validate(xSegments, ySegments);
|
||||
std::vector<glm::vec2> textureCoordinates;
|
||||
textureCoordinates.reserve(numVertices(xSegments + 2, ySegments + 2));
|
||||
|
||||
int SkirtedGrid::ySegments() const {
|
||||
return _ySegments;
|
||||
}
|
||||
|
||||
void SkirtedGrid::validate(int xSegments, int ySegments) {
|
||||
ghoul_assert(xSegments > 0 && ySegments > 0,
|
||||
"Resolution must be at least 1x1. (" << xSegments << ", " << ySegments << ")");
|
||||
}
|
||||
|
||||
inline size_t SkirtedGrid::numElements(int xSegments, int ySegments) {
|
||||
return 3 * 2 * xSegments * ySegments;
|
||||
}
|
||||
|
||||
inline size_t SkirtedGrid::numVertices(int xSegments, int ySegments) {
|
||||
return (xSegments + 1) * (ySegments + 1);
|
||||
}
|
||||
|
||||
std::vector<GLuint> SkirtedGrid::CreateElements(int xSegments, int ySegments) {
|
||||
validate(xSegments, ySegments);
|
||||
|
||||
std::vector<GLuint> elements;
|
||||
elements.reserve(numElements(xSegments + 2, ySegments + 2));
|
||||
for (unsigned int y = 0; y < ySegments + 2; y++) {
|
||||
for (unsigned int x = 0; x < xSegments + 2; x++) {
|
||||
|
||||
// x v01---v11 x ..
|
||||
// | / |
|
||||
// x v00---v10 x ..
|
||||
//
|
||||
// x x x x ..
|
||||
// : : : :
|
||||
|
||||
GLuint v00 = (y + 0) * (xSegments + 2 + 1) + x + 0;
|
||||
GLuint v10 = (y + 0) * (xSegments + 2 + 1) + x + 1;
|
||||
GLuint v01 = (y + 1) * (xSegments + 2 + 1) + x + 0;
|
||||
GLuint v11 = (y + 1) * (xSegments + 2 + 1) + x + 1;
|
||||
|
||||
// add upper triangle
|
||||
elements.push_back(v00);
|
||||
elements.push_back(v10);
|
||||
elements.push_back(v11);
|
||||
|
||||
// add lower triangle
|
||||
elements.push_back(v00);
|
||||
elements.push_back(v11);
|
||||
elements.push_back(v01);
|
||||
}
|
||||
for (int y = -1; y < ySegments + 2; y++) {
|
||||
for (int x = -1; x < xSegments + 2; x++) {
|
||||
textureCoordinates.push_back(glm::vec2(
|
||||
glm::clamp(
|
||||
static_cast<float>(x) / static_cast<float>(xSegments),
|
||||
0 - 1.0f / (2 * xSegments),
|
||||
1 + 1.0f / (2 * xSegments)
|
||||
),
|
||||
glm::clamp(
|
||||
static_cast<float>(y) / static_cast<float>(ySegments),
|
||||
0 - 1.0f / (2 * ySegments),
|
||||
1 + 1.0f / (2 * ySegments)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
return textureCoordinates;
|
||||
}
|
||||
|
||||
std::vector<glm::vec4> SkirtedGrid::CreatePositions(
|
||||
int xSegments,
|
||||
int ySegments)
|
||||
{
|
||||
validate(xSegments, ySegments);
|
||||
std::vector<glm::vec4> positions;
|
||||
positions.reserve(numVertices(xSegments, ySegments));
|
||||
std::vector<glm::vec3> SkirtedGrid::CreateNormals(int xSegments, int ySegments) {
|
||||
validate(xSegments, ySegments);
|
||||
std::vector<glm::vec3> normals;
|
||||
normals.reserve(numVertices(xSegments + 2, ySegments + 2));
|
||||
|
||||
// Copy from 2d texture coordinates and use as template to create positions
|
||||
std::vector<glm::vec2> templateTextureCoords = CreateTextureCoordinates(xSegments, ySegments);
|
||||
for (unsigned int i = 0; i < templateTextureCoords.size(); i++)
|
||||
{
|
||||
positions.push_back(glm::vec4(
|
||||
templateTextureCoords[i],
|
||||
0.0f,
|
||||
1.0f
|
||||
));
|
||||
for (int y = -1; y < ySegments + 2; y++) {
|
||||
for (int x = -1; x < xSegments + 2; x++) {
|
||||
normals.push_back(glm::vec3(0, 0, 1));
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
std::vector<glm::vec2> SkirtedGrid::CreateTextureCoordinates(int xSegments, int ySegments) {
|
||||
validate(xSegments, ySegments);
|
||||
std::vector<glm::vec2> textureCoordinates;
|
||||
textureCoordinates.reserve(numVertices(xSegments + 2, ySegments + 2));
|
||||
|
||||
for (int y = -1; y < ySegments + 2; y++) {
|
||||
for (int x = -1; x < xSegments + 2; x++) {
|
||||
textureCoordinates.push_back(glm::vec2(
|
||||
glm::clamp(static_cast<float>(x) / static_cast<float>(xSegments), 0 - 1.0f / (2 * xSegments), 1 + 1.0f / (2 * xSegments)),
|
||||
glm::clamp(static_cast<float>(y) / static_cast<float>(ySegments), 0 - 1.0f / (2 * ySegments), 1 + 1.0f / (2 * ySegments))
|
||||
));
|
||||
}
|
||||
}
|
||||
return textureCoordinates;
|
||||
}
|
||||
|
||||
std::vector<glm::vec3> SkirtedGrid::CreateNormals(int xSegments, int ySegments) {
|
||||
validate(xSegments, ySegments);
|
||||
std::vector<glm::vec3> normals;
|
||||
normals.reserve(numVertices(xSegments + 2, ySegments + 2));
|
||||
|
||||
for (int y = -1; y < ySegments + 2; y++) {
|
||||
for (int x = -1; x < xSegments + 2; x++) {
|
||||
normals.push_back(glm::vec3(0, 0, 1));
|
||||
}
|
||||
}
|
||||
|
||||
return normals;
|
||||
}
|
||||
return normals;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,82 +1,78 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __SKIRTEDGRID_H__
|
||||
#define __SKIRTEDGRID_H__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_SKIRTEDGRID_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_SKIRTEDGRID_H__
|
||||
|
||||
#include <modules/globebrowsing/meshes/basicgrid.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
/**
|
||||
* This grid is the same as <code>BasicGrid</code> except it has skirts around its edges.
|
||||
* The areas covered by the skirts have position coordinates and texture coordinates
|
||||
* that are outside of the range [0, 1]. The width of the skirts is half the size of one
|
||||
* segment width or a cell.
|
||||
*/
|
||||
class SkirtedGrid : public Grid
|
||||
{
|
||||
* This grid is the same as <code>BasicGrid</code> except it has skirts around its edges.
|
||||
* The areas covered by the skirts have position coordinates and texture coordinates
|
||||
* that are outside of the range [0, 1]. The width of the skirts is half the size of one
|
||||
* segment width or a cell.
|
||||
*/
|
||||
class SkirtedGrid : public Grid {
|
||||
public:
|
||||
/**
|
||||
* \param xSegments is the number of grid cells in the x direction.
|
||||
* \param ySegments is the number of grid cells in the y direction.
|
||||
* \param usePositions determines whether or not to upload any vertex position data
|
||||
* to the GPU.
|
||||
* \param useTextureCoordinates determines whether or not to upload any vertex texture
|
||||
* coordinate data to the GPU.
|
||||
* \param useNormals determines whether or not to upload any vertex normal data
|
||||
* to the GPU.
|
||||
*/
|
||||
SkirtedGrid(
|
||||
unsigned int xSegments,
|
||||
unsigned int ySegments,
|
||||
* \param xSegments is the number of grid cells in the x direction.
|
||||
* \param ySegments is the number of grid cells in the y direction.
|
||||
* \param usePositions determines whether or not to upload any vertex position data
|
||||
* to the GPU.
|
||||
* \param useTextureCoordinates determines whether or not to upload any vertex texture
|
||||
* coordinate data to the GPU.
|
||||
* \param useNormals determines whether or not to upload any vertex normal data
|
||||
* to the GPU.
|
||||
*/
|
||||
SkirtedGrid(unsigned int xSegments, unsigned int ySegments,
|
||||
TriangleSoup::Positions usePositions,
|
||||
TriangleSoup::TextureCoordinates useTextureCoordinates,
|
||||
TriangleSoup::Normals useNormals);
|
||||
~SkirtedGrid();
|
||||
~SkirtedGrid() = default;
|
||||
|
||||
virtual int xSegments() const;
|
||||
virtual int ySegments() const;
|
||||
|
||||
private:
|
||||
virtual std::vector<GLuint> CreateElements(int xRes, int yRes);
|
||||
virtual std::vector<glm::vec4> CreatePositions(int xRes, int yRes);
|
||||
virtual std::vector<glm::vec2> CreateTextureCoordinates(int xRes, int yRes);
|
||||
virtual std::vector<glm::vec3> CreateNormals(int xRes, int yRes);
|
||||
virtual std::vector<GLuint> CreateElements(int xRes, int yRes);
|
||||
virtual std::vector<glm::vec4> CreatePositions(int xRes, int yRes);
|
||||
virtual std::vector<glm::vec2> CreateTextureCoordinates(int xRes, int yRes);
|
||||
virtual std::vector<glm::vec3> CreateNormals(int xRes, int yRes);
|
||||
|
||||
void validate(int xSegments, int ySegments);
|
||||
|
||||
inline size_t numElements(int xSegments, int ySegments);
|
||||
inline size_t numVertices(int xSegments, int ySegments);
|
||||
size_t numElements(int xSegments, int ySegments);
|
||||
size_t numVertices(int xSegments, int ySegments);
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
#endif // __SKIRTEDGRID_H__
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_SKIRTEDGRID_H__
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/meshes/trianglesoup.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TriangleSoup";
|
||||
}
|
||||
@@ -31,14 +33,14 @@ namespace {
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
TriangleSoup::TriangleSoup(std::vector<unsigned int> elements,
|
||||
Positions usePositions, TextureCoordinates useTextures, Normals useNormals)
|
||||
TriangleSoup::TriangleSoup(std::vector<unsigned int> elements, Positions usePositions,
|
||||
TextureCoordinates useTextures, Normals useNormals)
|
||||
: _vaoID(0)
|
||||
,_vertexBufferID(0)
|
||||
,_elementBufferID(0)
|
||||
,_useVertexPositions(usePositions)
|
||||
,_useTextureCoordinates(useTextures)
|
||||
,_useVertexNormals(useNormals)
|
||||
, _vertexBufferID(0)
|
||||
, _elementBufferID(0)
|
||||
, _useVertexPositions(usePositions)
|
||||
, _useTextureCoordinates(useTextures)
|
||||
, _useVertexNormals(useNormals)
|
||||
{
|
||||
setElements(elements);
|
||||
}
|
||||
@@ -53,8 +55,7 @@ void TriangleSoup::setVertexPositions(std::vector<glm::vec4> positions) {
|
||||
_useVertexPositions = true;
|
||||
_gpuDataNeedUpdate = true;
|
||||
_vertexData.resize(positions.size());
|
||||
for (size_t i = 0; i < positions.size(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < positions.size(); i++) {
|
||||
_vertexData[i].position[0] = static_cast<GLfloat>(positions[i].x);
|
||||
_vertexData[i].position[1] = static_cast<GLfloat>(positions[i].y);
|
||||
_vertexData[i].position[2] = static_cast<GLfloat>(positions[i].z);
|
||||
@@ -66,8 +67,7 @@ void TriangleSoup::setVertexTextureCoordinates(std::vector<glm::vec2> textures)
|
||||
_useTextureCoordinates = true;
|
||||
_gpuDataNeedUpdate = true;
|
||||
_vertexData.resize(textures.size());
|
||||
for (size_t i = 0; i < textures.size(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < textures.size(); i++) {
|
||||
_vertexData[i].texture[0] = static_cast<GLfloat>(textures[i].s);
|
||||
_vertexData[i].texture[1] = static_cast<GLfloat>(textures[i].t);
|
||||
}
|
||||
@@ -77,8 +77,7 @@ void TriangleSoup::setVertexNormals(std::vector<glm::vec3> normals) {
|
||||
_useVertexNormals = true;
|
||||
_gpuDataNeedUpdate = true;
|
||||
_vertexData.resize(normals.size());
|
||||
for (size_t i = 0; i < normals.size(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < normals.size(); i++) {
|
||||
_vertexData[i].normal[0] = static_cast<GLfloat>(normals[i].x);
|
||||
_vertexData[i].normal[1] = static_cast<GLfloat>(normals[i].y);
|
||||
_vertexData[i].normal[2] = static_cast<GLfloat>(normals[i].z);
|
||||
@@ -88,16 +87,16 @@ void TriangleSoup::setVertexNormals(std::vector<glm::vec3> normals) {
|
||||
void TriangleSoup::setElements(std::vector<unsigned int> elements) {
|
||||
_elementData.resize(elements.size());
|
||||
_gpuDataNeedUpdate = true;
|
||||
for (size_t i = 0; i < elements.size(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < elements.size(); i++) {
|
||||
_elementData[i] = static_cast<GLuint>(elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool TriangleSoup::updateDataOnGPU() {
|
||||
// Create VAO
|
||||
if (_vaoID == 0)
|
||||
if (_vaoID == 0) {
|
||||
glGenVertexArrays(1, &_vaoID);
|
||||
}
|
||||
|
||||
// Create VBOs
|
||||
if (_vertexBufferID == 0 && _vertexData.size() > 0) {
|
||||
@@ -124,7 +123,8 @@ bool TriangleSoup::updateDataOnGPU() {
|
||||
GL_ARRAY_BUFFER,
|
||||
_vertexData.size() * sizeof(Vertex),
|
||||
&_vertexData[0],
|
||||
GL_STATIC_DRAW);
|
||||
GL_STATIC_DRAW
|
||||
);
|
||||
|
||||
// Positions at location 0
|
||||
if (_useVertexPositions) {
|
||||
|
||||
@@ -1,35 +1,33 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TRIANGLESOUP_H__
|
||||
#define __TRIANGLESOUP_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TRIANGLESOUP_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TRIANGLESOUP_H__
|
||||
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/misc/boolean.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -37,16 +35,15 @@ namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
/**
|
||||
* Class to hold vertex data and handling OpenGL interfacing and rendering.
|
||||
* A <code>TriangleSoup</code> has all data needed such as position buffer and normal
|
||||
* buffer but all data is not necessarily needed for all purpouses so some vertex buffers
|
||||
* such as normals can be disabled if not needed.
|
||||
*/
|
||||
* Class to hold vertex data and handling OpenGL interfacing and rendering.
|
||||
* A <code>TriangleSoup</code> has all data needed such as position buffer and normal
|
||||
* buffer but all data is not necessarily needed for all purpouses so some vertex buffers
|
||||
* such as normals can be disabled if not needed.
|
||||
*/
|
||||
|
||||
// TODO : Possibly render triangle strips in this class instead of triangles since
|
||||
// that is faster
|
||||
class TriangleSoup
|
||||
{
|
||||
class TriangleSoup {
|
||||
public:
|
||||
using Positions = ghoul::Boolean;
|
||||
using TextureCoordinates = ghoul::Boolean;
|
||||
@@ -93,8 +90,8 @@ protected:
|
||||
// Vertex data
|
||||
std::vector<Vertex> _vertexData;
|
||||
std::vector<GLuint> _elementData;
|
||||
private:
|
||||
|
||||
private:
|
||||
bool updateDataOnGPU();
|
||||
|
||||
// GL handles
|
||||
@@ -108,4 +105,4 @@ private:
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __TRIANGLESOUP_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TRIANGLESOUP_H__
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace globebrowsing {
|
||||
virtual ~Job() { }
|
||||
|
||||
virtual void execute() = 0;
|
||||
virtual std::shared_ptr<P> product() = 0;
|
||||
virtual std::shared_ptr<P> product() const = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,45 +1,32 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
// open space includes
|
||||
#include <modules/globebrowsing/other/distanceswitch.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "DistanceSwitch";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
DistanceSwitch::DistanceSwitch(){
|
||||
|
||||
}
|
||||
|
||||
DistanceSwitch::~DistanceSwitch() {
|
||||
|
||||
}
|
||||
|
||||
bool DistanceSwitch::initialize() {
|
||||
for (int i = 0; i < _renderables.size(); ++i) {
|
||||
_renderables[i]->initialize();
|
||||
@@ -54,9 +41,6 @@ bool DistanceSwitch::deinitialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DistanceSwitch::isReady() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DistanceSwitch::render(const RenderData& data) {
|
||||
if (_maxDistances.size() == 0) {
|
||||
@@ -85,9 +69,11 @@ void DistanceSwitch::update(const UpdateData& data) {
|
||||
}
|
||||
}
|
||||
|
||||
void DistanceSwitch::addSwitchValue(std::shared_ptr<Renderable> renderable, double maxDistance) {
|
||||
void DistanceSwitch::addSwitchValue(std::shared_ptr<Renderable> renderable,
|
||||
double maxDistance)
|
||||
{
|
||||
ghoul_assert(maxDistance > 0, "Renderable must have a positive maxDistance");
|
||||
if (_maxDistances.size() > 0){
|
||||
if (_maxDistances.size() > 0) {
|
||||
ghoul_assert(maxDistance > _maxDistances.back(),
|
||||
"Renderables must be inserted in ascending order wrt distance");
|
||||
}
|
||||
@@ -97,4 +83,3 @@ void DistanceSwitch::addSwitchValue(std::shared_ptr<Renderable> renderable, doub
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
@@ -1,75 +1,70 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __DISTANCESWITCH_H__
|
||||
#define __DISTANCESWITCH_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_DISTANCESWITCH_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_DISTANCESWITCH_H__
|
||||
|
||||
// open space includes
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <openspace/util/powerscaledcoordinate.h>
|
||||
#include <openspace/util/powerscaledscalar.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
struct RenderData;
|
||||
struct UpdateData;
|
||||
|
||||
namespace globebrowsing {
|
||||
|
||||
/**
|
||||
Selects a specific Renderable to be used for rendering, based on distance to the
|
||||
camera
|
||||
* Selects a specific Renderable to be used for rendering, based on distance to the
|
||||
* camera
|
||||
*/
|
||||
class DistanceSwitch {
|
||||
public:
|
||||
DistanceSwitch();
|
||||
virtual ~DistanceSwitch();
|
||||
|
||||
bool initialize();
|
||||
bool deinitialize();
|
||||
bool isReady() const;
|
||||
|
||||
/**
|
||||
Picks the first Renderable with the associated maxDistance greater than the
|
||||
current distance to the camera
|
||||
* Picks the first Renderable with the associated maxDistance greater than the
|
||||
* current distance to the camera
|
||||
*/
|
||||
void render(const RenderData& data);
|
||||
void update(const UpdateData& data);
|
||||
|
||||
/**
|
||||
Adds a new renderable (first argument) which may be rendered only if the distance
|
||||
to the camera is less than maxDistance (second argument)
|
||||
* Adds a new renderable (first argument) which may be rendered only if the distance
|
||||
* to the camera is less than maxDistance (second argument)
|
||||
*/
|
||||
void addSwitchValue(std::shared_ptr<Renderable> renderable, double maxDistance);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Renderable>> _renderables;
|
||||
std::vector<double> _maxDistances;
|
||||
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // openspace
|
||||
|
||||
#endif //__DISTANCESWITCH_H__
|
||||
#endif //__OPENSPACE_MODULE_GLOBEBROWSING_DISTANCESWITCH_H__
|
||||
|
||||
@@ -22,12 +22,101 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include <modules/globebrowsing/other/statscollector.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
StatsCollector::StatsCollector(const std::string& filename, int dumpEveryXRecord,
|
||||
Enabled enabled, const std::string & delimiter)
|
||||
: _filename(filename)
|
||||
, _dumpEveryXRecord(dumpEveryXRecord)
|
||||
, _recordsSinceLastDump(0)
|
||||
, _enabled(enabled)
|
||||
, _delimiter(delimiter)
|
||||
, _hasWrittenHeader(false)
|
||||
, i(TemplatedStatsCollector<long long>(_enabled, delimiter))
|
||||
, d(TemplatedStatsCollector<double>(_enabled, delimiter))
|
||||
{}
|
||||
|
||||
StatsCollector::~StatsCollector() {
|
||||
dumpToDisk();
|
||||
}
|
||||
|
||||
void StatsCollector::startNewRecord() {
|
||||
if (_enabled) {
|
||||
if (_dumpEveryXRecord && ++_recordsSinceLastDump >= _dumpEveryXRecord) {
|
||||
dumpToDisk();
|
||||
_recordsSinceLastDump = 0;
|
||||
}
|
||||
|
||||
i.startNewRecord();
|
||||
d.startNewRecord();
|
||||
}
|
||||
}
|
||||
|
||||
void StatsCollector::setEnabled(bool enabled) {
|
||||
_enabled = enabled;
|
||||
}
|
||||
|
||||
void StatsCollector::disable() {
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
void StatsCollector::enable() {
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
int StatsCollector::hasHeaders() {
|
||||
return i.hasHeaders() || d.hasHeaders();
|
||||
}
|
||||
|
||||
void StatsCollector::dumpToDisk() {
|
||||
if (_enabled && hasHeaders()) {
|
||||
if (!_hasWrittenHeader) {
|
||||
writeHeader();
|
||||
}
|
||||
writeData();
|
||||
}
|
||||
}
|
||||
|
||||
void StatsCollector::writeHeader() {
|
||||
std::ofstream ofs(_filename);
|
||||
if (i.hasHeaders()) {
|
||||
i.writeHeader(ofs);
|
||||
if (d.hasHeaders()) {
|
||||
ofs << _delimiter;
|
||||
d.writeHeader(ofs);
|
||||
}
|
||||
}
|
||||
else {
|
||||
d.writeHeader(ofs);
|
||||
}
|
||||
_hasWrittenHeader = true;
|
||||
ofs << std::endl;
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
void StatsCollector::writeData() {
|
||||
std::ofstream ofs(_filename, std::ofstream::out | std::ofstream::app);
|
||||
ofs << std::setprecision(32);
|
||||
while (i.hasRecordsToWrite() || d.hasRecordsToWrite()) {
|
||||
if (i.hasHeaders() && d.hasHeaders()) {
|
||||
i.writeNextRecord(ofs); ofs << _delimiter; d.writeNextRecord(ofs);
|
||||
}
|
||||
else {
|
||||
i.writeNextRecord(ofs); d.writeNextRecord(ofs);
|
||||
}
|
||||
ofs << std::endl;
|
||||
}
|
||||
i.reset();
|
||||
d.reset();
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
} // namespace openspace
|
||||
|
||||
@@ -21,264 +21,103 @@
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
#ifndef __STATS_TRACKER_H__
|
||||
#define __STATS_TRACKER_H__
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_STATS_TRACKER_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_STATS_TRACKER_H__
|
||||
|
||||
#include <ghoul/misc/boolean.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/filesystem/filesystem>
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
template <typename T>
|
||||
struct StatsRecord : public std::unordered_map<std::string, T> {
|
||||
template <typename T>
|
||||
using StatsRecord = std::unordered_map<std::string, T>;
|
||||
|
||||
};
|
||||
template <typename T>
|
||||
struct StatsCollection : public std::vector<StatsRecord<T>> {
|
||||
std::set<std::string> keys;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct StatsCollection : public std::vector<StatsRecord<T>> {
|
||||
std::set<std::string> keys;
|
||||
};
|
||||
template <typename T>
|
||||
class TemplatedStatsCollector {
|
||||
public:
|
||||
TemplatedStatsCollector(bool& enabled, const std::string& delimiter);
|
||||
|
||||
template <typename T> class TemplatedStatsCollector{
|
||||
public:
|
||||
~TemplatedStatsCollector() = default;
|
||||
|
||||
TemplatedStatsCollector(bool& enabled, const std::string& delimiter)
|
||||
: _enabled(enabled)
|
||||
, _delimiter(delimiter)
|
||||
, _writePos(0) { };
|
||||
void startNewRecord();
|
||||
|
||||
~TemplatedStatsCollector() { };
|
||||
T& operator[](const std::string& name);
|
||||
|
||||
void startNewRecord() {
|
||||
if(_enabled)
|
||||
_data.push_back(StatsRecord<T>());
|
||||
}
|
||||
T previous(const std::string& name);
|
||||
|
||||
T& operator[](const std::string& name) {
|
||||
if (_enabled) {
|
||||
_data.keys.insert(name);
|
||||
return _data.back()[name];
|
||||
}
|
||||
else return _dummy;
|
||||
}
|
||||
bool hasHeaders();
|
||||
|
||||
T previous(const std::string& name) {
|
||||
if (_data.size() > 1) {
|
||||
return _data[_data.size() - 2][name];
|
||||
}
|
||||
return T();
|
||||
}
|
||||
bool hasRecordsToWrite();
|
||||
|
||||
bool hasHeaders() {
|
||||
return _data.keys.size() > 0;
|
||||
}
|
||||
void reset();
|
||||
|
||||
bool hasRecordsToWrite() {
|
||||
return _writePos < _data.size() - 1;
|
||||
}
|
||||
void writeHeader(std::ostream& os);
|
||||
|
||||
void reset() {
|
||||
// copy last, i.e. current record
|
||||
StatsRecord<T> lastRecord = _data.back();
|
||||
_data.clear();
|
||||
// add it again after cleared the vector
|
||||
_data.push_back(lastRecord);
|
||||
_writePos = 0;
|
||||
|
||||
}
|
||||
void writeNextRecord(std::ostream& os);
|
||||
|
||||
void writeHeader(std::ostream& os) {
|
||||
auto keyIt = _data.keys.begin();
|
||||
os << *keyIt;
|
||||
while (++keyIt != _data.keys.end()) {
|
||||
os << _delimiter << *keyIt;
|
||||
}
|
||||
}
|
||||
private:
|
||||
StatsCollection<T> _data;
|
||||
T _dummy; // used when disabled
|
||||
bool& _enabled;
|
||||
|
||||
void writeNextRecord(std::ostream& os) {
|
||||
if (hasRecordsToWrite()) {
|
||||
// output line by line
|
||||
StatsRecord<T>& record = _data[_writePos];
|
||||
size_t _writePos;
|
||||
std::string _delimiter;
|
||||
};
|
||||
|
||||
// Access every key. Records with no entry will get a default value
|
||||
auto keyIt = _data.keys.begin();
|
||||
if (keyIt != _data.keys.end()) {
|
||||
os << record[(*keyIt)];
|
||||
while (++keyIt != _data.keys.end()) {
|
||||
os << _delimiter << record[(*keyIt)];
|
||||
}
|
||||
}
|
||||
class StatsCollector {
|
||||
public:
|
||||
StatsCollector() = delete;
|
||||
|
||||
_writePos++;
|
||||
}
|
||||
}
|
||||
using Enabled = ghoul::Boolean;
|
||||
|
||||
private:
|
||||
StatsCollector(const std::string& filename, int dumpEveryXRecord,
|
||||
Enabled enabled = Enabled::Yes, const std::string& delimiter = ",");
|
||||
|
||||
~StatsCollector();
|
||||
|
||||
StatsCollection<T> _data;
|
||||
T _dummy; // used when disabled
|
||||
bool& _enabled;
|
||||
void startNewRecord();
|
||||
|
||||
size_t _writePos;
|
||||
std::string _delimiter;
|
||||
};
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
class StatsCollector {
|
||||
void disable();
|
||||
|
||||
public:
|
||||
void enable();
|
||||
|
||||
StatsCollector() = delete;
|
||||
int hasHeaders();
|
||||
|
||||
using Enabled = ghoul::Boolean;
|
||||
void dumpToDisk();
|
||||
|
||||
StatsCollector(const std::string& filename, int dumpEveryXRecord, Enabled enabled = Enabled::Yes, const std::string& delimiter = ",")
|
||||
: _filename(filename)
|
||||
, _dumpEveryXRecord(dumpEveryXRecord)
|
||||
, _recordsSinceLastDump(0)
|
||||
, _enabled(enabled)
|
||||
, _delimiter(delimiter)
|
||||
, _hasWrittenHeader(false)
|
||||
, i(TemplatedStatsCollector<long long>(_enabled, delimiter))
|
||||
, d(TemplatedStatsCollector<double>(_enabled, delimiter))
|
||||
{
|
||||
TemplatedStatsCollector<long long> i;
|
||||
TemplatedStatsCollector<double> d;
|
||||
|
||||
};
|
||||
private:
|
||||
void writeHeader();
|
||||
|
||||
~StatsCollector() {
|
||||
dumpToDisk();
|
||||
}
|
||||
|
||||
void startNewRecord() {
|
||||
if (_enabled) {
|
||||
if (_dumpEveryXRecord && ++_recordsSinceLastDump >= _dumpEveryXRecord) {
|
||||
dumpToDisk();
|
||||
_recordsSinceLastDump = 0;
|
||||
}
|
||||
void writeData();
|
||||
|
||||
i.startNewRecord();
|
||||
d.startNewRecord();
|
||||
}
|
||||
}
|
||||
std::string _filename;
|
||||
std::string _delimiter;
|
||||
|
||||
void setEnabled(bool enabled){
|
||||
_enabled = enabled;
|
||||
}
|
||||
int _dumpEveryXRecord;
|
||||
int _recordsSinceLastDump;
|
||||
|
||||
void disable() {
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
void enable() {
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
int hasHeaders() {
|
||||
return i.hasHeaders() || d.hasHeaders();
|
||||
}
|
||||
|
||||
void dumpToDisk() {
|
||||
if (_enabled && hasHeaders()) {
|
||||
if (!_hasWrittenHeader) {
|
||||
writeHeader();
|
||||
}
|
||||
writeData();
|
||||
}
|
||||
}
|
||||
|
||||
TemplatedStatsCollector<long long> i;
|
||||
TemplatedStatsCollector<double> d;
|
||||
|
||||
private:
|
||||
void writeHeader() {
|
||||
std::ofstream ofs(_filename);
|
||||
if (i.hasHeaders()) {
|
||||
i.writeHeader(ofs);
|
||||
if (d.hasHeaders()) {
|
||||
ofs << _delimiter;
|
||||
d.writeHeader(ofs);
|
||||
}
|
||||
}
|
||||
else {
|
||||
d.writeHeader(ofs);
|
||||
}
|
||||
_hasWrittenHeader = true;
|
||||
ofs << std::endl;
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
void writeData() {
|
||||
std::ofstream ofs(_filename, std::ofstream::out | std::ofstream::app);
|
||||
ofs << std::setprecision(32);
|
||||
while (i.hasRecordsToWrite() || d.hasRecordsToWrite()) {
|
||||
if (i.hasHeaders() && d.hasHeaders()) {
|
||||
i.writeNextRecord(ofs); ofs << _delimiter; d.writeNextRecord(ofs);
|
||||
}
|
||||
else {
|
||||
i.writeNextRecord(ofs); d.writeNextRecord(ofs);
|
||||
}
|
||||
ofs << std::endl;
|
||||
}
|
||||
i.reset(); d.reset();
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
std::string _filename;
|
||||
std::string _delimiter;
|
||||
|
||||
int _dumpEveryXRecord;
|
||||
int _recordsSinceLastDump;
|
||||
|
||||
bool _enabled;
|
||||
bool _hasWrittenHeader;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
template <typename T>
|
||||
struct StatsCsvWriter {
|
||||
StatsCsvWriter(const std::string& delimiter)
|
||||
: _delimiter(delimiter) { };
|
||||
|
||||
virtual void write(const StatsCollection<T>& stats, const std::string& filename) {
|
||||
std::ofstream ofs(filename);
|
||||
|
||||
// output headers
|
||||
auto keyIt = stats.keys.begin();
|
||||
ofs << *keyIt;
|
||||
while (keyIt++ != stats.keys.end()) {
|
||||
ofs << _delimiter << *keyIt;
|
||||
}
|
||||
ofs << std::endl;
|
||||
|
||||
// output line by line
|
||||
for (const StatsRecord<T>& record : stats) {
|
||||
// Access every key. Records with no entry will get a default value
|
||||
auto keyIt = stats.keys.begin();
|
||||
ofs << record[*keyIt];
|
||||
while (keyIt++ != stats.keys.end()) {
|
||||
ofs << _delimiter << record[*keyIt];
|
||||
}
|
||||
ofs << std::endl;
|
||||
}
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _delimiter;
|
||||
};
|
||||
*/
|
||||
bool _enabled;
|
||||
bool _hasWrittenHeader;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __STATS_TRACKER_H__
|
||||
#include "statscollector.inl"
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_STATS_TRACKER_H__
|
||||
|
||||
113
modules/globebrowsing/other/statscollector.inl
Normal file
113
modules/globebrowsing/other/statscollector.inl
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "statscollector.h"
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
template <typename T>
|
||||
TemplatedStatsCollector<T>::TemplatedStatsCollector(bool& enabled,
|
||||
const std::string& delimiter)
|
||||
: _enabled(enabled)
|
||||
, _delimiter(delimiter)
|
||||
, _writePos(0)
|
||||
{}
|
||||
|
||||
template <typename T>
|
||||
void TemplatedStatsCollector<T>::startNewRecord() {
|
||||
if (_enabled) {
|
||||
_data.push_back(StatsRecord<T>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& TemplatedStatsCollector<T>::operator[](const std::string& name) {
|
||||
if (_enabled) {
|
||||
_data.keys.insert(name);
|
||||
return _data.back()[name];
|
||||
}
|
||||
else {
|
||||
return _dummy;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T TemplatedStatsCollector<T>::previous(const std::string& name) {
|
||||
if (_data.size() > 1) {
|
||||
return _data[_data.size() - 2][name];
|
||||
}
|
||||
return T();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool TemplatedStatsCollector<T>::hasHeaders() {
|
||||
return _data.keys.size() > 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool TemplatedStatsCollector<T>::hasRecordsToWrite() {
|
||||
return _writePos < _data.size() - 1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void TemplatedStatsCollector<T>::reset() {
|
||||
// copy last, i.e. current record
|
||||
StatsRecord<T> lastRecord = _data.back();
|
||||
_data.clear();
|
||||
// add it again after cleared the vector
|
||||
_data.push_back(lastRecord);
|
||||
_writePos = 0;
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void TemplatedStatsCollector<T>::writeHeader(std::ostream& os) {
|
||||
auto keyIt = _data.keys.begin();
|
||||
os << *keyIt;
|
||||
while (++keyIt != _data.keys.end()) {
|
||||
os << _delimiter << *keyIt;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void TemplatedStatsCollector<T>::writeNextRecord(std::ostream& os) {
|
||||
if (hasRecordsToWrite()) {
|
||||
// output line by line
|
||||
StatsRecord<T>& record = _data[_writePos];
|
||||
|
||||
// Access every key. Records with no entry will get a default value
|
||||
auto keyIt = _data.keys.begin();
|
||||
if (keyIt != _data.keys.end()) {
|
||||
os << record[(*keyIt)];
|
||||
while (++keyIt != _data.keys.end()) {
|
||||
os << _delimiter << record[(*keyIt)];
|
||||
}
|
||||
}
|
||||
|
||||
_writePos++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
@@ -22,94 +22,82 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
|
||||
#include <modules/globebrowsing/other/concurrentqueue.h>
|
||||
#include <modules/globebrowsing/other/threadpool.h>
|
||||
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
Worker::Worker(ThreadPool& pool)
|
||||
: pool(pool)
|
||||
{
|
||||
Worker::Worker(ThreadPool& pool)
|
||||
: pool(pool)
|
||||
{}
|
||||
|
||||
void Worker::operator()() {
|
||||
std::function<void()> task;
|
||||
while (true) {
|
||||
// acquire lock
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(pool.queue_mutex);
|
||||
|
||||
// look for a work item
|
||||
while (!pool.stop && pool.tasks.empty()) {
|
||||
// if there are none wait for notification
|
||||
pool.condition.wait(lock);
|
||||
}
|
||||
|
||||
if (pool.stop) { // exit if the pool is stopped
|
||||
return;
|
||||
}
|
||||
|
||||
// get the task from the queue
|
||||
task = pool.tasks.front();
|
||||
pool.tasks.pop_front();
|
||||
|
||||
}// release lock
|
||||
|
||||
// execute the task
|
||||
task();
|
||||
}
|
||||
}
|
||||
|
||||
void Worker::operator()() {
|
||||
std::function<void()> task;
|
||||
while (true) {
|
||||
|
||||
// acquire lock
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(pool.queue_mutex);
|
||||
|
||||
// look for a work item
|
||||
while (!pool.stop && pool.tasks.empty()) {
|
||||
// if there are none wait for notification
|
||||
pool.condition.wait(lock);
|
||||
}
|
||||
|
||||
if (pool.stop) { // exit if the pool is stopped
|
||||
return;
|
||||
}
|
||||
|
||||
// get the task from the queue
|
||||
task = pool.tasks.front();
|
||||
pool.tasks.pop_front();
|
||||
|
||||
}// release lock
|
||||
|
||||
// execute the task
|
||||
task();
|
||||
}
|
||||
ThreadPool::ThreadPool(size_t numThreads)
|
||||
: stop(false)
|
||||
{
|
||||
for (size_t i = 0; i < numThreads; ++i) {
|
||||
workers.push_back(std::thread(Worker(*this)));
|
||||
}
|
||||
}
|
||||
|
||||
ThreadPool::ThreadPool(size_t numThreads)
|
||||
: stop(false)
|
||||
{
|
||||
for (size_t i = 0; i < numThreads; ++i) {
|
||||
workers.push_back(std::thread(Worker(*this)));
|
||||
}
|
||||
// the destructor joins all threads
|
||||
ThreadPool::~ThreadPool() {
|
||||
// stop all threads
|
||||
stop = true;
|
||||
condition.notify_all();
|
||||
|
||||
// join them
|
||||
for (size_t i = 0; i < workers.size(); ++i) {
|
||||
workers[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
// the destructor joins all threads
|
||||
ThreadPool::~ThreadPool() {
|
||||
// stop all threads
|
||||
stop = true;
|
||||
condition.notify_all();
|
||||
// add new work item to the pool
|
||||
void ThreadPool::enqueue(std::function<void()> f) {
|
||||
{ // acquire lock
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
|
||||
// join them
|
||||
for (size_t i = 0; i < workers.size(); ++i) {
|
||||
workers[i].join();
|
||||
}
|
||||
}
|
||||
// add the task
|
||||
tasks.push_back(f);
|
||||
} // release lock
|
||||
|
||||
// add new work item to the pool
|
||||
void ThreadPool::enqueue(std::function<void()> f) {
|
||||
{ // acquire lock
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
// wake up one thread
|
||||
condition.notify_one();
|
||||
}
|
||||
|
||||
// add the task
|
||||
tasks.push_back(f);
|
||||
} // release lock
|
||||
|
||||
// wake up one thread
|
||||
condition.notify_one();
|
||||
}
|
||||
|
||||
void ThreadPool::clearTasks() {
|
||||
{ // acquire lock
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
tasks.clear();
|
||||
} // release lock
|
||||
}
|
||||
void ThreadPool::clearTasks() {
|
||||
{ // acquire lock
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
tasks.clear();
|
||||
} // release lock
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
} // namespace openspace
|
||||
|
||||
@@ -22,56 +22,52 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __THREAD_POOL_H__
|
||||
#define __THREAD_POOL_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_THREAD_POOL_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_THREAD_POOL_H__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include <modules/globebrowsing/other/concurrentqueue.h>
|
||||
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
// Implementatin based on http://progsch.net/wordpress/?p=81
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
class ThreadPool;
|
||||
class ThreadPool;
|
||||
|
||||
class Worker {
|
||||
public:
|
||||
Worker(ThreadPool& pool);
|
||||
void operator()();
|
||||
private:
|
||||
ThreadPool& pool;
|
||||
};
|
||||
class Worker {
|
||||
public:
|
||||
Worker(ThreadPool& pool);
|
||||
void operator()();
|
||||
private:
|
||||
ThreadPool& pool;
|
||||
};
|
||||
|
||||
class ThreadPool {
|
||||
public:
|
||||
ThreadPool(size_t numThreads);
|
||||
~ThreadPool();
|
||||
class ThreadPool {
|
||||
public:
|
||||
ThreadPool(size_t numThreads);
|
||||
~ThreadPool();
|
||||
|
||||
void enqueue(std::function<void()> f);
|
||||
void clearTasks();
|
||||
void enqueue(std::function<void()> f);
|
||||
void clearTasks();
|
||||
|
||||
private:
|
||||
friend class Worker;
|
||||
private:
|
||||
friend class Worker;
|
||||
|
||||
std::vector<std::thread> workers;
|
||||
std::vector<std::thread> workers;
|
||||
|
||||
std::deque<std::function<void()>> tasks;
|
||||
std::deque<std::function<void()>> tasks;
|
||||
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable condition;
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable condition;
|
||||
|
||||
bool stop;
|
||||
};
|
||||
bool stop;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __THREAD_POOL_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_THREAD_POOL_H__
|
||||
|
||||
@@ -1,314 +1,297 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/globes/chunkedlodglobe.h>
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
#include <modules/globebrowsing/tile/chunktile.h>
|
||||
#include <modules/globebrowsing/rendering/chunkrenderer.h>
|
||||
#include <modules/globebrowsing/rendering/layermanager.h>
|
||||
|
||||
// open space includes
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
|
||||
// ghoul includes
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
|
||||
// STL includes
|
||||
#include <sstream>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <modules/globebrowsing/chunk/chunk.h>
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
#include <modules/globebrowsing/meshes/grid.h>
|
||||
#include <modules/globebrowsing/rendering/layershadermanager.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "ChunkRenderer";
|
||||
const char* keyFrame = "Frame";
|
||||
const char* keyGeometry = "Geometry";
|
||||
const char* keyShading = "PerformShading";
|
||||
|
||||
const std::string keyFrame = "Frame";
|
||||
const std::string keyGeometry = "Geometry";
|
||||
const std::string keyShading = "PerformShading";
|
||||
|
||||
const std::string keyBody = "Body";
|
||||
const char* keyBody = "Body";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
ChunkRenderer::ChunkRenderer(
|
||||
std::shared_ptr<Grid> grid,
|
||||
std::shared_ptr<LayerManager> layerManager)
|
||||
: _layerManager(layerManager)
|
||||
, _grid(grid)
|
||||
{
|
||||
_globalLayerShaderManager = std::make_shared<LayerShaderManager>(
|
||||
"GlobalChunkedLodPatch",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/globalchunkedlodpatch_vs.glsl",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/globalchunkedlodpatch_fs.glsl");
|
||||
ChunkRenderer::ChunkRenderer(std::shared_ptr<Grid> grid,
|
||||
std::shared_ptr<LayerManager> layerManager)
|
||||
: _layerManager(layerManager)
|
||||
, _grid(grid)
|
||||
{
|
||||
_globalLayerShaderManager = std::make_shared<LayerShaderManager>(
|
||||
"GlobalChunkedLodPatch",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/globalchunkedlodpatch_vs.glsl",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/globalchunkedlodpatch_fs.glsl");
|
||||
|
||||
_localLayerShaderManager = std::make_shared<LayerShaderManager>(
|
||||
"LocalChunkedLodPatch",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/localchunkedlodpatch_vs.glsl",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/localchunkedlodpatch_fs.glsl");
|
||||
_localLayerShaderManager = std::make_shared<LayerShaderManager>(
|
||||
"LocalChunkedLodPatch",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/localchunkedlodpatch_vs.glsl",
|
||||
"${MODULE_GLOBEBROWSING}/shaders/localchunkedlodpatch_fs.glsl");
|
||||
|
||||
_globalGpuLayerManager = std::make_shared<GPULayerManager>();
|
||||
_localGpuLayerManager = std::make_shared<GPULayerManager>();
|
||||
_globalGpuLayerManager = std::make_shared<GPULayerManager>();
|
||||
_localGpuLayerManager = std::make_shared<GPULayerManager>();
|
||||
|
||||
}
|
||||
|
||||
void ChunkRenderer::renderChunk(const Chunk& chunk, const RenderData& data) {
|
||||
// A little arbitrary with 10 but it works
|
||||
if (chunk.owner().debugProperties().onlyModelSpaceRendering || chunk.tileIndex().level < 10) {
|
||||
renderChunkGlobally(chunk, data);
|
||||
}
|
||||
else {
|
||||
renderChunkLocally(chunk, data);
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkRenderer::update() {
|
||||
// unused atm. Could be used for caching or precalculating
|
||||
}
|
||||
|
||||
ghoul::opengl::ProgramObject* ChunkRenderer::getActivatedProgramWithTileData(
|
||||
std::shared_ptr<LayerShaderManager> layeredShaderManager,
|
||||
std::shared_ptr<GPULayerManager> gpuLayerManager,
|
||||
const Chunk& chunk)
|
||||
{
|
||||
const TileIndex& tileIndex = chunk.tileIndex();
|
||||
|
||||
LayerShaderPreprocessingData layeredTexturePreprocessingData;
|
||||
|
||||
for (size_t i = 0; i < LayerManager::NUM_LAYER_GROUPS; i++) {
|
||||
LayerGroupPreprocessingData layeredTextureInfo;
|
||||
auto layerGroup = _layerManager->layerGroup(i);
|
||||
layeredTextureInfo.lastLayerIdx = layerGroup.activeLayers().size() - 1;
|
||||
layeredTextureInfo.layerBlendingEnabled = layerGroup.layerBlendingEnabled();
|
||||
|
||||
layeredTexturePreprocessingData.layeredTextureInfo[i] = layeredTextureInfo;
|
||||
}
|
||||
|
||||
const auto& generalProps = chunk.owner().generalProperties();
|
||||
const auto& debugProps = chunk.owner().debugProperties();
|
||||
auto& pairs = layeredTexturePreprocessingData.keyValuePairs;
|
||||
|
||||
pairs.push_back(std::make_pair("useAtmosphere",
|
||||
std::to_string(generalProps.atmosphereEnabled)));
|
||||
pairs.push_back(std::make_pair("performShading",
|
||||
std::to_string(generalProps.performShading)));
|
||||
pairs.push_back(std::make_pair("showChunkEdges",
|
||||
std::to_string(debugProps.showChunkEdges)));
|
||||
pairs.push_back(std::make_pair("showHeightResolution",
|
||||
std::to_string(debugProps.showHeightResolution)));
|
||||
pairs.push_back(std::make_pair("showHeightIntensities",
|
||||
std::to_string(debugProps.showHeightIntensities)));
|
||||
pairs.push_back(std::make_pair("defaultHeight",
|
||||
std::to_string(Chunk::DEFAULT_HEIGHT)));
|
||||
|
||||
// Now the shader program can be accessed
|
||||
ProgramObject* programObject =
|
||||
layeredShaderManager->programObject(
|
||||
layeredTexturePreprocessingData);
|
||||
|
||||
if (layeredShaderManager->updatedOnLastCall()) {
|
||||
gpuLayerManager->bind(programObject, *_layerManager);
|
||||
}
|
||||
|
||||
void ChunkRenderer::renderChunk(const Chunk& chunk, const RenderData& data) {
|
||||
// A little arbitrary with 10 but it works
|
||||
if (chunk.owner().debugProperties().onlyModelSpaceRendering || chunk.tileIndex().level < 10) {
|
||||
renderChunkGlobally(chunk, data);
|
||||
}
|
||||
else {
|
||||
renderChunkLocally(chunk, data);
|
||||
}
|
||||
// Activate the shader program
|
||||
programObject->activate();
|
||||
|
||||
gpuLayerManager->setValue(programObject, *_layerManager, tileIndex);
|
||||
|
||||
// The length of the skirts is proportional to its size
|
||||
// TODO: Skirt length should probably be proportional to the size reffered to by
|
||||
// the chunk's most high resolution height map.
|
||||
programObject->setUniform("skirtLength",
|
||||
glm::min(static_cast<float>(chunk.surfacePatch().halfSize().lat * 1000000),
|
||||
8700.0f));
|
||||
programObject->setUniform("xSegments", _grid->xSegments());
|
||||
|
||||
if (chunk.owner().debugProperties().showHeightResolution) {
|
||||
programObject->setUniform("vertexResolution",
|
||||
glm::vec2(_grid->xSegments(), _grid->ySegments()));
|
||||
}
|
||||
|
||||
return programObject;
|
||||
}
|
||||
|
||||
void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& data){
|
||||
|
||||
ProgramObject* programObject = getActivatedProgramWithTileData(
|
||||
_globalLayerShaderManager,
|
||||
_globalGpuLayerManager,
|
||||
chunk);
|
||||
if (programObject == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
void ChunkRenderer::update() {
|
||||
// unused atm. Could be used for caching or precalculating
|
||||
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
|
||||
|
||||
if (_layerManager->hasAnyBlendingLayersEnabled()) {
|
||||
// Calculations are done in the reference frame of the globe. Hence, the
|
||||
// camera position needs to be transformed with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
glm::dvec3 cameraPosition = glm::dvec3(
|
||||
inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
|
||||
float distanceScaleFactor = chunk.owner().generalProperties().lodScaleFactor *
|
||||
ellipsoid.minimumRadius();
|
||||
programObject->setUniform("cameraPosition", glm::vec3(cameraPosition));
|
||||
programObject->setUniform("distanceScaleFactor", distanceScaleFactor);
|
||||
programObject->setUniform("chunkLevel", chunk.tileIndex().level);
|
||||
}
|
||||
|
||||
ProgramObject* ChunkRenderer::getActivatedProgramWithTileData(
|
||||
std::shared_ptr<LayerShaderManager> layeredShaderManager,
|
||||
std::shared_ptr<GPULayerManager> gpuLayerManager,
|
||||
const Chunk& chunk)
|
||||
{
|
||||
const TileIndex& tileIndex = chunk.tileIndex();
|
||||
|
||||
LayerShaderPreprocessingData layeredTexturePreprocessingData;
|
||||
|
||||
for (size_t i = 0; i < LayerManager::NUM_LAYER_GROUPS; i++) {
|
||||
LayerGroupPreprocessingData layeredTextureInfo;
|
||||
auto layerGroup = _layerManager->layerGroup(i);
|
||||
layeredTextureInfo.lastLayerIdx = layerGroup.activeLayers().size() - 1;
|
||||
layeredTextureInfo.layerBlendingEnabled = layerGroup.layerBlendingEnabled();
|
||||
|
||||
layeredTexturePreprocessingData.layeredTextureInfo[i] = layeredTextureInfo;
|
||||
}
|
||||
// Calculate other uniform variables needed for rendering
|
||||
Geodetic2 swCorner = chunk.surfacePatch().getCorner(Quad::SOUTH_WEST);
|
||||
auto patchSize = chunk.surfacePatch().size();
|
||||
|
||||
const auto& generalProps = chunk.owner().generalProperties();
|
||||
const auto& debugProps = chunk.owner().debugProperties();
|
||||
auto& pairs = layeredTexturePreprocessingData.keyValuePairs;
|
||||
|
||||
pairs.push_back(std::make_pair("useAtmosphere",
|
||||
std::to_string(generalProps.atmosphereEnabled)));
|
||||
pairs.push_back(std::make_pair("performShading",
|
||||
std::to_string(generalProps.performShading)));
|
||||
pairs.push_back(std::make_pair("showChunkEdges",
|
||||
std::to_string(debugProps.showChunkEdges)));
|
||||
pairs.push_back(std::make_pair("showHeightResolution",
|
||||
std::to_string(debugProps.showHeightResolution)));
|
||||
pairs.push_back(std::make_pair("showHeightIntensities",
|
||||
std::to_string(debugProps.showHeightIntensities)));
|
||||
pairs.push_back(std::make_pair("defaultHeight",
|
||||
std::to_string(Chunk::DEFAULT_HEIGHT)));
|
||||
glm::dmat4 modelTransform = chunk.owner().modelTransform();
|
||||
glm::dmat4 viewTransform = data.camera.combinedViewMatrix();
|
||||
glm::mat4 modelViewTransform = glm::mat4(viewTransform * modelTransform);
|
||||
glm::mat4 modelViewProjectionTransform = data.camera.projectionMatrix() *
|
||||
modelViewTransform;
|
||||
|
||||
// Now the shader program can be accessed
|
||||
ProgramObject* programObject =
|
||||
layeredShaderManager->programObject(
|
||||
layeredTexturePreprocessingData);
|
||||
|
||||
if (layeredShaderManager->updatedOnLastCall()) {
|
||||
gpuLayerManager->bind(programObject, *_layerManager);
|
||||
}
|
||||
// Upload the uniform variables
|
||||
programObject->setUniform(
|
||||
"modelViewProjectionTransform", modelViewProjectionTransform);
|
||||
programObject->setUniform("minLatLon", glm::vec2(swCorner.toLonLatVec2()));
|
||||
programObject->setUniform("lonLatScalingFactor", glm::vec2(patchSize.toLonLatVec2()));
|
||||
programObject->setUniform("radiiSquared", glm::vec3(ellipsoid.radiiSquared()));
|
||||
|
||||
// Activate the shader program
|
||||
programObject->activate();
|
||||
|
||||
gpuLayerManager->setValue(programObject, *_layerManager, tileIndex);
|
||||
|
||||
// The length of the skirts is proportional to its size
|
||||
// TODO: Skirt length should probably be proportional to the size reffered to by
|
||||
// the chunk's most high resolution height map.
|
||||
programObject->setUniform("skirtLength",
|
||||
min(static_cast<float>(chunk.surfacePatch().halfSize().lat * 1000000),
|
||||
8700.0f));
|
||||
programObject->setUniform("xSegments", _grid->xSegments());
|
||||
|
||||
if (chunk.owner().debugProperties().showHeightResolution) {
|
||||
programObject->setUniform("vertexResolution",
|
||||
glm::vec2(_grid->xSegments(), _grid->ySegments()));
|
||||
}
|
||||
|
||||
return programObject;
|
||||
}
|
||||
|
||||
void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& data){
|
||||
|
||||
ProgramObject* programObject = getActivatedProgramWithTileData(
|
||||
_globalLayerShaderManager,
|
||||
_globalGpuLayerManager,
|
||||
chunk);
|
||||
if (programObject == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
|
||||
|
||||
if (_layerManager->hasAnyBlendingLayersEnabled()) {
|
||||
// Calculations are done in the reference frame of the globe. Hence, the
|
||||
// camera position needs to be transformed with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform();
|
||||
glm::dvec3 cameraPosition = glm::dvec3(
|
||||
inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1));
|
||||
float distanceScaleFactor = chunk.owner().generalProperties().lodScaleFactor *
|
||||
ellipsoid.minimumRadius();
|
||||
programObject->setUniform("cameraPosition", vec3(cameraPosition));
|
||||
programObject->setUniform("distanceScaleFactor", distanceScaleFactor);
|
||||
programObject->setUniform("chunkLevel", chunk.tileIndex().level);
|
||||
}
|
||||
|
||||
// Calculate other uniform variables needed for rendering
|
||||
Geodetic2 swCorner = chunk.surfacePatch().getCorner(Quad::SOUTH_WEST);
|
||||
auto patchSize = chunk.surfacePatch().size();
|
||||
|
||||
dmat4 modelTransform = chunk.owner().modelTransform();
|
||||
dmat4 viewTransform = data.camera.combinedViewMatrix();
|
||||
mat4 modelViewTransform = mat4(viewTransform * modelTransform);
|
||||
mat4 modelViewProjectionTransform = data.camera.projectionMatrix() *
|
||||
modelViewTransform;
|
||||
|
||||
// Upload the uniform variables
|
||||
if (_layerManager->layerGroup(
|
||||
LayerManager::NightLayers).activeLayers().size() > 0 ||
|
||||
_layerManager->layerGroup(
|
||||
LayerManager::WaterMasks).activeLayers().size() > 0 ||
|
||||
chunk.owner().generalProperties().atmosphereEnabled ||
|
||||
chunk.owner().generalProperties().performShading) {
|
||||
// This code temporary until real light sources can be implemented.
|
||||
glm::vec3 directionToSunWorldSpace =
|
||||
glm::normalize(-data.modelTransform.translation);
|
||||
glm::vec3 directionToSunCameraSpace =
|
||||
(viewTransform * glm::dvec4(directionToSunWorldSpace, 0));
|
||||
data.modelTransform.translation;
|
||||
programObject->setUniform("modelViewTransform", modelViewTransform);
|
||||
programObject->setUniform(
|
||||
"modelViewProjectionTransform", modelViewProjectionTransform);
|
||||
programObject->setUniform("minLatLon", vec2(swCorner.toLonLatVec2()));
|
||||
programObject->setUniform("lonLatScalingFactor", vec2(patchSize.toLonLatVec2()));
|
||||
programObject->setUniform("radiiSquared", vec3(ellipsoid.radiiSquared()));
|
||||
"lightDirectionCameraSpace", -directionToSunCameraSpace);
|
||||
}
|
||||
|
||||
if (_layerManager->layerGroup(
|
||||
LayerManager::NightLayers).activeLayers().size() > 0 ||
|
||||
_layerManager->layerGroup(
|
||||
LayerManager::WaterMasks).activeLayers().size() > 0 ||
|
||||
chunk.owner().generalProperties().atmosphereEnabled ||
|
||||
chunk.owner().generalProperties().performShading) {
|
||||
// This code temporary until real light sources can be implemented.
|
||||
glm::vec3 directionToSunWorldSpace =
|
||||
glm::normalize(-data.modelTransform.translation);
|
||||
glm::vec3 directionToSunCameraSpace =
|
||||
(viewTransform * glm::dvec4(directionToSunWorldSpace, 0));
|
||||
data.modelTransform.translation;
|
||||
programObject->setUniform("modelViewTransform", modelViewTransform);
|
||||
programObject->setUniform(
|
||||
"lightDirectionCameraSpace", -directionToSunCameraSpace);
|
||||
}
|
||||
// OpenGL rendering settings
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
// OpenGL rendering settings
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
// render
|
||||
_grid->geometry().drawUsingActiveProgram();
|
||||
// render
|
||||
_grid->geometry().drawUsingActiveProgram();
|
||||
|
||||
_globalGpuLayerManager->deactivate();
|
||||
_globalGpuLayerManager->deactivate();
|
||||
|
||||
// disable shader
|
||||
programObject->deactivate();
|
||||
// disable shader
|
||||
programObject->deactivate();
|
||||
|
||||
}
|
||||
|
||||
void ChunkRenderer::renderChunkLocally(const Chunk& chunk, const RenderData& data) {
|
||||
|
||||
ProgramObject* programObject = getActivatedProgramWithTileData(
|
||||
_localLayerShaderManager,
|
||||
_localGpuLayerManager,
|
||||
chunk);
|
||||
if (programObject == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
void ChunkRenderer::renderChunkLocally(const Chunk& chunk, const RenderData& data) {
|
||||
|
||||
ProgramObject* programObject = getActivatedProgramWithTileData(
|
||||
_localLayerShaderManager,
|
||||
_localGpuLayerManager,
|
||||
chunk);
|
||||
if (programObject == nullptr) {
|
||||
return;
|
||||
}
|
||||
using namespace glm;
|
||||
|
||||
using namespace glm;
|
||||
|
||||
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
|
||||
const Ellipsoid& ellipsoid = chunk.owner().ellipsoid();
|
||||
|
||||
|
||||
if (_layerManager->hasAnyBlendingLayersEnabled()) {
|
||||
float distanceScaleFactor = chunk.owner().generalProperties().lodScaleFactor *
|
||||
chunk.owner().ellipsoid().minimumRadius();
|
||||
programObject->setUniform("distanceScaleFactor", distanceScaleFactor);
|
||||
programObject->setUniform("chunkLevel", chunk.tileIndex().level);
|
||||
}
|
||||
|
||||
// Calculate other uniform variables needed for rendering
|
||||
dmat4 modelTransform = chunk.owner().modelTransform();
|
||||
dmat4 viewTransform = data.camera.combinedViewMatrix();
|
||||
dmat4 modelViewTransform = viewTransform * modelTransform;
|
||||
|
||||
std::vector<std::string> cornerNames = { "p01", "p11", "p00", "p10" };
|
||||
std::vector<Vec3> cornersCameraSpace(4);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
Quad q = (Quad)i;
|
||||
Geodetic2 corner = chunk.surfacePatch().getCorner(q);
|
||||
Vec3 cornerModelSpace = ellipsoid.cartesianSurfacePosition(corner);
|
||||
Vec3 cornerCameraSpace =
|
||||
Vec3(dmat4(modelViewTransform) * glm::dvec4(cornerModelSpace, 1));
|
||||
cornersCameraSpace[i] = cornerCameraSpace;
|
||||
programObject->setUniform(cornerNames[i], vec3(cornerCameraSpace));
|
||||
}
|
||||
|
||||
// TODO: Patch normal can be calculated for all corners and then linearly
|
||||
// interpolated on the GPU to avoid cracks for high altitudes.
|
||||
vec3 patchNormalCameraSpace = normalize(
|
||||
cross(cornersCameraSpace[Quad::SOUTH_EAST] -
|
||||
cornersCameraSpace[Quad::SOUTH_WEST],
|
||||
cornersCameraSpace[Quad::NORTH_EAST] -
|
||||
cornersCameraSpace[Quad::SOUTH_WEST]));
|
||||
|
||||
programObject->setUniform("patchNormalCameraSpace", patchNormalCameraSpace);
|
||||
programObject->setUniform("projectionTransform", data.camera.projectionMatrix());
|
||||
|
||||
if (_layerManager->layerGroup(
|
||||
LayerManager::NightLayers).activeLayers().size() > 0 ||
|
||||
_layerManager->layerGroup(
|
||||
LayerManager::WaterMasks).activeLayers().size() > 0 ||
|
||||
chunk.owner().generalProperties().atmosphereEnabled ||
|
||||
chunk.owner().generalProperties().performShading)
|
||||
{
|
||||
glm::vec3 directionToSunWorldSpace =
|
||||
glm::normalize(-data.modelTransform.translation);
|
||||
glm::vec3 directionToSunCameraSpace =
|
||||
(viewTransform * glm::dvec4(directionToSunWorldSpace, 0));
|
||||
data.modelTransform.translation;
|
||||
programObject->setUniform(
|
||||
"lightDirectionCameraSpace", -directionToSunCameraSpace);
|
||||
}
|
||||
|
||||
// OpenGL rendering settings
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
// render
|
||||
_grid->geometry().drawUsingActiveProgram();
|
||||
|
||||
_localGpuLayerManager->deactivate();
|
||||
|
||||
// disable shader
|
||||
programObject->deactivate();
|
||||
if (_layerManager->hasAnyBlendingLayersEnabled()) {
|
||||
float distanceScaleFactor = chunk.owner().generalProperties().lodScaleFactor *
|
||||
chunk.owner().ellipsoid().minimumRadius();
|
||||
programObject->setUniform("distanceScaleFactor", distanceScaleFactor);
|
||||
programObject->setUniform("chunkLevel", chunk.tileIndex().level);
|
||||
}
|
||||
|
||||
// Calculate other uniform variables needed for rendering
|
||||
dmat4 modelTransform = chunk.owner().modelTransform();
|
||||
dmat4 viewTransform = data.camera.combinedViewMatrix();
|
||||
dmat4 modelViewTransform = viewTransform * modelTransform;
|
||||
|
||||
std::vector<std::string> cornerNames = { "p01", "p11", "p00", "p10" };
|
||||
std::vector<glm::dvec3> cornersCameraSpace(4);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
Quad q = (Quad)i;
|
||||
Geodetic2 corner = chunk.surfacePatch().getCorner(q);
|
||||
glm::dvec3 cornerModelSpace = ellipsoid.cartesianSurfacePosition(corner);
|
||||
glm::dvec3 cornerCameraSpace =
|
||||
glm::dvec3(dmat4(modelViewTransform) * glm::dvec4(cornerModelSpace, 1));
|
||||
cornersCameraSpace[i] = cornerCameraSpace;
|
||||
programObject->setUniform(cornerNames[i], vec3(cornerCameraSpace));
|
||||
}
|
||||
|
||||
// TODO: Patch normal can be calculated for all corners and then linearly
|
||||
// interpolated on the GPU to avoid cracks for high altitudes.
|
||||
vec3 patchNormalCameraSpace = normalize(
|
||||
cross(cornersCameraSpace[Quad::SOUTH_EAST] -
|
||||
cornersCameraSpace[Quad::SOUTH_WEST],
|
||||
cornersCameraSpace[Quad::NORTH_EAST] -
|
||||
cornersCameraSpace[Quad::SOUTH_WEST]));
|
||||
|
||||
programObject->setUniform("patchNormalCameraSpace", patchNormalCameraSpace);
|
||||
programObject->setUniform("projectionTransform", data.camera.projectionMatrix());
|
||||
|
||||
if (_layerManager->layerGroup(
|
||||
LayerManager::NightLayers).activeLayers().size() > 0 ||
|
||||
_layerManager->layerGroup(
|
||||
LayerManager::WaterMasks).activeLayers().size() > 0 ||
|
||||
chunk.owner().generalProperties().atmosphereEnabled ||
|
||||
chunk.owner().generalProperties().performShading)
|
||||
{
|
||||
glm::vec3 directionToSunWorldSpace =
|
||||
glm::normalize(-data.modelTransform.translation);
|
||||
glm::vec3 directionToSunCameraSpace =
|
||||
(viewTransform * glm::dvec4(directionToSunWorldSpace, 0));
|
||||
data.modelTransform.translation;
|
||||
programObject->setUniform(
|
||||
"lightDirectionCameraSpace", -directionToSunCameraSpace);
|
||||
}
|
||||
|
||||
// OpenGL rendering settings
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
// render
|
||||
_grid->geometry().drawUsingActiveProgram();
|
||||
|
||||
_localGpuLayerManager->deactivate();
|
||||
|
||||
// disable shader
|
||||
programObject->deactivate();
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,109 +1,103 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __CHUNK_RENDERER_H__
|
||||
#define __CHUNK_RENDERER_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_RENDERER_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_RENDERER_H__
|
||||
|
||||
#include <memory>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
// open space includes
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/geometry/ellipsoid.h>
|
||||
#include <modules/globebrowsing/meshes/grid.h>
|
||||
#include <modules/globebrowsing/rendering/layershadermanager.h>
|
||||
#include <modules/globebrowsing/tile/tileselector.h>
|
||||
#include <modules/globebrowsing/chunk/chunknode.h>
|
||||
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
|
||||
namespace ghoul {
|
||||
namespace opengl {
|
||||
namespace ghoul { namespace opengl {
|
||||
class ProgramObject;
|
||||
}
|
||||
}
|
||||
} }
|
||||
|
||||
namespace openspace {
|
||||
|
||||
struct RenderData;
|
||||
|
||||
namespace globebrowsing {
|
||||
|
||||
class ChunkRenderer {
|
||||
public:
|
||||
ChunkRenderer(std::shared_ptr<Grid> grid,
|
||||
std::shared_ptr<LayerManager> layerManager);
|
||||
class Chunk;
|
||||
class Grid;
|
||||
class GPULayerManager;
|
||||
class LayerManager;
|
||||
class LayerShaderManager;
|
||||
|
||||
/**
|
||||
Chooses to render a chunk either locally or globally depending on the chunklevel
|
||||
of the <code>Chunk</code>.
|
||||
*/
|
||||
void renderChunk(const Chunk& chunk, const RenderData& data);
|
||||
void update();
|
||||
class ChunkRenderer {
|
||||
public:
|
||||
ChunkRenderer(std::shared_ptr<Grid> grid,
|
||||
std::shared_ptr<LayerManager> layerManager);
|
||||
|
||||
private:
|
||||
/**
|
||||
Chunks can be rendered either globally or locally. Global rendering is performed
|
||||
in the model space of the globe. With global rendering, the vertex positions
|
||||
of a chunk are calculated in the vertex shader by transforming the geodetic
|
||||
coordinates of the chunk to model space coordinates. We can only achieve floating
|
||||
point precision by doing this which means that the camera too close to a global
|
||||
tile will lead to jagging. We only render global chunks for lower chunk levels.
|
||||
*/
|
||||
void renderChunkGlobally(const Chunk& chunk, const RenderData& data);
|
||||
/**
|
||||
* Chooses to render a chunk either locally or globally depending on the chunklevel
|
||||
* of the <code>Chunk</code>.
|
||||
*/
|
||||
void renderChunk(const Chunk& chunk, const RenderData& data);
|
||||
void update();
|
||||
|
||||
/**
|
||||
Local rendering of chunks are done using linear interpolation in camera space.
|
||||
All four corner points of the chunk are calculated in double precision on the
|
||||
CPU and transformed to camera space with double precision matrix transforms.
|
||||
These positions can then be cast to floats and uploaded to the vertex shader.
|
||||
The vertex shader rendering performs linear interpolation between the four
|
||||
corner points to get the resulting chunk. This means that there will be an error
|
||||
due to the curvature of the globe. The smaller the patch is (with higher chunk
|
||||
levels) the better the approximation becomes. This is why we only render local
|
||||
chunks for higher chunk levels.
|
||||
*/
|
||||
void renderChunkLocally(const Chunk& chunk, const RenderData& data);
|
||||
private:
|
||||
/**
|
||||
* Chunks can be rendered either globally or locally. Global rendering is performed
|
||||
* in the model space of the globe. With global rendering, the vertex positions
|
||||
* of a chunk are calculated in the vertex shader by transforming the geodetic
|
||||
* coordinates of the chunk to model space coordinates. We can only achieve floating
|
||||
* point precision by doing this which means that the camera too close to a global
|
||||
* tile will lead to jagging. We only render global chunks for lower chunk levels.
|
||||
*/
|
||||
void renderChunkGlobally(const Chunk& chunk, const RenderData& data);
|
||||
|
||||
/**
|
||||
* Local rendering of chunks are done using linear interpolation in camera space.
|
||||
* All four corner points of the chunk are calculated in double precision on the
|
||||
* CPU and transformed to camera space with double precision matrix transforms.
|
||||
* These positions can then be cast to floats and uploaded to the vertex shader.
|
||||
* The vertex shader rendering performs linear interpolation between the four
|
||||
* corner points to get the resulting chunk. This means that there will be an error
|
||||
* due to the curvature of the globe. The smaller the patch is (with higher chunk
|
||||
* levels) the better the approximation becomes. This is why we only render local
|
||||
* chunks for higher chunk levels.
|
||||
*/
|
||||
void renderChunkLocally(const Chunk& chunk, const RenderData& data);
|
||||
|
||||
ProgramObject* getActivatedProgramWithTileData(
|
||||
std::shared_ptr<LayerShaderManager> layeredShaderManager,
|
||||
std::shared_ptr<GPULayerManager> gpuLayerManager,
|
||||
const Chunk& chunk);
|
||||
ghoul::opengl::ProgramObject* getActivatedProgramWithTileData(
|
||||
std::shared_ptr<LayerShaderManager> layeredShaderManager,
|
||||
std::shared_ptr<GPULayerManager> gpuLayerManager,
|
||||
const Chunk& chunk);
|
||||
|
||||
// shared pointer to a grid which can be the same for all rendered chunks.
|
||||
std::shared_ptr<Grid> _grid;
|
||||
std::shared_ptr<LayerManager> _layerManager;
|
||||
// shared pointer to a grid which can be the same for all rendered chunks.
|
||||
std::shared_ptr<Grid> _grid;
|
||||
std::shared_ptr<LayerManager> _layerManager;
|
||||
|
||||
// Two different shader programs. One for global and one for local rendering.
|
||||
std::shared_ptr<LayerShaderManager> _globalLayerShaderManager;
|
||||
std::shared_ptr<LayerShaderManager> _localLayerShaderManager;
|
||||
// Two different shader programs. One for global and one for local rendering.
|
||||
std::shared_ptr<LayerShaderManager> _globalLayerShaderManager;
|
||||
std::shared_ptr<LayerShaderManager> _localLayerShaderManager;
|
||||
|
||||
// Layered texture uniforms are chached in the uniform ID handles.
|
||||
std::shared_ptr<GPULayerManager> _globalGpuLayerManager;
|
||||
std::shared_ptr<GPULayerManager> _localGpuLayerManager;
|
||||
};
|
||||
// Layered texture uniforms are chached in the uniform ID handles.
|
||||
std::shared_ptr<GPULayerManager> _globalGpuLayerManager;
|
||||
std::shared_ptr<GPULayerManager> _localGpuLayerManager;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __CHUNK_RENDERER_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNK_RENDERER_H__
|
||||
|
||||
@@ -1,56 +1,41 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/tile/tileIndex.h>
|
||||
#include <modules/globebrowsing/tile/chunktile.h>
|
||||
#include <modules/globebrowsing/tile/tileselector.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
* *
|
||||
* 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/rendering/gpulayermanager.h>
|
||||
|
||||
#include <modules/globebrowsing/rendering/layermanager.h>
|
||||
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "GPULayerManager";
|
||||
}
|
||||
#include <modules/globebrowsing/tile/chunktile.h>
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
#include <modules/globebrowsing/tile/tiledepthtransform.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
|
||||
// TileUvTransform
|
||||
|
||||
void GPUTileUvTransform::setValue(ProgramObject* programObject,
|
||||
const TileUvTransform& tileUvTransform){
|
||||
const TileUvTransform& tileUvTransform)
|
||||
{
|
||||
gpuUvOffset.setValue(programObject, tileUvTransform.uvOffset);
|
||||
gpuUvScale.setValue(programObject, tileUvTransform.uvScale);
|
||||
}
|
||||
@@ -60,173 +45,185 @@ void GPUTileUvTransform::bind(ProgramObject* programObject, const std::string& n
|
||||
gpuUvScale.bind(programObject, nameBase + "uvScale");
|
||||
}
|
||||
|
||||
|
||||
// TileDepthTransform
|
||||
|
||||
void GPUTileDepthTransform::setValue(ProgramObject* programObject,
|
||||
const TileDepthTransform& depthTransform){
|
||||
const TileDepthTransform& depthTransform)
|
||||
{
|
||||
gpuDepthOffset.setValue(programObject, depthTransform.depthOffset);
|
||||
gpuDepthScale.setValue(programObject, depthTransform.depthScale);
|
||||
}
|
||||
|
||||
void GPUTileDepthTransform::bind(ProgramObject* programObject, const std::string& nameBase){
|
||||
void GPUTileDepthTransform::bind(ProgramObject* programObject,
|
||||
const std::string& nameBase)
|
||||
{
|
||||
gpuDepthOffset.bind(programObject, nameBase + "depthOffset");
|
||||
gpuDepthScale.bind(programObject, nameBase + "depthScale");
|
||||
}
|
||||
|
||||
|
||||
// ChunkTile
|
||||
|
||||
void GPUChunkTile::setValue(ProgramObject* programObject, const ChunkTile& chunkTile){
|
||||
void GPUChunkTile::setValue(ProgramObject* programObject, const ChunkTile& chunkTile) {
|
||||
gpuTexture.setValue(programObject, chunkTile.tile.texture);
|
||||
gpuTileUvTransform.setValue(programObject, chunkTile.uvTransform);
|
||||
}
|
||||
|
||||
void GPUChunkTile::bind(ProgramObject* programObject, const std::string& nameBase){
|
||||
void GPUChunkTile::bind(ProgramObject* programObject, const std::string& nameBase) {
|
||||
gpuTexture.bind(programObject, nameBase + "textureSampler");
|
||||
gpuTileUvTransform.bind(programObject, nameBase + "uvTransform.");
|
||||
}
|
||||
|
||||
void GPUChunkTile::deactivate(){
|
||||
void GPUChunkTile::deactivate() {
|
||||
gpuTexture.deactivate();
|
||||
}
|
||||
|
||||
|
||||
// ChunkTilePile
|
||||
|
||||
void GPUChunkTilePile::setValue(ProgramObject* programObject, const ChunkTilePile& chunkTilePile){
|
||||
ghoul_assert(gpuChunkTiles.size() == chunkTilePile.chunkTiles.size(), "GPU and CPU ChunkTilePile must have same size!");
|
||||
for (size_t i = 0; i < gpuChunkTiles.size(); ++i){
|
||||
void GPUChunkTilePile::setValue(ProgramObject* programObject,
|
||||
const ChunkTilePile& chunkTilePile)
|
||||
{
|
||||
ghoul_assert(
|
||||
gpuChunkTiles.size() == chunkTilePile.chunkTiles.size(),
|
||||
"GPU and CPU ChunkTilePile must have same size!"
|
||||
);
|
||||
for (size_t i = 0; i < gpuChunkTiles.size(); ++i) {
|
||||
gpuChunkTiles[i].setValue(programObject, chunkTilePile.chunkTiles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUChunkTilePile::bind(ProgramObject* programObject, const std::string& nameBase,
|
||||
int pileSize){
|
||||
int pileSize)
|
||||
{
|
||||
gpuChunkTiles.resize(pileSize);
|
||||
for (size_t i = 0; i < gpuChunkTiles.size(); ++i){
|
||||
for (size_t i = 0; i < gpuChunkTiles.size(); ++i) {
|
||||
std::string nameExtension = "chunkTile" + std::to_string(i) + ".";
|
||||
gpuChunkTiles[i].bind(programObject, nameBase + nameExtension);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUChunkTilePile::deactivate(){
|
||||
for (auto& gpuChunkTile : gpuChunkTiles){
|
||||
void GPUChunkTilePile::deactivate() {
|
||||
for (auto& gpuChunkTile : gpuChunkTiles) {
|
||||
gpuChunkTile.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GPULayerRenderSettings::setValue(ProgramObject* programObject,
|
||||
const LayerRenderSettings& layerSettings){
|
||||
const LayerRenderSettings& layerSettings)
|
||||
{
|
||||
gpuOpacity.setValue(programObject, layerSettings.opacity.value());
|
||||
gpuGamma.setValue(programObject, layerSettings.gamma.value());
|
||||
gpuMultiplier.setValue(programObject, layerSettings.multiplier.value());
|
||||
}
|
||||
|
||||
void GPULayerRenderSettings::bind(ProgramObject* programObject, const std::string& nameBase){
|
||||
void GPULayerRenderSettings::bind(ProgramObject* programObject,
|
||||
const std::string& nameBase)
|
||||
{
|
||||
gpuOpacity.bind(programObject, nameBase + "opacity");
|
||||
gpuGamma.bind(programObject, nameBase + "gamma");
|
||||
gpuMultiplier.bind(programObject, nameBase + "multiplier");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Layer
|
||||
|
||||
void GPULayer::setValue(ProgramObject* programObject, const Layer& layer,
|
||||
const TileIndex& tileIndex, int pileSize){
|
||||
const TileIndex& tileIndex, int pileSize)
|
||||
{
|
||||
ChunkTilePile chunkTilePile = layer.getChunkTilePile(tileIndex, pileSize);
|
||||
gpuChunkTilePile.setValue(programObject, chunkTilePile);
|
||||
gpuRenderSettings.setValue(programObject, layer.renderSettings());
|
||||
}
|
||||
|
||||
void GPULayer::bind(ProgramObject* programObject, const Layer& layer,
|
||||
const std::string& nameBase, int pileSize){
|
||||
const std::string& nameBase, int pileSize)
|
||||
{
|
||||
gpuChunkTilePile.bind(programObject, nameBase + "pile.", pileSize);
|
||||
gpuRenderSettings.bind(programObject, nameBase + "settings.");
|
||||
}
|
||||
|
||||
void GPULayer::deactivate(){
|
||||
void GPULayer::deactivate() {
|
||||
gpuChunkTilePile.deactivate();
|
||||
}
|
||||
|
||||
|
||||
// Override behavior for HeightLayer
|
||||
|
||||
void GPUHeightLayer::setValue(ProgramObject* programObject, const Layer& layer,
|
||||
const TileIndex& tileIndex, int pileSize){
|
||||
const TileIndex& tileIndex, int pileSize)
|
||||
{
|
||||
GPULayer::setValue(programObject, layer, tileIndex, pileSize);
|
||||
gpuDepthTransform.setValue(programObject, layer.tileProvider()->depthTransform());
|
||||
}
|
||||
|
||||
void GPUHeightLayer::bind(ProgramObject* programObject, const Layer& layer, const std::string& nameBase, int pileSize){
|
||||
void GPUHeightLayer::bind(ProgramObject* programObject, const Layer& layer,
|
||||
const std::string& nameBase, int pileSize)
|
||||
{
|
||||
GPULayer::bind(programObject, layer, nameBase, pileSize);
|
||||
gpuDepthTransform.bind(programObject, nameBase + "depthTransform.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// LayerGroup
|
||||
|
||||
void GPULayerGroup::setValue(ProgramObject* programObject, const LayerGroup& layerGroup,
|
||||
const TileIndex& tileIndex){
|
||||
const TileIndex& tileIndex)
|
||||
{
|
||||
auto& activeLayers = layerGroup.activeLayers();
|
||||
ghoul_assert(activeLayers.size() == gpuActiveLayers.size(), "GPU and CPU active layers must have same size!");
|
||||
for (int i = 0; i < activeLayers.size(); ++i){
|
||||
gpuActiveLayers[i]->setValue(programObject, *activeLayers[i], tileIndex, layerGroup.pileSize());
|
||||
ghoul_assert(
|
||||
activeLayers.size() == gpuActiveLayers.size(),
|
||||
"GPU and CPU active layers must have same size!"
|
||||
);
|
||||
for (int i = 0; i < activeLayers.size(); ++i) {
|
||||
gpuActiveLayers[i]->setValue(
|
||||
programObject,
|
||||
*activeLayers[i],
|
||||
tileIndex,
|
||||
layerGroup.pileSize()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULayerGroup::bind(ProgramObject* programObject, const LayerGroup& layerGroup,
|
||||
const std::string& nameBase, int category){
|
||||
const std::string& nameBase, int category)
|
||||
{
|
||||
auto activeLayers = layerGroup.activeLayers();
|
||||
gpuActiveLayers.resize(activeLayers.size());
|
||||
int pileSize = layerGroup.pileSize();
|
||||
for (size_t i = 0; i < gpuActiveLayers.size(); ++i){
|
||||
for (size_t i = 0; i < gpuActiveLayers.size(); ++i) {
|
||||
// should maybe a proper GPULayer factory
|
||||
gpuActiveLayers[i] = category == LayerManager::HeightLayers ?
|
||||
gpuActiveLayers[i] = (category == LayerManager::HeightLayers) ?
|
||||
std::make_unique<GPUHeightLayer>() :
|
||||
std::make_unique<GPULayer>();
|
||||
std::string nameExtension = "[" + std::to_string(i) + "].";
|
||||
gpuActiveLayers[i]->bind(programObject, *activeLayers[i], nameBase + nameExtension, pileSize);
|
||||
gpuActiveLayers[i]->bind(
|
||||
programObject,
|
||||
*activeLayers[i],
|
||||
nameBase + nameExtension,
|
||||
pileSize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULayerGroup::deactivate(){
|
||||
for (size_t i = 0; i < gpuActiveLayers.size(); ++i){
|
||||
void GPULayerGroup::deactivate() {
|
||||
for (size_t i = 0; i < gpuActiveLayers.size(); ++i) {
|
||||
gpuActiveLayers[i]->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// LayerManager
|
||||
|
||||
void GPULayerManager::setValue(ProgramObject* programObject, const LayerManager& layerManager,
|
||||
const TileIndex& tileIndex){
|
||||
void GPULayerManager::setValue(ProgramObject* programObject,
|
||||
const LayerManager& layerManager,
|
||||
const TileIndex& tileIndex)
|
||||
{
|
||||
auto layerGroups = layerManager.layerGroups();
|
||||
for (size_t i = 0; i < layerGroups.size(); ++i){
|
||||
for (size_t i = 0; i < layerGroups.size(); ++i) {
|
||||
gpuLayerGroups[i]->setValue(programObject, *layerGroups[i], tileIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULayerManager::bind(ProgramObject* programObject, const LayerManager& layerManager){
|
||||
void GPULayerManager::bind(ProgramObject* programObject, const LayerManager& layerManager)
|
||||
{
|
||||
auto layerGroups = layerManager.layerGroups();
|
||||
if(gpuLayerGroups.size() != layerGroups.size()){
|
||||
if (gpuLayerGroups.size() != layerGroups.size()) {
|
||||
gpuLayerGroups.resize(layerGroups.size());
|
||||
for(auto& gpuLayerGroup : gpuLayerGroups){
|
||||
for (auto& gpuLayerGroup : gpuLayerGroups){
|
||||
gpuLayerGroup = std::make_unique<GPULayerGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < layerGroups.size(); ++i){
|
||||
for (size_t i = 0; i < layerGroups.size(); ++i) {
|
||||
std::string nameBase = LayerManager::LAYER_GROUP_NAMES[i];
|
||||
gpuLayerGroups[i]->bind(programObject, *layerGroups[i], nameBase, i);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULayerManager::deactivate(){
|
||||
for (size_t i = 0; i < gpuLayerGroups.size(); ++i){
|
||||
void GPULayerManager::deactivate() {
|
||||
for (size_t i = 0; i < gpuLayerGroups.size(); ++i) {
|
||||
gpuLayerGroups[i]->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +1,54 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __GPU_LAYER_MANAGER_H__
|
||||
#define __GPU_LAYER_MANAGER_H__
|
||||
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
#include <modules/globebrowsing/tile/chunktile.h>
|
||||
#include <modules/globebrowsing/rendering/layermanager.h>
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_GPU_LAYER_MANAGER_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_GPU_LAYER_MANAGER_H__
|
||||
|
||||
#include <openspace/util/gpudata.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ghoul{
|
||||
namespace opengl{
|
||||
class ProgramObject;
|
||||
}//namespace opengl
|
||||
}//namespace ghoul
|
||||
namespace ghoul { namespace opengl {
|
||||
class ProgramObject;
|
||||
}}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace ghoul::opengl;
|
||||
struct ChunkTile;
|
||||
struct ChunkTilePile;
|
||||
class Layer;
|
||||
class LayerRenderSettings;
|
||||
struct TileDepthTransform;
|
||||
struct TileIndex;
|
||||
struct TileUvTransform;
|
||||
|
||||
/**
|
||||
* Manages a GPU representation of a <code>TileUvTransform</code>
|
||||
*/
|
||||
class GPUTileUvTransform {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Sets the value of <code>TileUvTransform</code> to its corresponding
|
||||
* GPU struct. OBS! Users must ensure bind has been
|
||||
@@ -319,4 +316,5 @@ private:
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
#endif // __GPU_LAYER_MANAGER_H__
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_GPU_LAYER_MANAGER_H__
|
||||
|
||||
@@ -1,226 +1,194 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <openspace/util/factorymanager.h>
|
||||
#include <openspace/properties/scalarproperty.h>
|
||||
* *
|
||||
* 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/rendering/layermanager.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileselector.h>
|
||||
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include "cpl_minixml.h"
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "LayerManager";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
LayerRenderSettings::LayerRenderSettings()
|
||||
: opacity(properties::FloatProperty("opacity", "opacity", 1, 0, 1))
|
||||
, gamma(properties::FloatProperty("gamma", "gamma", 1, 0, 5))
|
||||
, multiplier(properties::FloatProperty("multiplier", "multiplier", 1, 0, 20))
|
||||
{
|
||||
setName("settings");
|
||||
addProperty(opacity);
|
||||
addProperty(gamma);
|
||||
addProperty(multiplier);
|
||||
}
|
||||
LayerRenderSettings::LayerRenderSettings()
|
||||
: opacity(properties::FloatProperty("opacity", "opacity", 1.f, 0.f, 1.f))
|
||||
, gamma(properties::FloatProperty("gamma", "gamma", 1, 0, 5))
|
||||
, multiplier(properties::FloatProperty("multiplier", "multiplier", 1.f, 0.f, 20.f))
|
||||
{
|
||||
setName("settings");
|
||||
|
||||
addProperty(opacity);
|
||||
addProperty(gamma);
|
||||
addProperty(multiplier);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Layer //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Layer::Layer(const ghoul::Dictionary& layerDict)
|
||||
: _enabled(properties::BoolProperty("enabled", "enabled", false))
|
||||
{
|
||||
std::string layerName = "error!";
|
||||
layerDict.getValue("Name", layerName);
|
||||
setName(layerName);
|
||||
Layer::Layer(const ghoul::Dictionary& layerDict)
|
||||
: _enabled(properties::BoolProperty("enabled", "enabled", false))
|
||||
{
|
||||
std::string layerName = "error!";
|
||||
layerDict.getValue("Name", layerName);
|
||||
setName(layerName);
|
||||
|
||||
_tileProvider = std::shared_ptr<TileProvider>(
|
||||
TileProvider::createFromDictionary(layerDict));
|
||||
_tileProvider = std::shared_ptr<TileProvider>(
|
||||
TileProvider::createFromDictionary(layerDict));
|
||||
|
||||
// Something else went wrong and no exception was thrown
|
||||
if (_tileProvider == nullptr) {
|
||||
throw ghoul::RuntimeError("Unable to create TileProvider '" + name() + "'");
|
||||
// Something else went wrong and no exception was thrown
|
||||
if (_tileProvider == nullptr) {
|
||||
throw ghoul::RuntimeError("Unable to create TileProvider '" + name() + "'");
|
||||
}
|
||||
|
||||
bool enabled = false; // defaults to false if unspecified
|
||||
layerDict.getValue("Enabled", enabled);
|
||||
_enabled.setValue(enabled);
|
||||
addProperty(_enabled);
|
||||
|
||||
addPropertySubOwner(_renderSettings);
|
||||
}
|
||||
|
||||
ChunkTilePile Layer::getChunkTilePile(const TileIndex& tileIndex, int pileSize) const {
|
||||
return std::move(_tileProvider->getChunkTilePile(tileIndex, pileSize));
|
||||
}
|
||||
|
||||
LayerGroup::LayerGroup(std::string name)
|
||||
: _levelBlendingEnabled("blendTileLevels", "blend tile levels", true)
|
||||
{
|
||||
setName(std::move(name));
|
||||
addProperty(_levelBlendingEnabled);
|
||||
}
|
||||
|
||||
LayerGroup::LayerGroup(std::string name, const ghoul::Dictionary& dict)
|
||||
: LayerGroup(std::move(name))
|
||||
{
|
||||
for (size_t i = 0; i < dict.size(); i++) {
|
||||
std::string dictKey = std::to_string(i + 1);
|
||||
ghoul::Dictionary layerDict = dict.value<ghoul::Dictionary>(dictKey);
|
||||
|
||||
try {
|
||||
_layers.push_back(std::make_shared<Layer>(layerDict));
|
||||
}
|
||||
|
||||
bool enabled = false; // defaults to false if unspecified
|
||||
layerDict.getValue("Enabled", enabled);
|
||||
_enabled.setValue(enabled);
|
||||
addProperty(_enabled);
|
||||
|
||||
addPropertySubOwner(_renderSettings);
|
||||
}
|
||||
|
||||
Layer::~Layer(){
|
||||
|
||||
}
|
||||
|
||||
ChunkTilePile Layer::getChunkTilePile(const TileIndex& tileIndex, int pileSize) const {
|
||||
return std::move(_tileProvider->getChunkTilePile(tileIndex, pileSize));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Layer Group //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LayerGroup::LayerGroup(std::string name)
|
||||
: _levelBlendingEnabled("blendTileLevels", "blend tile levels", true)
|
||||
{
|
||||
setName(name);
|
||||
addProperty(_levelBlendingEnabled);
|
||||
}
|
||||
|
||||
LayerGroup::LayerGroup(std::string name, const ghoul::Dictionary& dict)
|
||||
: LayerGroup(name)
|
||||
{
|
||||
for (size_t i = 0; i < dict.size(); i++) {
|
||||
std::string dictKey = std::to_string(i + 1);
|
||||
ghoul::Dictionary layerDict = dict.value<ghoul::Dictionary>(dictKey);
|
||||
|
||||
try {
|
||||
_layers.push_back(std::make_shared<Layer>(layerDict));
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERROR(e.what());
|
||||
continue;
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC(e.component, e.message);
|
||||
continue;
|
||||
}
|
||||
//_layers.push_back(std::make_shared<Layer>(layerDict));
|
||||
}
|
||||
|
||||
for(auto layer : _layers){
|
||||
addPropertySubOwner(layer.get());
|
||||
for (const auto& layer : _layers) {
|
||||
addPropertySubOwner(layer.get());
|
||||
}
|
||||
}
|
||||
|
||||
void LayerGroup::update() {
|
||||
_activeLayers.clear();
|
||||
|
||||
for (const auto& layer : _layers) {
|
||||
if (layer->enabled()) {
|
||||
layer->tileProvider()->update();
|
||||
_activeLayers.push_back(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LayerGroup::update() {
|
||||
_activeLayers.clear();
|
||||
const std::vector<std::shared_ptr<Layer>>& LayerGroup::layers() const {
|
||||
return _layers;
|
||||
}
|
||||
|
||||
for (auto layer : _layers) {
|
||||
if (layer->enabled()) {
|
||||
layer->tileProvider()->update();
|
||||
_activeLayers.push_back(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::shared_ptr<Layer>>& LayerGroup::layers() const {
|
||||
return _layers;
|
||||
}
|
||||
|
||||
const std::vector<std::shared_ptr<Layer>>& LayerGroup::activeLayers() const {
|
||||
return _activeLayers;
|
||||
}
|
||||
|
||||
int LayerGroup::pileSize() const{
|
||||
return _levelBlendingEnabled.value() ? 3 : 1;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// LayerManager //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const std::string LayerManager::LAYER_GROUP_NAMES[NUM_LAYER_GROUPS] = {
|
||||
"HeightLayers",
|
||||
"ColorLayers",
|
||||
"ColorOverlays",
|
||||
"GrayScaleLayers",
|
||||
"GrayScaleColorOverlays",
|
||||
"NightLayers",
|
||||
"WaterMasks",
|
||||
};
|
||||
|
||||
LayerManager::LayerManager(const ghoul::Dictionary& layerGroupsDict) {
|
||||
|
||||
setName("Layers");
|
||||
|
||||
if (NUM_LAYER_GROUPS != layerGroupsDict.size()) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Number of Layer Groups must be equal to " + NUM_LAYER_GROUPS);
|
||||
}
|
||||
// Create all the categories of tile providers
|
||||
for (size_t i = 0; i < layerGroupsDict.size(); i++) {
|
||||
std::string groupName = LayerManager::LAYER_GROUP_NAMES[i];
|
||||
ghoul::Dictionary layerGroupDict =
|
||||
layerGroupsDict.value<ghoul::Dictionary>(groupName);
|
||||
|
||||
_layerGroups.push_back(
|
||||
std::make_shared<LayerGroup>(groupName, layerGroupDict));
|
||||
}
|
||||
|
||||
for(auto layerGroup : _layerGroups){
|
||||
addPropertySubOwner(layerGroup.get());
|
||||
}
|
||||
}
|
||||
|
||||
LayerManager::~LayerManager(){
|
||||
|
||||
}
|
||||
|
||||
const LayerGroup& LayerManager::layerGroup(size_t groupId) {
|
||||
return *_layerGroups[groupId];
|
||||
}
|
||||
|
||||
const LayerGroup& LayerManager::layerGroup(LayerGroupId groupId) {
|
||||
return *_layerGroups[groupId];
|
||||
}
|
||||
|
||||
bool LayerManager::hasAnyBlendingLayersEnabled() const {
|
||||
for (const auto& layerGroup : _layerGroups){
|
||||
if (layerGroup->layerBlendingEnabled() &&
|
||||
layerGroup->activeLayers().size() > 0){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<std::shared_ptr<LayerGroup>>& LayerManager::layerGroups() const {
|
||||
return _layerGroups;
|
||||
}
|
||||
|
||||
|
||||
void LayerManager::update() {
|
||||
for (auto& layerGroup : _layerGroups) {
|
||||
layerGroup->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LayerManager::reset(bool includeDisabled) {
|
||||
for (auto& layerGroup : _layerGroups) {
|
||||
for (auto layer : layerGroup->layers()) {
|
||||
if (layer->enabled() || includeDisabled) {
|
||||
layer->tileProvider()->reset();
|
||||
}
|
||||
const std::vector<std::shared_ptr<Layer>>& LayerGroup::activeLayers() const {
|
||||
return _activeLayers;
|
||||
}
|
||||
|
||||
int LayerGroup::pileSize() const{
|
||||
return _levelBlendingEnabled.value() ? 3 : 1;
|
||||
}
|
||||
|
||||
const char* LayerManager::LAYER_GROUP_NAMES[NUM_LAYER_GROUPS] = {
|
||||
"HeightLayers",
|
||||
"ColorLayers",
|
||||
"ColorOverlays",
|
||||
"GrayScaleLayers",
|
||||
"GrayScaleColorOverlays",
|
||||
"NightLayers",
|
||||
"WaterMasks"
|
||||
};
|
||||
|
||||
LayerManager::LayerManager(const ghoul::Dictionary& layerGroupsDict) {
|
||||
setName("Layers");
|
||||
|
||||
if (NUM_LAYER_GROUPS != layerGroupsDict.size()) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Number of Layer Groups must be equal to " + NUM_LAYER_GROUPS);
|
||||
}
|
||||
|
||||
// Create all the categories of tile providers
|
||||
for (size_t i = 0; i < layerGroupsDict.size(); i++) {
|
||||
std::string groupName = LayerManager::LAYER_GROUP_NAMES[i];
|
||||
ghoul::Dictionary layerGroupDict =
|
||||
layerGroupsDict.value<ghoul::Dictionary>(groupName);
|
||||
|
||||
_layerGroups.push_back(
|
||||
std::make_shared<LayerGroup>(groupName, layerGroupDict));
|
||||
}
|
||||
|
||||
for (const auto& layerGroup : _layerGroups) {
|
||||
addPropertySubOwner(layerGroup.get());
|
||||
}
|
||||
}
|
||||
|
||||
const LayerGroup& LayerManager::layerGroup(size_t groupId) {
|
||||
return *_layerGroups[groupId];
|
||||
}
|
||||
|
||||
const LayerGroup& LayerManager::layerGroup(LayerGroupId groupId) {
|
||||
return *_layerGroups[groupId];
|
||||
}
|
||||
|
||||
bool LayerManager::hasAnyBlendingLayersEnabled() const {
|
||||
for (const auto& layerGroup : _layerGroups) {
|
||||
if (layerGroup->layerBlendingEnabled() && layerGroup->activeLayers().size() > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<std::shared_ptr<LayerGroup>>& LayerManager::layerGroups() const {
|
||||
return _layerGroups;
|
||||
}
|
||||
|
||||
void LayerManager::update() {
|
||||
for (auto& layerGroup : _layerGroups) {
|
||||
layerGroup->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LayerManager::reset(bool includeDisabled) {
|
||||
for (auto& layerGroup : _layerGroups) {
|
||||
for (auto layer : layerGroup->layers()) {
|
||||
if (layer->enabled() || includeDisabled) {
|
||||
layer->tileProvider()->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,137 +1,132 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __LAYERMANAGER_H__
|
||||
#define __LAYERMANAGER_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_LAYERMANAGER_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_LAYERMANAGER_H__
|
||||
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/chunktile.h>
|
||||
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
#include <openspace/properties/scalarproperty.h>
|
||||
#include <openspace/util/gpudata.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
class TileProvider;
|
||||
class TileProvider;
|
||||
|
||||
struct LayerRenderSettings : public properties::PropertyOwner{
|
||||
LayerRenderSettings();
|
||||
properties::FloatProperty opacity;
|
||||
properties::FloatProperty gamma;
|
||||
properties::FloatProperty multiplier;
|
||||
struct LayerRenderSettings : public properties::PropertyOwner {
|
||||
LayerRenderSettings();
|
||||
properties::FloatProperty opacity;
|
||||
properties::FloatProperty gamma;
|
||||
properties::FloatProperty multiplier;
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple struct which is used to enable/disable <code>TileProvider</code>
|
||||
* and associate is with a name. It also holds layer specific information
|
||||
* which is used in rendering of layer.
|
||||
*/
|
||||
class Layer : public properties::PropertyOwner {
|
||||
public:
|
||||
Layer(const ghoul::Dictionary& layerDict);
|
||||
|
||||
ChunkTilePile getChunkTilePile(const TileIndex& tileIndex, int pileSize) const;
|
||||
|
||||
bool enabled() const { return _enabled.value(); }
|
||||
TileProvider* tileProvider() const { return _tileProvider.get(); }
|
||||
const LayerRenderSettings& renderSettings() const { return _renderSettings; }
|
||||
|
||||
private:
|
||||
properties::BoolProperty _enabled;
|
||||
std::shared_ptr<TileProvider> _tileProvider;
|
||||
LayerRenderSettings _renderSettings;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience class for dealing with multiple <code>Layer</code>s.
|
||||
*/
|
||||
struct LayerGroup : public properties::PropertyOwner {
|
||||
LayerGroup(std::string name);
|
||||
LayerGroup(std::string name, const ghoul::Dictionary& dict);
|
||||
|
||||
/// Updates all layers tile providers within this group
|
||||
void update();
|
||||
|
||||
/// @returns const vector of all layers
|
||||
const std::vector<std::shared_ptr<Layer>>& layers() const;
|
||||
|
||||
/// @returns const vector of all active layers
|
||||
const std::vector<std::shared_ptr<Layer>>& activeLayers() const;
|
||||
|
||||
/// @returns the size of the pile to be used in rendering of this layer
|
||||
int pileSize() const;
|
||||
|
||||
bool layerBlendingEnabled() const { return _levelBlendingEnabled.value(); }
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Layer>> _layers;
|
||||
std::vector<std::shared_ptr<Layer>> _activeLayers;
|
||||
|
||||
properties::BoolProperty _levelBlendingEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages multiple LayerGroups.
|
||||
*/
|
||||
class LayerManager : public properties::PropertyOwner {
|
||||
public:
|
||||
static const size_t NUM_LAYER_GROUPS = 7;
|
||||
static const char* LAYER_GROUP_NAMES[NUM_LAYER_GROUPS];
|
||||
static enum LayerGroupId {
|
||||
HeightLayers,
|
||||
ColorLayers,
|
||||
ColorOverlays,
|
||||
GrayScaleLayers,
|
||||
GrayScaleColorOverlays,
|
||||
NightLayers,
|
||||
WaterMasks,
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple struct which is used to enable/disable <code>TileProvider</code>
|
||||
* and associate is with a name. It also holds layer specific information
|
||||
* which is used in rendering of layer.
|
||||
*/
|
||||
class Layer : public properties::PropertyOwner {
|
||||
public:
|
||||
Layer(const ghoul::Dictionary& layerDict);
|
||||
~Layer();
|
||||
LayerManager(const ghoul::Dictionary& textureCategoriesDictionary);
|
||||
|
||||
ChunkTilePile getChunkTilePile(const TileIndex& tileIndex, int pileSize) const;
|
||||
const LayerGroup& layerGroup(size_t groupId);
|
||||
const LayerGroup& layerGroup(LayerGroupId);
|
||||
|
||||
bool enabled() const { return _enabled.value(); }
|
||||
TileProvider* tileProvider() const { return _tileProvider.get(); }
|
||||
const LayerRenderSettings& renderSettings() const { return _renderSettings; }
|
||||
bool hasAnyBlendingLayersEnabled() const;
|
||||
|
||||
private:
|
||||
properties::BoolProperty _enabled;
|
||||
std::shared_ptr<TileProvider> _tileProvider;
|
||||
LayerRenderSettings _renderSettings;
|
||||
};
|
||||
const std::vector<std::shared_ptr<LayerGroup>>& layerGroups() const;
|
||||
|
||||
/**
|
||||
* Convenience class for dealing with multiple <code>Layer</code>s.
|
||||
*/
|
||||
struct LayerGroup : public properties::PropertyOwner {
|
||||
LayerGroup(std::string name);
|
||||
LayerGroup(std::string name, const ghoul::Dictionary& dict);
|
||||
void update();
|
||||
void reset(bool includingDisabled = false);
|
||||
|
||||
/// Updates all layers tile providers within this group
|
||||
void update();
|
||||
|
||||
/// @returns const vector of all layers
|
||||
const std::vector<std::shared_ptr<Layer>>& layers() const;
|
||||
|
||||
/// @returns const vector of all active layers
|
||||
const std::vector<std::shared_ptr<Layer>>& activeLayers() const;
|
||||
|
||||
/// @returns the size of the pile to be used in rendering of this layer
|
||||
int pileSize() const;
|
||||
|
||||
bool layerBlendingEnabled() const { return _levelBlendingEnabled.value(); }
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Layer>> _layers;
|
||||
std::vector<std::shared_ptr<Layer>> _activeLayers;
|
||||
|
||||
properties::BoolProperty _levelBlendingEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages multiple LayerGroups.
|
||||
*/
|
||||
class LayerManager : public properties::PropertyOwner {
|
||||
public:
|
||||
static const size_t NUM_LAYER_GROUPS = 7;
|
||||
static const std::string LAYER_GROUP_NAMES[NUM_LAYER_GROUPS];
|
||||
static enum LayerGroupId{
|
||||
HeightLayers,
|
||||
ColorLayers,
|
||||
ColorOverlays,
|
||||
GrayScaleLayers,
|
||||
GrayScaleColorOverlays,
|
||||
NightLayers,
|
||||
WaterMasks,
|
||||
};
|
||||
|
||||
LayerManager(const ghoul::Dictionary& textureCategoriesDictionary);
|
||||
~LayerManager();
|
||||
|
||||
const LayerGroup& layerGroup(size_t groupId);
|
||||
const LayerGroup& layerGroup(LayerGroupId);
|
||||
|
||||
bool hasAnyBlendingLayersEnabled() const;
|
||||
|
||||
const std::vector<std::shared_ptr<LayerGroup>>& layerGroups() const;
|
||||
|
||||
void update();
|
||||
void reset(bool includingDisabled = false);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<LayerGroup>> _layerGroups;
|
||||
};
|
||||
private:
|
||||
std::vector<std::shared_ptr<LayerGroup>> _layerGroups;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __LAYERMANAGER_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_LAYERMANAGER_H__
|
||||
|
||||
@@ -1,73 +1,57 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/tile/asynctilereader.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tiledataset.h>
|
||||
#include <modules/globebrowsing/tile/tilediskcache.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/angle.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "AsyncTextureDataProvider";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
void TileLoadJob::execute() {
|
||||
_rawTile = _tileDataset->readTileData(_chunkIndex);
|
||||
}
|
||||
void TileLoadJob::execute() {
|
||||
_rawTile = _tileDataset->readTileData(_chunkIndex);
|
||||
}
|
||||
|
||||
DiskCachedTileLoadJob::DiskCachedTileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
|
||||
const TileIndex& tileIndex, std::shared_ptr<TileDiskCache> tdc, CacheMode m)
|
||||
: TileLoadJob(textureDataProvider, tileIndex)
|
||||
, _tileDiskCache(tdc)
|
||||
, _mode(m)
|
||||
{
|
||||
std::shared_ptr<RawTile> TileLoadJob::product() const {
|
||||
return _rawTile;
|
||||
}
|
||||
|
||||
}
|
||||
DiskCachedTileLoadJob::DiskCachedTileLoadJob(
|
||||
std::shared_ptr<TileDataset> textureDataProvider,
|
||||
const TileIndex& tileIndex,
|
||||
std::shared_ptr<TileDiskCache> tdc,
|
||||
CacheMode m)
|
||||
: TileLoadJob(textureDataProvider, tileIndex)
|
||||
, _tileDiskCache(tdc)
|
||||
, _mode(m)
|
||||
{}
|
||||
|
||||
DiskCachedTileLoadJob::DiskCachedTileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
|
||||
const TileIndex& tileIndex, std::shared_ptr<TileDiskCache> tdc, const std::string cacheMode)
|
||||
: TileLoadJob(textureDataProvider, tileIndex)
|
||||
, _tileDiskCache(tdc)
|
||||
{
|
||||
if (cacheMode == "Disabled") _mode = CacheMode::Disabled;
|
||||
else if (cacheMode == "ReadOnly") _mode = CacheMode::ReadOnly;
|
||||
else if (cacheMode == "ReadAndWrite") _mode = CacheMode::ReadAndWrite;
|
||||
else if (cacheMode == "WriteOnly") _mode = CacheMode::WriteOnly;
|
||||
else if (cacheMode == "CacheHitsOnly") _mode = CacheMode::CacheHitsOnly;
|
||||
}
|
||||
void DiskCachedTileLoadJob::execute() {
|
||||
_rawTile = nullptr;
|
||||
|
||||
void DiskCachedTileLoadJob::execute() {
|
||||
_rawTile = nullptr;
|
||||
|
||||
switch (_mode) {
|
||||
switch (_mode) {
|
||||
case CacheMode::Disabled:
|
||||
_rawTile = _tileDataset->readTileData(_chunkIndex);
|
||||
break;
|
||||
@@ -100,72 +84,68 @@ namespace globebrowsing {
|
||||
_rawTile = std::make_shared<RawTile>(res);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AsyncTileDataProvider::AsyncTileDataProvider(
|
||||
std::shared_ptr<TileDataset> tileDataset,
|
||||
std::shared_ptr<ThreadPool> pool)
|
||||
: _tileDataset(tileDataset)
|
||||
, _concurrentJobManager(pool)
|
||||
{}
|
||||
AsyncTileDataProvider::AsyncTileDataProvider(std::shared_ptr<TileDataset> tileDataset,
|
||||
std::shared_ptr<ThreadPool> pool)
|
||||
: _tileDataset(tileDataset)
|
||||
, _concurrentJobManager(pool)
|
||||
{}
|
||||
|
||||
AsyncTileDataProvider::~AsyncTileDataProvider()
|
||||
{}
|
||||
std::shared_ptr<TileDataset> AsyncTileDataProvider::getTextureDataProvider() const {
|
||||
return _tileDataset;
|
||||
}
|
||||
|
||||
std::shared_ptr<TileDataset> AsyncTileDataProvider::getTextureDataProvider() const {
|
||||
return _tileDataset;
|
||||
bool AsyncTileDataProvider::enqueueTileIO(const TileIndex& tileIndex) {
|
||||
if (satisfiesEnqueueCriteria(tileIndex)) {
|
||||
auto job = std::make_shared<TileLoadJob>(_tileDataset, tileIndex);
|
||||
//auto job = std::make_shared<DiskCachedTileLoadJob>(_tileDataset, tileIndex, tileDiskCache, "ReadAndWrite");
|
||||
_concurrentJobManager.enqueueJob(job);
|
||||
_enqueuedTileRequests[tileIndex.hashKey()] = tileIndex;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AsyncTileDataProvider::enqueueTileIO(const TileIndex& tileIndex) {
|
||||
if (satisfiesEnqueueCriteria(tileIndex)) {
|
||||
auto job = std::make_shared<TileLoadJob>(_tileDataset, tileIndex);
|
||||
//auto job = std::make_shared<DiskCachedTileLoadJob>(_tileDataset, tileIndex, tileDiskCache, "ReadAndWrite");
|
||||
_concurrentJobManager.enqueueJob(job);
|
||||
_enqueuedTileRequests[tileIndex.hashKey()] = tileIndex;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
std::vector<std::shared_ptr<RawTile>> AsyncTileDataProvider::getRawTiles() {
|
||||
std::vector<std::shared_ptr<RawTile>> readyResults;
|
||||
while (_concurrentJobManager.numFinishedJobs() > 0) {
|
||||
readyResults.push_back(_concurrentJobManager.popFinishedJob()->product());
|
||||
}
|
||||
return readyResults;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<RawTile>> AsyncTileDataProvider::getRawTiles() {
|
||||
std::vector<std::shared_ptr<RawTile>> readyResults;
|
||||
while (_concurrentJobManager.numFinishedJobs() > 0) {
|
||||
readyResults.push_back(_concurrentJobManager.popFinishedJob()->product());
|
||||
}
|
||||
return readyResults;
|
||||
}
|
||||
bool AsyncTileDataProvider::satisfiesEnqueueCriteria(const TileIndex& tileIndex) const {
|
||||
// only allow tile to be enqueued if it's not already enqueued
|
||||
//return _futureTileIOResults.find(tileIndex.hashKey()) == _futureTileIOResults.end();
|
||||
return _enqueuedTileRequests.find(tileIndex.hashKey()) == _enqueuedTileRequests.end();
|
||||
|
||||
bool AsyncTileDataProvider::satisfiesEnqueueCriteria(const TileIndex& tileIndex) const {
|
||||
// only allow tile to be enqueued if it's not already enqueued
|
||||
//return _futureTileIOResults.find(tileIndex.hashKey()) == _futureTileIOResults.end();
|
||||
return _enqueuedTileRequests.find(tileIndex.hashKey()) == _enqueuedTileRequests.end();
|
||||
}
|
||||
|
||||
void AsyncTileDataProvider::reset() {
|
||||
//_futureTileIOResults.clear();
|
||||
//_threadPool->stop(ghoul::ThreadPool::RunRemainingTasks::No);
|
||||
//_threadPool->start();
|
||||
_enqueuedTileRequests.clear();
|
||||
_concurrentJobManager.reset();
|
||||
while (_concurrentJobManager.numFinishedJobs() > 0) {
|
||||
_concurrentJobManager.popFinishedJob();
|
||||
}
|
||||
getTextureDataProvider()->reset();
|
||||
}
|
||||
|
||||
void AsyncTileDataProvider::reset() {
|
||||
//_futureTileIOResults.clear();
|
||||
//_threadPool->stop(ghoul::ThreadPool::RunRemainingTasks::No);
|
||||
//_threadPool->start();
|
||||
_enqueuedTileRequests.clear();
|
||||
_concurrentJobManager.reset();
|
||||
while (_concurrentJobManager.numFinishedJobs() > 0) {
|
||||
_concurrentJobManager.popFinishedJob();
|
||||
}
|
||||
getTextureDataProvider()->reset();
|
||||
}
|
||||
void AsyncTileDataProvider::clearRequestQueue() {
|
||||
//_threadPool->clearRemainingTasks();
|
||||
//_futureTileIOResults.clear();
|
||||
_concurrentJobManager.clearEnqueuedJobs();
|
||||
_enqueuedTileRequests.clear();
|
||||
}
|
||||
|
||||
void AsyncTileDataProvider::clearRequestQueue() {
|
||||
//_threadPool->clearRemainingTasks();
|
||||
//_futureTileIOResults.clear();
|
||||
_concurrentJobManager.clearEnqueuedJobs();
|
||||
_enqueuedTileRequests.clear();
|
||||
}
|
||||
|
||||
float AsyncTileDataProvider::noDataValueAsFloat() {
|
||||
return _tileDataset->noDataValueAsFloat();
|
||||
}
|
||||
float AsyncTileDataProvider::noDataValueAsFloat() {
|
||||
return _tileDataset->noDataValueAsFloat();
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,134 +1,110 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __OPENSPACE_MODULE_GLOBEBROWSING_ASYNC_TILE_DATA_PROVIDER_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_ASYNC_TILE_DATA_PROVIDER_H__
|
||||
|
||||
#ifndef __ASYNC_TILE_DATA_PROVIDER_H__
|
||||
#define __ASYNC_TILE_DATA_PROVIDER_H__
|
||||
|
||||
//#include <modules/globebrowsing/other/tileprovider.h>
|
||||
|
||||
#include <ghoul/opengl/texture.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
#include <modules/globebrowsing/other/concurrentjobmanager.h>
|
||||
#include <modules/globebrowsing/other/threadpool.h>
|
||||
//#include <ghoul/misc/threadpool.h>
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tiledataset.h>
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <sstream>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
struct LoadJob : public Job<RawTile> {
|
||||
virtual void execute() = 0;
|
||||
virtual std::shared_ptr<RawTile> product() = 0;
|
||||
class TileDataset;
|
||||
|
||||
struct LoadJob : public Job<RawTile> {
|
||||
virtual void execute() = 0;
|
||||
virtual std::shared_ptr<RawTile> product() const = 0;
|
||||
};
|
||||
|
||||
struct TileLoadJob : LoadJob {
|
||||
TileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
|
||||
const TileIndex& tileIndex)
|
||||
: _tileDataset(textureDataProvider)
|
||||
, _chunkIndex(tileIndex)
|
||||
{}
|
||||
|
||||
virtual ~TileLoadJob() = default;
|
||||
|
||||
virtual void execute() override;
|
||||
|
||||
virtual std::shared_ptr<RawTile> product() const override;
|
||||
|
||||
protected:
|
||||
TileIndex _chunkIndex;
|
||||
std::shared_ptr<TileDataset> _tileDataset;
|
||||
std::shared_ptr<RawTile> _rawTile;
|
||||
};
|
||||
|
||||
class TileDiskCache;
|
||||
|
||||
struct DiskCachedTileLoadJob : public TileLoadJob {
|
||||
enum CacheMode {
|
||||
Disabled,
|
||||
ReadOnly,
|
||||
ReadAndWrite,
|
||||
WriteOnly,
|
||||
CacheHitsOnly,
|
||||
};
|
||||
|
||||
struct TileLoadJob : LoadJob {
|
||||
TileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
|
||||
const TileIndex& tileIndex)
|
||||
: _tileDataset(textureDataProvider)
|
||||
, _chunkIndex(tileIndex)
|
||||
{}
|
||||
|
||||
virtual ~TileLoadJob() { }
|
||||
|
||||
virtual void execute();
|
||||
|
||||
virtual std::shared_ptr<RawTile> product() {
|
||||
return _rawTile;
|
||||
}
|
||||
|
||||
protected:
|
||||
TileIndex _chunkIndex;
|
||||
std::shared_ptr<TileDataset> _tileDataset;
|
||||
std::shared_ptr<RawTile> _rawTile;
|
||||
};
|
||||
|
||||
class TileDiskCache;
|
||||
|
||||
struct DiskCachedTileLoadJob : public TileLoadJob {
|
||||
enum CacheMode {
|
||||
Disabled,
|
||||
ReadOnly,
|
||||
ReadAndWrite,
|
||||
WriteOnly,
|
||||
CacheHitsOnly,
|
||||
};
|
||||
|
||||
DiskCachedTileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
|
||||
const TileIndex& tileIndex, std::shared_ptr<TileDiskCache> tdc,
|
||||
const std::string cacheMode);
|
||||
DiskCachedTileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
|
||||
const TileIndex& tileIndex, std::shared_ptr<TileDiskCache> tdc,
|
||||
CacheMode cacheMode = CacheMode::ReadOnly);
|
||||
|
||||
DiskCachedTileLoadJob(std::shared_ptr<TileDataset> textureDataProvider,
|
||||
const TileIndex& tileIndex, std::shared_ptr<TileDiskCache> tdc,
|
||||
CacheMode cacheMode = CacheMode::ReadOnly);
|
||||
void execute() override;
|
||||
|
||||
virtual void execute();
|
||||
protected:
|
||||
std::shared_ptr<TileDiskCache> _tileDiskCache;
|
||||
CacheMode _mode;
|
||||
};
|
||||
|
||||
protected:
|
||||
std::shared_ptr<TileDiskCache> _tileDiskCache;
|
||||
CacheMode _mode;
|
||||
class AsyncTileDataProvider {
|
||||
public:
|
||||
AsyncTileDataProvider(std::shared_ptr<TileDataset> textureDataProvider,
|
||||
std::shared_ptr<ThreadPool> pool);
|
||||
|
||||
};
|
||||
|
||||
class AsyncTileDataProvider {
|
||||
public:
|
||||
AsyncTileDataProvider(std::shared_ptr<TileDataset> textureDataProvider,
|
||||
std::shared_ptr<ThreadPool> pool);
|
||||
|
||||
~AsyncTileDataProvider();
|
||||
|
||||
bool enqueueTileIO(const TileIndex& tileIndex);
|
||||
std::vector<std::shared_ptr<RawTile>> getRawTiles();
|
||||
bool enqueueTileIO(const TileIndex& tileIndex);
|
||||
std::vector<std::shared_ptr<RawTile>> getRawTiles();
|
||||
|
||||
void reset();
|
||||
void clearRequestQueue();
|
||||
void reset();
|
||||
void clearRequestQueue();
|
||||
|
||||
std::shared_ptr<TileDataset> getTextureDataProvider() const;
|
||||
float noDataValueAsFloat();
|
||||
std::shared_ptr<TileDataset> getTextureDataProvider() const;
|
||||
float noDataValueAsFloat();
|
||||
|
||||
protected:
|
||||
virtual bool satisfiesEnqueueCriteria(const TileIndex&) const;
|
||||
protected:
|
||||
virtual bool satisfiesEnqueueCriteria(const TileIndex&) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<TileDataset> _tileDataset;
|
||||
ConcurrentJobManager<RawTile> _concurrentJobManager;
|
||||
std::unordered_map<TileHashKey, TileIndex> _enqueuedTileRequests;
|
||||
};
|
||||
private:
|
||||
std::shared_ptr<TileDataset> _tileDataset;
|
||||
ConcurrentJobManager<RawTile> _concurrentJobManager;
|
||||
std::unordered_map<TileHashKey, TileIndex> _enqueuedTileRequests;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // __ASYNC_TILE_DATA_PROVIDER_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_ASYNC_TILE_DATA_PROVIDER_H__
|
||||
|
||||
@@ -1,37 +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/tile/chunktile.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "ChunkTile";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
@@ -1,52 +1,49 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 __TILEANDTRANSFORM_H__
|
||||
#define __TILEANDTRANSFORM_H__
|
||||
|
||||
* *
|
||||
* 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 __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKTILE_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKTILE_H__
|
||||
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
#include <modules/globebrowsing/tile/tiledepthtransform.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace ghoul::opengl;
|
||||
struct ChunkTile {
|
||||
Tile tile;
|
||||
TileUvTransform uvTransform;
|
||||
TileDepthTransform depthTransform;
|
||||
};
|
||||
|
||||
struct ChunkTile {
|
||||
Tile tile;
|
||||
TileUvTransform uvTransform;
|
||||
TileDepthTransform depthTransform;
|
||||
};
|
||||
|
||||
struct ChunkTilePile {
|
||||
std::vector<ChunkTile> chunkTiles;
|
||||
};
|
||||
struct ChunkTilePile {
|
||||
std::vector<ChunkTile> chunkTiles;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
#endif // __TILEANDTRANSFORM_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CHUNKTILE_H__
|
||||
|
||||
@@ -1,252 +1,255 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/tile/pixelregion.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "PixelRegion";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
PixelRegion::PixelRegion()
|
||||
: start(0)
|
||||
, numPixels(0)
|
||||
{}
|
||||
PixelRegion::PixelRegion(const PixelCoordinate& pixelStart,
|
||||
const PixelRange& numberOfPixels)
|
||||
: start(pixelStart)
|
||||
, numPixels(numberOfPixels)
|
||||
{}
|
||||
|
||||
PixelRegion::PixelRegion(const PixelRegion& o)
|
||||
: start(o.start)
|
||||
, numPixels(o.numPixels)
|
||||
{}
|
||||
PixelRegion::PixelRegion(const PixelRegion& o)
|
||||
: start(o.start)
|
||||
, numPixels(o.numPixels)
|
||||
{}
|
||||
|
||||
PixelRegion::PixelRegion(const PixelCoordinate& pixelStart, const PixelRange& numberOfPixels)
|
||||
: start(pixelStart)
|
||||
, numPixels(numberOfPixels)
|
||||
{}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Mutators //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PixelRegion::setSide(Side side, int pos) {
|
||||
switch (side) {
|
||||
case LEFT: setLeft(pos); break;
|
||||
case TOP: setTop(pos); break;
|
||||
case RIGHT: setRight(pos); break;
|
||||
case BOTTOM: setBottom(pos); break;
|
||||
}
|
||||
}
|
||||
|
||||
void PixelRegion::setLeft(int x) {
|
||||
numPixels.x += (start.x - x);
|
||||
start.x = x;
|
||||
}
|
||||
|
||||
void PixelRegion::setTop(int p) {
|
||||
numPixels.y += (start.y - p);
|
||||
start.y = p;
|
||||
}
|
||||
|
||||
void PixelRegion::setRight(int x) {
|
||||
numPixels.x = x - start.x;
|
||||
}
|
||||
|
||||
void PixelRegion::setBottom(int y) {
|
||||
numPixels.y = y - start.y;
|
||||
}
|
||||
|
||||
void PixelRegion::align(Side side, int pos) {
|
||||
switch (side) {
|
||||
case LEFT: alignLeft(pos); break;
|
||||
case TOP: alignTop(pos); break;
|
||||
case RIGHT: alignRight(pos); break;
|
||||
case BOTTOM: alignBottom(pos); break;
|
||||
}
|
||||
}
|
||||
|
||||
void PixelRegion::alignLeft(int x) {
|
||||
start.x = x;
|
||||
}
|
||||
|
||||
void PixelRegion::alignTop(int y) {
|
||||
start.y = y;
|
||||
}
|
||||
|
||||
void PixelRegion::alignRight(int x) {
|
||||
start.x = x - numPixels.x;
|
||||
}
|
||||
|
||||
void PixelRegion::alignBottom(int y) {
|
||||
start.y = y - numPixels.y;
|
||||
}
|
||||
|
||||
void PixelRegion::scale(const glm::dvec2& s) {
|
||||
start = PixelCoordinate(glm::round(s * glm::dvec2(start)));
|
||||
numPixels = PixelCoordinate(glm::round(s * glm::dvec2(numPixels)));
|
||||
}
|
||||
|
||||
void PixelRegion::scale(double s) {
|
||||
scale(glm::dvec2(s));
|
||||
}
|
||||
|
||||
void PixelRegion::downscalePow2(int exponent, PixelCoordinate wrt) {
|
||||
start += wrt;
|
||||
start.x >>= exponent;
|
||||
start.y >>= exponent;
|
||||
numPixels.x >>= exponent;
|
||||
numPixels.y >>= exponent;
|
||||
start -= wrt;
|
||||
}
|
||||
|
||||
void PixelRegion::upscalePow2(int exponent, PixelCoordinate wrt) {
|
||||
start += wrt;
|
||||
start.x <<= exponent;
|
||||
start.y <<= exponent;
|
||||
numPixels.x <<= exponent;
|
||||
numPixels.y <<= exponent;
|
||||
start -= wrt;
|
||||
}
|
||||
|
||||
void PixelRegion::move(Side side, int amount) {
|
||||
switch (side) {
|
||||
case LEFT: start.x -= amount; break;
|
||||
case TOP: start.y -= amount; break;
|
||||
case RIGHT: start.x += amount; break;
|
||||
case BOTTOM: start.y += amount; break;
|
||||
}
|
||||
}
|
||||
|
||||
void PixelRegion::pad(const PixelRegion& padding) {
|
||||
start += padding.start;
|
||||
numPixels += padding.numPixels;
|
||||
}
|
||||
|
||||
void PixelRegion::clampTo(const PixelRegion& boundingRegion) {
|
||||
start = glm::max(start, boundingRegion.start);
|
||||
numPixels = glm::min(end(), boundingRegion.end()) - start;
|
||||
}
|
||||
|
||||
void PixelRegion::forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple) {
|
||||
ghoul_assert(multiple > 0, "multiple must be 1 or larger");
|
||||
int sizeDiff = numPixels.x - numPixels.y;
|
||||
if (std::abs(sizeDiff) > 0) {
|
||||
if (sizeDiff > 0) {
|
||||
numPixels.y += sizeDiff % multiple;
|
||||
}
|
||||
else {
|
||||
numPixels.x += std::abs(sizeDiff) % multiple;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PixelRegion::roundUpNumPixelToNearestMultipleOf(unsigned int multiple) {
|
||||
ghoul_assert(multiple > 0, "multiple must be 1 or larger");
|
||||
numPixels.x += numPixels.x % multiple;
|
||||
numPixels.y += numPixels.y % multiple;
|
||||
}
|
||||
|
||||
void PixelRegion::roundDownToQuadratic() {
|
||||
if (numPixels.x < numPixels.y) {
|
||||
numPixels.y = numPixels.x;
|
||||
}
|
||||
else if (numPixels.x > numPixels.y) {
|
||||
numPixels.x = numPixels.y;
|
||||
}
|
||||
}
|
||||
|
||||
PixelRegion PixelRegion::globalCut(Side side, int p) {
|
||||
if (!lineIntersect(side, p)) {
|
||||
return PixelRegion({ 0, 0 }, { 0, 0 });
|
||||
}
|
||||
|
||||
PixelRegion cutOff(*this);
|
||||
int cutSize = 0;
|
||||
switch (side) {
|
||||
void PixelRegion::setSide(Side side, int pos) {
|
||||
switch (side) {
|
||||
case LEFT:
|
||||
setLeft(p);
|
||||
cutOff.setRight(p - cutSize);
|
||||
setLeft(pos);
|
||||
break;
|
||||
case TOP:
|
||||
setTop(p);
|
||||
cutOff.setBottom(p - cutSize);
|
||||
setTop(pos);
|
||||
break;
|
||||
case RIGHT:
|
||||
setRight(p);
|
||||
cutOff.setLeft(p + cutSize);
|
||||
setRight(pos);
|
||||
break;
|
||||
case BOTTOM:
|
||||
setBottom(p);
|
||||
cutOff.setTop(p + cutSize);
|
||||
setBottom(pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PixelRegion::setLeft(int x) {
|
||||
numPixels.x += (start.x - x);
|
||||
start.x = x;
|
||||
}
|
||||
|
||||
void PixelRegion::setTop(int p) {
|
||||
numPixels.y += (start.y - p);
|
||||
start.y = p;
|
||||
}
|
||||
|
||||
void PixelRegion::setRight(int x) {
|
||||
numPixels.x = x - start.x;
|
||||
}
|
||||
|
||||
void PixelRegion::setBottom(int y) {
|
||||
numPixels.y = y - start.y;
|
||||
}
|
||||
|
||||
void PixelRegion::align(Side side, int pos) {
|
||||
switch (side) {
|
||||
case LEFT:
|
||||
alignLeft(pos);
|
||||
break;
|
||||
case TOP:
|
||||
alignTop(pos);
|
||||
break;
|
||||
case RIGHT:
|
||||
alignRight(pos);
|
||||
break;
|
||||
case BOTTOM:
|
||||
alignBottom(pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PixelRegion::alignLeft(int x) {
|
||||
start.x = x;
|
||||
}
|
||||
|
||||
void PixelRegion::alignTop(int y) {
|
||||
start.y = y;
|
||||
}
|
||||
|
||||
void PixelRegion::alignRight(int x) {
|
||||
start.x = x - numPixels.x;
|
||||
}
|
||||
|
||||
void PixelRegion::alignBottom(int y) {
|
||||
start.y = y - numPixels.y;
|
||||
}
|
||||
|
||||
void PixelRegion::scale(const glm::dvec2& s) {
|
||||
start = PixelCoordinate(glm::round(s * glm::dvec2(start)));
|
||||
numPixels = PixelCoordinate(glm::round(s * glm::dvec2(numPixels)));
|
||||
}
|
||||
|
||||
void PixelRegion::scale(double s) {
|
||||
scale(glm::dvec2(s));
|
||||
}
|
||||
|
||||
void PixelRegion::downscalePow2(int exponent, PixelCoordinate wrt) {
|
||||
start += wrt;
|
||||
start.x >>= exponent;
|
||||
start.y >>= exponent;
|
||||
numPixels.x >>= exponent;
|
||||
numPixels.y >>= exponent;
|
||||
start -= wrt;
|
||||
}
|
||||
|
||||
void PixelRegion::upscalePow2(int exponent, PixelCoordinate wrt) {
|
||||
start += wrt;
|
||||
start.x <<= exponent;
|
||||
start.y <<= exponent;
|
||||
numPixels.x <<= exponent;
|
||||
numPixels.y <<= exponent;
|
||||
start -= wrt;
|
||||
}
|
||||
|
||||
void PixelRegion::move(Side side, int amount) {
|
||||
switch (side) {
|
||||
case LEFT:
|
||||
start.x -= amount;
|
||||
break;
|
||||
case TOP:
|
||||
start.y -= amount;
|
||||
break;
|
||||
case RIGHT:
|
||||
start.x += amount;
|
||||
break;
|
||||
case BOTTOM:
|
||||
start.y += amount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PixelRegion::pad(const PixelRegion& padding) {
|
||||
start += padding.start;
|
||||
numPixels += padding.numPixels;
|
||||
}
|
||||
|
||||
void PixelRegion::clampTo(const PixelRegion& boundingRegion) {
|
||||
start = glm::max(start, boundingRegion.start);
|
||||
numPixels = glm::min(end(), boundingRegion.end()) - start;
|
||||
}
|
||||
|
||||
void PixelRegion::forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple) {
|
||||
ghoul_assert(multiple > 0, "multiple must be 1 or larger");
|
||||
int sizeDiff = numPixels.x - numPixels.y;
|
||||
if (std::abs(sizeDiff) > 0) {
|
||||
if (sizeDiff > 0) {
|
||||
numPixels.y += sizeDiff % multiple;
|
||||
}
|
||||
return cutOff;
|
||||
}
|
||||
|
||||
PixelRegion PixelRegion::localCut(Side side, int p) {
|
||||
if (p < 1) {
|
||||
return PixelRegion({ 0, 0 }, { 0, 0 });
|
||||
}
|
||||
else return globalCut(side, edge(side) - edgeDirectionSign(side) * p);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Accessors //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int PixelRegion::area() const {
|
||||
return numPixels.x * numPixels.y;
|
||||
}
|
||||
|
||||
int PixelRegion::edge(Side side) const {
|
||||
switch (side) {
|
||||
case LEFT: return start.x;
|
||||
case TOP: return start.y;
|
||||
case RIGHT: return start.x + numPixels.x;
|
||||
case BOTTOM: return start.y + numPixels.y;
|
||||
else {
|
||||
numPixels.x += std::abs(sizeDiff) % multiple;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PixelRegion::edgeDirectionSign(Side side) const {
|
||||
return side < RIGHT ? -1 : 1;
|
||||
void PixelRegion::roundUpNumPixelToNearestMultipleOf(unsigned int multiple) {
|
||||
ghoul_assert(multiple > 0, "multiple must be 1 or larger");
|
||||
numPixels.x += numPixels.x % multiple;
|
||||
numPixels.y += numPixels.y % multiple;
|
||||
}
|
||||
|
||||
void PixelRegion::roundDownToQuadratic() {
|
||||
if (numPixels.x < numPixels.y) {
|
||||
numPixels.y = numPixels.x;
|
||||
}
|
||||
else if (numPixels.x > numPixels.y) {
|
||||
numPixels.x = numPixels.y;
|
||||
}
|
||||
}
|
||||
|
||||
PixelRegion PixelRegion::globalCut(Side side, int p) {
|
||||
if (!lineIntersect(side, p)) {
|
||||
return PixelRegion({ 0, 0 }, { 0, 0 });
|
||||
}
|
||||
|
||||
PixelCoordinate PixelRegion::end() const {
|
||||
return start + numPixels;
|
||||
PixelRegion cutOff(*this);
|
||||
int cutSize = 0;
|
||||
switch (side) {
|
||||
case LEFT:
|
||||
setLeft(p);
|
||||
cutOff.setRight(p - cutSize);
|
||||
break;
|
||||
case TOP:
|
||||
setTop(p);
|
||||
cutOff.setBottom(p - cutSize);
|
||||
break;
|
||||
case RIGHT:
|
||||
setRight(p);
|
||||
cutOff.setLeft(p + cutSize);
|
||||
break;
|
||||
case BOTTOM:
|
||||
setBottom(p);
|
||||
cutOff.setTop(p + cutSize);
|
||||
break;
|
||||
}
|
||||
return cutOff;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Comparators //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
PixelRegion PixelRegion::localCut(Side side, int p) {
|
||||
if (p < 1) {
|
||||
return PixelRegion({ 0, 0 }, { 0, 0 });
|
||||
}
|
||||
else {
|
||||
return globalCut(side, edge(side) - edgeDirectionSign(side) * p);
|
||||
}
|
||||
}
|
||||
|
||||
bool PixelRegion::lineIntersect(Side side, int p) {
|
||||
switch (side)
|
||||
{
|
||||
int PixelRegion::area() const {
|
||||
return numPixels.x * numPixels.y;
|
||||
}
|
||||
|
||||
int PixelRegion::edge(Side side) const {
|
||||
switch (side) {
|
||||
case LEFT: return start.x;
|
||||
case TOP: return start.y;
|
||||
case RIGHT: return start.x + numPixels.x;
|
||||
case BOTTOM: return start.y + numPixels.y;
|
||||
}
|
||||
}
|
||||
|
||||
int PixelRegion::edgeDirectionSign(Side side) const {
|
||||
return side < RIGHT ? -1 : 1;
|
||||
}
|
||||
|
||||
PixelCoordinate PixelRegion::end() const {
|
||||
return start + numPixels;
|
||||
}
|
||||
|
||||
bool PixelRegion::lineIntersect(Side side, int p) {
|
||||
switch (side) {
|
||||
case PixelRegion::LEFT:
|
||||
case PixelRegion::RIGHT:
|
||||
return start.x <= p && p <= (start.x + numPixels.x);
|
||||
@@ -254,19 +257,18 @@ namespace globebrowsing {
|
||||
case PixelRegion::TOP:
|
||||
case PixelRegion::BOTTOM:
|
||||
return start.y <= p && p <= (start.y + numPixels.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PixelRegion::isInside(const PixelRegion& r) const {
|
||||
PixelCoordinate e = end();
|
||||
PixelCoordinate re = r.end();
|
||||
return r.start.x <= start.x && e.x <= re.x
|
||||
&& r.start.y <= start.y && e.y <= re.y;
|
||||
}
|
||||
bool PixelRegion::isInside(const PixelRegion& r) const {
|
||||
PixelCoordinate e = end();
|
||||
PixelCoordinate re = r.end();
|
||||
return r.start.x <= start.x && e.x <= re.x && r.start.y <= start.y && e.y <= re.y;
|
||||
}
|
||||
|
||||
bool PixelRegion::equals(const PixelRegion& r) const {
|
||||
return start == r.start && numPixels == r.numPixels;
|
||||
}
|
||||
bool PixelRegion::equals(const PixelRegion& r) const {
|
||||
return start == r.start && numPixels == r.numPixels;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,120 +1,106 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __PIXEL_REGION_H__
|
||||
#define __PIXEL_REGION_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_PIXELREGION_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_PIXELREGION_H__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
typedef glm::ivec2 PixelCoordinate;
|
||||
typedef glm::ivec2 PixelRange;
|
||||
using PixelCoordinate = glm::ivec2;
|
||||
using PixelRange= glm::ivec2;
|
||||
|
||||
struct PixelRegion {
|
||||
|
||||
enum Side {
|
||||
LEFT = 0, TOP, RIGHT, BOTTOM,
|
||||
};
|
||||
|
||||
PixelRegion();
|
||||
PixelRegion(const PixelRegion& o);
|
||||
PixelRegion(const PixelCoordinate& pixelStart, const PixelRange& numberOfPixels);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Mutators //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Sets one of the sides of the pixel region the specified position. This changes
|
||||
* the number of pixels in the region.
|
||||
*
|
||||
* Example: side = LEFT and pos 16:
|
||||
* set start.x = 16 and keep the end position the same.
|
||||
*/
|
||||
void setSide(Side side, int pos);
|
||||
void setLeft(int x);
|
||||
void setTop(int p);
|
||||
void setRight(int x);
|
||||
void setBottom(int y);
|
||||
|
||||
/**
|
||||
* Aligns one the sides of the pixel regino to the specified position. This does
|
||||
* not change the number of pixels within the region.
|
||||
*
|
||||
* Example: Side = left and pos = 16:
|
||||
* start.x = 16 and keep the size the same
|
||||
*/
|
||||
void align(Side side, int pos);
|
||||
void alignLeft(int x);
|
||||
void alignTop(int y);
|
||||
void alignRight(int x);
|
||||
void alignBottom(int y);
|
||||
|
||||
void scale(const glm::dvec2& s);
|
||||
void scale(double s);
|
||||
void downscalePow2(int exponent, PixelCoordinate wrt = {0,0});
|
||||
void upscalePow2(int exponent, PixelCoordinate wrt = { 0,0 });
|
||||
|
||||
void move(Side side, int amount);
|
||||
void pad(const PixelRegion& padding);
|
||||
void clampTo(const PixelRegion& boundingRegion);
|
||||
|
||||
void forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple);
|
||||
void roundUpNumPixelToNearestMultipleOf(unsigned int multiple);
|
||||
void roundDownToQuadratic();
|
||||
|
||||
PixelRegion globalCut(Side side, int globalPos);
|
||||
PixelRegion localCut(Side side, int localPos);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Accessors //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int area() const;
|
||||
int edge(Side side) const;
|
||||
int edgeDirectionSign(Side side) const;
|
||||
PixelCoordinate end() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Comparators //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool lineIntersect(Side side, int p);
|
||||
bool isInside(const PixelRegion& r) const;
|
||||
bool equals(const PixelRegion& r) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Members //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PixelCoordinate start;
|
||||
PixelRange numPixels;
|
||||
struct PixelRegion {
|
||||
enum Side {
|
||||
LEFT = 0,
|
||||
TOP,
|
||||
RIGHT,
|
||||
BOTTOM
|
||||
};
|
||||
|
||||
PixelRegion(const PixelRegion& o);
|
||||
PixelRegion(const PixelCoordinate& pixelStart = PixelCoordinate(0, 0),
|
||||
const PixelRange& numberOfPixels = PixelRange(0, 0));
|
||||
|
||||
/**
|
||||
* Sets one of the sides of the pixel region the specified position. This changes
|
||||
* the number of pixels in the region.
|
||||
*
|
||||
* Example: side = LEFT and pos 16:
|
||||
* set start.x = 16 and keep the end position the same.
|
||||
*/
|
||||
void setSide(Side side, int pos);
|
||||
void setLeft(int x);
|
||||
void setTop(int p);
|
||||
void setRight(int x);
|
||||
void setBottom(int y);
|
||||
|
||||
/**
|
||||
* Aligns one the sides of the pixel regino to the specified position. This does
|
||||
* not change the number of pixels within the region.
|
||||
*
|
||||
* Example: Side = left and pos = 16:
|
||||
* start.x = 16 and keep the size the same
|
||||
*/
|
||||
void align(Side side, int pos);
|
||||
void alignLeft(int x);
|
||||
void alignTop(int y);
|
||||
void alignRight(int x);
|
||||
void alignBottom(int y);
|
||||
|
||||
void scale(const glm::dvec2& s);
|
||||
void scale(double s);
|
||||
void downscalePow2(int exponent, PixelCoordinate wrt = {0,0});
|
||||
void upscalePow2(int exponent, PixelCoordinate wrt = { 0,0 });
|
||||
|
||||
void move(Side side, int amount);
|
||||
void pad(const PixelRegion& padding);
|
||||
void clampTo(const PixelRegion& boundingRegion);
|
||||
|
||||
void forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple);
|
||||
void roundUpNumPixelToNearestMultipleOf(unsigned int multiple);
|
||||
void roundDownToQuadratic();
|
||||
|
||||
PixelRegion globalCut(Side side, int globalPos);
|
||||
PixelRegion localCut(Side side, int localPos);
|
||||
|
||||
int area() const;
|
||||
int edge(Side side) const;
|
||||
int edgeDirectionSign(Side side) const;
|
||||
PixelCoordinate end() const;
|
||||
|
||||
bool lineIntersect(Side side, int p);
|
||||
bool isInside(const PixelRegion& r) const;
|
||||
bool equals(const PixelRegion& r) const;
|
||||
|
||||
PixelCoordinate start;
|
||||
PixelRange numPixels;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __PIXEL_REGION_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_PIXELREGION_H__
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/tile/tiledataset.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <gdal_priv.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "Tile";
|
||||
@@ -33,150 +33,144 @@ namespace {
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
void TileMetaData::serialize(std::ostream& os) {
|
||||
os << maxValues.size() << std::endl;
|
||||
for (float f : maxValues) {
|
||||
os << f << " ";
|
||||
}
|
||||
os << std::endl;
|
||||
for (float f : minValues) {
|
||||
os << f << " ";
|
||||
}
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void TileMetaData::serialize(std::ostream& os) {
|
||||
os << maxValues.size() << std::endl;
|
||||
for (float f : maxValues) {
|
||||
os << f << " ";
|
||||
}
|
||||
os << std::endl;
|
||||
for (float f : minValues) {
|
||||
os << f << " ";
|
||||
}
|
||||
os << std::endl;
|
||||
TileMetaData TileMetaData::deserialize(std::istream& is) {
|
||||
TileMetaData res;
|
||||
int n; is >> n;
|
||||
res.maxValues.resize(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
is >> res.maxValues[i];
|
||||
}
|
||||
res.minValues.resize(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
is >> res.minValues[i];
|
||||
}
|
||||
|
||||
TileMetaData TileMetaData::deserialize(std::istream& is) {
|
||||
TileMetaData res;
|
||||
int n; is >> n;
|
||||
res.maxValues.resize(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
is >> res.maxValues[i];
|
||||
}
|
||||
res.minValues.resize(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
is >> res.minValues[i];
|
||||
}
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
return std::move(res);
|
||||
RawTile::RawTile()
|
||||
: imageData(nullptr)
|
||||
, dimensions(0, 0, 0)
|
||||
, tileMetaData(nullptr)
|
||||
, tileIndex(0, 0, 0)
|
||||
, error(CE_None)
|
||||
, nBytesImageData(0)
|
||||
{}
|
||||
|
||||
RawTile RawTile::createDefaultRes() {
|
||||
RawTile defaultRes;
|
||||
int w = 8;
|
||||
int h = 8;
|
||||
defaultRes.dimensions = glm::uvec3(w, h, 1);
|
||||
defaultRes.nBytesImageData = w * h * 1 * 3 * 4; // assume max 3 channels, max 4 bytes per pixel
|
||||
defaultRes.imageData = new char[defaultRes.nBytesImageData];
|
||||
std::fill_n((char*)defaultRes.imageData, defaultRes.nBytesImageData, 0);
|
||||
return std::move(defaultRes);
|
||||
}
|
||||
|
||||
void RawTile::serializeMetaData(std::ostream& os) {
|
||||
os << dimensions.x << " " << dimensions.y << " " << dimensions.z << std::endl;
|
||||
os << tileIndex.x << " " << tileIndex.y << " " << tileIndex.level << std::endl;
|
||||
os << error << std::endl;
|
||||
|
||||
// preprocess data
|
||||
os << (tileMetaData != nullptr) << std::endl;
|
||||
if (tileMetaData != nullptr) {
|
||||
tileMetaData->serialize(os);
|
||||
}
|
||||
|
||||
RawTile::RawTile()
|
||||
: imageData(nullptr)
|
||||
, dimensions(0, 0, 0)
|
||||
, tileMetaData(nullptr)
|
||||
, tileIndex(0, 0, 0)
|
||||
, error(CE_None)
|
||||
, nBytesImageData(0)
|
||||
{}
|
||||
|
||||
RawTile RawTile::createDefaultRes() {
|
||||
RawTile defaultRes;
|
||||
int w = 8;
|
||||
int h = 8;
|
||||
defaultRes.dimensions = glm::uvec3(w, h, 1);
|
||||
defaultRes.nBytesImageData = w * h * 1 * 3 * 4; // assume max 3 channels, max 4 bytes per pixel
|
||||
defaultRes.imageData = new char[defaultRes.nBytesImageData];
|
||||
std::fill_n((char*)defaultRes.imageData, defaultRes.nBytesImageData, 0);
|
||||
return std::move(defaultRes);
|
||||
os << nBytesImageData << std::endl;
|
||||
}
|
||||
|
||||
RawTile RawTile::deserializeMetaData(std::istream& is) {
|
||||
RawTile res;
|
||||
is >> res.dimensions.x >> res.dimensions.y >> res.dimensions.z;
|
||||
is >> res.tileIndex.x >> res.tileIndex.y >> res.tileIndex.level;
|
||||
int err; is >> err; res.error = (CPLErr) err;
|
||||
|
||||
res.tileMetaData = nullptr;
|
||||
bool hastileMetaData;
|
||||
is >> hastileMetaData;
|
||||
if (hastileMetaData) {
|
||||
TileMetaData tileMetaData = TileMetaData::deserialize(is);
|
||||
res.tileMetaData = std::make_shared<TileMetaData>(tileMetaData);
|
||||
}
|
||||
|
||||
void RawTile::serializeMetaData(std::ostream& os) {
|
||||
os << dimensions.x << " " << dimensions.y << " " << dimensions.z << std::endl;
|
||||
os << tileIndex.x << " " << tileIndex.y << " " << tileIndex.level << std::endl;
|
||||
os << error << std::endl;
|
||||
|
||||
// preprocess data
|
||||
os << (tileMetaData != nullptr) << std::endl;
|
||||
if (tileMetaData != nullptr) {
|
||||
tileMetaData->serialize(os);
|
||||
}
|
||||
|
||||
os << nBytesImageData << std::endl;
|
||||
}
|
||||
is >> res.nBytesImageData;
|
||||
|
||||
RawTile RawTile::deserializeMetaData(std::istream& is) {
|
||||
RawTile res;
|
||||
is >> res.dimensions.x >> res.dimensions.y >> res.dimensions.z;
|
||||
is >> res.tileIndex.x >> res.tileIndex.y >> res.tileIndex.level;
|
||||
int err; is >> err; res.error = (CPLErr) err;
|
||||
char binaryDataSeparator;
|
||||
is >> binaryDataSeparator; // not used
|
||||
|
||||
res.tileMetaData = nullptr;
|
||||
bool hastileMetaData;
|
||||
is >> hastileMetaData;
|
||||
if (hastileMetaData) {
|
||||
TileMetaData tileMetaData = TileMetaData::deserialize(is);
|
||||
res.tileMetaData = std::make_shared<TileMetaData>(tileMetaData);
|
||||
}
|
||||
|
||||
is >> res.nBytesImageData;
|
||||
char* buffer = new char[res.nBytesImageData]();
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
char binaryDataSeparator;
|
||||
is >> binaryDataSeparator; // not used
|
||||
|
||||
char* buffer = new char[res.nBytesImageData]();
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
|
||||
const Tile Tile::TileUnavailable = {nullptr, nullptr, Tile::Status::Unavailable };
|
||||
const Tile Tile::TileUnavailable = {nullptr, nullptr, Tile::Status::Unavailable };
|
||||
|
||||
Tile Tile::createPlainTile(const glm::uvec2& size, const glm::uvec4& color) {
|
||||
using namespace ghoul::opengl;
|
||||
Tile Tile::createPlainTile(const glm::uvec2& size, const glm::uvec4& color) {
|
||||
using namespace ghoul::opengl;
|
||||
|
||||
// Create pixel data
|
||||
int numBytes = size.x * size.y * 4 * 1;
|
||||
char* pixels = new char[numBytes];
|
||||
size_t numPixels = size.x * size.y;
|
||||
size_t i = 0;
|
||||
for (size_t p = 0; p < numPixels; p++){
|
||||
pixels[i++] = color.r;
|
||||
pixels[i++] = color.g;
|
||||
pixels[i++] = color.b;
|
||||
pixels[i++] = color.a;
|
||||
}
|
||||
|
||||
// Create ghoul texture
|
||||
auto texture = std::make_shared<Texture>(glm::uvec3(size, 1));
|
||||
texture->setDataOwnership(Texture::TakeOwnership::Yes);
|
||||
texture->setPixelData(pixels);
|
||||
texture->uploadTexture();
|
||||
texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
|
||||
|
||||
// Create tile
|
||||
Tile tile;
|
||||
tile.status = Tile::Status::OK;
|
||||
tile.metaData = nullptr;
|
||||
tile.texture = texture;
|
||||
|
||||
return tile;
|
||||
// Create pixel data
|
||||
int numBytes = size.x * size.y * 4 * 1;
|
||||
char* pixels = new char[numBytes];
|
||||
size_t numPixels = size.x * size.y;
|
||||
size_t i = 0;
|
||||
for (size_t p = 0; p < numPixels; p++){
|
||||
pixels[i++] = color.r;
|
||||
pixels[i++] = color.g;
|
||||
pixels[i++] = color.b;
|
||||
pixels[i++] = color.a;
|
||||
}
|
||||
|
||||
glm::vec2 Tile::compensateSourceTextureSampling(
|
||||
glm::vec2 startOffset,
|
||||
glm::vec2 sizeDiff,
|
||||
glm::uvec2 resolution,
|
||||
glm::vec2 tileUV) {
|
||||
glm::vec2 sourceSize = glm::vec2(resolution) + sizeDiff;
|
||||
glm::vec2 currentSize = glm::vec2(resolution);
|
||||
glm::vec2 sourceToCurrentSize = currentSize / sourceSize;
|
||||
tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize);
|
||||
return tileUV;
|
||||
}
|
||||
// Create ghoul texture
|
||||
auto texture = std::make_shared<Texture>(glm::uvec3(size, 1));
|
||||
texture->setDataOwnership(Texture::TakeOwnership::Yes);
|
||||
texture->setPixelData(pixels);
|
||||
texture->uploadTexture();
|
||||
texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
|
||||
|
||||
glm::vec2 Tile::TileUvToTextureSamplePosition(
|
||||
const TileUvTransform uvTransform,
|
||||
glm::vec2 tileUV,
|
||||
glm::uvec2 resolution) {
|
||||
glm::vec2 uv = uvTransform.uvOffset + uvTransform.uvScale * tileUV;
|
||||
uv = compensateSourceTextureSampling(
|
||||
TileDataset::tilePixelStartOffset,
|
||||
TileDataset::tilePixelSizeDifference,
|
||||
resolution,
|
||||
uv);
|
||||
return uv;
|
||||
}
|
||||
// Create tile
|
||||
Tile tile;
|
||||
tile.status = Tile::Status::OK;
|
||||
tile.metaData = nullptr;
|
||||
tile.texture = texture;
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
glm::vec2 Tile::compensateSourceTextureSampling(glm::vec2 startOffset, glm::vec2 sizeDiff,
|
||||
glm::uvec2 resolution, glm::vec2 tileUV)
|
||||
{
|
||||
glm::vec2 sourceSize = glm::vec2(resolution) + sizeDiff;
|
||||
glm::vec2 currentSize = glm::vec2(resolution);
|
||||
glm::vec2 sourceToCurrentSize = currentSize / sourceSize;
|
||||
tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize);
|
||||
return tileUV;
|
||||
}
|
||||
|
||||
glm::vec2 Tile::TileUvToTextureSamplePosition(const TileUvTransform uvTransform,
|
||||
glm::vec2 tileUV, glm::uvec2 resolution)
|
||||
{
|
||||
glm::vec2 uv = uvTransform.uvOffset + uvTransform.uvScale * tileUV;
|
||||
uv = compensateSourceTextureSampling(
|
||||
TileDataset::tilePixelStartOffset,
|
||||
TileDataset::tilePixelSizeDifference,
|
||||
resolution,
|
||||
uv);
|
||||
return uv;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,41 +1,40 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TILE_H__
|
||||
#define __TILE_H__
|
||||
|
||||
#include <ghoul/opengl/texture.h> // Texture
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_H__
|
||||
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <memory>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
|
||||
#include <gdal_priv.h>
|
||||
#include <cpl_error.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
|
||||
struct TileMetaData {
|
||||
std::vector<float> maxValues;
|
||||
@@ -67,88 +66,78 @@ struct RawTile {
|
||||
static RawTile deserializeMetaData(std::istream& s);
|
||||
|
||||
static RawTile createDefaultRes();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct TileUvTransform {
|
||||
glm::vec2 uvOffset;
|
||||
glm::vec2 uvScale;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Defines a status and may have a Texture and TileMetaData
|
||||
*/
|
||||
* Defines a status and may have a Texture and TileMetaData
|
||||
*/
|
||||
struct Tile {
|
||||
std::shared_ptr<Texture> texture;
|
||||
std::shared_ptr<TileMetaData> metaData;
|
||||
|
||||
/**
|
||||
* Describe if this Tile is good for usage (OK) or otherwise
|
||||
* the reason why it is not.
|
||||
*/
|
||||
* Describe if this Tile is good for usage (OK) or otherwise
|
||||
* the reason why it is not.
|
||||
*/
|
||||
enum class Status {
|
||||
/**
|
||||
* E.g when texture data is not currently in memory.
|
||||
* texture and tileMetaData are both null
|
||||
*/
|
||||
* E.g when texture data is not currently in memory.
|
||||
* texture and tileMetaData are both null
|
||||
*/
|
||||
Unavailable,
|
||||
|
||||
/**
|
||||
* Can be set by <code>TileProvider</code>s if the requested
|
||||
* <code>TileIndex</code> is undefined for that particular
|
||||
* provider.
|
||||
* texture and metaData are both null
|
||||
*/
|
||||
* Can be set by <code>TileProvider</code>s if the requested
|
||||
* <code>TileIndex</code> is undefined for that particular
|
||||
* provider.
|
||||
* texture and metaData are both null
|
||||
*/
|
||||
OutOfRange,
|
||||
|
||||
/**
|
||||
* An IO Error happend
|
||||
* texture and metaData are both null
|
||||
*/
|
||||
* An IO Error happend
|
||||
* texture and metaData are both null
|
||||
*/
|
||||
IOError,
|
||||
|
||||
/**
|
||||
* The Texture is uploaded to the GPU and good for usage.
|
||||
* texture is defined. metaData may be defined.
|
||||
*/
|
||||
* The Texture is uploaded to the GPU and good for usage.
|
||||
* texture is defined. metaData may be defined.
|
||||
*/
|
||||
OK
|
||||
} status;
|
||||
|
||||
/**
|
||||
* Instantiates a new tile with a single color.
|
||||
*
|
||||
* \param size The size of texture to be created
|
||||
* \param color defined RGBA values in range 0-255.
|
||||
*
|
||||
* \returns a Tile with status OK and the a texture
|
||||
* with the requested size and color
|
||||
*/
|
||||
* Instantiates a new tile with a single color.
|
||||
*
|
||||
* \param size The size of texture to be created
|
||||
* \param color defined RGBA values in range 0-255.
|
||||
*
|
||||
* \returns a Tile with status OK and the a texture
|
||||
* with the requested size and color
|
||||
*/
|
||||
static Tile createPlainTile(const glm::uvec2& size, const glm::uvec4& color);
|
||||
|
||||
static glm::vec2 compensateSourceTextureSampling(
|
||||
glm::vec2 startOffset,
|
||||
glm::vec2 sizeDiff,
|
||||
glm::uvec2 resolution,
|
||||
glm::vec2 tileUV);
|
||||
static glm::vec2 compensateSourceTextureSampling(glm::vec2 startOffset,
|
||||
glm::vec2 sizeDiff, glm::uvec2 resolution, glm::vec2 tileUV);
|
||||
|
||||
static glm::vec2 TileUvToTextureSamplePosition(
|
||||
const TileUvTransform uvTransform,
|
||||
glm::vec2 tileUV,
|
||||
glm::uvec2 resolution);
|
||||
static glm::vec2 TileUvToTextureSamplePosition(const TileUvTransform uvTransform,
|
||||
glm::vec2 tileUV, glm::uvec2 resolution);
|
||||
|
||||
/**
|
||||
* A tile with status unavailable that any user can return to
|
||||
* indicate that a tile was unavailable.
|
||||
*/
|
||||
* A tile with status unavailable that any user can return to
|
||||
* indicate that a tile was unavailable.
|
||||
*/
|
||||
static const Tile TileUnavailable;
|
||||
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
#endif // __TILE_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_H__
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,203 +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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TILE_DATASET_H__
|
||||
#define __TILE_DATASET_H__
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <queue>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <ghoul/filesystem/file.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/misc/threadpool.h>
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATASET_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATASET_H__
|
||||
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
#include <modules/globebrowsing/tile/tiledatatype.h>
|
||||
#include <modules/globebrowsing/tile/tiledepthtransform.h>
|
||||
#include <modules/globebrowsing/tile/tiledataset.h>
|
||||
#include <modules/globebrowsing/tile/pixelregion.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
|
||||
#include <gdal.h>
|
||||
#include <string>
|
||||
|
||||
class GDALDataset;
|
||||
class GDALRasterBand;
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
struct TileDataLayout {
|
||||
TileDataLayout();
|
||||
TileDataLayout(GDALDataset* dataSet, GLuint preferredGlType);
|
||||
class GeodeticPatch;
|
||||
|
||||
GDALDataType gdalType;
|
||||
GLuint glType;
|
||||
struct TileDataLayout {
|
||||
TileDataLayout();
|
||||
TileDataLayout(GDALDataset* dataSet, GLuint preferredGlType);
|
||||
|
||||
size_t bytesPerDatum;
|
||||
size_t numRasters;
|
||||
size_t bytesPerPixel;
|
||||
GDALDataType gdalType;
|
||||
GLuint glType;
|
||||
|
||||
TextureFormat textureFormat;
|
||||
size_t bytesPerDatum;
|
||||
size_t numRasters;
|
||||
size_t bytesPerPixel;
|
||||
|
||||
TextureFormat textureFormat;
|
||||
};
|
||||
|
||||
struct IODescription {
|
||||
struct ReadData {
|
||||
int overview;
|
||||
PixelRegion region;
|
||||
} read;
|
||||
|
||||
struct WriteData {
|
||||
PixelRegion region;
|
||||
size_t bytesPerLine;
|
||||
size_t totalNumBytes;
|
||||
} write;
|
||||
|
||||
IODescription cut(PixelRegion::Side side, int pos);
|
||||
};
|
||||
|
||||
class TileDataset {
|
||||
public:
|
||||
struct Configuration {
|
||||
bool doPreProcessing;
|
||||
int minimumTilePixelSize;
|
||||
GLuint dataType = 0; // default = no datatype reinterpretation
|
||||
};
|
||||
|
||||
struct IODescription {
|
||||
|
||||
struct ReadData {
|
||||
int overview;
|
||||
PixelRegion region;
|
||||
} read;
|
||||
/**
|
||||
* Opens a GDALDataset in readonly mode and calculates meta data required for
|
||||
* reading tile using a TileIndex.
|
||||
*
|
||||
* \param gdalDatasetDesc - A path to a specific file or raw XML describing the dataset
|
||||
* \param minimumPixelSize - minimum number of pixels per side per tile requested
|
||||
* \param datatype - datatype for storing pixel data in requested tile
|
||||
*/
|
||||
TileDataset(const std::string& gdalDatasetDesc, const Configuration& config);
|
||||
|
||||
struct WriteData {
|
||||
PixelRegion region;
|
||||
size_t bytesPerLine;
|
||||
size_t totalNumBytes;
|
||||
} write;
|
||||
~TileDataset();
|
||||
|
||||
IODescription cut(PixelRegion::Side side, int pos);
|
||||
};
|
||||
|
||||
using namespace ghoul::opengl;
|
||||
using namespace ghoul::filesystem;
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Public interface //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
std::shared_ptr<RawTile> readTileData(TileIndex tileIndex);
|
||||
std::shared_ptr<RawTile> defaultTileData();
|
||||
int maxChunkLevel();
|
||||
TileDepthTransform getDepthTransform();
|
||||
const TileDataLayout& getDataLayout();
|
||||
void reset();
|
||||
float noDataValueAsFloat();
|
||||
|
||||
class TileDataset {
|
||||
public:
|
||||
|
||||
struct Configuration {
|
||||
bool doPreProcessing;
|
||||
int minimumTilePixelSize;
|
||||
GLuint dataType = 0; // default = no datatype reinterpretation
|
||||
};
|
||||
const static glm::ivec2 tilePixelStartOffset;
|
||||
const static glm::ivec2 tilePixelSizeDifference;
|
||||
const static PixelRegion padding; // same as the two above
|
||||
|
||||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Initialization //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void initialize();
|
||||
void ensureInitialized();
|
||||
TileDepthTransform calculateTileDepthTransform();
|
||||
int calculateTileLevelDifference(int minimumPixelSize);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// GDAL helper methods //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void gdalEnsureInitialized();
|
||||
void setGdalProxyConfiguration();
|
||||
GDALDataset* gdalDataset(const std::string& gdalDatasetDesc);
|
||||
bool gdalHasOverviews() const;
|
||||
int gdalOverview(const PixelRange& baseRegionSize) const;
|
||||
int gdalOverview(const TileIndex& tileIndex) const;
|
||||
int gdalVirtualOverview(const TileIndex& tileIndex) const;
|
||||
PixelRegion gdalPixelRegion(const GeodeticPatch& geodeticPatch) const;
|
||||
PixelRegion gdalPixelRegion(GDALRasterBand* rasterBand) const;
|
||||
GDALRasterBand* gdalRasterBand(int overview, int raster = 1) const;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// ReadTileData helper functions //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
Returns the geo transform from raster space to projection coordinates as defined
|
||||
by GDAL.
|
||||
|
||||
If the transform is not available, the function returns a transform to map
|
||||
the pixel coordinates to cover the whole geodetic lat long space.
|
||||
*/
|
||||
std::array<double, 6> getGeoTransform() const;
|
||||
|
||||
PixelCoordinate geodeticToPixel(const Geodetic2& geo) const;
|
||||
Geodetic2 pixelToGeodetic(const PixelCoordinate& p) const;
|
||||
IODescription getIODescription(const TileIndex& tileIndex) const;
|
||||
char* readImageData(IODescription& io, CPLErr& worstError) const;
|
||||
CPLErr rasterIO(GDALRasterBand* rasterBand, const IODescription& io, char* dst) const;
|
||||
CPLErr repeatedRasterIO(GDALRasterBand* rasterBand, const IODescription& io, char* dst, int depth = 0) const;
|
||||
std::shared_ptr<TileMetaData> getTileMetaData(std::shared_ptr<RawTile> result, const PixelRegion& region) const;
|
||||
CPLErr postProcessErrorCheck(std::shared_ptr<const RawTile> ioResult, const IODescription& io) const;
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Member variables //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// init data
|
||||
struct InitData {
|
||||
std::string initDirectory;
|
||||
std::string gdalDatasetDesc;
|
||||
int minimumPixelSize;
|
||||
GLuint dataType;
|
||||
} _initData;
|
||||
|
||||
/**
|
||||
* Opens a GDALDataset in readonly mode and calculates meta data required for
|
||||
* reading tile using a TileIndex.
|
||||
*
|
||||
* \param gdalDatasetDesc - A path to a specific file or raw XML describing the dataset
|
||||
* \param minimumPixelSize - minimum number of pixels per side per tile requested
|
||||
* \param datatype - datatype for storing pixel data in requested tile
|
||||
*/
|
||||
TileDataset(const std::string& gdalDatasetDesc, const Configuration& config);
|
||||
struct Cached {
|
||||
int _maxLevel = -1;
|
||||
double _tileLevelDifference;
|
||||
} _cached;
|
||||
|
||||
~TileDataset();
|
||||
const Configuration _config;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Public interface //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
std::shared_ptr<RawTile> readTileData(TileIndex tileIndex);
|
||||
std::shared_ptr<RawTile> defaultTileData();
|
||||
int maxChunkLevel();
|
||||
TileDepthTransform getDepthTransform();
|
||||
const TileDataLayout& getDataLayout();
|
||||
void reset();
|
||||
float noDataValueAsFloat();
|
||||
GDALDataset* _dataset;
|
||||
TileDepthTransform _depthTransform;
|
||||
TileDataLayout _dataLayout;
|
||||
|
||||
|
||||
const static glm::ivec2 tilePixelStartOffset;
|
||||
const static glm::ivec2 tilePixelSizeDifference;
|
||||
const static PixelRegion padding; // same as the two above
|
||||
|
||||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Initialization //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void initialize();
|
||||
void ensureInitialized();
|
||||
TileDepthTransform calculateTileDepthTransform();
|
||||
int calculateTileLevelDifference(int minimumPixelSize);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// GDAL helper methods //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void gdalEnsureInitialized();
|
||||
void setGdalProxyConfiguration();
|
||||
GDALDataset* gdalDataset(const std::string& gdalDatasetDesc);
|
||||
bool gdalHasOverviews() const;
|
||||
int gdalOverview(const PixelRange& baseRegionSize) const;
|
||||
int gdalOverview(const TileIndex& tileIndex) const;
|
||||
int gdalVirtualOverview(const TileIndex& tileIndex) const;
|
||||
PixelRegion gdalPixelRegion(const GeodeticPatch& geodeticPatch) const;
|
||||
PixelRegion gdalPixelRegion(GDALRasterBand* rasterBand) const;
|
||||
GDALRasterBand* gdalRasterBand(int overview, int raster = 1) const;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// ReadTileData helper functions //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
Returns the geo transform from raster space to projection coordinates as defined
|
||||
by GDAL.
|
||||
|
||||
If the transform is not available, the function returns a transform to map
|
||||
the pixel coordinates to cover the whole geodetic lat long space.
|
||||
*/
|
||||
std::array<double, 6> getGeoTransform() const;
|
||||
|
||||
PixelCoordinate geodeticToPixel(const Geodetic2& geo) const;
|
||||
Geodetic2 pixelToGeodetic(const PixelCoordinate& p) const;
|
||||
IODescription getIODescription(const TileIndex& tileIndex) const;
|
||||
char* readImageData(IODescription& io, CPLErr& worstError) const;
|
||||
CPLErr rasterIO(GDALRasterBand* rasterBand, const IODescription& io, char* dst) const;
|
||||
CPLErr repeatedRasterIO(GDALRasterBand* rasterBand, const IODescription& io, char* dst, int depth = 0) const;
|
||||
std::shared_ptr<TileMetaData> getTileMetaData(std::shared_ptr<RawTile> result, const PixelRegion& region) const;
|
||||
CPLErr postProcessErrorCheck(std::shared_ptr<const RawTile> ioResult, const IODescription& io) const;
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Member variables //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// init data
|
||||
struct InitData {
|
||||
std::string initDirectory;
|
||||
std::string gdalDatasetDesc;
|
||||
int minimumPixelSize;
|
||||
GLuint dataType;
|
||||
} _initData;
|
||||
|
||||
struct Cached {
|
||||
int _maxLevel = -1;
|
||||
double _tileLevelDifference;
|
||||
} _cached;
|
||||
|
||||
const Configuration _config;
|
||||
|
||||
|
||||
GDALDataset* _dataset;
|
||||
TileDepthTransform _depthTransform;
|
||||
TileDataLayout _dataLayout;
|
||||
|
||||
static bool GdalHasBeenInitialized;
|
||||
bool hasBeenInitialized;
|
||||
};
|
||||
static bool GdalHasBeenInitialized;
|
||||
bool hasBeenInitialized;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __TILE_DATASET_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATASET_H__
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
#include <modules/globebrowsing/tile/tiledatatype.h>
|
||||
|
||||
#include <ogr_featurestyle.h>
|
||||
@@ -46,145 +45,238 @@ namespace {
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
float TileDataType::interpretFloat(GDALDataType gdalType, const char* src) {
|
||||
switch (gdalType) {
|
||||
case GDT_Byte: return static_cast<float>(*reinterpret_cast<const GLubyte*>(src));
|
||||
case GDT_UInt16: return static_cast<float>(*reinterpret_cast<const GLushort*>(src));
|
||||
case GDT_Int16: return static_cast<float>(*reinterpret_cast<const GLshort*>(src));
|
||||
case GDT_UInt32: return static_cast<float>(*reinterpret_cast<const GLuint*>(src));
|
||||
case GDT_Int32: return static_cast<float>(*reinterpret_cast<const GLint*>(src));
|
||||
case GDT_Float32: return static_cast<float>(*reinterpret_cast<const GLfloat*>(src));
|
||||
case GDT_Float64: return static_cast<float>(*reinterpret_cast<const GLdouble*>(src));
|
||||
float TileDataType::interpretFloat(GDALDataType gdalType, const char* src) {
|
||||
switch (gdalType) {
|
||||
case GDT_Byte:
|
||||
return static_cast<float>(*reinterpret_cast<const GLubyte*>(src));
|
||||
case GDT_UInt16:
|
||||
return static_cast<float>(*reinterpret_cast<const GLushort*>(src));
|
||||
case GDT_Int16:
|
||||
return static_cast<float>(*reinterpret_cast<const GLshort*>(src));
|
||||
case GDT_UInt32:
|
||||
return static_cast<float>(*reinterpret_cast<const GLuint*>(src));
|
||||
case GDT_Int32:
|
||||
return static_cast<float>(*reinterpret_cast<const GLint*>(src));
|
||||
case GDT_Float32:
|
||||
return static_cast<float>(*reinterpret_cast<const GLfloat*>(src));
|
||||
case GDT_Float64:
|
||||
return static_cast<float>(*reinterpret_cast<const GLdouble*>(src));
|
||||
default:
|
||||
LERROR("Unknown data type");
|
||||
ghoul_assert(false, "Unknown data type");
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t TileDataType::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);
|
||||
size_t TileDataType::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");
|
||||
ghoul_assert(false, "Unknown data type");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t TileDataType::getMaximumValue(GDALDataType gdalType) {
|
||||
switch (gdalType) {
|
||||
case GDT_Byte: return 1 << 8;
|
||||
case GDT_UInt16: return 1 << 16;
|
||||
case GDT_Int16: return 1 << 15;
|
||||
case GDT_UInt32: return 1 << 32;
|
||||
case GDT_Int32: return 1 << 31;
|
||||
}
|
||||
}
|
||||
|
||||
size_t TileDataType::getMaximumValue(GDALDataType gdalType) {
|
||||
switch (gdalType) {
|
||||
case GDT_Byte:
|
||||
return 1 << 8;
|
||||
case GDT_UInt16:
|
||||
return 1 << 16;
|
||||
case GDT_Int16:
|
||||
return 1 << 15;
|
||||
case GDT_UInt32:
|
||||
return 1 << 32;
|
||||
case GDT_Int32:
|
||||
return 1 << 31;
|
||||
default:
|
||||
LERROR("Unknown data type");
|
||||
return -1;
|
||||
}
|
||||
ghoul_assert(false, "Unknown data type");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
TextureFormat TileDataType::getTextureFormat(
|
||||
int rasterCount, GDALDataType gdalType)
|
||||
{
|
||||
TextureFormat format;
|
||||
TextureFormat TileDataType::getTextureFormat(
|
||||
int rasterCount, GDALDataType gdalType)
|
||||
{
|
||||
TextureFormat format;
|
||||
|
||||
switch (rasterCount) {
|
||||
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_R16UI; break;
|
||||
case GDT_Int16: format.glFormat = GL_R16_SNORM; 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);
|
||||
case GDT_Byte:
|
||||
format.glFormat = GL_R8;
|
||||
break;
|
||||
case GDT_UInt16:
|
||||
format.glFormat = GL_R16UI;
|
||||
break;
|
||||
case GDT_Int16:
|
||||
format.glFormat = GL_R16_SNORM;
|
||||
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;
|
||||
// No representation of 64 bit float?
|
||||
//case GDT_Float64:
|
||||
// format.glFormat = GL_RED;
|
||||
// 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_RG16UI; break;
|
||||
case GDT_Int16: format.glFormat = GL_RG16_SNORM; 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);
|
||||
case GDT_Byte:
|
||||
format.glFormat = GL_RG8;
|
||||
break;
|
||||
case GDT_UInt16:
|
||||
format.glFormat = GL_RG16UI;
|
||||
break;
|
||||
case GDT_Int16:
|
||||
format.glFormat = GL_RG16_SNORM;
|
||||
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;
|
||||
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_RGB16UI; break;
|
||||
case GDT_Int16: format.glFormat = GL_RGB16_SNORM; 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);
|
||||
case GDT_Byte:
|
||||
format.glFormat = GL_RGB8;
|
||||
break;
|
||||
case GDT_UInt16:
|
||||
format.glFormat = GL_RGB16UI;
|
||||
break;
|
||||
case GDT_Int16:
|
||||
format.glFormat = GL_RGB16_SNORM;
|
||||
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;
|
||||
// No representation of 64 bit float?
|
||||
//case GDT_Float64:
|
||||
// format.glFormat = GL_RED;
|
||||
// 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_RGBA16UI; break;
|
||||
case GDT_Int16: format.glFormat = GL_RGB16_SNORM; 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);
|
||||
case GDT_Byte:
|
||||
format.glFormat = GL_RGBA8;
|
||||
break;
|
||||
case GDT_UInt16:
|
||||
format.glFormat = GL_RGBA16UI;
|
||||
break;
|
||||
case GDT_Int16:
|
||||
format.glFormat = GL_RGB16_SNORM;
|
||||
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;
|
||||
// No representation of 64 bit float?
|
||||
//case GDT_Float64:
|
||||
// format.glFormat = GL_RED;
|
||||
// break;
|
||||
default:
|
||||
LERROR("GDAL data type unknown to OpenGL: " << gdalType);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LERROR("Unknown number of channels for OpenGL texture: " << rasterCount);
|
||||
break;
|
||||
}
|
||||
return format;
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
GLuint TileDataType::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;
|
||||
GLuint TileDataType::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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GDALDataType TileDataType::getGdalDataType(GLuint glType) {
|
||||
switch (glType) {
|
||||
case GL_UNSIGNED_BYTE: return GDT_Byte;
|
||||
case GL_UNSIGNED_SHORT: return GDT_UInt16;
|
||||
case GL_SHORT: return GDT_Int16;
|
||||
case GL_UNSIGNED_INT: return GDT_UInt32;
|
||||
case GL_INT: return GDT_Int32;
|
||||
case GL_FLOAT: return GDT_Float32;
|
||||
case GL_DOUBLE: return GDT_Float64;
|
||||
GDALDataType TileDataType::getGdalDataType(GLuint glType) {
|
||||
switch (glType) {
|
||||
case GL_UNSIGNED_BYTE:
|
||||
return GDT_Byte;
|
||||
case GL_UNSIGNED_SHORT:
|
||||
return GDT_UInt16;
|
||||
case GL_SHORT:
|
||||
return GDT_Int16;
|
||||
case GL_UNSIGNED_INT:
|
||||
return GDT_UInt32;
|
||||
case GL_INT:
|
||||
return GDT_Int32;
|
||||
case GL_FLOAT:
|
||||
return GDT_Float32;
|
||||
case GL_DOUBLE:
|
||||
return GDT_Float64;
|
||||
default:
|
||||
LERROR("OpenGL data type unknown to GDAL: " << glType);
|
||||
return GDT_Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,57 +1,54 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TILE_DATA_TYPE_H__
|
||||
#define __TILE_DATA_TYPE_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATA_TYPE_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATA_TYPE_H__
|
||||
|
||||
#include <ghoul/opengl/texture.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
|
||||
#include "gdal_priv.h"
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
|
||||
#include <gdal.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
struct TileDataType {
|
||||
struct TileDataType {
|
||||
static GLuint getOpenGLDataType(GDALDataType gdalType);
|
||||
|
||||
static GLuint getOpenGLDataType(GDALDataType gdalType);
|
||||
static GDALDataType getGdalDataType(GLuint glType);
|
||||
|
||||
static GDALDataType getGdalDataType(GLuint glType);
|
||||
static TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType);
|
||||
|
||||
static TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType);
|
||||
static size_t getMaximumValue(GDALDataType gdalType);
|
||||
|
||||
static size_t getMaximumValue(GDALDataType gdalType);
|
||||
static size_t numberOfBytes(GDALDataType gdalType);
|
||||
|
||||
static size_t numberOfBytes(GDALDataType gdalType);
|
||||
|
||||
static float interpretFloat(GDALDataType gdalType, const char* src);
|
||||
|
||||
};
|
||||
static float interpretFloat(GDALDataType gdalType, const char* src);
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __TILE_DATA_TYPE_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DATA_TYPE_H__
|
||||
|
||||
@@ -1,122 +1,115 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/tile/tilediskcache.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TileDiskCache";
|
||||
}
|
||||
using namespace ghoul::filesystem;
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
const std::string TileDiskCache::CACHE_ROOT = "tilecache";
|
||||
const std::string TileDiskCache::CACHE_ROOT = "tilecache";
|
||||
|
||||
TileDiskCache::TileDiskCache(const std::string& name)
|
||||
: _name(name)
|
||||
{
|
||||
if (!FileSystem::isInitialized()) {
|
||||
FileSystem::initialize();
|
||||
}
|
||||
|
||||
std::string pathToCacheDir = FileSys.pathByAppendingComponent(CACHE_ROOT, name);
|
||||
Directory cacheDir(pathToCacheDir, Directory::RawPath::No);
|
||||
if (!FileSys.directoryExists(cacheDir)) {
|
||||
FileSys.createDirectory(pathToCacheDir, FileSystem::Recursive::Yes);
|
||||
}
|
||||
_cacheDir = cacheDir;
|
||||
TileDiskCache::TileDiskCache(const std::string& name)
|
||||
: _name(name)
|
||||
{
|
||||
std::string pathToCacheDir = FileSys.pathByAppendingComponent(CACHE_ROOT, name);
|
||||
Directory cacheDir(pathToCacheDir, Directory::RawPath::No);
|
||||
if (!FileSys.directoryExists(cacheDir)) {
|
||||
FileSys.createDirectory(pathToCacheDir, FileSystem::Recursive::Yes);
|
||||
}
|
||||
_cacheDir = cacheDir;
|
||||
}
|
||||
|
||||
bool TileDiskCache::has(const TileIndex& tileIndex) const {
|
||||
File metaFile = getMetaDataFile(tileIndex);
|
||||
return FileSys.fileExists(metaFile);
|
||||
bool TileDiskCache::has(const TileIndex& tileIndex) const {
|
||||
File metaFile = getMetaDataFile(tileIndex);
|
||||
return FileSys.fileExists(metaFile);
|
||||
}
|
||||
|
||||
std::shared_ptr<RawTile> TileDiskCache::get(const TileIndex& tileIndex) {
|
||||
File metaDataFile = getMetaDataFile(tileIndex);
|
||||
File dataFile = getDataFile(tileIndex);
|
||||
if (FileSys.fileExists(metaDataFile) && FileSys.fileExists(dataFile)) {
|
||||
// read meta
|
||||
std::ifstream ifsMeta;
|
||||
ifsMeta.open(metaDataFile.path(), std::ifstream::in);
|
||||
RawTile res = RawTile::deserializeMetaData(ifsMeta);
|
||||
ifsMeta.close();
|
||||
|
||||
// read data
|
||||
std::ifstream ifsData;
|
||||
ifsData.open(dataFile.path(), std::ifstream::binary);
|
||||
char * buffer = new char[res.nBytesImageData];
|
||||
ifsData.read(buffer, res.nBytesImageData);
|
||||
res.imageData = buffer;
|
||||
|
||||
return std::make_shared<RawTile>(res);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<RawTile> TileDiskCache::get(const TileIndex& tileIndex) {
|
||||
File metaDataFile = getMetaDataFile(tileIndex);
|
||||
bool TileDiskCache::put(const TileIndex& tileIndex, std::shared_ptr<RawTile> rawTile) {
|
||||
File metaDataFile = getMetaDataFile(tileIndex);
|
||||
if (!FileSys.fileExists(metaDataFile)) {
|
||||
std::ofstream ofsMeta;
|
||||
ofsMeta.open(metaDataFile.path());
|
||||
rawTile->serializeMetaData(ofsMeta);
|
||||
ofsMeta.close();
|
||||
|
||||
std::ofstream ofsData;
|
||||
File dataFile = getDataFile(tileIndex);
|
||||
if (FileSys.fileExists(metaDataFile) && FileSys.fileExists(dataFile)) {
|
||||
// read meta
|
||||
std::ifstream ifsMeta;
|
||||
ifsMeta.open(metaDataFile.path(), std::ifstream::in);
|
||||
RawTile res = RawTile::deserializeMetaData(ifsMeta);
|
||||
ifsMeta.close();
|
||||
|
||||
// read data
|
||||
std::ifstream ifsData;
|
||||
ifsData.open(dataFile.path(), std::ifstream::binary);
|
||||
char * buffer = new char[res.nBytesImageData];
|
||||
ifsData.read(buffer, res.nBytesImageData);
|
||||
res.imageData = buffer;
|
||||
|
||||
return std::make_shared<RawTile>(res);
|
||||
}
|
||||
return nullptr;
|
||||
ofsData.open(dataFile.path(), std::ofstream::binary);
|
||||
char* data = (char*)rawTile->imageData;
|
||||
ofsData.write(data, rawTile->nBytesImageData);
|
||||
ofsData.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TileDiskCache::put(const TileIndex& tileIndex, std::shared_ptr<RawTile> rawTile) {
|
||||
File metaDataFile = getMetaDataFile(tileIndex);
|
||||
if (!FileSys.fileExists(metaDataFile)) {
|
||||
std::ofstream ofsMeta;
|
||||
ofsMeta.open(metaDataFile.path());
|
||||
rawTile->serializeMetaData(ofsMeta);
|
||||
ofsMeta.close();
|
||||
std::string TileDiskCache::getFilePath(const TileIndex& tileIndex) const {
|
||||
std::stringstream ss;
|
||||
ss << tileIndex.level;
|
||||
ss << "_" << tileIndex.x;
|
||||
ss << "_" << tileIndex.y;
|
||||
std::string filePath = FileSys.pathByAppendingComponent(_cacheDir.path(), ss.str());
|
||||
return filePath;
|
||||
}
|
||||
|
||||
std::ofstream ofsData;
|
||||
File dataFile = getDataFile(tileIndex);
|
||||
ofsData.open(dataFile.path(), std::ofstream::binary);
|
||||
char * data = (char*)rawTile->imageData;
|
||||
ofsData.write(data, rawTile->nBytesImageData);
|
||||
ofsData.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
File TileDiskCache::getMetaDataFile(const TileIndex& tileIndex) const {
|
||||
return File(getFilePath(tileIndex) + ".meta");
|
||||
}
|
||||
|
||||
std::string TileDiskCache::getFilePath(const TileIndex& tileIndex) const {
|
||||
std::stringstream ss;
|
||||
ss << tileIndex.level;
|
||||
ss << "_" << tileIndex.x;
|
||||
ss << "_" << tileIndex.y;
|
||||
std::string filePath = FileSys.pathByAppendingComponent(_cacheDir.path(), ss.str());
|
||||
return filePath;
|
||||
}
|
||||
|
||||
File TileDiskCache::getMetaDataFile(const TileIndex& tileIndex) const {
|
||||
return File(getFilePath(tileIndex) + ".meta");
|
||||
}
|
||||
|
||||
File TileDiskCache::getDataFile(const TileIndex& tileIndex) const {
|
||||
return File(getFilePath(tileIndex) + ".data");
|
||||
}
|
||||
File TileDiskCache::getDataFile(const TileIndex& tileIndex) const {
|
||||
return File(getFilePath(tileIndex) + ".data");
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,64 +1,63 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TILE_DISK_CACHE_H__
|
||||
#define __TILE_DISK_CACHE_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DISK_CACHE_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DISK_CACHE_H__
|
||||
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <ghoul/filesystem/directory.h>
|
||||
#include <ghoul/filesystem/file.h>
|
||||
|
||||
#include <ghoul/filesystem/filesystem>
|
||||
#include <memory>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
struct TileIndex;
|
||||
struct RawTile;
|
||||
|
||||
using namespace ghoul::filesystem;
|
||||
|
||||
class TileDiskCache {
|
||||
public:
|
||||
TileDiskCache(const std::string& name);
|
||||
class TileDiskCache {
|
||||
public:
|
||||
TileDiskCache(const std::string& name);
|
||||
|
||||
std::shared_ptr<RawTile> get(const TileIndex& tileIndex);
|
||||
bool has(const TileIndex& tileIndex) const;
|
||||
bool put(const TileIndex& tileIndex, std::shared_ptr<RawTile> rawTile);
|
||||
std::shared_ptr<RawTile> get(const TileIndex& tileIndex);
|
||||
bool has(const TileIndex& tileIndex) const;
|
||||
bool put(const TileIndex& tileIndex, std::shared_ptr<RawTile> rawTile);
|
||||
|
||||
static const std::string CACHE_ROOT;
|
||||
static const std::string CACHE_ROOT;
|
||||
|
||||
private:
|
||||
const std::string _name;
|
||||
private:
|
||||
const std::string _name;
|
||||
|
||||
Directory _cacheDir;
|
||||
ghoul::filesystem::Directory _cacheDir;
|
||||
|
||||
std::string getFilePath(const TileIndex& tileIndex) const;
|
||||
File getMetaDataFile(const TileIndex& tileIndex) const;
|
||||
File getDataFile(const TileIndex& tileIndex) const;
|
||||
std::string getFilePath(const TileIndex& tileIndex) const;
|
||||
ghoul::filesystem::File getMetaDataFile(const TileIndex& tileIndex) const;
|
||||
ghoul::filesystem::File getDataFile(const TileIndex& tileIndex) const;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __TILE_DISK_CACHE_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_DISK_CACHE_H__
|
||||
|
||||
@@ -23,144 +23,138 @@
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TileIndex";
|
||||
|
||||
const std::string KeyLevel = "Level";
|
||||
const std::string KeyX = "X";
|
||||
const std::string KeyY = "Y";
|
||||
const char* KeyLevel = "Level";
|
||||
const char* KeyX = "X";
|
||||
const char* KeyY = "Y";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
/**
|
||||
Creates the geodetic tile index for the Geodetic patch that covers the
|
||||
point p at the specified level
|
||||
*/
|
||||
TileIndex::TileIndex(const Geodetic2& point, int level)
|
||||
: level(level) {
|
||||
int numIndicesAtLevel = 1 << level;
|
||||
double u = 0.5 + point.lon / (2 * M_PI);
|
||||
double v = 0.25 - point.lat / (2 * M_PI);
|
||||
double xIndexSpace = u * numIndicesAtLevel;
|
||||
double yIndexSpace = v * numIndicesAtLevel;
|
||||
TileIndex::TileIndex(int x, int y, int level)
|
||||
: x(x), y(y), level(level)
|
||||
{}
|
||||
|
||||
x = floor(xIndexSpace);
|
||||
y = floor(yIndexSpace);
|
||||
}
|
||||
TileIndex::TileIndex(const TileIndex& other)
|
||||
: x(other.x), y(other.y), level(other.level)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Initializes a TileIndex from a Dictionary
|
||||
*/
|
||||
TileIndex::TileIndex(const ghoul::Dictionary& dict){
|
||||
level = static_cast<int>(dict.value<double>(KeyLevel));
|
||||
x = static_cast<int>(dict.value<double>(KeyX));
|
||||
y = static_cast<int>(dict.value<double>(KeyY));
|
||||
}
|
||||
TileIndex::TileIndex(const Geodetic2& point, int level)
|
||||
: level(level)
|
||||
{
|
||||
int numIndicesAtLevel = 1 << level;
|
||||
double u = 0.5 + point.lon / (2 * glm::pi<double>());
|
||||
double v = 0.25 - point.lat / (2 * glm::pi<double>());
|
||||
double xIndexSpace = u * numIndicesAtLevel;
|
||||
double yIndexSpace = v * numIndicesAtLevel;
|
||||
|
||||
TileIndex TileIndex::child(Quad q) const {
|
||||
return TileIndex(2 * x + q % 2, 2 * y + q / 2, level + 1);
|
||||
}
|
||||
x = floor(xIndexSpace);
|
||||
y = floor(yIndexSpace);
|
||||
}
|
||||
|
||||
TileIndex TileIndex::parent() const {
|
||||
//ghoul_assert(level > 0, "tile at level 0 has no parent!");
|
||||
return TileIndex(x / 2, y / 2, level - 1);
|
||||
}
|
||||
TileIndex::TileIndex(const ghoul::Dictionary& dict) {
|
||||
level = static_cast<int>(dict.value<double>(KeyLevel));
|
||||
x = static_cast<int>(dict.value<double>(KeyX));
|
||||
y = static_cast<int>(dict.value<double>(KeyY));
|
||||
}
|
||||
|
||||
TileIndex& TileIndex::operator--() {
|
||||
x /= 2;
|
||||
y /= 2;
|
||||
level--;
|
||||
return *this;
|
||||
}
|
||||
TileIndex TileIndex::child(Quad q) const {
|
||||
return TileIndex(2 * x + q % 2, 2 * y + q / 2, level + 1);
|
||||
}
|
||||
|
||||
TileIndex TileIndex::operator--(int) {
|
||||
TileIndex tmp(*this);
|
||||
--(*this);
|
||||
return tmp;
|
||||
}
|
||||
TileIndex TileIndex::parent() const {
|
||||
//ghoul_assert(level > 0, "tile at level 0 has no parent!");
|
||||
return TileIndex(x / 2, y / 2, level - 1);
|
||||
}
|
||||
|
||||
TileIndex& TileIndex::operator-=(unsigned int levels) {
|
||||
x <<= levels;
|
||||
y <<= levels;
|
||||
level -= levels;
|
||||
return *this;
|
||||
}
|
||||
TileIndex& TileIndex::operator--() {
|
||||
x /= 2;
|
||||
y /= 2;
|
||||
level--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TileIndex TileIndex::operator--(int) {
|
||||
TileIndex tmp(*this);
|
||||
--(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
glm::vec2 TileIndex::positionRelativeParent() const{
|
||||
// In OpenGL, positive y direction is up
|
||||
return glm::vec2(isEastChild() ? 0.5 : 0, isNorthChild() ? 0.5 : 0);
|
||||
}
|
||||
TileIndex& TileIndex::operator-=(unsigned int levels) {
|
||||
x <<= levels;
|
||||
y <<= levels;
|
||||
level -= levels;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
Gets the tile at a specified offset from this tile.
|
||||
Accepts delta indices ranging from [-2^level, Infinity[
|
||||
*/
|
||||
TileIndex TileIndex::getRelatedTile(int deltaX, int deltaY) const {
|
||||
int indicesAtThisLevel = 1 << level;
|
||||
int newX = (indicesAtThisLevel + x + deltaX) % indicesAtThisLevel;
|
||||
int newY = (indicesAtThisLevel + y + deltaY) % indicesAtThisLevel;
|
||||
return TileIndex(newX, newY, level);
|
||||
}
|
||||
glm::vec2 TileIndex::positionRelativeParent() const {
|
||||
// In OpenGL, positive y direction is up
|
||||
return glm::vec2(isEastChild() ? 0.5 : 0, isNorthChild() ? 0.5 : 0);
|
||||
}
|
||||
|
||||
int TileIndex::manhattan(const TileIndex& 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);
|
||||
}
|
||||
TileIndex TileIndex::getRelatedTile(int deltaX, int deltaY) const {
|
||||
int indicesAtThisLevel = 1 << level;
|
||||
int newX = (indicesAtThisLevel + x + deltaX) % indicesAtThisLevel;
|
||||
int newY = (indicesAtThisLevel + y + deltaY) % indicesAtThisLevel;
|
||||
return TileIndex(newX, newY, level);
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a hash which can be used as key in hash maps.
|
||||
int TileIndex::manhattan(const TileIndex& 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);
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a hash which can be used as key in hash maps.
|
||||
|
||||
+-------+------------+-------+------------+
|
||||
| USAGE | BIT RANGE | #BITS | MAX VALUE |
|
||||
+-------+------------+-------+------------+
|
||||
| level | 0 - 5 | 5 | 31 |
|
||||
| x | 5 - 35 | 30 | 1073741824 |
|
||||
| y | 35 - 64 | 29 | 536870912 |
|
||||
+-------+------------+-------+------------+
|
||||
+-------+------------+-------+------------+
|
||||
| USAGE | BIT RANGE | #BITS | MAX VALUE |
|
||||
+-------+------------+-------+------------+
|
||||
| level | 0 - 5 | 5 | 31 |
|
||||
| x | 5 - 35 | 30 | 1073741824 |
|
||||
| y | 35 - 64 | 29 | 536870912 |
|
||||
+-------+------------+-------+------------+
|
||||
|
||||
*/
|
||||
TileHashKey TileIndex::hashKey() const {
|
||||
TileHashKey key = 0LL;
|
||||
key |= level;
|
||||
key |= x << 5;
|
||||
key |= ((TileHashKey)y) << 35;
|
||||
return key;
|
||||
}
|
||||
*/
|
||||
TileHashKey TileIndex::hashKey() const {
|
||||
TileHashKey key = 0LL;
|
||||
key |= level;
|
||||
key |= x << 5;
|
||||
key |= ((TileHashKey)y) << 35;
|
||||
return key;
|
||||
}
|
||||
|
||||
std::string TileIndex::toString() const {
|
||||
std::stringstream ss;
|
||||
for (int i = level; i > 0; i--){
|
||||
char digit = '0';
|
||||
int mask = 1 << (i - 1);
|
||||
if ((x & mask) != 0) {
|
||||
digit++;
|
||||
}
|
||||
if ((y & mask) != 0) {
|
||||
digit++;
|
||||
digit++;
|
||||
}
|
||||
ss << digit;
|
||||
std::string TileIndex::toString() const {
|
||||
std::stringstream ss;
|
||||
for (int i = level; i > 0; i--) {
|
||||
char digit = '0';
|
||||
int mask = 1 << (i - 1);
|
||||
if ((x & mask) != 0) {
|
||||
digit++;
|
||||
}
|
||||
return ss.str();
|
||||
if ((y & mask) != 0) {
|
||||
digit++;
|
||||
digit++;
|
||||
}
|
||||
ss << digit;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool TileIndex::operator==(const TileIndex& other) const {
|
||||
return x == other.x && y == other.y && level == other.level;
|
||||
}
|
||||
bool TileIndex::operator==(const TileIndex& other) const {
|
||||
return x == other.x && y == other.y && level == other.level;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const TileIndex& ci) {
|
||||
os << "{ x = " << ci.x << ", y = " << ci.y << ", level = " << ci.level << " }";
|
||||
return os;
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, const TileIndex& ci) {
|
||||
os << "{ x = " << ci.x << ", y = " << ci.y << ", level = " << ci.level << " }";
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -22,13 +22,10 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __TILE_INDEX_H__
|
||||
#define __TILE_INDEX_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_INDEX_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_INDEX_H__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ghoul/glm.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace ghoul {
|
||||
@@ -59,10 +56,18 @@ using TileHashKey = uint64_t;
|
||||
struct TileIndex {
|
||||
int x, y, level;
|
||||
|
||||
TileIndex() : x(0), y(0), level(0) { }
|
||||
TileIndex(int x, int y, int level) : x(x), y(y), level(level) { }
|
||||
TileIndex(const TileIndex& other) : x(other.x), y(other.y), level(other.level) { }
|
||||
TileIndex(int x = 0, int y = 0, int level = 0);
|
||||
TileIndex(const TileIndex& other);
|
||||
|
||||
/**
|
||||
* Creates the geodetic tile index for the Geodetic patch that covers the
|
||||
* point p at the specified level
|
||||
*/
|
||||
TileIndex(const Geodetic2& point, int level);
|
||||
|
||||
/**
|
||||
* Initializes a TileIndex from a Dictionary
|
||||
*/
|
||||
TileIndex(const ghoul::Dictionary& dict);
|
||||
|
||||
|
||||
@@ -101,9 +106,9 @@ struct TileIndex {
|
||||
std::string toString() const;
|
||||
|
||||
/**
|
||||
Gets the tile at a specified offset from this tile.
|
||||
Accepts delta indices ranging from [-2^level, Infinity[
|
||||
*/
|
||||
* Gets the tile at a specified offset from this tile.
|
||||
* Accepts delta indices ranging from [-2^level, Infinity[
|
||||
*/
|
||||
TileIndex getRelatedTile(int deltaX, int deltaY) const;
|
||||
|
||||
int manhattan(const TileIndex& other) const;
|
||||
@@ -118,4 +123,4 @@ std::ostream& operator<<(std::ostream& os, const TileIndex& ti);
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __TILE_INDEX_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_INDEX_H__
|
||||
|
||||
@@ -1,51 +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/tile/tilepile.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileselector.h>
|
||||
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TilePile";
|
||||
}
|
||||
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
/*
|
||||
void TilePile::update(TileProvider* tileProvider, const TileIndex& tileIndex){
|
||||
|
||||
}
|
||||
|
||||
void TilePile::bind(ProgramObject* programObject){
|
||||
|
||||
}*/
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
@@ -1,29 +1,29 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TILEPILE_H__
|
||||
#define __TILEPILE_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILEPILE_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILEPILE_H__
|
||||
|
||||
#include <ghoul/opengl/texture.h> // Texture
|
||||
|
||||
@@ -51,4 +51,4 @@ namespace globebrowsing {
|
||||
|
||||
|
||||
|
||||
#endif // __TILEPILE_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILEPILE_H__
|
||||
|
||||
@@ -1,39 +1,37 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/cachingtileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <modules/globebrowsing/tile/asynctilereader.h>
|
||||
#include <modules/globebrowsing/tile/tiledataset.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "CachingTileProvider";
|
||||
const char* _loggerCat = "CachingTileProvider";
|
||||
|
||||
const char* KeyDoPreProcessing = "DoPreProcessing";
|
||||
const char* KeyMinimumPixelSize = "MinimumPixelSize";
|
||||
@@ -45,187 +43,187 @@ namespace {
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary)
|
||||
CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary)
|
||||
: _framesSinceLastRequestFlush(0)
|
||||
{
|
||||
std::string name = "Name unspecified";
|
||||
dictionary.getValue("Name", name);
|
||||
std::string _loggerCat = "CachingTileProvider : " + name;
|
||||
{
|
||||
std::string name = "Name unspecified";
|
||||
dictionary.getValue("Name", name);
|
||||
std::string _loggerCat = "CachingTileProvider : " + name;
|
||||
|
||||
// 1. Get required Keys
|
||||
std::string filePath;
|
||||
if (!dictionary.getValue<std::string>(KeyFilePath, filePath)) {
|
||||
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
|
||||
}
|
||||
|
||||
// 2. Initialize default values for any optional Keys
|
||||
TileDataset::Configuration config;
|
||||
config.doPreProcessing = false;
|
||||
config.minimumTilePixelSize = 512;
|
||||
|
||||
// getValue does not work for integers
|
||||
double minimumPixelSize;
|
||||
double cacheSize = 512;
|
||||
double framesUntilRequestFlush = 60;
|
||||
|
||||
// 3. Check for used spcified optional keys
|
||||
if (dictionary.getValue<bool>(KeyDoPreProcessing, config.doPreProcessing)) {
|
||||
LDEBUG("Default doPreProcessing overridden: " << config.doPreProcessing);
|
||||
}
|
||||
if (dictionary.getValue<double>(KeyMinimumPixelSize, minimumPixelSize)) {
|
||||
LDEBUG("Default minimumPixelSize overridden: " << minimumPixelSize);
|
||||
config.minimumTilePixelSize = static_cast<int>(minimumPixelSize);
|
||||
}
|
||||
if (dictionary.getValue<double>(KeyCacheSize, cacheSize)) {
|
||||
LDEBUG("Default cacheSize overridden: " << cacheSize);
|
||||
}
|
||||
if (dictionary.getValue<double>(KeyFlushInterval, framesUntilRequestFlush)) {
|
||||
LDEBUG("Default framesUntilRequestFlush overridden: " <<
|
||||
framesUntilRequestFlush);
|
||||
}
|
||||
|
||||
// Initialize instance variables
|
||||
auto tileDataset = std::make_shared<TileDataset>(filePath, config);
|
||||
|
||||
// only one thread per provider supported atm
|
||||
// (GDAL does not handle multiple threads for a single dataset very well
|
||||
// currently)
|
||||
auto threadPool = std::make_shared<ThreadPool>(1);
|
||||
|
||||
_asyncTextureDataProvider = std::make_shared<AsyncTileDataProvider>(
|
||||
tileDataset, threadPool);
|
||||
_tileCache = std::make_shared<TileCache>(cacheSize);
|
||||
_framesUntilRequestFlush = framesUntilRequestFlush;
|
||||
// 1. Get required Keys
|
||||
std::string filePath;
|
||||
if (!dictionary.getValue<std::string>(KeyFilePath, filePath)) {
|
||||
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
|
||||
}
|
||||
|
||||
CachingTileProvider::CachingTileProvider(
|
||||
std::shared_ptr<AsyncTileDataProvider> tileReader,
|
||||
std::shared_ptr<TileCache> tileCache,
|
||||
int framesUntilFlushRequestQueue)
|
||||
: _asyncTextureDataProvider(tileReader)
|
||||
, _tileCache(tileCache)
|
||||
, _framesUntilRequestFlush(framesUntilFlushRequestQueue)
|
||||
, _framesSinceLastRequestFlush(0)
|
||||
{
|
||||
// 2. Initialize default values for any optional Keys
|
||||
TileDataset::Configuration config;
|
||||
config.doPreProcessing = false;
|
||||
config.minimumTilePixelSize = 512;
|
||||
|
||||
// getValue does not work for integers
|
||||
double minimumPixelSize;
|
||||
double cacheSize = 512;
|
||||
double framesUntilRequestFlush = 60;
|
||||
|
||||
// 3. Check for used spcified optional keys
|
||||
if (dictionary.getValue<bool>(KeyDoPreProcessing, config.doPreProcessing)) {
|
||||
LDEBUG("Default doPreProcessing overridden: " << config.doPreProcessing);
|
||||
}
|
||||
if (dictionary.getValue<double>(KeyMinimumPixelSize, minimumPixelSize)) {
|
||||
LDEBUG("Default minimumPixelSize overridden: " << minimumPixelSize);
|
||||
config.minimumTilePixelSize = static_cast<int>(minimumPixelSize);
|
||||
}
|
||||
if (dictionary.getValue<double>(KeyCacheSize, cacheSize)) {
|
||||
LDEBUG("Default cacheSize overridden: " << cacheSize);
|
||||
}
|
||||
if (dictionary.getValue<double>(KeyFlushInterval, framesUntilRequestFlush)) {
|
||||
LDEBUG("Default framesUntilRequestFlush overridden: " <<
|
||||
framesUntilRequestFlush);
|
||||
}
|
||||
|
||||
CachingTileProvider::~CachingTileProvider(){
|
||||
// Initialize instance variables
|
||||
auto tileDataset = std::make_shared<TileDataset>(filePath, config);
|
||||
|
||||
// only one thread per provider supported atm
|
||||
// (GDAL does not handle multiple threads for a single dataset very well
|
||||
// currently)
|
||||
auto threadPool = std::make_shared<ThreadPool>(1);
|
||||
|
||||
_asyncTextureDataProvider = std::make_shared<AsyncTileDataProvider>(
|
||||
tileDataset, threadPool);
|
||||
_tileCache = std::make_shared<TileCache>(static_cast<size_t>(cacheSize));
|
||||
_framesUntilRequestFlush = framesUntilRequestFlush;
|
||||
}
|
||||
|
||||
CachingTileProvider::CachingTileProvider(
|
||||
std::shared_ptr<AsyncTileDataProvider> tileReader,
|
||||
std::shared_ptr<TileCache> tileCache,
|
||||
int framesUntilFlushRequestQueue)
|
||||
: _asyncTextureDataProvider(tileReader)
|
||||
, _tileCache(tileCache)
|
||||
, _framesUntilRequestFlush(framesUntilFlushRequestQueue)
|
||||
, _framesSinceLastRequestFlush(0)
|
||||
{}
|
||||
|
||||
CachingTileProvider::~CachingTileProvider(){
|
||||
clearRequestQueue();
|
||||
}
|
||||
|
||||
void CachingTileProvider::update() {
|
||||
initTexturesFromLoadedData();
|
||||
if (_framesSinceLastRequestFlush++ > _framesUntilRequestFlush) {
|
||||
clearRequestQueue();
|
||||
}
|
||||
}
|
||||
|
||||
void CachingTileProvider::update() {
|
||||
initTexturesFromLoadedData();
|
||||
if (_framesSinceLastRequestFlush++ > _framesUntilRequestFlush) {
|
||||
clearRequestQueue();
|
||||
}
|
||||
}
|
||||
void CachingTileProvider::reset() {
|
||||
_tileCache->clear();
|
||||
_asyncTextureDataProvider->reset();
|
||||
}
|
||||
|
||||
void CachingTileProvider::reset() {
|
||||
_tileCache->clear();
|
||||
_asyncTextureDataProvider->reset();
|
||||
}
|
||||
int CachingTileProvider::maxLevel() {
|
||||
return _asyncTextureDataProvider->getTextureDataProvider()->maxChunkLevel();
|
||||
}
|
||||
|
||||
int CachingTileProvider::maxLevel() {
|
||||
return _asyncTextureDataProvider->getTextureDataProvider()->maxChunkLevel();
|
||||
}
|
||||
Tile CachingTileProvider::getTile(const TileIndex& tileIndex) {
|
||||
Tile tile = Tile::TileUnavailable;
|
||||
|
||||
Tile CachingTileProvider::getTile(const TileIndex& tileIndex) {
|
||||
Tile tile = Tile::TileUnavailable;
|
||||
|
||||
if (tileIndex.level > maxLevel()) {
|
||||
tile.status = Tile::Status::OutOfRange;
|
||||
return tile;
|
||||
}
|
||||
|
||||
TileHashKey key = tileIndex.hashKey();
|
||||
|
||||
if (_tileCache->exist(key)) {
|
||||
return _tileCache->get(key);
|
||||
}
|
||||
else {
|
||||
_asyncTextureDataProvider->enqueueTileIO(tileIndex);
|
||||
}
|
||||
|
||||
if (tileIndex.level > maxLevel()) {
|
||||
tile.status = Tile::Status::OutOfRange;
|
||||
return tile;
|
||||
}
|
||||
|
||||
float CachingTileProvider::noDataValueAsFloat() {
|
||||
return _asyncTextureDataProvider->noDataValueAsFloat();
|
||||
TileHashKey key = tileIndex.hashKey();
|
||||
|
||||
if (_tileCache->exist(key)) {
|
||||
return _tileCache->get(key);
|
||||
}
|
||||
|
||||
Tile CachingTileProvider::getDefaultTile() {
|
||||
if (_defaultTile.texture == nullptr) {
|
||||
_defaultTile = createTile(_asyncTextureDataProvider->getTextureDataProvider()->defaultTileData());
|
||||
}
|
||||
return _defaultTile;
|
||||
else {
|
||||
_asyncTextureDataProvider->enqueueTileIO(tileIndex);
|
||||
}
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
void CachingTileProvider::initTexturesFromLoadedData() {
|
||||
auto rawTiles = _asyncTextureDataProvider->getRawTiles();
|
||||
for(auto rawTile : rawTiles){
|
||||
TileHashKey key = rawTile->tileIndex.hashKey();
|
||||
Tile tile = createTile(rawTile);
|
||||
_tileCache->put(key, tile);
|
||||
}
|
||||
float CachingTileProvider::noDataValueAsFloat() {
|
||||
return _asyncTextureDataProvider->noDataValueAsFloat();
|
||||
}
|
||||
|
||||
Tile CachingTileProvider::getDefaultTile() {
|
||||
if (_defaultTile.texture == nullptr) {
|
||||
_defaultTile = createTile(
|
||||
_asyncTextureDataProvider->getTextureDataProvider()->defaultTileData()
|
||||
);
|
||||
}
|
||||
return _defaultTile;
|
||||
}
|
||||
|
||||
void CachingTileProvider::clearRequestQueue() {
|
||||
_asyncTextureDataProvider->clearRequestQueue();
|
||||
_framesSinceLastRequestFlush = 0;
|
||||
}
|
||||
|
||||
Tile::Status CachingTileProvider::getTileStatus(const TileIndex& tileIndex) {
|
||||
auto tileDataset = _asyncTextureDataProvider->getTextureDataProvider();
|
||||
if (tileIndex.level > tileDataset->maxChunkLevel()) {
|
||||
return Tile::Status::OutOfRange;
|
||||
}
|
||||
|
||||
TileHashKey key = tileIndex.hashKey();
|
||||
|
||||
if (_tileCache->exist(key)) {
|
||||
return _tileCache->get(key).status;
|
||||
}
|
||||
|
||||
return Tile::Status::Unavailable;
|
||||
}
|
||||
|
||||
TileDepthTransform CachingTileProvider::depthTransform() {
|
||||
return _asyncTextureDataProvider->getTextureDataProvider()->getDepthTransform();
|
||||
}
|
||||
|
||||
Tile CachingTileProvider::createTile(std::shared_ptr<RawTile> rawTile) {
|
||||
if (rawTile->error != CE_None) {
|
||||
return{ nullptr, nullptr, Tile::Status::IOError };
|
||||
}
|
||||
|
||||
void CachingTileProvider::initTexturesFromLoadedData() {
|
||||
auto rawTiles = _asyncTextureDataProvider->getRawTiles();
|
||||
for (auto rawTile : rawTiles){
|
||||
TileHashKey key = rawTile->tileIndex.hashKey();
|
||||
TileDataLayout dataLayout =
|
||||
_asyncTextureDataProvider->getTextureDataProvider()->getDataLayout();
|
||||
|
||||
// The texture should take ownership of the data
|
||||
std::shared_ptr<Texture> texture = std::make_shared<Texture>(
|
||||
rawTile->imageData,
|
||||
rawTile->dimensions,
|
||||
dataLayout.textureFormat.ghoulFormat,
|
||||
dataLayout.textureFormat.glFormat,
|
||||
dataLayout.glType,
|
||||
Texture::FilterMode::Linear,
|
||||
Texture::WrappingMode::ClampToEdge);
|
||||
|
||||
texture->uploadTexture();
|
||||
|
||||
// AnisotropicMipMap must be set after texture is uploaded. Why?!
|
||||
texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap);
|
||||
|
||||
Tile tile = {
|
||||
texture,
|
||||
rawTile->tileMetaData,
|
||||
Tile::Status::OK
|
||||
};
|
||||
|
||||
return tile;
|
||||
Tile tile = createTile(rawTile);
|
||||
_tileCache->put(key, tile);
|
||||
}
|
||||
}
|
||||
|
||||
void CachingTileProvider::clearRequestQueue() {
|
||||
_asyncTextureDataProvider->clearRequestQueue();
|
||||
_framesSinceLastRequestFlush = 0;
|
||||
}
|
||||
|
||||
Tile::Status CachingTileProvider::getTileStatus(const TileIndex& tileIndex) {
|
||||
auto tileDataset = _asyncTextureDataProvider->getTextureDataProvider();
|
||||
if (tileIndex.level > tileDataset->maxChunkLevel()) {
|
||||
return Tile::Status::OutOfRange;
|
||||
}
|
||||
|
||||
TileHashKey key = tileIndex.hashKey();
|
||||
|
||||
if (_tileCache->exist(key)) {
|
||||
return _tileCache->get(key).status;
|
||||
}
|
||||
|
||||
return Tile::Status::Unavailable;
|
||||
}
|
||||
|
||||
TileDepthTransform CachingTileProvider::depthTransform() {
|
||||
return _asyncTextureDataProvider->getTextureDataProvider()->getDepthTransform();
|
||||
}
|
||||
|
||||
Tile CachingTileProvider::createTile(std::shared_ptr<RawTile> rawTile) {
|
||||
if (rawTile->error != CE_None) {
|
||||
return{ nullptr, nullptr, Tile::Status::IOError };
|
||||
}
|
||||
|
||||
TileHashKey key = rawTile->tileIndex.hashKey();
|
||||
TileDataLayout dataLayout =
|
||||
_asyncTextureDataProvider->getTextureDataProvider()->getDataLayout();
|
||||
|
||||
// The texture should take ownership of the data
|
||||
std::shared_ptr<Texture> texture = std::make_shared<Texture>(
|
||||
rawTile->imageData,
|
||||
rawTile->dimensions,
|
||||
dataLayout.textureFormat.ghoulFormat,
|
||||
dataLayout.textureFormat.glFormat,
|
||||
dataLayout.glType,
|
||||
Texture::FilterMode::Linear,
|
||||
Texture::WrappingMode::ClampToEdge);
|
||||
|
||||
texture->uploadTexture();
|
||||
|
||||
// AnisotropicMipMap must be set after texture is uploaded. Why?!
|
||||
texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap);
|
||||
|
||||
Tile tile = {
|
||||
texture,
|
||||
rawTile->tileMetaData,
|
||||
Tile::Status::OK
|
||||
};
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,117 +1,98 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __CACHING_TILE_PROVIDER_H__
|
||||
#define __CACHING_TILE_PROVIDER_H__
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h> // absPath
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_CACHING_TILE_PROVIDER_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_CACHING_TILE_PROVIDER_H__
|
||||
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/tile/asynctilereader.h>
|
||||
#include <modules/globebrowsing/other/lrucache.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TILE PROVIDER //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
/**
|
||||
* Provides tiles loaded by <code>AsyncTileDataProvider</code> and
|
||||
* caches them in memory using LRU caching
|
||||
*/
|
||||
class CachingTileProvider : public TileProvider {
|
||||
public:
|
||||
class AsyncTileDataProvider;
|
||||
|
||||
CachingTileProvider(const ghoul::Dictionary& dictionary);
|
||||
/**
|
||||
* Provides tiles loaded by <code>AsyncTileDataProvider</code> and
|
||||
* caches them in memory using LRU caching
|
||||
*/
|
||||
class CachingTileProvider : public TileProvider {
|
||||
public:
|
||||
CachingTileProvider(const ghoul::Dictionary& dictionary);
|
||||
|
||||
CachingTileProvider(
|
||||
std::shared_ptr<AsyncTileDataProvider> tileReader,
|
||||
std::shared_ptr<TileCache> tileCache,
|
||||
int framesUntilFlushRequestQueue);
|
||||
CachingTileProvider(
|
||||
std::shared_ptr<AsyncTileDataProvider> tileReader,
|
||||
std::shared_ptr<TileCache> tileCache,
|
||||
int framesUntilFlushRequestQueue);
|
||||
|
||||
virtual ~CachingTileProvider();
|
||||
virtual ~CachingTileProvider();
|
||||
|
||||
/**
|
||||
* \returns a Tile with status OK iff it exists in in-memory
|
||||
* cache. If not, it may enqueue some IO operations on a
|
||||
* separate thread.
|
||||
*/
|
||||
virtual Tile getTile(const TileIndex& tileIndex);
|
||||
/**
|
||||
* \returns a Tile with status OK iff it exists in in-memory
|
||||
* cache. If not, it may enqueue some IO operations on a
|
||||
* separate thread.
|
||||
*/
|
||||
virtual Tile getTile(const TileIndex& tileIndex);
|
||||
|
||||
virtual Tile getDefaultTile();
|
||||
virtual Tile::Status getTileStatus(const TileIndex& tileIndex);
|
||||
virtual TileDepthTransform depthTransform();
|
||||
virtual void update();
|
||||
virtual void reset();
|
||||
virtual int maxLevel();
|
||||
virtual float noDataValueAsFloat();
|
||||
virtual Tile getDefaultTile();
|
||||
virtual Tile::Status getTileStatus(const TileIndex& tileIndex);
|
||||
virtual TileDepthTransform depthTransform();
|
||||
virtual void update();
|
||||
virtual void reset();
|
||||
virtual int maxLevel();
|
||||
virtual float noDataValueAsFloat();
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Collects all asynchronously downloaded <code>RawTile</code>
|
||||
* and uses <code>createTile</code> to create <code>Tile</code>s,
|
||||
* which are put in the LRU cache - potentially pushing out outdated
|
||||
* Tiles.
|
||||
*/
|
||||
void initTexturesFromLoadedData();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Helper functions //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* \returns A tile with <code>Tile::Status::OK</code> if no errors
|
||||
* occured, a tile with <code>Tile::Status::IOError</code> otherwise
|
||||
*/
|
||||
Tile createTile(std::shared_ptr<RawTile> res);
|
||||
|
||||
/**
|
||||
* Collects all asynchronously downloaded <code>RawTile</code>
|
||||
* and uses <code>createTile</code> to create <code>Tile</code>s,
|
||||
* which are put in the LRU cache - potentially pushing out outdated
|
||||
* Tiles.
|
||||
*/
|
||||
void initTexturesFromLoadedData();
|
||||
/**
|
||||
* Deletes all enqueued, but not yet started async downloads of textures.
|
||||
* Note that this does not cancel any currently ongoing async downloads.
|
||||
*/
|
||||
void clearRequestQueue();
|
||||
|
||||
/**
|
||||
* \returns A tile with <code>Tile::Status::OK</code> if no errors
|
||||
* occured, a tile with <code>Tile::Status::IOError</code> otherwise
|
||||
*/
|
||||
Tile createTile(std::shared_ptr<RawTile> res);
|
||||
std::shared_ptr<AsyncTileDataProvider> _asyncTextureDataProvider;
|
||||
std::shared_ptr<TileCache> _tileCache;
|
||||
|
||||
/**
|
||||
* Deletes all enqueued, but not yet started async downloads of textures.
|
||||
* Note that this does not cancel any currently ongoing async downloads.
|
||||
*/
|
||||
void clearRequestQueue();
|
||||
int _framesSinceLastRequestFlush;
|
||||
int _framesUntilRequestFlush;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Member variables //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::shared_ptr<AsyncTileDataProvider> _asyncTextureDataProvider;
|
||||
std::shared_ptr<TileCache> _tileCache;
|
||||
|
||||
int _framesSinceLastRequestFlush;
|
||||
int _framesUntilRequestFlush;
|
||||
|
||||
Tile _defaultTile;
|
||||
};
|
||||
Tile _defaultTile;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __CACHING_TILE_PROVIDER_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_CACHING_TILE_PROVIDER_H__
|
||||
|
||||
@@ -1,97 +1,90 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/singleimageprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "SingleImageProvider";
|
||||
|
||||
const char* KeyFilePath = "FilePath";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) {
|
||||
// Required input
|
||||
if (!dictionary.getValue<std::string>(KeyFilePath, _imagePath)) {
|
||||
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
|
||||
}
|
||||
|
||||
reset();
|
||||
SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) {
|
||||
// Required input
|
||||
if (!dictionary.getValue<std::string>(KeyFilePath, _imagePath)) {
|
||||
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
|
||||
}
|
||||
|
||||
SingleImageProvider::SingleImageProvider(const std::string& imagePath)
|
||||
: _imagePath(imagePath)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
Tile SingleImageProvider::getTile(const TileIndex& tileIndex) {
|
||||
return _tile;
|
||||
}
|
||||
SingleImageProvider::SingleImageProvider(const std::string& imagePath)
|
||||
: _imagePath(imagePath)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
Tile SingleImageProvider::getDefaultTile() {
|
||||
return _tile;
|
||||
}
|
||||
Tile SingleImageProvider::getTile(const TileIndex& tileIndex) {
|
||||
return _tile;
|
||||
}
|
||||
|
||||
Tile::Status SingleImageProvider::getTileStatus(const TileIndex& index) {
|
||||
return _tile.status;
|
||||
}
|
||||
Tile SingleImageProvider::getDefaultTile() {
|
||||
return _tile;
|
||||
}
|
||||
|
||||
TileDepthTransform SingleImageProvider::depthTransform() {
|
||||
TileDepthTransform transform;
|
||||
transform.depthOffset = 0.0f;
|
||||
transform.depthScale = 1.0f;
|
||||
return transform;
|
||||
}
|
||||
Tile::Status SingleImageProvider::getTileStatus(const TileIndex& index) {
|
||||
return _tile.status;
|
||||
}
|
||||
|
||||
void SingleImageProvider::update() {
|
||||
// nothing to be done
|
||||
}
|
||||
TileDepthTransform SingleImageProvider::depthTransform() {
|
||||
TileDepthTransform transform;
|
||||
transform.depthOffset = 0.0f;
|
||||
transform.depthScale = 1.0f;
|
||||
return transform;
|
||||
}
|
||||
|
||||
void SingleImageProvider::reset() {
|
||||
_tile = Tile();
|
||||
_tile.texture = std::shared_ptr<Texture>(ghoul::io::TextureReader::ref().loadTexture(_imagePath).release());
|
||||
_tile.status = _tile.texture != nullptr ? Tile::Status::OK : Tile::Status::IOError;
|
||||
_tile.metaData = nullptr;
|
||||
void SingleImageProvider::update() {
|
||||
// nothing to be done
|
||||
}
|
||||
|
||||
_tile.texture->uploadTexture();
|
||||
_tile.texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
|
||||
}
|
||||
void SingleImageProvider::reset() {
|
||||
_tile = Tile();
|
||||
_tile.texture = std::shared_ptr<Texture>(ghoul::io::TextureReader::ref().loadTexture(_imagePath).release());
|
||||
_tile.status = _tile.texture != nullptr ? Tile::Status::OK : Tile::Status::IOError;
|
||||
_tile.metaData = nullptr;
|
||||
|
||||
int SingleImageProvider::maxLevel() {
|
||||
return 1337; // unlimited
|
||||
}
|
||||
_tile.texture->uploadTexture();
|
||||
_tile.texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
|
||||
}
|
||||
|
||||
int SingleImageProvider::maxLevel() {
|
||||
return 1337; // unlimited
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,71 +1,57 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __SINGLE_IMAGE_PROVIDER_H__
|
||||
#define __SINGLE_IMAGE_PROVIDER_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_SINGLE_IMAGE_PROVIDER_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_SINGLE_IMAGE_PROVIDER_H__
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/tile/asynctilereader.h>
|
||||
|
||||
#include <gdal_priv.h>
|
||||
|
||||
#include <openspace/engine/downloadmanager.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h> // absPath
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <ghoul/font/fontrenderer.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace ghoul::opengl;
|
||||
using namespace ghoul::opengl;
|
||||
|
||||
class SingleImageProvider : public TileProvider {
|
||||
public:
|
||||
|
||||
SingleImageProvider(const ghoul::Dictionary& dictionary);
|
||||
SingleImageProvider(const std::string& imagePath);
|
||||
virtual ~SingleImageProvider() { }
|
||||
class SingleImageProvider : public TileProvider {
|
||||
public:
|
||||
SingleImageProvider(const ghoul::Dictionary& dictionary);
|
||||
SingleImageProvider(const std::string& imagePath);
|
||||
virtual ~SingleImageProvider() = default;
|
||||
|
||||
virtual Tile getTile(const TileIndex& tileIndex);
|
||||
virtual Tile getDefaultTile();
|
||||
virtual Tile::Status getTileStatus(const TileIndex& index);
|
||||
virtual TileDepthTransform depthTransform();
|
||||
virtual void update();
|
||||
virtual void reset();
|
||||
virtual int maxLevel();
|
||||
private:
|
||||
Tile _tile;
|
||||
std::string _imagePath;
|
||||
};
|
||||
virtual Tile getTile(const TileIndex& tileIndex);
|
||||
virtual Tile getDefaultTile();
|
||||
virtual Tile::Status getTileStatus(const TileIndex& index);
|
||||
virtual TileDepthTransform depthTransform();
|
||||
virtual void update();
|
||||
virtual void reset();
|
||||
virtual int maxLevel();
|
||||
|
||||
private:
|
||||
Tile _tile;
|
||||
std::string _imagePath;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __SINGLE_IMAGE_PROVIDER_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_SINGLE_IMAGE_PROVIDER_H__
|
||||
|
||||
@@ -1,47 +1,35 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/geometry/geodetic2.h>
|
||||
* *
|
||||
* 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/tile/tileprovider/temporaltileprovider.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileprovider/cachingtileprovider.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <openspace/engine/downloadmanager.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h> // abspath
|
||||
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <streambuf>
|
||||
|
||||
#include "cpl_minixml.h"
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TemporalTileProvider";
|
||||
@@ -56,283 +44,306 @@ namespace {
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
const std::string TemporalTileProvider::URL_TIME_PLACEHOLDER("${OpenSpaceTimeId}");
|
||||
const char* TemporalTileProvider::URL_TIME_PLACEHOLDER("${OpenSpaceTimeId}");
|
||||
|
||||
const std::string TemporalTileProvider::TemporalXMLTags::TIME_START = "OpenSpaceTimeStart";
|
||||
const std::string TemporalTileProvider::TemporalXMLTags::TIME_END = "OpenSpaceTimeEnd";
|
||||
const std::string TemporalTileProvider::TemporalXMLTags::TIME_RESOLUTION = "OpenSpaceTimeResolution";
|
||||
const std::string TemporalTileProvider::TemporalXMLTags::TIME_FORMAT = "OpenSpaceTimeIdFormat";
|
||||
const char* TemporalTileProvider::TemporalXMLTags::TIME_START = "OpenSpaceTimeStart";
|
||||
const char* TemporalTileProvider::TemporalXMLTags::TIME_END = "OpenSpaceTimeEnd";
|
||||
const char* TemporalTileProvider::TemporalXMLTags::TIME_RESOLUTION =
|
||||
"OpenSpaceTimeResolution";
|
||||
const char* TemporalTileProvider::TemporalXMLTags::TIME_FORMAT = "OpenSpaceTimeIdFormat";
|
||||
|
||||
TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary)
|
||||
: _initDict(dictionary)
|
||||
{
|
||||
TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary)
|
||||
: _initDict(dictionary)
|
||||
{
|
||||
|
||||
if (!dictionary.getValue<std::string>(KeyFilePath, _datasetFile)) {
|
||||
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
|
||||
}
|
||||
|
||||
std::ifstream in(_datasetFile.c_str());
|
||||
if (!in.is_open()) {
|
||||
throw ghoul::FileNotFoundError(_datasetFile);
|
||||
}
|
||||
|
||||
// read file
|
||||
std::string xml((std::istreambuf_iterator<char>(in)), (std::istreambuf_iterator<char>()));
|
||||
_gdalXmlTemplate = consumeTemporalMetaData(xml);
|
||||
_defaultTile = getTileProvider()->getDefaultTile();
|
||||
if (!dictionary.getValue<std::string>(KeyFilePath, _datasetFile)) {
|
||||
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
|
||||
}
|
||||
|
||||
std::string TemporalTileProvider::consumeTemporalMetaData(const std::string& xml) {
|
||||
CPLXMLNode* node = CPLParseXMLString(xml.c_str());
|
||||
std::ifstream in(_datasetFile.c_str());
|
||||
if (!in.is_open()) {
|
||||
throw ghoul::FileNotFoundError(_datasetFile);
|
||||
}
|
||||
|
||||
// read file
|
||||
std::string xml(
|
||||
std::istreambuf_iterator<char>(in),
|
||||
(std::istreambuf_iterator<char>())
|
||||
);
|
||||
_gdalXmlTemplate = consumeTemporalMetaData(xml);
|
||||
_defaultTile = getTileProvider()->getDefaultTile();
|
||||
}
|
||||
|
||||
std::string timeStart = getXMLValue(node, TemporalXMLTags::TIME_START, "2000 Jan 1");
|
||||
std::string timeResolution = getXMLValue(node, TemporalXMLTags::TIME_RESOLUTION, "2d");
|
||||
std::string timeEnd = getXMLValue(node, TemporalXMLTags::TIME_END, "Now");
|
||||
std::string timeIdFormat = getXMLValue(node, TemporalXMLTags::TIME_FORMAT, "YYYY-MM-DDThh:mm:ssZ");
|
||||
std::string TemporalTileProvider::consumeTemporalMetaData(const std::string& xml) {
|
||||
CPLXMLNode* node = CPLParseXMLString(xml.c_str());
|
||||
|
||||
Time start; start.setTime(timeStart);
|
||||
Time end(Time::now());
|
||||
if (timeEnd != "Now") {
|
||||
end.setTime(timeEnd);
|
||||
}
|
||||
std::string timeStart = getXMLValue(
|
||||
node,
|
||||
TemporalXMLTags::TIME_START,
|
||||
"2000 Jan 1"
|
||||
);
|
||||
std::string timeResolution = getXMLValue(
|
||||
node,
|
||||
TemporalXMLTags::TIME_RESOLUTION,
|
||||
"2d"
|
||||
);
|
||||
std::string timeEnd = getXMLValue(
|
||||
node,
|
||||
TemporalXMLTags::TIME_END,
|
||||
"Now"
|
||||
);
|
||||
std::string timeIdFormat = getXMLValue(
|
||||
node,
|
||||
TemporalXMLTags::TIME_FORMAT,
|
||||
"YYYY-MM-DDThh:mm:ssZ"
|
||||
);
|
||||
|
||||
Time start; start.setTime(timeStart);
|
||||
Time end(Time::now());
|
||||
if (timeEnd != "Now") {
|
||||
end.setTime(timeEnd);
|
||||
}
|
||||
|
||||
try {
|
||||
_timeQuantizer = TimeQuantizer(start, end, timeResolution);
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Could not create time quantizer for Temporal GDAL dataset '" +
|
||||
_datasetFile + "'. " + e.message);
|
||||
}
|
||||
_timeFormat = TimeIdProviderFactory::getProvider(timeIdFormat);
|
||||
if (!_timeFormat) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Invalid Time Format " + timeIdFormat + " in " + _datasetFile
|
||||
);
|
||||
}
|
||||
|
||||
std::string gdalDescription;
|
||||
CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "GDAL_WMS");
|
||||
if (gdalNode) {
|
||||
gdalDescription = CPLSerializeXMLTree(gdalNode);
|
||||
}
|
||||
if (!gdalNode) {
|
||||
CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "FilePath");
|
||||
gdalDescription = std::string(gdalNode->psChild->pszValue);
|
||||
}
|
||||
|
||||
return gdalDescription;
|
||||
}
|
||||
|
||||
std::string TemporalTileProvider::getXMLValue(CPLXMLNode* root, const std::string& key,
|
||||
const std::string& defaultVal)
|
||||
{
|
||||
CPLXMLNode * n = CPLSearchXMLNode(root, key.c_str());
|
||||
if (!n) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Unable to parse file " + _datasetFile + ". " + key + " missing."
|
||||
);
|
||||
}
|
||||
|
||||
bool hasValue =
|
||||
(n != nullptr && n->psChild != nullptr && n->psChild->pszValue != nullptr);
|
||||
return hasValue ? std::string(n->psChild->pszValue) : defaultVal;
|
||||
}
|
||||
|
||||
TileDepthTransform TemporalTileProvider::depthTransform() {
|
||||
ensureUpdated();
|
||||
return _currentTileProvider->depthTransform();
|
||||
}
|
||||
|
||||
Tile::Status TemporalTileProvider::getTileStatus(const TileIndex& tileIndex) {
|
||||
ensureUpdated();
|
||||
return _currentTileProvider->getTileStatus(tileIndex);
|
||||
}
|
||||
|
||||
Tile TemporalTileProvider::getTile(const TileIndex& tileIndex) {
|
||||
ensureUpdated();
|
||||
return _currentTileProvider->getTile(tileIndex);
|
||||
}
|
||||
|
||||
Tile TemporalTileProvider::getDefaultTile() {
|
||||
return _defaultTile;
|
||||
}
|
||||
|
||||
int TemporalTileProvider::maxLevel() {
|
||||
ensureUpdated();
|
||||
return _currentTileProvider->maxLevel();
|
||||
}
|
||||
|
||||
void TemporalTileProvider::ensureUpdated() {
|
||||
if (_currentTileProvider == nullptr) {
|
||||
LDEBUG("Warning: update was done lazily");
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void TemporalTileProvider::update() {
|
||||
auto newCurrent = getTileProvider();
|
||||
if (newCurrent) {
|
||||
_currentTileProvider = newCurrent;
|
||||
}
|
||||
_currentTileProvider->update();
|
||||
}
|
||||
|
||||
void TemporalTileProvider::reset() {
|
||||
for (auto& it : _tileProviderMap) {
|
||||
it.second->reset();
|
||||
}
|
||||
//auto end = _tileProviderMap.end();
|
||||
//for (auto it = _tileProviderMap.begin(); it != end; it++) {
|
||||
// it->second->reset();
|
||||
//}
|
||||
}
|
||||
|
||||
std::shared_ptr<TileProvider> TemporalTileProvider::getTileProvider(Time t) {
|
||||
Time tCopy(t);
|
||||
if (_timeQuantizer.quantize(tCopy, true)) {
|
||||
TimeKey timekey = _timeFormat->stringify(tCopy);
|
||||
try {
|
||||
_timeQuantizer = TimeQuantizer(start, end, timeResolution);
|
||||
return getTileProvider(timekey);
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Could not create time quantizer for Temporal GDAL dataset '" +
|
||||
_datasetFile + "'. " + e.message);
|
||||
}
|
||||
_timeFormat = TimeIdProviderFactory::getProvider(timeIdFormat);
|
||||
if (!_timeFormat) {
|
||||
throw ghoul::RuntimeError("Invalid Time Format " + timeIdFormat + " in " + _datasetFile);
|
||||
}
|
||||
|
||||
std::string gdalDescription;
|
||||
CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "GDAL_WMS");
|
||||
if (gdalNode) {
|
||||
gdalDescription = CPLSerializeXMLTree(gdalNode);
|
||||
}
|
||||
if (!gdalNode) {
|
||||
CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "FilePath");
|
||||
gdalDescription = std::string(gdalNode->psChild->pszValue);
|
||||
}
|
||||
|
||||
return gdalDescription;
|
||||
}
|
||||
|
||||
std::string TemporalTileProvider::getXMLValue(CPLXMLNode* root, const std::string& key, const std::string& defaultVal) {
|
||||
CPLXMLNode * n = CPLSearchXMLNode(root, key.c_str());
|
||||
if (!n) {
|
||||
throw ghoul::RuntimeError("Unable to parse file " + _datasetFile + ". " + key + " missing.");
|
||||
}
|
||||
|
||||
bool hasValue = (n != nullptr && n->psChild != nullptr && n->psChild->pszValue != nullptr);
|
||||
return hasValue ? std::string(n->psChild->pszValue) : defaultVal;
|
||||
}
|
||||
|
||||
TileDepthTransform TemporalTileProvider::depthTransform() {
|
||||
ensureUpdated();
|
||||
return _currentTileProvider->depthTransform();
|
||||
}
|
||||
|
||||
Tile::Status TemporalTileProvider::getTileStatus(const TileIndex& tileIndex) {
|
||||
ensureUpdated();
|
||||
return _currentTileProvider->getTileStatus(tileIndex);
|
||||
}
|
||||
|
||||
Tile TemporalTileProvider::getTile(const TileIndex& tileIndex) {
|
||||
ensureUpdated();
|
||||
return _currentTileProvider->getTile(tileIndex);
|
||||
}
|
||||
|
||||
Tile TemporalTileProvider::getDefaultTile() {
|
||||
return _defaultTile;
|
||||
}
|
||||
|
||||
|
||||
int TemporalTileProvider::maxLevel() {
|
||||
ensureUpdated();
|
||||
return _currentTileProvider->maxLevel();
|
||||
}
|
||||
|
||||
void TemporalTileProvider::ensureUpdated() {
|
||||
if (_currentTileProvider == nullptr) {
|
||||
LDEBUG("Warning: update was done lazily");
|
||||
update();
|
||||
LERROR(e.message);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TemporalTileProvider::update() {
|
||||
auto newCurrent = getTileProvider();
|
||||
if (newCurrent) {
|
||||
_currentTileProvider = newCurrent;
|
||||
}
|
||||
_currentTileProvider->update();
|
||||
std::shared_ptr<TileProvider> TemporalTileProvider::getTileProvider(TimeKey timekey) {
|
||||
auto it = _tileProviderMap.find(timekey);
|
||||
if (it != _tileProviderMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
else {
|
||||
auto tileProvider = initTileProvider(timekey);
|
||||
|
||||
void TemporalTileProvider::reset() {
|
||||
auto end = _tileProviderMap.end();
|
||||
for (auto it = _tileProviderMap.begin(); it != end; it++) {
|
||||
it->second->reset();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<TileProvider> TemporalTileProvider::getTileProvider(Time t) {
|
||||
Time tCopy(t);
|
||||
if (_timeQuantizer.quantize(tCopy, true)) {
|
||||
TimeKey timekey = _timeFormat->stringify(tCopy);
|
||||
try {
|
||||
return getTileProvider(timekey);
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERROR(e.message);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<TileProvider> TemporalTileProvider::getTileProvider(TimeKey timekey) {
|
||||
auto it = _tileProviderMap.find(timekey);
|
||||
if (it != _tileProviderMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
else {
|
||||
auto tileProvider = initTileProvider(timekey);
|
||||
|
||||
_tileProviderMap[timekey] = tileProvider;
|
||||
return tileProvider;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<TileProvider> TemporalTileProvider::initTileProvider(TimeKey timekey) {
|
||||
std::string gdalDatasetXml = getGdalDatasetXML(timekey);
|
||||
_initDict.setValue<std::string>(KeyFilePath, gdalDatasetXml);
|
||||
auto tileProvider = std::make_shared<CachingTileProvider>(_initDict);
|
||||
_tileProviderMap[timekey] = tileProvider;
|
||||
return tileProvider;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<TileProvider> TemporalTileProvider::initTileProvider(TimeKey timekey) {
|
||||
std::string gdalDatasetXml = getGdalDatasetXML(timekey);
|
||||
_initDict.setValue<std::string>(KeyFilePath, gdalDatasetXml);
|
||||
auto tileProvider = std::make_shared<CachingTileProvider>(_initDict);
|
||||
return tileProvider;
|
||||
}
|
||||
|
||||
std::string TemporalTileProvider::getGdalDatasetXML(Time t) {
|
||||
TimeKey timekey = _timeFormat->stringify(t);
|
||||
return getGdalDatasetXML(timekey);
|
||||
}
|
||||
std::string TemporalTileProvider::getGdalDatasetXML(Time t) {
|
||||
TimeKey timekey = _timeFormat->stringify(t);
|
||||
return getGdalDatasetXML(timekey);
|
||||
}
|
||||
|
||||
std::string TemporalTileProvider::getGdalDatasetXML(TimeKey timeKey) {
|
||||
std::string xmlTemplate(_gdalXmlTemplate);
|
||||
size_t pos = xmlTemplate.find(URL_TIME_PLACEHOLDER);
|
||||
size_t numChars = URL_TIME_PLACEHOLDER.length();
|
||||
ghoul_assert(pos != std::string::npos, "Invalid dataset file");
|
||||
std::string timeSpecifiedXml = xmlTemplate.replace(pos, numChars, timeKey);
|
||||
return timeSpecifiedXml;
|
||||
}
|
||||
std::string TemporalTileProvider::getGdalDatasetXML(TimeKey timeKey) {
|
||||
std::string xmlTemplate(_gdalXmlTemplate);
|
||||
size_t pos = xmlTemplate.find(URL_TIME_PLACEHOLDER);
|
||||
//size_t numChars = std::string(URL_TIME_PLACEHOLDER).length();
|
||||
size_t numChars = strlen(URL_TIME_PLACEHOLDER);
|
||||
ghoul_assert(pos != std::string::npos, "Invalid dataset file");
|
||||
std::string timeSpecifiedXml = xmlTemplate.replace(pos, numChars, timeKey);
|
||||
return timeSpecifiedXml;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Time Id Providers //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
std::string YYYY_MM_DD::stringify(const Time& t) const {
|
||||
return t.ISO8601().substr(0, 10);
|
||||
}
|
||||
std::string YYYY_MM_DD::stringify(const Time& t) const {
|
||||
return t.ISO8601().substr(0, 10);
|
||||
}
|
||||
|
||||
std::string YYYY_MM_DDThhColonmmColonssZ::stringify(const Time& t) const {
|
||||
return t.ISO8601().substr(0, 19) + "Z";
|
||||
}
|
||||
std::string YYYY_MM_DDThhColonmmColonssZ::stringify(const Time& t) const {
|
||||
return t.ISO8601().substr(0, 19) + "Z";
|
||||
}
|
||||
|
||||
std::string YYYY_MM_DDThh_mm_ssZ::stringify(const Time& t) const {
|
||||
std::string timeString = t.ISO8601().substr(0, 19) + "Z";
|
||||
replace( timeString.begin(), timeString.end(), ':', '_' );
|
||||
return timeString;
|
||||
std::string YYYY_MM_DDThh_mm_ssZ::stringify(const Time& t) const {
|
||||
std::string timeString = t.ISO8601().substr(0, 19) + "Z";
|
||||
replace( timeString.begin(), timeString.end(), ':', '_' );
|
||||
return timeString;
|
||||
}
|
||||
|
||||
bool TimeIdProviderFactory::initialized = false;
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<TimeFormat>>
|
||||
TimeIdProviderFactory::_timeIdProviderMap =
|
||||
std::unordered_map<std::string, std::unique_ptr<TimeFormat>>();
|
||||
|
||||
void TimeIdProviderFactory::init() {
|
||||
_timeIdProviderMap.insert({ "YYYY-MM-DD" , std::make_unique<YYYY_MM_DD>() });
|
||||
_timeIdProviderMap.insert(
|
||||
{ "YYYY-MM-DDThh:mm:ssZ", std::make_unique<YYYY_MM_DDThhColonmmColonssZ>() }
|
||||
);
|
||||
initialized = true;
|
||||
_timeIdProviderMap.insert(
|
||||
{ "YYYY-MM-DDThh_mm_ssZ", std::make_unique<YYYY_MM_DDThh_mm_ssZ>() }
|
||||
);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
TimeFormat* TimeIdProviderFactory::getProvider(const std::string& format) {
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
ghoul_assert(
|
||||
_timeIdProviderMap.find(format) != _timeIdProviderMap.end(),
|
||||
"Unsupported Time format: " << format
|
||||
);
|
||||
return _timeIdProviderMap[format].get();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Time Id Providers Facotry //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
TimeQuantizer::TimeQuantizer(const Time& start, const Time& end, double resolution)
|
||||
: _timerange(start.j2000Seconds(), end.j2000Seconds())
|
||||
, _resolution(resolution)
|
||||
{}
|
||||
|
||||
bool TimeIdProviderFactory::initialized = false;
|
||||
TimeQuantizer::TimeQuantizer(const Time& start, const Time& end,
|
||||
const std::string& resolution)
|
||||
: TimeQuantizer(start, end, parseTimeResolutionStr(resolution))
|
||||
{}
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<TimeFormat>> TimeIdProviderFactory::_timeIdProviderMap = std::unordered_map<std::string, std::unique_ptr<TimeFormat>>();
|
||||
|
||||
void TimeIdProviderFactory::init() {
|
||||
_timeIdProviderMap.insert(
|
||||
std::pair<std::string, std::unique_ptr<TimeFormat> >( "YYYY-MM-DD", std::make_unique<YYYY_MM_DD>() ));
|
||||
_timeIdProviderMap.insert(std::pair<std::string, std::unique_ptr<TimeFormat> > ( "YYYY-MM-DDThh:mm:ssZ", std::make_unique<YYYY_MM_DDThhColonmmColonssZ>() ));
|
||||
initialized = true;
|
||||
_timeIdProviderMap.insert(std::pair<std::string, std::unique_ptr<TimeFormat> > ( "YYYY-MM-DDThh_mm_ssZ", std::make_unique<YYYY_MM_DDThh_mm_ssZ>() ));
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
TimeFormat* TimeIdProviderFactory::getProvider(const std::string& format) {
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
ghoul_assert(_timeIdProviderMap.find(format) != _timeIdProviderMap.end(),
|
||||
"Unsupported Time format: " << format);
|
||||
return _timeIdProviderMap[format].get();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Time Quantizer //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
TimeQuantizer::TimeQuantizer(const Time& start, const Time& end, double resolution)
|
||||
: _timerange(start.j2000Seconds(), end.j2000Seconds())
|
||||
, _resolution(resolution)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TimeQuantizer::TimeQuantizer(const Time& start, const Time& end, const std::string& resolution)
|
||||
: TimeQuantizer(start, end, parseTimeResolutionStr(resolution))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
double TimeQuantizer::parseTimeResolutionStr(const std::string& resoltutionStr) {
|
||||
const char unit = resoltutionStr.back();
|
||||
std::string numberString = resoltutionStr.substr(0, resoltutionStr.length() - 1);
|
||||
double TimeQuantizer::parseTimeResolutionStr(const std::string& resoltutionStr) {
|
||||
const char unit = resoltutionStr.back();
|
||||
std::string numberString = resoltutionStr.substr(0, resoltutionStr.length() - 1);
|
||||
|
||||
char* p;
|
||||
double value = strtol(numberString.c_str(), &p, 10);
|
||||
if (*p) { // not a number
|
||||
throw ghoul::RuntimeError("Cannot convert " + numberString + " to number");
|
||||
}
|
||||
else {
|
||||
// convert value to seconds, based on unit.
|
||||
// The switch statment has intentional fall throughs
|
||||
switch (unit) {
|
||||
case 'y': value *= 365;
|
||||
case 'd': value *= 24.0;
|
||||
case 'h': value *= 60.0;
|
||||
case 'm': value *= 60.0;
|
||||
case 's': value *= 1.0;
|
||||
break;
|
||||
default:
|
||||
throw ghoul::RuntimeError("Invalid unit format '" + std::string(1, unit) +
|
||||
"'. Expected 'y', 'd', 'h', 'm' or 's'.");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
char* p;
|
||||
double value = strtol(numberString.c_str(), &p, 10);
|
||||
if (*p) { // not a number
|
||||
throw ghoul::RuntimeError("Cannot convert " + numberString + " to number");
|
||||
}
|
||||
else {
|
||||
// convert value to seconds, based on unit.
|
||||
// The switch statment has intentional fall throughs
|
||||
switch (unit) {
|
||||
case 'y': value *= 365;
|
||||
case 'd': value *= 24.0;
|
||||
case 'h': value *= 60.0;
|
||||
case 'm': value *= 60.0;
|
||||
case 's': value *= 1.0;
|
||||
break;
|
||||
default:
|
||||
throw ghoul::RuntimeError("Invalid unit format '" + std::string(1, unit) +
|
||||
"'. Expected 'y', 'd', 'h', 'm' or 's'.");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
bool TimeQuantizer::quantize(Time& t, bool clamp) const {
|
||||
double unquantized = t.j2000Seconds();
|
||||
if (_timerange.includes(unquantized)) {
|
||||
double quantized = std::floor((unquantized - _timerange.start) / _resolution) * _resolution + _timerange.start;
|
||||
t.setTime(quantized);
|
||||
return true;
|
||||
}
|
||||
else if (clamp) {
|
||||
double clampedTime = unquantized;
|
||||
clampedTime = std::max(clampedTime, _timerange.start);
|
||||
clampedTime = std::min(clampedTime, _timerange.end);
|
||||
t.setTime(clampedTime);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
bool TimeQuantizer::quantize(Time& t, bool clamp) const {
|
||||
double unquantized = t.j2000Seconds();
|
||||
if (_timerange.includes(unquantized)) {
|
||||
double quantized = std::floor((unquantized - _timerange.start) / _resolution) * _resolution + _timerange.start;
|
||||
t.setTime(quantized);
|
||||
return true;
|
||||
}
|
||||
else if (clamp) {
|
||||
double clampedTime = unquantized;
|
||||
clampedTime = std::max(clampedTime, _timerange.start);
|
||||
clampedTime = std::min(clampedTime, _timerange.end);
|
||||
t.setTime(clampedTime);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,323 +1,299 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TEMPORAL_TILE_PROVIDER_H__
|
||||
#define __TEMPORAL_TILE_PROVIDER_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TEMPORAL_TILE_PROVIDER_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TEMPORAL_TILE_PROVIDER_H__
|
||||
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
|
||||
#include <openspace/util/time.h>
|
||||
#include <openspace/util/timerange.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <gdal_priv.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TILE PROVIDER //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct CPLXMLNode;
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Time Id Providers //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Interface for stringifying OpenSpace Time instances.
|
||||
*
|
||||
* Once OpenSpace has a proper Time format class, this should be handled by that instead
|
||||
* of here.
|
||||
*/
|
||||
struct TimeFormat {
|
||||
/**
|
||||
* Interface for stringifying OpenSpace Time instances.
|
||||
*
|
||||
* Once OpenSpace has a proper Time format class, this should be
|
||||
* handled by that instead of here.
|
||||
*/
|
||||
struct TimeFormat {
|
||||
/**
|
||||
* Stringifies a OpenSpace time instance
|
||||
* \param t The time to be stringifyed
|
||||
* \returns A string description of the provided time
|
||||
*/
|
||||
virtual std::string stringify(const Time& t) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stringifies OpenSpace to the format "YYYY-MM-DD".
|
||||
* Example: 2016-09-08
|
||||
*/
|
||||
struct YYYY_MM_DD : public TimeFormat {
|
||||
virtual std::string stringify(const Time& t) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stringifies OpenSpace to the format "YYYY-MM-DDThh:mm:ssZ"
|
||||
* Example: 2016-09-08T23:05:05Z
|
||||
*/
|
||||
struct YYYY_MM_DDThhColonmmColonssZ : public TimeFormat {
|
||||
virtual std::string stringify(const Time& t) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stringifies OpenSpace to the format "YYYY-MM-DDThh:mm:ssZ"
|
||||
* Example: 2016-09-08T23:05:05Z
|
||||
* Stringifies a OpenSpace time instance
|
||||
* \param t The time to be stringifyed
|
||||
* \returns A string description of the provided time
|
||||
*/
|
||||
struct YYYY_MM_DDThh_mm_ssZ : public TimeFormat {
|
||||
virtual std::string stringify(const Time& t) const;
|
||||
};
|
||||
virtual std::string stringify(const Time& t) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stringifies OpenSpace to the format "YYYY-MM-DD".
|
||||
* Example: 2016-09-08
|
||||
*/
|
||||
struct YYYY_MM_DD : public TimeFormat {
|
||||
virtual std::string stringify(const Time& t) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stringifies OpenSpace to the format "YYYY-MM-DDThh:mm:ssZ"
|
||||
* Example: 2016-09-08T23:05:05Z
|
||||
*/
|
||||
struct YYYY_MM_DDThhColonmmColonssZ : public TimeFormat {
|
||||
virtual std::string stringify(const Time& t) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stringifies OpenSpace to the format "YYYY-MM-DDThh:mm:ssZ"
|
||||
* Example: 2016-09-08T23:05:05Z
|
||||
*/
|
||||
struct YYYY_MM_DDThh_mm_ssZ : public TimeFormat {
|
||||
virtual std::string stringify(const Time& t) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Static factory class for providing different TimeFormats.
|
||||
* A time format stringifier is retrieved by a name of the format.
|
||||
* See implementation of <code>init()</code> to see what time
|
||||
* id formats are supported.
|
||||
*/
|
||||
struct TimeIdProviderFactory {
|
||||
/**
|
||||
* Maps a name of a format to an implementation of a TimeFormat.
|
||||
* Calling this method will also initialize the TimeIdProviderFactory
|
||||
* if it hasn't been.
|
||||
*
|
||||
* See implementation of <code>init()</code> for supported time formats.
|
||||
*
|
||||
* \param format - name of TimeFormat, eg "YYYY-MM-DDThh:mm:ssZ".
|
||||
* \returns a concrete TimeFormat used to stringify instances of Time
|
||||
*/
|
||||
static TimeFormat* getProvider(const std::string& format);
|
||||
|
||||
/**
|
||||
* Static factory class for providing different TimeFormats.
|
||||
* A time format stringifier is retrieved by a name of the format.
|
||||
* See implementation of <code>init()</code> to see what time
|
||||
* id formats are supported.
|
||||
*/
|
||||
struct TimeIdProviderFactory {
|
||||
/**
|
||||
* Maps a name of a format to an implementation of a TimeFormat.
|
||||
* Calling this method will also initialize the TimeIdProviderFactory
|
||||
* if it hasn't been.
|
||||
*
|
||||
* See implementation of <code>init()</code> for supported time formats.
|
||||
*
|
||||
* \param format - name of TimeFormat, eg "YYYY-MM-DDThh:mm:ssZ".
|
||||
* \returns a concrete TimeFormat used to stringify instances of Time
|
||||
*/
|
||||
static TimeFormat* getProvider(const std::string& format);
|
||||
* Registers all supported TimeFormats.
|
||||
*/
|
||||
static void init();
|
||||
|
||||
/**
|
||||
* Registers all supported TimeFormats.
|
||||
*/
|
||||
static void init();
|
||||
static std::unordered_map<std::string, std::unique_ptr<TimeFormat>> _timeIdProviderMap;
|
||||
static bool initialized;
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, std::unique_ptr<TimeFormat>> _timeIdProviderMap;
|
||||
static bool initialized;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Time Quantizer //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Used to quantize time to descrete values.
|
||||
*/
|
||||
struct TimeQuantizer {
|
||||
TimeQuantizer() {}
|
||||
TimeQuantizer(const Time& start, const Time& end, double resolution);
|
||||
TimeQuantizer(const Time& start, const Time& end, const std::string& resolutionStr);
|
||||
|
||||
/**
|
||||
* Used to quantize time to descrete values.
|
||||
*/
|
||||
struct TimeQuantizer {
|
||||
TimeQuantizer() {}
|
||||
TimeQuantizer(const Time& start, const Time& end, double resolution);
|
||||
TimeQuantizer(const Time& start, const Time& end, const std::string& resolutionStr);
|
||||
|
||||
/**
|
||||
* Takes a time resulition string and parses it into a double
|
||||
* value representing the time resolution as seconds.
|
||||
*
|
||||
* Example: parseTimeResolutionStr("1d");
|
||||
*
|
||||
* \param resoltutionStr with the format {number}{unit}
|
||||
* where supported units are:
|
||||
* (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears
|
||||
*
|
||||
* \returns the time resolution in seconds
|
||||
*/
|
||||
static double parseTimeResolutionStr(const std::string& resoltutionStr);
|
||||
|
||||
/**
|
||||
* Quantizes a OpenSpace Time into descrete values.
|
||||
* If the provided Time t is outside the time range, it will
|
||||
* be clamped to the the time range.
|
||||
*
|
||||
* \param t Time instance, which will be quantized
|
||||
* \param clamp Whether or not time should be clamped if not t is in the time range
|
||||
* \returns wether or not time was quantized
|
||||
*/
|
||||
bool quantize(Time& t, bool clamp) const;
|
||||
|
||||
private:
|
||||
TimeRange _timerange;
|
||||
double _resolution;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Temporal tile Provider //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
* Takes a time resulition string and parses it into a double
|
||||
* value representing the time resolution as seconds.
|
||||
*
|
||||
* Example: parseTimeResolutionStr("1d");
|
||||
*
|
||||
* \param resoltutionStr with the format {number}{unit}
|
||||
* where supported units are:
|
||||
* (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears
|
||||
*
|
||||
* \returns the time resolution in seconds
|
||||
*/
|
||||
static double parseTimeResolutionStr(const std::string& resoltutionStr);
|
||||
|
||||
/**
|
||||
* Provide <code>Tile</code>s from web map services that have temporal resolution.
|
||||
*
|
||||
* TemporalTileProviders are instantiated using a ghoul::Dictionary,
|
||||
* and must define a filepath to a Openspace Temporal dataset description file.
|
||||
* This is an xml-file that defines the same meta data as the GDAL wms description
|
||||
* (http://www.gdal.org/frmt_wms.html), but augmented with some
|
||||
* extra tags describing the temporal properties of the dataset. See
|
||||
* <code>TemporalTileProvider::TemporalXMLTags</code>
|
||||
*
|
||||
*/
|
||||
class TemporalTileProvider : public TileProvider {
|
||||
public:
|
||||
* Quantizes a OpenSpace Time into descrete values.
|
||||
* If the provided Time t is outside the time range, it will
|
||||
* be clamped to the the time range.
|
||||
*
|
||||
* \param t Time instance, which will be quantized
|
||||
* \param clamp Whether or not time should be clamped if not t is in the time range
|
||||
* \returns wether or not time was quantized
|
||||
*/
|
||||
bool quantize(Time& t, bool clamp) const;
|
||||
|
||||
private:
|
||||
TimeRange _timerange;
|
||||
double _resolution;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide <code>Tile</code>s from web map services that have temporal resolution.
|
||||
*
|
||||
* TemporalTileProviders are instantiated using a ghoul::Dictionary,
|
||||
* and must define a filepath to a Openspace Temporal dataset description file.
|
||||
* This is an xml-file that defines the same meta data as the GDAL wms description
|
||||
* (http://www.gdal.org/frmt_wms.html), but augmented with some
|
||||
* extra tags describing the temporal properties of the dataset. See
|
||||
* <code>TemporalTileProvider::TemporalXMLTags</code>
|
||||
*
|
||||
*/
|
||||
class TemporalTileProvider : public TileProvider {
|
||||
public:
|
||||
/**
|
||||
* Dictionary constructor. Must provide KeyFilePath as defined in .cpp file.
|
||||
*/
|
||||
TemporalTileProvider(const ghoul::Dictionary& dictionary);
|
||||
|
||||
// These methods implements the TileProvider interface
|
||||
|
||||
virtual Tile getTile(const TileIndex& tileIndex);
|
||||
virtual Tile getDefaultTile();
|
||||
virtual Tile::Status getTileStatus(const TileIndex& tileIndex);
|
||||
virtual TileDepthTransform depthTransform();
|
||||
virtual void update();
|
||||
virtual void reset();
|
||||
virtual int maxLevel();
|
||||
|
||||
|
||||
typedef std::string TimeKey;
|
||||
|
||||
std::shared_ptr<TileProvider> getTileProvider(Time t = Time::ref());
|
||||
std::shared_ptr<TileProvider> getTileProvider(TimeKey timekey);
|
||||
|
||||
private:
|
||||
/**
|
||||
* A placeholder string that must be provided in the WMS template url. This
|
||||
* placeholder will be replaced by quantized date-time strings during run time
|
||||
* in order to access the datasets for different instances of time.
|
||||
*/
|
||||
static const char* URL_TIME_PLACEHOLDER;
|
||||
|
||||
/**
|
||||
* These are tags that TemporalTileProviders must be able to read from the XML
|
||||
* file provided in the ghoul::Dictionary used to create this provider. These
|
||||
* tags describe the temporal properties of the dataset.
|
||||
*/
|
||||
static const struct TemporalXMLTags {
|
||||
/**
|
||||
* Dictionary constructor. Must provide KeyFilePath as defined in .cpp file.
|
||||
*/
|
||||
TemporalTileProvider(const ghoul::Dictionary& dictionary);
|
||||
|
||||
// These methods implements the TileProvider interface
|
||||
|
||||
virtual Tile getTile(const TileIndex& tileIndex);
|
||||
virtual Tile getDefaultTile();
|
||||
virtual Tile::Status getTileStatus(const TileIndex& tileIndex);
|
||||
virtual TileDepthTransform depthTransform();
|
||||
virtual void update();
|
||||
virtual void reset();
|
||||
virtual int maxLevel();
|
||||
|
||||
|
||||
typedef std::string TimeKey;
|
||||
|
||||
std::shared_ptr<TileProvider> getTileProvider(Time t = Time::ref());
|
||||
std::shared_ptr<TileProvider> getTileProvider(TimeKey timekey);
|
||||
|
||||
private:
|
||||
* Tag should contain a ISO8601 time specifying the datasets start time
|
||||
*/
|
||||
static const char* TIME_START;
|
||||
|
||||
/**
|
||||
* A placeholder string that must be provided in the WMS template url. This
|
||||
* placeholder will be replaced by quantized date-time strings during run time
|
||||
* in order to access the datasets for different instances of time.
|
||||
*/
|
||||
static const std::string URL_TIME_PLACEHOLDER;
|
||||
* Tag should contain a ISO8601 time specifying the datasets end time
|
||||
* Example 1: "2016 SEP 08".
|
||||
* Example 2: "now" - sets the dataset's end time to the current time.
|
||||
*/
|
||||
static const char* TIME_END;
|
||||
|
||||
/**
|
||||
* These are tags that TemporalTileProviders must be able to read from the XML
|
||||
* file provided in the ghoul::Dictionary used to create this provider. These
|
||||
* tags describe the temporal properties of the dataset.
|
||||
*/
|
||||
static const struct TemporalXMLTags {
|
||||
/**
|
||||
* Tag should contain a ISO8601 time specifying the datasets start time
|
||||
*/
|
||||
static const std::string TIME_START;
|
||||
* Tag should contain the time resolution of the dataset.
|
||||
* The resolution is defined by a number along with a unit specifying how
|
||||
* often the dataset is updated temporally. Supported units are:
|
||||
* (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears.
|
||||
*
|
||||
* Example 1: "2d" - dataset updated every other day.
|
||||
* Example 2: "1h" - dataset is updated every hour.
|
||||
*/
|
||||
static const char* TIME_RESOLUTION;
|
||||
|
||||
/**
|
||||
* Tag should contain a ISO8601 time specifying the datasets end time
|
||||
* Example 1: "2016 SEP 08".
|
||||
* Example 2: "now" - sets the dataset's end time to the current time.
|
||||
*/
|
||||
static const std::string TIME_END;
|
||||
|
||||
/**
|
||||
* Tag should contain the time resolution of the dataset.
|
||||
* The resolution is defined by a number along with a unit specifying how
|
||||
* often the dataset is updated temporally. Supported units are:
|
||||
* (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears.
|
||||
*
|
||||
* Example 1: "2d" - dataset updated every other day.
|
||||
* Example 2: "1h" - dataset is updated every hour.
|
||||
*/
|
||||
static const std::string TIME_RESOLUTION;
|
||||
|
||||
/**
|
||||
* Tag should contain a string specifying the date-time format expected by the
|
||||
* WMS.
|
||||
*/
|
||||
static const std::string TIME_FORMAT;
|
||||
};
|
||||
/**
|
||||
* Tag should contain a string specifying the date-time format expected by the
|
||||
* WMS.
|
||||
*/
|
||||
static const char* TIME_FORMAT;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a GDAL dataset description based on the time t
|
||||
* \param t Time to generate a GDAL dataset description for
|
||||
* \returns a GDAL dataset description
|
||||
*/
|
||||
std::string getGdalDatasetXML(Time t);
|
||||
/**
|
||||
* Create a GDAL dataset description based on the time t
|
||||
* \param t Time to generate a GDAL dataset description for
|
||||
* \returns a GDAL dataset description
|
||||
*/
|
||||
std::string getGdalDatasetXML(Time t);
|
||||
|
||||
/**
|
||||
* Create a GDAL dataset description associated with the provided TimeKey
|
||||
* \param key The TimeKey specifying time
|
||||
* \returns a GDAL dataset description
|
||||
*/
|
||||
std::string getGdalDatasetXML(TimeKey key);
|
||||
/**
|
||||
* Create a GDAL dataset description associated with the provided TimeKey
|
||||
* \param key The TimeKey specifying time
|
||||
* \returns a GDAL dataset description
|
||||
*/
|
||||
std::string getGdalDatasetXML(TimeKey key);
|
||||
|
||||
/**
|
||||
* Instantiates a new TileProvder for the temporal dataset at the time
|
||||
* specified.
|
||||
*
|
||||
* This method replaced the <code>URL_TIME_PLACEHOLDER</code> in the template URL
|
||||
* with the provided timekey, the opens a new GDAL dataset with that URL.
|
||||
*
|
||||
* \param timekey time specifying dataset's temporality
|
||||
* \returns newly instantiated TileProvider
|
||||
*/
|
||||
std::shared_ptr<TileProvider> initTileProvider(TimeKey timekey);
|
||||
/**
|
||||
* Instantiates a new TileProvder for the temporal dataset at the time
|
||||
* specified.
|
||||
*
|
||||
* This method replaced the <code>URL_TIME_PLACEHOLDER</code> in the template URL
|
||||
* with the provided timekey, the opens a new GDAL dataset with that URL.
|
||||
*
|
||||
* \param timekey time specifying dataset's temporality
|
||||
* \returns newly instantiated TileProvider
|
||||
*/
|
||||
std::shared_ptr<TileProvider> initTileProvider(TimeKey timekey);
|
||||
|
||||
/**
|
||||
* Takes as input a Openspace Temporal dataset description, extracts the temporal
|
||||
* metadata provided by reading the <code>TemporalXMLTags</code>, removes the
|
||||
* read tags from the description, and returns a GDAL template GDAL dataset
|
||||
* description. The template GDAL dataset description has the a
|
||||
* <code>URL_TIME_PLACEHOLDER</code> still in it, which needs to be replaced before
|
||||
* GDAL can open it as a GDALDataset.
|
||||
*
|
||||
* \param xml Openspace Temporal dataset description
|
||||
* \returns a GDAL template data description.
|
||||
*/
|
||||
std::string consumeTemporalMetaData(const std::string &xml);
|
||||
/**
|
||||
* Takes as input a Openspace Temporal dataset description, extracts the temporal
|
||||
* metadata provided by reading the <code>TemporalXMLTags</code>, removes the
|
||||
* read tags from the description, and returns a GDAL template GDAL dataset
|
||||
* description. The template GDAL dataset description has the a
|
||||
* <code>URL_TIME_PLACEHOLDER</code> still in it, which needs to be replaced before
|
||||
* GDAL can open it as a GDALDataset.
|
||||
*
|
||||
* \param xml Openspace Temporal dataset description
|
||||
* \returns a GDAL template data description.
|
||||
*/
|
||||
std::string consumeTemporalMetaData(const std::string &xml);
|
||||
|
||||
/**
|
||||
* Helper method to read a XML value from a XML tree.
|
||||
* \param node XML tree to search in
|
||||
* \param key XML tag to find the value for
|
||||
* \param defaultVal value to return if key was not found
|
||||
* \returns the value of the Key, or defaultVal if key was undefined.
|
||||
*/
|
||||
std::string getXMLValue(CPLXMLNode* node, const std::string& key, const std::string& defaultVal);
|
||||
/**
|
||||
* Helper method to read a XML value from a XML tree.
|
||||
* \param node XML tree to search in
|
||||
* \param key XML tag to find the value for
|
||||
* \param defaultVal value to return if key was not found
|
||||
* \returns the value of the Key, or defaultVal if key was undefined.
|
||||
*/
|
||||
std::string getXMLValue(CPLXMLNode* node, const std::string& key, const std::string& defaultVal);
|
||||
|
||||
/**
|
||||
* Ensures that the TemporalTileProvider is up to date.
|
||||
*/
|
||||
void ensureUpdated();
|
||||
/**
|
||||
* Ensures that the TemporalTileProvider is up to date.
|
||||
*/
|
||||
void ensureUpdated();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Members variables //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
std::string _datasetFile;
|
||||
std::string _gdalXmlTemplate;
|
||||
|
||||
std::string _datasetFile;
|
||||
std::string _gdalXmlTemplate;
|
||||
std::unordered_map<TimeKey, std::shared_ptr<TileProvider> > _tileProviderMap;
|
||||
|
||||
std::unordered_map<TimeKey, std::shared_ptr<TileProvider> > _tileProviderMap;
|
||||
|
||||
// Used for creation of time specific instances of CachingTileProvider
|
||||
ghoul::Dictionary _initDict;
|
||||
// Used for creation of time specific instances of CachingTileProvider
|
||||
ghoul::Dictionary _initDict;
|
||||
|
||||
|
||||
Tile _defaultTile;
|
||||
|
||||
std::shared_ptr<TileProvider> _currentTileProvider;
|
||||
Tile _defaultTile;
|
||||
|
||||
std::shared_ptr<TileProvider> _currentTileProvider;
|
||||
|
||||
TimeFormat * _timeFormat;
|
||||
TimeQuantizer _timeQuantizer;
|
||||
};
|
||||
TimeFormat* _timeFormat;
|
||||
TimeQuantizer _timeQuantizer;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __TEMPORAL_TILE_PROVIDER_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TEMPORAL_TILE_PROVIDER_H__
|
||||
|
||||
@@ -1,268 +1,261 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/tile/tileprovider/texttileprovider.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <ghoul/font/fontrenderer.h>
|
||||
#include <ghoul/font/fontmanager.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/font/fontmanager.h>
|
||||
#include <ghoul/font/fontrenderer.h>
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TextTileProvider";
|
||||
}
|
||||
using namespace ghoul::fontrendering;
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
TextTileProvider::TextTileProvider(const glm::uvec2& textureSize, size_t fontSize)
|
||||
: _tileCache(500)
|
||||
, _textureSize(textureSize)
|
||||
, _fontSize(fontSize)
|
||||
{
|
||||
|
||||
_font = OsEng.fontManager().font("Mono", _fontSize);
|
||||
TextTileProvider::TextTileProvider(const glm::uvec2& textureSize, size_t fontSize)
|
||||
: _tileCache(500)
|
||||
, _textureSize(textureSize)
|
||||
, _fontSize(fontSize)
|
||||
{
|
||||
_font = OsEng.fontManager().font("Mono", _fontSize);
|
||||
|
||||
_fontRenderer = std::unique_ptr<FontRenderer>(FontRenderer::createDefault());
|
||||
_fontRenderer->setFramebufferSize(textureSize);
|
||||
_fontRenderer = std::unique_ptr<FontRenderer>(FontRenderer::createDefault());
|
||||
_fontRenderer->setFramebufferSize(textureSize);
|
||||
|
||||
glGenFramebuffers(1, &_fbo);
|
||||
}
|
||||
|
||||
glGenFramebuffers(1, &_fbo);
|
||||
}
|
||||
TextTileProvider::~TextTileProvider() {
|
||||
glDeleteFramebuffers(1, &_fbo);
|
||||
}
|
||||
|
||||
TextTileProvider::~TextTileProvider() {
|
||||
glDeleteFramebuffers(1, &_fbo);
|
||||
}
|
||||
|
||||
Tile TextTileProvider::getTile(const TileIndex& tileIndex) {
|
||||
TileHashKey key = tileIndex.hashKey();
|
||||
Tile TextTileProvider::getTile(const TileIndex& tileIndex) {
|
||||
TileHashKey key = tileIndex.hashKey();
|
||||
|
||||
if (!_tileCache.exist(key)) {
|
||||
_tileCache.put(key, createChunkIndexTile(tileIndex));
|
||||
}
|
||||
|
||||
return _tileCache.get(key);
|
||||
if (!_tileCache.exist(key)) {
|
||||
_tileCache.put(key, createChunkIndexTile(tileIndex));
|
||||
}
|
||||
|
||||
Tile TextTileProvider::getDefaultTile() {
|
||||
return Tile::TileUnavailable;
|
||||
}
|
||||
return _tileCache.get(key);
|
||||
}
|
||||
|
||||
Tile TextTileProvider::getDefaultTile() {
|
||||
return Tile::TileUnavailable;
|
||||
}
|
||||
|
||||
Tile::Status TextTileProvider::getTileStatus(const TileIndex& index) {
|
||||
return Tile::Status::OK;
|
||||
}
|
||||
Tile::Status TextTileProvider::getTileStatus(const TileIndex& index) {
|
||||
return Tile::Status::OK;
|
||||
}
|
||||
|
||||
TileDepthTransform TextTileProvider::depthTransform() {
|
||||
TileDepthTransform transform;
|
||||
transform.depthOffset = 0.0f;
|
||||
transform.depthScale = 1.0f;
|
||||
return transform;
|
||||
}
|
||||
TileDepthTransform TextTileProvider::depthTransform() {
|
||||
TileDepthTransform transform;
|
||||
transform.depthOffset = 0.0f;
|
||||
transform.depthScale = 1.0f;
|
||||
return transform;
|
||||
}
|
||||
|
||||
void TextTileProvider::update() {
|
||||
// nothing to be done
|
||||
}
|
||||
void TextTileProvider::update() {}
|
||||
|
||||
void TextTileProvider::reset() {
|
||||
_tileCache.clear();
|
||||
}
|
||||
void TextTileProvider::reset() {
|
||||
_tileCache.clear();
|
||||
}
|
||||
|
||||
Tile TextTileProvider::createChunkIndexTile(const TileIndex& tileIndex) {
|
||||
Tile tile = backgroundTile(tileIndex);
|
||||
Tile TextTileProvider::createChunkIndexTile(const TileIndex& tileIndex) {
|
||||
Tile tile = backgroundTile(tileIndex);
|
||||
|
||||
// Keep track of defaultFBO and viewport to be able to reset state when done
|
||||
GLint defaultFBO;
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
// Keep track of defaultFBO and viewport to be able to reset state when done
|
||||
GLint defaultFBO;
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
|
||||
// Render to texture
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
|
||||
glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D,
|
||||
*(tile.texture),
|
||||
0
|
||||
);
|
||||
// Render to texture
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
|
||||
glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D,
|
||||
*(tile.texture),
|
||||
0
|
||||
);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
//LDEBUG(status);
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
|
||||
glViewport(
|
||||
0, 0,
|
||||
static_cast<GLsizei>(tile.texture->width()),
|
||||
static_cast<GLsizei>(tile.texture->height())
|
||||
);
|
||||
glViewport(
|
||||
0, 0,
|
||||
static_cast<GLsizei>(tile.texture->width()),
|
||||
static_cast<GLsizei>(tile.texture->height())
|
||||
);
|
||||
|
||||
ghoul_assert(_fontRenderer != nullptr, "_fontRenderer must not be null");
|
||||
renderText(*_fontRenderer, tileIndex);
|
||||
ghoul_assert(_fontRenderer != nullptr, "_fontRenderer must not be null");
|
||||
renderText(*_fontRenderer, tileIndex);
|
||||
|
||||
// Reset state: bind default FBO and set viewport to what it was
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
// Reset state: bind default FBO and set viewport to what it was
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
int TextTileProvider::maxLevel() {
|
||||
return 1337; // unlimited
|
||||
}
|
||||
|
||||
TileHashKey TextTileProvider::toHash(const TileIndex& tileIndex) const {
|
||||
return tileIndex.hashKey();
|
||||
}
|
||||
|
||||
Tile TextTileProvider::backgroundTile(const TileIndex& tileIndex) const {
|
||||
glm::uvec4 color = { 0, 0, 0, 0 };
|
||||
return Tile::createPlainTile(_textureSize, color);
|
||||
}
|
||||
|
||||
void TileIndexTileProvider::renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const {
|
||||
fontRenderer.render(
|
||||
*_font,
|
||||
glm::vec2(
|
||||
_textureSize.x / 4 - (_textureSize.x / 32) * log10(1 << tileIndex.level),
|
||||
_textureSize.y / 2 + _fontSize),
|
||||
glm::vec4(1.0, 0.0, 0.0, 1.0),
|
||||
"level: %i \nx: %i \ny: %i",
|
||||
tileIndex.level, tileIndex.x, tileIndex.y
|
||||
);
|
||||
}
|
||||
|
||||
namespace {
|
||||
const char* KeyRadii = "Radii";
|
||||
const char* KeyBackgroundImagePath = "BackgroundImagePath";
|
||||
}
|
||||
|
||||
SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
_fontSize = 50;
|
||||
FontManager& fm = OsEng.fontManager();
|
||||
_font = fm.font("Mono", _fontSize);
|
||||
|
||||
glm::dvec3 radii(1,1,1);
|
||||
if (!dictionary.getValue(KeyRadii, radii)) {
|
||||
throw std::runtime_error("Must define key '" + std::string(KeyRadii) + "'");
|
||||
}
|
||||
_ellipsoid = Ellipsoid(radii);
|
||||
|
||||
_backgroundTile.status = Tile::Status::Unavailable;
|
||||
std::string backgroundImagePath;
|
||||
if (dictionary.getValue(KeyBackgroundImagePath, backgroundImagePath)) {
|
||||
using namespace ghoul::io;
|
||||
std::string imgAbsPath = absPath(backgroundImagePath);
|
||||
_backgroundTile.texture = TextureReader::ref().loadTexture(imgAbsPath);
|
||||
_backgroundTile.texture->uploadTexture();
|
||||
_backgroundTile.texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
|
||||
_backgroundTile.status = Tile::Status::OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SizeReferenceTileProvider::renderText(const FontRenderer& fontRenderer,
|
||||
const TileIndex& tileIndex) const
|
||||
{
|
||||
GeodeticPatch patch(tileIndex);
|
||||
bool aboveEquator = patch.isNorthern();
|
||||
|
||||
double tileLongitudalLength = roundedLongitudalLength(tileIndex);
|
||||
|
||||
std::string unit = "m";
|
||||
if (tileLongitudalLength > 9999) {
|
||||
tileLongitudalLength *= 0.001;
|
||||
unit = "km";
|
||||
}
|
||||
|
||||
glm::vec2 textPosition;
|
||||
textPosition.x = 0;
|
||||
textPosition.y = aboveEquator ? _fontSize / 2 : _textureSize.y - 3 * _fontSize / 2;
|
||||
glm::vec4 color(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
fontRenderer.render(
|
||||
*_font,
|
||||
textPosition,
|
||||
color,
|
||||
" %.0f %s",
|
||||
tileLongitudalLength, unit.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
int SizeReferenceTileProvider::roundedLongitudalLength(const TileIndex& tileIndex) const {
|
||||
GeodeticPatch patch(tileIndex);
|
||||
bool aboveEquator = patch.isNorthern();
|
||||
double lat = aboveEquator ? patch.minLat() : patch.maxLat();
|
||||
double lon1 = patch.minLon();
|
||||
double lon2 = patch.maxLon();
|
||||
int l = static_cast<int>(_ellipsoid.longitudalDistance(lat, lon1, lon2));
|
||||
|
||||
bool useKm = l > 9999;
|
||||
if (useKm) {
|
||||
l /= 1000;
|
||||
}
|
||||
l = std::round(l);
|
||||
if (useKm) {
|
||||
l *= 1000;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
TileHashKey SizeReferenceTileProvider::toHash(const TileIndex& tileIndex) const {
|
||||
int l = roundedLongitudalLength(tileIndex);
|
||||
TileHashKey key = static_cast<TileHashKey>(l);
|
||||
return key;
|
||||
}
|
||||
|
||||
Tile SizeReferenceTileProvider::backgroundTile(const TileIndex& tileIndex) const {
|
||||
if (_backgroundTile.status == Tile::Status::OK) {
|
||||
Tile tile;
|
||||
auto t = _backgroundTile.texture;
|
||||
void* pixelData = new char[t->expectedPixelDataSize()];
|
||||
memcpy(pixelData, t->pixelData(), t->expectedPixelDataSize());
|
||||
tile.texture = std::make_shared<Texture>(
|
||||
pixelData,
|
||||
t->dimensions(),
|
||||
t->format(),
|
||||
t->internalFormat(),
|
||||
t->dataType(),
|
||||
t->filter(),
|
||||
t->wrapping()
|
||||
);
|
||||
tile.texture->uploadTexture();
|
||||
tile.texture->setDataOwnership(Texture::TakeOwnership::Yes);
|
||||
tile.status = Tile::Status::OK;
|
||||
return tile;
|
||||
}
|
||||
|
||||
int TextTileProvider::maxLevel() {
|
||||
return 1337; // unlimited
|
||||
}
|
||||
|
||||
TileHashKey TextTileProvider::toHash(const TileIndex& tileIndex) const {
|
||||
return tileIndex.hashKey();
|
||||
}
|
||||
|
||||
|
||||
Tile TextTileProvider::backgroundTile(const TileIndex& tileIndex) const {
|
||||
glm::uvec4 color = { 0, 0, 0, 0 };
|
||||
return Tile::createPlainTile(_textureSize, color);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Chunk Index Tile Provider //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TileIndexTileProvider::renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const {
|
||||
fontRenderer.render(
|
||||
*_font,
|
||||
glm::vec2(
|
||||
_textureSize.x / 4 - (_textureSize.x / 32) * log10(1 << tileIndex.level),
|
||||
_textureSize.y / 2 + _fontSize),
|
||||
glm::vec4(1.0, 0.0, 0.0, 1.0),
|
||||
"level: %i \nx: %i \ny: %i",
|
||||
tileIndex.level, tileIndex.x, tileIndex.y
|
||||
);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tile Size Reference Tile Provider //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace {
|
||||
const std::string KeyRadii = "Radii";
|
||||
const std::string KeyBackgroundImagePath = "BackgroundImagePath";
|
||||
}
|
||||
|
||||
SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary) {
|
||||
_fontSize = 50;
|
||||
ghoul::fontrendering::FontManager& fm = OsEng.fontManager();
|
||||
_font = fm.font("Mono", _fontSize);
|
||||
|
||||
glm::dvec3 radii(1,1,1);
|
||||
if (!dictionary.getValue(KeyRadii, radii)) {
|
||||
throw std::runtime_error("Must define key '" + KeyRadii + "'");
|
||||
}
|
||||
_ellipsoid = Ellipsoid(radii);
|
||||
|
||||
_backgroundTile.status = Tile::Status::Unavailable;
|
||||
std::string backgroundImagePath;
|
||||
if (dictionary.getValue(KeyBackgroundImagePath, backgroundImagePath)) {
|
||||
using namespace ghoul::io;
|
||||
std::string imgAbsPath = absPath(backgroundImagePath);
|
||||
_backgroundTile.texture = TextureReader::ref().loadTexture(imgAbsPath);
|
||||
_backgroundTile.texture->uploadTexture();
|
||||
_backgroundTile.texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
|
||||
_backgroundTile.status = Tile::Status::OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SizeReferenceTileProvider::renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const {
|
||||
GeodeticPatch patch(tileIndex);
|
||||
bool aboveEquator = patch.isNorthern();
|
||||
|
||||
double tileLongitudalLength = roundedLongitudalLength(tileIndex);
|
||||
|
||||
std::string unit = "m";
|
||||
if (tileLongitudalLength > 9999) {
|
||||
tileLongitudalLength *= 0.001;
|
||||
unit = "km";
|
||||
}
|
||||
|
||||
glm::vec2 textPosition;
|
||||
textPosition.x = 0;
|
||||
textPosition.y = aboveEquator ? _fontSize / 2 : _textureSize.y - 3 * _fontSize / 2;
|
||||
glm::vec4 color(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
fontRenderer.render(
|
||||
*_font,
|
||||
textPosition,
|
||||
color,
|
||||
" %.0f %s",
|
||||
tileLongitudalLength, unit.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
int SizeReferenceTileProvider::roundedLongitudalLength(const TileIndex& tileIndex) const {
|
||||
GeodeticPatch patch(tileIndex);
|
||||
bool aboveEquator = patch.isNorthern();
|
||||
double lat = aboveEquator ? patch.minLat() : patch.maxLat();
|
||||
double lon1 = patch.minLon();
|
||||
double lon2 = patch.maxLon();
|
||||
int l = static_cast<int>(_ellipsoid.longitudalDistance(lat, lon1, lon2));
|
||||
|
||||
bool useKm = l > 9999;
|
||||
if (useKm) l /= 1000;
|
||||
l = std::round(l);
|
||||
if (useKm) l *= 1000;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
TileHashKey SizeReferenceTileProvider::toHash(const TileIndex& tileIndex) const {
|
||||
int l = roundedLongitudalLength(tileIndex);
|
||||
TileHashKey key = static_cast<TileHashKey>(l);
|
||||
return key;
|
||||
}
|
||||
|
||||
Tile SizeReferenceTileProvider::backgroundTile(const TileIndex& tileIndex) const {
|
||||
if (_backgroundTile.status == Tile::Status::OK) {
|
||||
Tile tile;
|
||||
auto t = _backgroundTile.texture;
|
||||
void* pixelData = new char[t->expectedPixelDataSize()];
|
||||
memcpy(pixelData, t->pixelData(), t->expectedPixelDataSize());
|
||||
tile.texture = std::make_shared<Texture>(
|
||||
pixelData, t->dimensions(), t->format(), t->internalFormat(), t->dataType(), t->filter(), t->wrapping());
|
||||
tile.texture->uploadTexture();
|
||||
tile.texture->setDataOwnership(Texture::TakeOwnership::Yes);
|
||||
tile.status = Tile::Status::OK;
|
||||
return tile;
|
||||
}
|
||||
else {
|
||||
// use default background
|
||||
return TextTileProvider::backgroundTile(tileIndex);
|
||||
}
|
||||
else {
|
||||
// use default background
|
||||
return TextTileProvider::backgroundTile(tileIndex);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,68 +1,55 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TEXT_TILE_PROVIDER_H__
|
||||
#define __TEXT_TILE_PROVIDER_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TEXT_TILE_PROVIDER_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TEXT_TILE_PROVIDER_H__
|
||||
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h> // absPath
|
||||
#include <ghoul/opengl/texture.h>
|
||||
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
|
||||
#include <ghoul/font/fontrenderer.h>
|
||||
#include <ghoul/font/fontmanager.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/asynctilereader.h>
|
||||
#include <modules/globebrowsing/other/lrucache.h>
|
||||
#include <modules/globebrowsing/geometry/ellipsoid.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TILE PROVIDER //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
namespace ghoul { namespace fontrendering {
|
||||
|
||||
class Font;
|
||||
class FontRenderer;
|
||||
|
||||
}}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace ghoul::fontrendering;
|
||||
|
||||
/**
|
||||
* Enables a simple way of providing tiles with any type of rendered text.
|
||||
* Internally it handles setting up a FBO for rendering the text, and defines a new
|
||||
* interface, consisting of only a single method for subclasses to implement:
|
||||
* renderText(const FontRenderer&, const TileIndex&) const;
|
||||
*/
|
||||
* Enables a simple way of providing tiles with any type of rendered text.
|
||||
* Internally it handles setting up a FBO for rendering the text, and defines a new
|
||||
* interface, consisting of only a single method for subclasses to implement:
|
||||
* renderText(const FontRenderer&, const TileIndex&) const;
|
||||
*/
|
||||
class TextTileProvider : public TileProvider {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor with default values for texture and font size
|
||||
*/
|
||||
* Default constructor with default values for texture and font size
|
||||
*/
|
||||
TextTileProvider(const glm::uvec2& textureSize = {512, 512}, size_t fontSize = 48);
|
||||
virtual ~TextTileProvider();
|
||||
|
||||
@@ -76,29 +63,29 @@ public:
|
||||
virtual int maxLevel();
|
||||
|
||||
/**
|
||||
* Returns the tile which will be used to draw text onto.
|
||||
* Default implementation returns a tile with a plain transparent texture.
|
||||
*/
|
||||
* Returns the tile which will be used to draw text onto.
|
||||
* Default implementation returns a tile with a plain transparent texture.
|
||||
*/
|
||||
virtual Tile backgroundTile(const TileIndex& tileIndex) const;
|
||||
|
||||
|
||||
/**
|
||||
* Allow overriding of hash function.
|
||||
* Default is <code>TileIndex::hashKey()</code>
|
||||
*
|
||||
* \param tileIndex tileIndex to hash
|
||||
* \returns hashkey used for in LRU cache for this tile
|
||||
*/
|
||||
* Allow overriding of hash function.
|
||||
* Default is <code>TileIndex::hashKey()</code>
|
||||
*
|
||||
* \param tileIndex tileIndex to hash
|
||||
* \returns hashkey used for in LRU cache for this tile
|
||||
*/
|
||||
virtual TileHashKey toHash(const TileIndex& tileIndex) const;
|
||||
|
||||
/**
|
||||
* Uses the fontRenderer to render some text onto the tile texture provided in
|
||||
* backgroundTile(const TileIndex& tileIndex).
|
||||
*
|
||||
* \param fontRenderer used for rendering text onto texture
|
||||
* \param tileIndex associated with the tile to be rendered onto
|
||||
*/
|
||||
virtual void renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const = 0;
|
||||
* Uses the fontRenderer to render some text onto the tile texture provided in
|
||||
* backgroundTile(const TileIndex& tileIndex).
|
||||
*
|
||||
* \param fontRenderer used for rendering text onto texture
|
||||
* \param tileIndex associated with the tile to be rendered onto
|
||||
*/
|
||||
virtual void renderText(const ghoul::fontrendering::FontRenderer& fontRenderer,
|
||||
const TileIndex& tileIndex) const = 0;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ghoul::fontrendering::Font> _font;
|
||||
@@ -114,22 +101,24 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides <code>Tile</code>s with the chunk index rendered as text onto its tiles.
|
||||
*/
|
||||
* Provides <code>Tile</code>s with the chunk index rendered as text onto its tiles.
|
||||
*/
|
||||
class TileIndexTileProvider : public TextTileProvider {
|
||||
public:
|
||||
virtual void renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const;
|
||||
virtual void renderText(const ghoul::fontrendering::FontRenderer& fontRenderer,
|
||||
const TileIndex& tileIndex) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructed with an ellipsoid and uses that to render the longitudal length of each
|
||||
* of each tile.
|
||||
*/
|
||||
* Constructed with an ellipsoid and uses that to render the longitudal length of each
|
||||
* of each tile.
|
||||
*/
|
||||
class SizeReferenceTileProvider : public TextTileProvider {
|
||||
public:
|
||||
SizeReferenceTileProvider(const ghoul::Dictionary& dictionary);
|
||||
|
||||
virtual void renderText(const FontRenderer& fontRenderer, const TileIndex& tileIndex) const;
|
||||
virtual void renderText(const ghoul::fontrendering::FontRenderer& fontRenderer,
|
||||
const TileIndex& tileIndex) const;
|
||||
virtual Tile backgroundTile(const TileIndex& tileIndex) const;
|
||||
|
||||
virtual TileHashKey toHash(const TileIndex& tileIndex) const;
|
||||
@@ -145,7 +134,4 @@ private:
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // __TEXT_TILE_PROVIDER_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TEXT_TILE_PROVIDER_H__
|
||||
|
||||
@@ -1,35 +1,34 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <limits>
|
||||
* *
|
||||
* 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/tile/tileprovider/tileprovider.h>
|
||||
|
||||
#include <openspace/util/factorymanager.h>
|
||||
#include <modules/globebrowsing/tile/chunktile.h>
|
||||
#include <modules/globebrowsing/tile/tileselector.h>
|
||||
|
||||
#include <openspace/util/factorymanager.h>
|
||||
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
@@ -42,11 +41,9 @@ namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
TileProvider* TileProvider::createFromDictionary(const ghoul::Dictionary& dictionary) {
|
||||
|
||||
std::string type = "LRUCaching";
|
||||
dictionary.getValue(KeyType, type);
|
||||
ghoul::TemplateFactory<TileProvider>* factory
|
||||
= FactoryManager::ref().factory<TileProvider>();
|
||||
auto factory = FactoryManager::ref().factory<TileProvider>();
|
||||
TileProvider* result = factory->create(type, dictionary);
|
||||
|
||||
if (result == nullptr) {
|
||||
@@ -57,7 +54,7 @@ TileProvider* TileProvider::createFromDictionary(const ghoul::Dictionary& dictio
|
||||
return result;
|
||||
}
|
||||
|
||||
TileProvider::TileProvider(const ghoul::Dictionary& dictionary) { };
|
||||
TileProvider::TileProvider(const ghoul::Dictionary& dictionary) {};
|
||||
|
||||
float TileProvider::noDataValueAsFloat() {
|
||||
return std::numeric_limits<float>::min();
|
||||
@@ -77,12 +74,12 @@ ChunkTile TileProvider::getChunkTile(TileIndex tileIndex, int parents, int maxPa
|
||||
// Step 2. Traverse 0 or more parents up the chunkTree to make sure we're inside
|
||||
// the range of defined data.
|
||||
int maximumLevel = maxLevel();
|
||||
while(tileIndex.level > maximumLevel){
|
||||
while (tileIndex.level > maximumLevel){
|
||||
TileSelector::ascendToParent(tileIndex, uvTransform);
|
||||
maxParents--;
|
||||
}
|
||||
if(maxParents < 0){
|
||||
return{ Tile::TileUnavailable, uvTransform };
|
||||
return { Tile::TileUnavailable, uvTransform };
|
||||
}
|
||||
|
||||
// Step 3. Traverse 0 or more parents up the chunkTree until we find a chunk that
|
||||
@@ -90,30 +87,32 @@ ChunkTile TileProvider::getChunkTile(TileIndex tileIndex, int parents, int maxPa
|
||||
while (tileIndex.level > 1) {
|
||||
Tile tile = getTile(tileIndex);
|
||||
if (tile.status != Tile::Status::OK) {
|
||||
if(--maxParents < 0){
|
||||
if (--maxParents < 0){
|
||||
return{ Tile::TileUnavailable, uvTransform };
|
||||
}
|
||||
TileSelector::ascendToParent(tileIndex, uvTransform);
|
||||
}
|
||||
else return { tile, uvTransform };
|
||||
else {
|
||||
return { tile, uvTransform };
|
||||
}
|
||||
}
|
||||
|
||||
return{ Tile::TileUnavailable, uvTransform };
|
||||
return { Tile::TileUnavailable, uvTransform };
|
||||
}
|
||||
|
||||
ChunkTilePile TileProvider::getChunkTilePile(TileIndex tileIndex, int pileSize){
|
||||
ghoul_assert(pileSize >= 0, "pileSize must be positive");
|
||||
ChunkTilePile chunkTilePile;
|
||||
chunkTilePile.chunkTiles.resize(pileSize);
|
||||
for (size_t i = 0; i < pileSize; ++i){
|
||||
for (size_t i = 0; i < pileSize; ++i) {
|
||||
chunkTilePile.chunkTiles[i] = getChunkTile(tileIndex, i);
|
||||
if (chunkTilePile.chunkTiles[i].tile.status == Tile::Status::Unavailable) {
|
||||
if(i>0){
|
||||
if (i>0) {
|
||||
chunkTilePile.chunkTiles[i].tile = chunkTilePile.chunkTiles[i-1].tile;
|
||||
chunkTilePile.chunkTiles[i].uvTransform.uvOffset = chunkTilePile.chunkTiles[i-1].uvTransform.uvOffset;
|
||||
chunkTilePile.chunkTiles[i].uvTransform.uvScale = chunkTilePile.chunkTiles[i-1].uvTransform.uvScale;
|
||||
}
|
||||
else{
|
||||
else {
|
||||
chunkTilePile.chunkTiles[i].tile = getDefaultTile();
|
||||
chunkTilePile.chunkTiles[i].uvTransform.uvOffset = { 0, 0 };
|
||||
chunkTilePile.chunkTiles[i].uvTransform.uvScale = { 1, 1 };
|
||||
|
||||
@@ -1,163 +1,149 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TILE_PROVIDER_H__
|
||||
#define __TILE_PROVIDER_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_H__
|
||||
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <ghoul/filesystem/filesystem.h> // absPath
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tiledepthtransform.h>
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
|
||||
#include <modules/globebrowsing/other/lrucache.h>
|
||||
#include <modules/globebrowsing/tile/chunktile.h>
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
#include <modules/globebrowsing/other/lrucache.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TILE PROVIDER //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace ghoul::opengl;
|
||||
|
||||
/**
|
||||
* Interface for providing <code>Tile</code>s given a
|
||||
* <code>TileIndex</code>.
|
||||
*/
|
||||
* Interface for providing <code>Tile</code>s given a
|
||||
* <code>TileIndex</code>.
|
||||
*/
|
||||
class TileProvider {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Factory method for instantiating different implementations of
|
||||
* <code>TileProviders</code>. The provided dictionary must
|
||||
* define a key specifying what implementation of TileProvider
|
||||
* to be instantiated.
|
||||
*/
|
||||
* Factory method for instantiating different implementations of
|
||||
* <code>TileProviders</code>. The provided dictionary must
|
||||
* define a key specifying what implementation of TileProvider
|
||||
* to be instantiated.
|
||||
*/
|
||||
static TileProvider* createFromDictionary(const ghoul::Dictionary& dictionary);
|
||||
|
||||
/**
|
||||
* Empty default constructor
|
||||
*/
|
||||
TileProvider() {};
|
||||
* Empty default constructor
|
||||
*/
|
||||
TileProvider() = default;
|
||||
|
||||
/**
|
||||
* Implementations of the TileProvider interface must implement
|
||||
* a constructor taking a dictionary as input. The provided
|
||||
* dictionary must define a key specifying what implementation
|
||||
* of TileProvider to be instantiated.
|
||||
*/
|
||||
* Implementations of the TileProvider interface must implement
|
||||
* a constructor taking a dictionary as input. The provided
|
||||
* dictionary must define a key specifying what implementation
|
||||
* of TileProvider to be instantiated.
|
||||
*/
|
||||
TileProvider(const ghoul::Dictionary& dictionary);
|
||||
|
||||
/**
|
||||
* Virtual destructor that subclasses should override to do
|
||||
* clean up.
|
||||
*/
|
||||
* Virtual destructor that subclasses should override to do
|
||||
* clean up.
|
||||
*/
|
||||
virtual ~TileProvider() { }
|
||||
|
||||
/**
|
||||
* Method for querying tiles, given a specified <code>TileIndex</code>.
|
||||
*
|
||||
* This method is expected to be invoked multiple times per frame,
|
||||
* and should therefore return quickly, e.g. not perform heavy I/O
|
||||
* operations. However, invoking this method may spawn separate threads
|
||||
* to perform such operations. Therefore, programmers shoud
|
||||
* note that there is no guarantee that the <code>Tile</code>
|
||||
* status and texture will be consistent over different invocations
|
||||
* of this method.
|
||||
*
|
||||
* \param tileIndex specifying a region of a map for which
|
||||
* we want tile data.
|
||||
*
|
||||
* \returns The tile corresponding to the TileIndex by the time
|
||||
* the method was invoked.
|
||||
*/
|
||||
* Method for querying tiles, given a specified <code>TileIndex</code>.
|
||||
*
|
||||
* This method is expected to be invoked multiple times per frame,
|
||||
* and should therefore return quickly, e.g. not perform heavy I/O
|
||||
* operations. However, invoking this method may spawn separate threads
|
||||
* to perform such operations. Therefore, programmers shoud
|
||||
* note that there is no guarantee that the <code>Tile</code>
|
||||
* status and texture will be consistent over different invocations
|
||||
* of this method.
|
||||
*
|
||||
* \param tileIndex specifying a region of a map for which
|
||||
* we want tile data.
|
||||
*
|
||||
* \returns The tile corresponding to the TileIndex by the time
|
||||
* the method was invoked.
|
||||
*/
|
||||
virtual Tile getTile(const TileIndex& tileIndex) = 0;
|
||||
|
||||
|
||||
virtual ChunkTile getChunkTile(TileIndex tileIndex, int parents = 0, int maxParents = 1337);
|
||||
|
||||
virtual ChunkTile getChunkTile(TileIndex tileIndex, int parents = 0,
|
||||
int maxParents = 1337);
|
||||
|
||||
virtual ChunkTilePile getChunkTilePile(TileIndex tileIndex, int pileSize);
|
||||
|
||||
|
||||
/**
|
||||
* TileProviders must be able to provide a defualt
|
||||
* <code>Tile</code> which may be used by clients in cases when
|
||||
* requested tiles were unavailable.
|
||||
*
|
||||
* \returns A default tile
|
||||
*/
|
||||
* TileProviders must be able to provide a defualt
|
||||
* <code>Tile</code> which may be used by clients in cases when
|
||||
* requested tiles were unavailable.
|
||||
*
|
||||
* \returns A default tile
|
||||
*/
|
||||
virtual Tile getDefaultTile() = 0;
|
||||
|
||||
/**
|
||||
* Returns the status of a <code>Tile</code>. The <code>Tile::Status</code>
|
||||
* corresponds the <code>Tile</code> that would be returned
|
||||
* if the function <code>getTile</code> would be invoked with the same
|
||||
* <code>TileIndex</code> argument at this point in time.
|
||||
*/
|
||||
* Returns the status of a <code>Tile</code>. The <code>Tile::Status</code>
|
||||
* corresponds the <code>Tile</code> that would be returned
|
||||
* if the function <code>getTile</code> would be invoked with the same
|
||||
* <code>TileIndex</code> argument at this point in time.
|
||||
*/
|
||||
virtual Tile::Status getTileStatus(const TileIndex& index) = 0;
|
||||
|
||||
/**
|
||||
* Get the associated depth transform for this TileProvider.
|
||||
* This is necessary for TileProviders serving height map
|
||||
* data, in order to correcly map pixel values to meters.
|
||||
*/
|
||||
* Get the associated depth transform for this TileProvider.
|
||||
* This is necessary for TileProviders serving height map
|
||||
* data, in order to correcly map pixel values to meters.
|
||||
*/
|
||||
virtual TileDepthTransform depthTransform() = 0;
|
||||
|
||||
/**
|
||||
* This method should be called once per frame. Here, TileProviders
|
||||
* are given the opportunity to update their internal state.
|
||||
*/
|
||||
* This method should be called once per frame. Here, TileProviders
|
||||
* are given the opportunity to update their internal state.
|
||||
*/
|
||||
virtual void update() = 0;
|
||||
|
||||
/**
|
||||
* Provides a uniform way of all TileProviders to reload or
|
||||
* restore all of its internal state. This is mainly useful
|
||||
* for debugging purposes.
|
||||
*/
|
||||
* Provides a uniform way of all TileProviders to reload or
|
||||
* restore all of its internal state. This is mainly useful
|
||||
* for debugging purposes.
|
||||
*/
|
||||
virtual void reset() = 0;
|
||||
|
||||
/**
|
||||
* \returns The maximum level as defined by <code>TileIndex</code>
|
||||
* that this TileProvider is able provide.
|
||||
*/
|
||||
* \returns The maximum level as defined by <code>TileIndex</code>
|
||||
* that this TileProvider is able provide.
|
||||
*/
|
||||
virtual int maxLevel() = 0;
|
||||
|
||||
/**
|
||||
* \returns the no data value for the dataset. Default is the minimum float avalue.
|
||||
*/
|
||||
* \returns the no data value for the dataset. Default is the minimum float avalue.
|
||||
*/
|
||||
virtual float noDataValueAsFloat();
|
||||
};
|
||||
|
||||
typedef LRUCache<TileHashKey, Tile> TileCache;
|
||||
using TileCache = LRUCache<TileHashKey, Tile>;
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __TILE_PROVIDER_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_H__
|
||||
|
||||
@@ -22,90 +22,96 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileproviderbyindex.h>
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TileProviderByIndex";
|
||||
|
||||
const std::string KeyDefaultProvider = "DefaultProvider";
|
||||
const std::string KeyProviders = "IndexTileProviders";
|
||||
const std::string KeyTileIndex = "TileIndex";
|
||||
const std::string KeyTileProvider = "TileProvider";
|
||||
const char* KeyDefaultProvider = "DefaultProvider";
|
||||
const char* KeyProviders = "IndexTileProviders";
|
||||
const char* KeyTileIndex = "TileIndex";
|
||||
const char* KeyTileProvider = "TileProvider";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
TileProviderByIndex::TileProviderByIndex(const ghoul::Dictionary& dictionary) {
|
||||
ghoul::Dictionary defaultProviderDict = dictionary.value<ghoul::Dictionary>(KeyDefaultProvider);
|
||||
TileProvider * defaultProvider = TileProvider::createFromDictionary(defaultProviderDict);
|
||||
_defaultTileProvider = std::shared_ptr<TileProvider>(defaultProvider);
|
||||
TileProviderByIndex::TileProviderByIndex(const ghoul::Dictionary& dictionary) {
|
||||
ghoul::Dictionary defaultProviderDict = dictionary.value<ghoul::Dictionary>(
|
||||
KeyDefaultProvider
|
||||
);
|
||||
TileProvider* defaultProvider = TileProvider::createFromDictionary(
|
||||
defaultProviderDict
|
||||
);
|
||||
_defaultTileProvider = std::shared_ptr<TileProvider>(defaultProvider);
|
||||
|
||||
ghoul::Dictionary indexProvidersDict = dictionary.value<ghoul::Dictionary>(KeyProviders);
|
||||
for (size_t i = 0; i < indexProvidersDict.size(); i++) {
|
||||
std::string dictKey = std::to_string(i + 1);
|
||||
ghoul::Dictionary indexProviderDict = indexProvidersDict.value<ghoul::Dictionary>(dictKey);
|
||||
ghoul::Dictionary tileIndexDict = indexProviderDict.value<ghoul::Dictionary>(KeyTileIndex);
|
||||
ghoul::Dictionary providerDict = indexProviderDict.value<ghoul::Dictionary>(KeyTileProvider);
|
||||
ghoul::Dictionary indexProvidersDict = dictionary.value<ghoul::Dictionary>(
|
||||
KeyProviders
|
||||
);
|
||||
for (size_t i = 0; i < indexProvidersDict.size(); i++) {
|
||||
std::string dictKey = std::to_string(i + 1);
|
||||
ghoul::Dictionary indexProviderDict = indexProvidersDict.value<ghoul::Dictionary>(
|
||||
dictKey
|
||||
);
|
||||
ghoul::Dictionary tileIndexDict = indexProviderDict.value<ghoul::Dictionary>(
|
||||
KeyTileIndex
|
||||
);
|
||||
ghoul::Dictionary providerDict = indexProviderDict.value<ghoul::Dictionary>(
|
||||
KeyTileProvider
|
||||
);
|
||||
|
||||
TileIndex tileIndex(tileIndexDict);
|
||||
TileProvider* tileProvider = TileProvider::createFromDictionary(providerDict);
|
||||
std::shared_ptr<TileProvider> stp = std::shared_ptr<TileProvider>(tileProvider);
|
||||
TileHashKey key = tileIndex.hashKey();
|
||||
_tileProviderMap.insert(std::make_pair(key, stp));
|
||||
}
|
||||
TileIndex tileIndex(tileIndexDict);
|
||||
TileProvider* tileProvider = TileProvider::createFromDictionary(providerDict);
|
||||
std::shared_ptr<TileProvider> stp = std::shared_ptr<TileProvider>(tileProvider);
|
||||
TileHashKey key = tileIndex.hashKey();
|
||||
_tileProviderMap.insert(std::make_pair(key, stp));
|
||||
}
|
||||
}
|
||||
|
||||
Tile TileProviderByIndex::getTile(const TileIndex& tileIndex) {
|
||||
auto it = _tileProviderMap.find(tileIndex.hashKey());
|
||||
bool hasProvider = it != _tileProviderMap.end();
|
||||
return hasProvider ? it->second->getTile(tileIndex) : Tile::TileUnavailable;
|
||||
}
|
||||
Tile TileProviderByIndex::getTile(const TileIndex& tileIndex) {
|
||||
auto it = _tileProviderMap.find(tileIndex.hashKey());
|
||||
bool hasProvider = it != _tileProviderMap.end();
|
||||
return hasProvider ? it->second->getTile(tileIndex) : Tile::TileUnavailable;
|
||||
}
|
||||
|
||||
Tile TileProviderByIndex::getDefaultTile() {
|
||||
return _defaultTileProvider->getDefaultTile();
|
||||
}
|
||||
Tile TileProviderByIndex::getDefaultTile() {
|
||||
return _defaultTileProvider->getDefaultTile();
|
||||
}
|
||||
|
||||
Tile::Status TileProviderByIndex::getTileStatus(const TileIndex& tileIndex) {
|
||||
auto it = _tileProviderMap.find(tileIndex.hashKey());
|
||||
bool hasProvider = it != _tileProviderMap.end();
|
||||
return hasProvider ? it->second->getTileStatus(tileIndex) : Tile::Status::Unavailable;
|
||||
}
|
||||
Tile::Status TileProviderByIndex::getTileStatus(const TileIndex& tileIndex) {
|
||||
auto it = _tileProviderMap.find(tileIndex.hashKey());
|
||||
bool hasProvider = it != _tileProviderMap.end();
|
||||
return hasProvider ? it->second->getTileStatus(tileIndex) : Tile::Status::Unavailable;
|
||||
}
|
||||
|
||||
TileDepthTransform TileProviderByIndex::depthTransform() {
|
||||
return _defaultTileProvider->depthTransform();
|
||||
}
|
||||
TileDepthTransform TileProviderByIndex::depthTransform() {
|
||||
return _defaultTileProvider->depthTransform();
|
||||
}
|
||||
|
||||
void TileProviderByIndex::update() {
|
||||
for(auto it : _tileProviderMap){
|
||||
it.second->update();
|
||||
}
|
||||
_defaultTileProvider->update();
|
||||
void TileProviderByIndex::update() {
|
||||
for (auto& it : _tileProviderMap){
|
||||
it.second->update();
|
||||
}
|
||||
_defaultTileProvider->update();
|
||||
}
|
||||
|
||||
void TileProviderByIndex::reset() {
|
||||
for(auto it : _tileProviderMap){
|
||||
it.second->reset();
|
||||
}
|
||||
_defaultTileProvider->reset();
|
||||
void TileProviderByIndex::reset() {
|
||||
for (auto& it : _tileProviderMap) {
|
||||
it.second->reset();
|
||||
}
|
||||
_defaultTileProvider->reset();
|
||||
}
|
||||
|
||||
int TileProviderByIndex::maxLevel() {
|
||||
return _defaultTileProvider->maxLevel();
|
||||
}
|
||||
int TileProviderByIndex::maxLevel() {
|
||||
return _defaultTileProvider->maxLevel();
|
||||
}
|
||||
|
||||
TileProvider* TileProviderByIndex::indexProvider(const TileIndex& tileIndex) const{
|
||||
auto it = _tileProviderMap.find(tileIndex.hashKey());
|
||||
return (it != _tileProviderMap.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
TileProvider* TileProviderByIndex::indexProvider(const TileIndex& tileIndex) const {
|
||||
auto it = _tileProviderMap.find(tileIndex.hashKey());
|
||||
return (it != _tileProviderMap.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,75 +1,57 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TILE_PROVIDER_BY_INDEX__
|
||||
#define __TILE_PROVIDER_BY_INDEX__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_INDEX_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_INDEX_H__
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/tile/asynctilereader.h>
|
||||
|
||||
#include <gdal_priv.h>
|
||||
|
||||
#include <openspace/engine/downloadmanager.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h> // absPath
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <ghoul/font/fontrenderer.h>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace ghoul::opengl;
|
||||
class TileProviderByIndex : public TileProvider {
|
||||
public:
|
||||
TileProviderByIndex(const ghoul::Dictionary& dictionary);
|
||||
TileProviderByIndex(const std::string& imagePath);
|
||||
virtual ~TileProviderByIndex() { }
|
||||
|
||||
class TileProviderByIndex : public TileProvider {
|
||||
public:
|
||||
|
||||
TileProviderByIndex(const ghoul::Dictionary& dictionary);
|
||||
TileProviderByIndex(const std::string& imagePath);
|
||||
virtual ~TileProviderByIndex() { }
|
||||
virtual Tile getTile(const TileIndex& tileIndex);
|
||||
virtual Tile getDefaultTile();
|
||||
virtual Tile::Status getTileStatus(const TileIndex& index);
|
||||
virtual TileDepthTransform depthTransform();
|
||||
virtual void update();
|
||||
virtual void reset();
|
||||
virtual int maxLevel();
|
||||
|
||||
virtual Tile getTile(const TileIndex& tileIndex);
|
||||
virtual Tile getDefaultTile();
|
||||
virtual Tile::Status getTileStatus(const TileIndex& index);
|
||||
virtual TileDepthTransform depthTransform();
|
||||
virtual void update();
|
||||
virtual void reset();
|
||||
virtual int maxLevel();
|
||||
private:
|
||||
TileProvider* indexProvider(const TileIndex& tileIndex) const;
|
||||
|
||||
private:
|
||||
|
||||
inline TileProvider* indexProvider(const TileIndex& tileIndex) const;
|
||||
|
||||
std::unordered_map<TileHashKey, std::shared_ptr<TileProvider>> _tileProviderMap;
|
||||
std::shared_ptr<TileProvider> _defaultTileProvider;
|
||||
};
|
||||
std::unordered_map<TileHashKey, std::shared_ptr<TileProvider>> _tileProviderMap;
|
||||
std::shared_ptr<TileProvider> _defaultTileProvider;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __TILE_PROVIDER_BY_INDEX__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_INDEX_H__
|
||||
|
||||
@@ -1,129 +1,132 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileproviderbylevel.h>
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TileProviderByLevel";
|
||||
|
||||
const std::string KeyProviders = "LevelTileProviders";
|
||||
const std::string KeyMaxLevel = "MaxLevel";
|
||||
const std::string KeyTileProvider = "TileProvider";
|
||||
const char* KeyProviders = "LevelTileProviders";
|
||||
const char* KeyMaxLevel = "MaxLevel";
|
||||
const char* KeyTileProvider = "TileProvider";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
TileProviderByLevel::TileProviderByLevel(const ghoul::Dictionary& dictionary) {
|
||||
TileProviderByLevel::TileProviderByLevel(const ghoul::Dictionary& dictionary) {
|
||||
ghoul::Dictionary levelProvidersDict = dictionary.value<ghoul::Dictionary>(
|
||||
KeyProviders
|
||||
);
|
||||
|
||||
for (size_t i = 0; i < levelProvidersDict.size(); i++) {
|
||||
std::string dictKey = std::to_string(i + 1);
|
||||
ghoul::Dictionary levelProviderDict = levelProvidersDict.value<ghoul::Dictionary>(
|
||||
dictKey
|
||||
);
|
||||
double floatMaxLevel;
|
||||
int maxLevel = 0;
|
||||
if (!levelProviderDict.getValue<double>(KeyMaxLevel, floatMaxLevel)) {
|
||||
throw std::runtime_error(
|
||||
"Must define key '" + std::string(KeyMaxLevel) + "'"
|
||||
);
|
||||
}
|
||||
maxLevel = std::round(floatMaxLevel);
|
||||
|
||||
ghoul::Dictionary providerDict;
|
||||
if (!levelProviderDict.getValue<ghoul::Dictionary>(KeyTileProvider, providerDict))
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Must define key '" + std::string(KeyTileProvider) + "'"
|
||||
);
|
||||
}
|
||||
|
||||
TileProvider* tileProvider = TileProvider::createFromDictionary(providerDict);
|
||||
_levelTileProviders.push_back(std::shared_ptr<TileProvider>(tileProvider));
|
||||
|
||||
// Ensure we can represent the max level
|
||||
if(_providerIndices.size() < maxLevel){
|
||||
_providerIndices.resize(maxLevel+1, -1);
|
||||
}
|
||||
|
||||
// map this level to the tile provider index
|
||||
_providerIndices[maxLevel] = _levelTileProviders.size() - 1;
|
||||
}
|
||||
|
||||
ghoul::Dictionary levelProvidersDict = dictionary.value<ghoul::Dictionary>(KeyProviders);
|
||||
for (size_t i = 0; i < levelProvidersDict.size(); i++) {
|
||||
std::string dictKey = std::to_string(i + 1);
|
||||
ghoul::Dictionary levelProviderDict = levelProvidersDict.value<ghoul::Dictionary>(dictKey);
|
||||
double floatMaxLevel;
|
||||
int maxLevel = 0;
|
||||
if (!levelProviderDict.getValue<double>(KeyMaxLevel, floatMaxLevel)) {
|
||||
throw std::runtime_error("Must define key '" + KeyMaxLevel + "'");
|
||||
}
|
||||
maxLevel = std::round(floatMaxLevel);
|
||||
|
||||
ghoul::Dictionary providerDict;
|
||||
if (!levelProviderDict.getValue<ghoul::Dictionary>(KeyTileProvider, providerDict)) {
|
||||
throw std::runtime_error("Must define key '" + KeyTileProvider + "'");
|
||||
}
|
||||
|
||||
TileProvider* tileProvider = TileProvider::createFromDictionary(providerDict);
|
||||
_levelTileProviders.push_back(std::shared_ptr<TileProvider>(tileProvider));
|
||||
|
||||
// Ensure we can represent the max level
|
||||
if(_providerIndices.size() < maxLevel){
|
||||
_providerIndices.resize(maxLevel+1, -1);
|
||||
}
|
||||
|
||||
// map this level to the tile provider index
|
||||
_providerIndices[maxLevel] = _levelTileProviders.size() - 1;
|
||||
}
|
||||
|
||||
// Fill in the gaps (value -1) in provider indices, from back to end
|
||||
for(int i = _providerIndices.size() - 2; i>=0; --i){
|
||||
if(_providerIndices[i] == -1){
|
||||
_providerIndices[i] = _providerIndices[i+1];
|
||||
}
|
||||
// Fill in the gaps (value -1) in provider indices, from back to end
|
||||
for(int i = _providerIndices.size() - 2; i >= 0; --i){
|
||||
if(_providerIndices[i] == -1){
|
||||
_providerIndices[i] = _providerIndices[i+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tile TileProviderByLevel::getTile(const TileIndex& tileIndex) {
|
||||
return levelProvider(tileIndex.level)->getTile(tileIndex);
|
||||
}
|
||||
Tile TileProviderByLevel::getTile(const TileIndex& tileIndex) {
|
||||
return levelProvider(tileIndex.level)->getTile(tileIndex);
|
||||
}
|
||||
|
||||
Tile TileProviderByLevel::getDefaultTile() {
|
||||
return levelProvider(0)->getDefaultTile();
|
||||
}
|
||||
Tile TileProviderByLevel::getDefaultTile() {
|
||||
return levelProvider(0)->getDefaultTile();
|
||||
}
|
||||
|
||||
Tile::Status TileProviderByLevel::getTileStatus(const TileIndex& index) {
|
||||
return levelProvider(index.level)->getTileStatus(index);
|
||||
}
|
||||
Tile::Status TileProviderByLevel::getTileStatus(const TileIndex& index) {
|
||||
return levelProvider(index.level)->getTileStatus(index);
|
||||
}
|
||||
|
||||
TileDepthTransform TileProviderByLevel::depthTransform() {
|
||||
TileDepthTransform transform;
|
||||
transform.depthOffset = 0.0f;
|
||||
transform.depthScale = 1.0f;
|
||||
return transform;
|
||||
}
|
||||
TileDepthTransform TileProviderByLevel::depthTransform() {
|
||||
TileDepthTransform transform;
|
||||
transform.depthOffset = 0.0f;
|
||||
transform.depthScale = 1.0f;
|
||||
return transform;
|
||||
}
|
||||
|
||||
void TileProviderByLevel::update() {
|
||||
for(auto provider : _levelTileProviders){
|
||||
provider->update();
|
||||
}
|
||||
void TileProviderByLevel::update() {
|
||||
for(auto provider : _levelTileProviders){
|
||||
provider->update();
|
||||
}
|
||||
}
|
||||
|
||||
void TileProviderByLevel::reset() {
|
||||
for(auto provider : _levelTileProviders){
|
||||
provider->reset();
|
||||
}
|
||||
void TileProviderByLevel::reset() {
|
||||
for(auto provider : _levelTileProviders){
|
||||
provider->reset();
|
||||
}
|
||||
}
|
||||
|
||||
int TileProviderByLevel::maxLevel() {
|
||||
return _providerIndices.size()-1;
|
||||
}
|
||||
int TileProviderByLevel::maxLevel() {
|
||||
return _providerIndices.size()-1;
|
||||
}
|
||||
|
||||
int TileProviderByLevel::providerIndex(int level) const {
|
||||
int clampedLevel = std::max(0, std::min(level, (int)_providerIndices.size()-1));
|
||||
return _providerIndices[clampedLevel];
|
||||
}
|
||||
int TileProviderByLevel::providerIndex(int level) const {
|
||||
int clampedLevel = std::max(0, std::min(level, (int)_providerIndices.size()-1));
|
||||
return _providerIndices[clampedLevel];
|
||||
}
|
||||
|
||||
TileProvider* TileProviderByLevel::levelProvider(int level) const{
|
||||
return _levelTileProviders[providerIndex(level)].get();
|
||||
}
|
||||
TileProvider* TileProviderByLevel::levelProvider(int level) const {
|
||||
return _levelTileProviders[providerIndex(level)].get();
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,74 +1,57 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TILE_PROVIDER_BY_LEVEL__
|
||||
#define __TILE_PROVIDER_BY_LEVEL__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_LEVEL_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_LEVEL_H__
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/tile/asynctilereader.h>
|
||||
|
||||
#include <gdal_priv.h>
|
||||
|
||||
#include <openspace/engine/downloadmanager.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h> // absPath
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <ghoul/font/fontrenderer.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
using namespace ghoul::opengl;
|
||||
class TileProviderByLevel : public TileProvider {
|
||||
public:
|
||||
TileProviderByLevel(const ghoul::Dictionary& dictionary);
|
||||
TileProviderByLevel(const std::string& imagePath);
|
||||
virtual ~TileProviderByLevel() { }
|
||||
|
||||
class TileProviderByLevel : public TileProvider {
|
||||
public:
|
||||
|
||||
TileProviderByLevel(const ghoul::Dictionary& dictionary);
|
||||
TileProviderByLevel(const std::string& imagePath);
|
||||
virtual ~TileProviderByLevel() { }
|
||||
virtual Tile getTile(const TileIndex& tileIndex);
|
||||
virtual Tile getDefaultTile();
|
||||
virtual Tile::Status getTileStatus(const TileIndex& index);
|
||||
virtual TileDepthTransform depthTransform();
|
||||
virtual void update();
|
||||
virtual void reset();
|
||||
virtual int maxLevel();
|
||||
private:
|
||||
inline int providerIndex(int level) const;
|
||||
inline TileProvider* levelProvider(int level) const;
|
||||
|
||||
virtual Tile getTile(const TileIndex& tileIndex);
|
||||
virtual Tile getDefaultTile();
|
||||
virtual Tile::Status getTileStatus(const TileIndex& index);
|
||||
virtual TileDepthTransform depthTransform();
|
||||
virtual void update();
|
||||
virtual void reset();
|
||||
virtual int maxLevel();
|
||||
private:
|
||||
inline int providerIndex(int level) const;
|
||||
inline TileProvider* levelProvider(int level) const;
|
||||
|
||||
std::vector<int> _providerIndices;
|
||||
std::vector<std::shared_ptr<TileProvider>> _levelTileProviders;
|
||||
};
|
||||
std::vector<int> _providerIndices;
|
||||
std::vector<std::shared_ptr<TileProvider>> _levelTileProviders;
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __TILE_PROVIDER_BY_LEVEL__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_PROVIDER_BY_LEVEL_H__
|
||||
|
||||
@@ -1,89 +1,84 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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/tile/tileselector.h>
|
||||
|
||||
#include <modules/globebrowsing/rendering/layermanager.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "gdal_priv.h"
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "TileSelector";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
const TileSelector::CompareResolution TileSelector::HIGHEST_RES = TileSelector::CompareResolution();
|
||||
ChunkTile TileSelector::getHighestResolutionTile(const LayerGroup& layerGroup,
|
||||
TileIndex tileIndex)
|
||||
{
|
||||
ChunkTile mostHighResolution;
|
||||
mostHighResolution.tile = Tile::TileUnavailable;
|
||||
mostHighResolution.uvTransform.uvScale.x = 0;
|
||||
|
||||
ChunkTile TileSelector::getHighestResolutionTile(const LayerGroup& layerGroup, TileIndex tileIndex) {
|
||||
ChunkTile mostHighResolution;
|
||||
mostHighResolution.tile = Tile::TileUnavailable;
|
||||
mostHighResolution.uvTransform.uvScale.x = 0;
|
||||
|
||||
for (const auto& layer : layerGroup.activeLayers()) {
|
||||
ChunkTile chunkTile = layer->tileProvider()->getChunkTile(tileIndex);
|
||||
bool tileIsOk = chunkTile.tile.status == Tile::Status::OK;
|
||||
bool tileHasMetaData = chunkTile.tile.metaData != nullptr;
|
||||
bool tileIsHigherResolution = chunkTile.uvTransform.uvScale.x > mostHighResolution.uvTransform.uvScale.x;
|
||||
if (tileIsOk && tileHasMetaData && tileIsHigherResolution) {
|
||||
mostHighResolution = chunkTile;
|
||||
}
|
||||
for (const auto& layer : layerGroup.activeLayers()) {
|
||||
ChunkTile chunkTile = layer->tileProvider()->getChunkTile(tileIndex);
|
||||
bool tileIsOk = chunkTile.tile.status == Tile::Status::OK;
|
||||
bool tileHasMetaData = chunkTile.tile.metaData != nullptr;
|
||||
bool tileIsHigherResolution =
|
||||
chunkTile.uvTransform.uvScale.x > mostHighResolution.uvTransform.uvScale.x;
|
||||
if (tileIsOk && tileHasMetaData && tileIsHigherResolution) {
|
||||
mostHighResolution = chunkTile;
|
||||
}
|
||||
|
||||
return mostHighResolution;
|
||||
}
|
||||
|
||||
bool TileSelector::CompareResolution::operator()(const ChunkTile& a, const ChunkTile& b) {
|
||||
// large uv scale means smaller resolution
|
||||
return a.uvTransform.uvScale.x > b.uvTransform.uvScale.x;
|
||||
return mostHighResolution;
|
||||
}
|
||||
|
||||
std::vector<ChunkTile> TileSelector::getTilesSortedByHighestResolution(
|
||||
const LayerGroup& layerGroup,
|
||||
const TileIndex& tileIndex)
|
||||
{
|
||||
std::vector<ChunkTile> tiles;
|
||||
for (const auto& layer : layerGroup.activeLayers()) {
|
||||
tiles.push_back(layer->tileProvider()->getChunkTile(tileIndex));
|
||||
}
|
||||
|
||||
std::vector<ChunkTile> TileSelector::getTilesSortedByHighestResolution(const LayerGroup& layerGroup, const TileIndex& tileIndex) {
|
||||
std::vector<ChunkTile> tiles;
|
||||
for (const auto& layer : layerGroup.activeLayers()) {
|
||||
tiles.push_back(layer->tileProvider()->getChunkTile(tileIndex));
|
||||
std::sort(
|
||||
tiles.begin(),
|
||||
tiles.end(),
|
||||
[](const ChunkTile& lhs, const ChunkTile& rhs) {
|
||||
return lhs.uvTransform.uvScale.x > rhs.uvTransform.uvScale.x;
|
||||
}
|
||||
);
|
||||
|
||||
std::sort(tiles.begin(), tiles.end(), TileSelector::HIGHEST_RES);
|
||||
return tiles;
|
||||
}
|
||||
|
||||
return tiles;
|
||||
}
|
||||
void TileSelector::ascendToParent(TileIndex& tileIndex, TileUvTransform& uv) {
|
||||
uv.uvOffset *= 0.5;
|
||||
uv.uvScale *= 0.5;
|
||||
|
||||
void TileSelector::ascendToParent(TileIndex& tileIndex, TileUvTransform& uv) {
|
||||
uv.uvOffset *= 0.5;
|
||||
uv.uvScale *= 0.5;
|
||||
uv.uvOffset += tileIndex.positionRelativeParent();
|
||||
|
||||
uv.uvOffset += tileIndex.positionRelativeParent();
|
||||
|
||||
--tileIndex;
|
||||
}
|
||||
--tileIndex;
|
||||
}
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
@@ -1,59 +1,52 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
* *
|
||||
* 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 __TILE_SELECTOR_H__
|
||||
#define __TILE_SELECTOR_H__
|
||||
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING_TILE_SELECTOR_H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING_TILE_SELECTOR_H__
|
||||
|
||||
#include <modules/globebrowsing/rendering/layermanager.h>
|
||||
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
#include <modules/globebrowsing/tile/chunktile.h>
|
||||
#include <modules/globebrowsing/tile/tile.h>
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
//struct LayerGroup;
|
||||
class TileProvider;
|
||||
struct LayerGroup;
|
||||
class TileProvider;
|
||||
|
||||
class TileSelector {
|
||||
public:
|
||||
static ChunkTile getHighestResolutionTile(const LayerGroup& layerGroup, TileIndex tileIndex);
|
||||
static std::vector<ChunkTile> getTilesSortedByHighestResolution(const LayerGroup& layerGroup, const TileIndex& tileIndex);
|
||||
class TileSelector {
|
||||
public:
|
||||
static ChunkTile getHighestResolutionTile(const LayerGroup& layerGroup,
|
||||
TileIndex tileIndex);
|
||||
static std::vector<ChunkTile> getTilesSortedByHighestResolution(
|
||||
const LayerGroup& layerGroup, const TileIndex& tileIndex);
|
||||
|
||||
struct CompareResolution {
|
||||
bool operator() (const ChunkTile& a, const ChunkTile& b);
|
||||
};
|
||||
|
||||
static const CompareResolution HIGHEST_RES;
|
||||
|
||||
static void ascendToParent(TileIndex& tileIndex, TileUvTransform& uv);
|
||||
};
|
||||
static void ascendToParent(TileIndex& tileIndex, TileUvTransform& uv);
|
||||
};
|
||||
|
||||
} // namespace globebrowsing
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __TILE_SELECTOR_H__
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING_TILE_SELECTOR_H__
|
||||
|
||||
@@ -7,9 +7,9 @@ return {
|
||||
|
||||
-- Sets the scene that is to be loaded by OpenSpace. A scene file is a description
|
||||
-- of all entities that will be visible during an instance of OpenSpace
|
||||
Scene = "${SCENE}/default.scene",
|
||||
-- Scene = "${SCENE}/default.scene",
|
||||
|
||||
-- Scene = "${SCENE}/globebrowsing.scene",
|
||||
Scene = "${SCENE}/globebrowsing.scene",
|
||||
-- Scene = "${SCENE}/rosetta.scene",
|
||||
-- Scene = "${SCENE}/dawn.scene",
|
||||
-- Scene = "${SCENE}/newhorizons.scene",
|
||||
|
||||
@@ -220,7 +220,10 @@ void InteractionHandler::goToGeo(double latitude, double longitude) {
|
||||
std::dynamic_pointer_cast<GlobeBrowsingInteractionMode> (_currentInteractionMode);
|
||||
|
||||
if (gbim) {
|
||||
gbim->goToGeodetic2(*_camera, globebrowsing::Geodetic2(latitude, longitude) / 180 * M_PI, true);
|
||||
gbim->goToGeodetic2(
|
||||
*_camera,
|
||||
globebrowsing::Geodetic2(latitude, longitude) / 180 * glm::pi<double>(), true
|
||||
);
|
||||
} else {
|
||||
LWARNING("Interaction mode must be set to 'GlobeBrowsing'");
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ struct TestJob : public openspace::globebrowsing::Job<int> {
|
||||
std::cout << "Finished job" << std::endl;
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<int> product() {
|
||||
virtual std::shared_ptr<int> product() const {
|
||||
return std::make_shared<int>(prod);
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ struct VerboseJob : public openspace::globebrowsing::Job<VerboseProduct>{
|
||||
std::cout << " ** Finished job" << std::endl;
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<VerboseProduct> product() {
|
||||
virtual std::shared_ptr<VerboseProduct> product() const {
|
||||
return _product;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ TEST_F(ConvexHull2Test, basic) {
|
||||
// 0 x x
|
||||
// -1 0 1
|
||||
|
||||
std::vector<Point2> points = {
|
||||
std::vector<glm::vec2> points = {
|
||||
{ -1.0, 0.0 },
|
||||
{ 1.0, 0.0 },
|
||||
{ 0.0, 2.0 },
|
||||
@@ -66,7 +66,7 @@ TEST_F(ConvexHull2Test, basic) {
|
||||
|
||||
TEST_F(ConvexHull2Test, intersection) {
|
||||
using namespace openspace::globebrowsing;
|
||||
std::vector<Point2> points1 = {
|
||||
std::vector<glm::vec2> points1 = {
|
||||
{ -1.0, 0.0 },
|
||||
{ 1.0, 0.0 },
|
||||
{ 0.0, 2.0 },
|
||||
@@ -74,7 +74,7 @@ TEST_F(ConvexHull2Test, intersection) {
|
||||
};
|
||||
ConvexHull2 hull1 = ConvexHull2::grahamScan_NOT_THREAD_SAFE(points1);
|
||||
|
||||
std::vector<Point2> points2 = {
|
||||
std::vector<glm::vec2> points2 = {
|
||||
{ 0.0, 0.0 },
|
||||
{ 2.0, 0.0 },
|
||||
{ 1.0, 2.0 },
|
||||
@@ -96,14 +96,14 @@ TEST_F(ConvexHull2Test, intersection) {
|
||||
|
||||
TEST_F(ConvexHull2Test, non_intersection) {
|
||||
using namespace openspace::globebrowsing;
|
||||
std::vector<Point2> points1 = {
|
||||
std::vector<glm::vec2> points1 = {
|
||||
{ -2.0, 0.0 },
|
||||
{ 2.0, 0.0 },
|
||||
{ 0.0, 2.0 },
|
||||
};
|
||||
ConvexHull2 hull1 = ConvexHull2::grahamScan_NOT_THREAD_SAFE(points1);
|
||||
|
||||
std::vector<Point2> points2 = {
|
||||
std::vector<glm::vec2> points2 = {
|
||||
{ 1.0, 2.0 },
|
||||
{ 3.0, 0.0 },
|
||||
{ 5.0, 2.0 }
|
||||
|
||||
Reference in New Issue
Block a user