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

This commit is contained in:
Kalle Bladin
2016-05-16 20:52:14 -04:00
22 changed files with 457 additions and 287 deletions

View File

@@ -55,6 +55,7 @@ set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/other/gdaldataconverter.h
${CMAKE_CURRENT_SOURCE_DIR}/other/lrucache.h
${CMAKE_CURRENT_SOURCE_DIR}/other/concurrentjobmanager.h
${CMAKE_CURRENT_SOURCE_DIR}/other/threadpool.h
${CMAKE_CURRENT_SOURCE_DIR}/other/concurrentqueue.h
${CMAKE_CURRENT_SOURCE_DIR}/other/tileprovidermanager.h
${CMAKE_CURRENT_SOURCE_DIR}/other/layeredtextureshaderprovider.h
@@ -91,6 +92,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/other/gdaldataconverter.inl
${CMAKE_CURRENT_SOURCE_DIR}/other/lrucache.inl
${CMAKE_CURRENT_SOURCE_DIR}/other/concurrentjobmanager.inl
${CMAKE_CURRENT_SOURCE_DIR}/other/threadpool.cpp
${CMAKE_CURRENT_SOURCE_DIR}/other/tileprovidermanager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/other/layeredtextureshaderprovider.cpp

View File

@@ -102,7 +102,8 @@ namespace openspace {
_isVisible &= HorizonCuller::isVisible(myRenderData, _surfacePatch, ellipsoid, maxHeight);
}
if (!_isVisible) return WANT_MERGE;
if(!_isVisible && owner()->mergeInvisible)
return WANT_MERGE;
Vec3 cameraPosition = myRenderData.camera.position().dvec3();
@@ -129,7 +130,9 @@ namespace openspace {
else return DO_NOTHING;
}
void Chunk::render(const RenderData& data) const {
_owner->getPatchRenderer().renderChunk(*this, data);
}
} // namespace openspace

View File

@@ -54,6 +54,7 @@ namespace openspace {
/// Updates chunk internally and returns a desired level
Status update(const RenderData& data);
void render(const RenderData& data) const;
const GeodeticPatch& surfacePatch() const;
ChunkedLodGlobe* const owner() const;

View File

@@ -95,23 +95,35 @@ namespace openspace {
void ChunkedLodGlobe::render(const RenderData& data){
minDistToCamera = INFINITY;
ChunkNode::renderedPatches = 0;
ChunkNode::renderedChunks = 0;
_leftRoot->render(data);
_rightRoot->render(data);
renderChunkTree(_leftRoot.get(), data);
renderChunkTree(_rightRoot.get(), data);
//LDEBUG("min distnace to camera: " << minDistToCamera);
Vec3 cameraPos = data.camera.position().dvec3();
//LDEBUG("cam pos x: " << cameraPos.x << " y: " << cameraPos.y << " z: " << cameraPos.z);
//LDEBUG("ChunkNode count: " << ChunkNode::instanceCount);
//LDEBUG("RenderedPatches count: " << ChunkNode::renderedPatches);
//LDEBUG(ChunkNode::renderedPatches << " / " << ChunkNode::instanceCount << " chunks rendered");
//LDEBUG("ChunkNode count: " << ChunkNode::chunkNodeCount);
//LDEBUG("RenderedPatches count: " << ChunkNode::renderedChunks);
//LDEBUG(ChunkNode::renderedChunks << " / " << ChunkNode::chunkNodeCount << " chunks rendered");
}
void ChunkedLodGlobe::renderChunkTree(ChunkNode* node, const RenderData& data) const {
node->updateChunkTree(data);
if (renderSmallChunksFirst) {
node->renderReversedBreadthFirst(data);
}
else {
node->renderDepthFirst(data);
}
}
void ChunkedLodGlobe::update(const UpdateData& data) {
_patchRenderer->update();
}
const Ellipsoid& ChunkedLodGlobe::ellipsoid() const

View File

@@ -87,13 +87,16 @@ namespace openspace {
bool doHorizonCulling = true;
bool doFrustumCulling = true;
int numPosZthres;
bool mergeInvisible;
float lodScaleFactor;
bool initChunkVisible;
bool renderSmallChunksFirst = true;
private:
void renderChunkTree(ChunkNode* node, const RenderData& data) const;
// Covers all negative longitudes
std::unique_ptr<ChunkNode> _leftRoot;

View File

@@ -48,7 +48,7 @@ using HashKey = unsigned long;
struct ChunkIndex {
int x, y, level;

View File

@@ -22,13 +22,14 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/globes/chunknode.h>
#include <queue>
#include <ghoul/misc/assert.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/engine/openspaceengine.h>
#include <modules/globebrowsing/globes/chunknode.h>
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
#include <modules/globebrowsing/rendering/culling.h>
@@ -39,8 +40,8 @@ namespace {
namespace openspace {
int ChunkNode::instanceCount = 0;
int ChunkNode::renderedPatches = 0;
int ChunkNode::chunkNodeCount = 0;
int ChunkNode::renderedChunks = 0;
ChunkNode::ChunkNode(const Chunk& chunk, ChunkNode* parent)
: _chunk(chunk)
@@ -50,11 +51,11 @@ ChunkNode::ChunkNode(const Chunk& chunk, ChunkNode* parent)
_children[1] = nullptr;
_children[2] = nullptr;
_children[3] = nullptr;
instanceCount++;
chunkNodeCount++;
}
ChunkNode::~ChunkNode() {
instanceCount--;
chunkNodeCount--;
}
bool ChunkNode::isRoot() const {
@@ -66,16 +67,8 @@ bool ChunkNode::isLeaf() const {
}
void ChunkNode::render(const RenderData& data) {
ghoul_assert(isRoot(), "this method should only be invoked on root");
//LDEBUG("-------------");
internalUpdateChunkTree(data);
internalRender(data);
}
// Returns true or false wether this node can be merge or not
bool ChunkNode::internalUpdateChunkTree(const RenderData& data) {
bool ChunkNode::updateChunkTree(const RenderData& data) {
//Geodetic2 center = _chunk.surfacePatch.center();
//LDEBUG("x: " << patch.x << " y: " << patch.y << " level: " << patch.level << " lat: " << center.lat << " lon: " << center.lon);
@@ -90,7 +83,7 @@ bool ChunkNode::internalUpdateChunkTree(const RenderData& data) {
char requestedMergeMask = 0;
for (int i = 0; i < 4; ++i) {
if (_children[i]->internalUpdateChunkTree(data)) {
if (_children[i]->updateChunkTree(data)) {
requestedMergeMask |= (1 << i);
}
}
@@ -99,26 +92,54 @@ bool ChunkNode::internalUpdateChunkTree(const RenderData& data) {
if (requestedMergeMask == 0xf && _chunk.update(data)) {
merge();
// re-run internalUpdateChunkTree on this, now that this is a leaf node
// re-run updateChunkTree on this, now that this is a leaf node
// OBS, this may currently cause a split() again ...
return internalUpdateChunkTree(data);
return updateChunkTree(data);
}
return false;
}
}
void ChunkNode::internalRender(const RenderData& data) {
void ChunkNode::renderReversedBreadthFirst(const RenderData& data) {
std::stack<ChunkNode*> S;
std::queue<ChunkNode*> Q;
Q.push(this);
while (Q.size() > 0) {
ChunkNode* node = Q.front();
Q.pop();
if (node->isLeaf()) {
if (node->_chunk.isVisible()) {
S.push(node);
}
}
else {
for (int i = 0; i < 4; ++i) {
Q.push(node->_children[i].get());
}
}
}
while (S.size() > 0) {
S.top()->renderThisChunk(data);
S.pop();
}
}
void ChunkNode::renderThisChunk(const RenderData& data) {
_chunk.render(data);
ChunkNode::renderedChunks++;
}
void ChunkNode::renderDepthFirst(const RenderData& data) {
if (isLeaf()) {
if (_chunk.isVisible()) {
ChunkRenderer& patchRenderer = _chunk.owner()->getPatchRenderer();
patchRenderer.renderChunk(_chunk, data);
ChunkNode::renderedPatches++;
renderThisChunk(data);
}
}
else {
for (int i = 0; i < 4; ++i) {
_children[i]->internalRender(data);
_children[i]->renderDepthFirst(data);
}
}
}

View File

@@ -27,6 +27,7 @@
#include <glm/glm.hpp>
#include <vector>
#include <stack>
#include <memory>
#include <ostream>
@@ -64,19 +65,17 @@ public:
const ChunkNode& getChild(Quad quad) const;
void render(const RenderData& data);
void renderDepthFirst(const RenderData& data);
static int instanceCount;
static int renderedPatches;
void renderReversedBreadthFirst(const RenderData& data);
void renderThisChunk(const RenderData& data);
bool updateChunkTree(const RenderData& data);
static int chunkNodeCount;
static int renderedChunks;
private:
void internalRender(const RenderData& data);
bool internalUpdateChunkTree(const RenderData& data);
ChunkNode* _parent;
std::unique_ptr<ChunkNode> _children[4];

View File

@@ -56,10 +56,10 @@ namespace openspace {
, _saveOrThrowCamera(properties::BoolProperty("saveOrThrowCamera", "saveOrThrowCamera"))
, doFrustumCulling(properties::BoolProperty("doFrustumCulling", "doFrustumCulling"))
, doHorizonCulling(properties::BoolProperty("doHorizonCulling", "doHorizonCulling"))
, numPosZthres(properties::IntProperty("numPosZthres", "numPosZthres", 0, 0, 9))
, mergeInvisible(properties::BoolProperty("mergeInvisible", "mergeInvisible", true))
, lodScaleFactor(properties::FloatProperty("lodScaleFactor", "lodScaleFactor", 10.0f, 0.0f, 100.0f))
, initChunkVisible(properties::BoolProperty("initChunkVisible", "initChunkVisible", true))
, renderSmallChunksFirst(properties::BoolProperty("renderSmallChunksFirst", "renderSmallChunksFirst", true))
{
setName("RenderableGlobe");
@@ -67,12 +67,16 @@ namespace openspace {
addProperty(_saveOrThrowCamera);
addProperty(doFrustumCulling);
addProperty(doHorizonCulling);
addProperty(numPosZthres);
addProperty(mergeInvisible);
addProperty(lodScaleFactor);
addProperty(initChunkVisible);
addProperty(renderSmallChunksFirst);
doFrustumCulling.setValue(true);
doHorizonCulling.setValue(true);
renderSmallChunksFirst.setValue(true);
// Read the radii in to its own dictionary
Vec3 radii;
@@ -96,7 +100,7 @@ namespace openspace {
colorTextureDictionary.getValue("FilePath", path);
std::shared_ptr<TileProvider> colorTextureProvider =
std::shared_ptr<TileProvider>(new TileProvider(
path, 5000, 512));
path, 5000, 1024, 60));
_tileProviderManager->addColorTexture(name, colorTextureProvider);
}
@@ -113,7 +117,7 @@ namespace openspace {
heightMapDictionary.getValue("FilePath", path);
std::shared_ptr<TileProvider> heightMapProvider =
std::shared_ptr<TileProvider>(new TileProvider(
path, 5000, 128));
path, 5000, 256, 60));
_tileProviderManager->addHeightMap(name, heightMapProvider);
}
@@ -158,7 +162,7 @@ namespace openspace {
}
_chunkedLodGlobe->doFrustumCulling = doFrustumCulling.value();
_chunkedLodGlobe->doHorizonCulling = doHorizonCulling.value();
_chunkedLodGlobe->numPosZthres = numPosZthres.value();
_chunkedLodGlobe->mergeInvisible = mergeInvisible.value();
_chunkedLodGlobe->lodScaleFactor= lodScaleFactor.value();
_chunkedLodGlobe->initChunkVisible = initChunkVisible.value();
_distanceSwitch.render(data);

View File

@@ -65,9 +65,10 @@ public:
properties::BoolProperty doFrustumCulling;
properties::BoolProperty doHorizonCulling;
properties::IntProperty numPosZthres;
properties::BoolProperty mergeInvisible;
properties::FloatProperty lodScaleFactor;
properties::BoolProperty initChunkVisible;
properties::BoolProperty renderSmallChunksFirst;
private:
double _time;

View File

@@ -83,6 +83,12 @@ namespace openspace {
}
}
void clearEnqueuedJobs() {
while (_incomingJobs.size()) {
_incomingJobs.pop();
}
}
std::shared_ptr<Job<P>> popFinishedJob() {
ghoul_assert(_finishedJobs.size() > 0, "There is no finished job to pop!");
return _finishedJobs.pop();

View File

@@ -0,0 +1,120 @@
/*****************************************************************************************
* *
* 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 <glm/glm.hpp>
#include <memory>
#include <ostream>
#include <thread>
#include <queue>
#include <atomic>
#include <modules/globebrowsing/other/concurrentqueue.h>
#include <modules/globebrowsing/other/threadpool.h>
#include <ghoul/misc/assert.h>
#include <iostream>
namespace openspace {
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();
}
}
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();
}
}
// add new work item to the pool
void ThreadPool::enqueue(std::function<void()> f) {
{ // acquire lock
std::unique_lock<std::mutex> lock(queue_mutex);
// add the task
tasks.push_back(f);
} // release lock
// wake up one thread
std::cout << "Notify one thread" << std::endl;
condition.notify_one();
}
} // namespace openspace

View File

@@ -0,0 +1,81 @@
/*****************************************************************************************
* *
* 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 __THREAD_POOL_H__
#define __THREAD_POOL_H__
#include <glm/glm.hpp>
#include <memory>
#include <ostream>
#include <thread>
#include <queue>
#include <atomic>
#include <modules/globebrowsing/other/concurrentqueue.h>
#include <ghoul/misc/assert.h>
// Implementatin based on http://progsch.net/wordpress/?p=81
namespace openspace {
class ThreadPool;
class Worker {
public:
Worker(ThreadPool& pool);
void operator()();
private:
ThreadPool& pool;
};
class ThreadPool {
public:
ThreadPool(size_t numThreads);
~ThreadPool();
void enqueue(std::function<void()> f);
private:
friend class Worker;
std::vector<std::thread> workers;
std::deque<std::function<void()>> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
} // namespace openspace
#endif // __THREAD_POOL_H__

View File

@@ -48,9 +48,12 @@ namespace openspace {
TileProvider::TileProvider(
const std::string& filePath,
int tileCacheSize,
int minimumPixelSize)
int minimumPixelSize,
int framesUntilRequestFlush)
: _filePath(filePath)
, _tileCache(tileCacheSize) // setting cache size
, _framesSinceLastRequestFlush(0)
, _framesUntilRequestFlush(framesUntilRequestFlush)
{
// Set a temporary texture
std::string fileName = "textures/earth_bluemarble.jpg";
@@ -101,11 +104,20 @@ namespace openspace {
}
TileProvider::~TileProvider(){
clearRequestQueue();
delete _gdalDataSet;
}
void TileProvider::prerender() {
initTexturesFromLoadedData();
if (_framesSinceLastRequestFlush++ > _framesUntilRequestFlush) {
clearRequestQueue();
}
}
void TileProvider::initTexturesFromLoadedData() {
while (_tileLoadManager.numFinishedJobs() > 0) {
auto finishedJob = _tileLoadManager.popFinishedJob();
std::shared_ptr<UninitializedTextureTile> uninitedTex =
@@ -116,87 +128,93 @@ namespace openspace {
}
}
void TileProvider::clearRequestQueue() {
_tileLoadManager.clearEnqueuedJobs();
_queuedTileRequests.clear();
_framesSinceLastRequestFlush = 0;
}
Tile TileProvider::getMostHiResTile(ChunkIndex chunkIndex) {
std::shared_ptr<Texture> tex = nullptr;
glm::vec2 uvOffset(0, 0);
glm::vec2 uvScale(1, 1);
// Check if we are trying to get a texture for a very small patch.
// In that case, use the biggest one defined for the dataset.
int maximumAllowedLevel =
_gdalDataSet->GetRasterBand(1)->GetOverviewCount() - 1;
int levelInDataset = chunkIndex.level + _tileLevelDifference;
int timesToStepUp = levelInDataset - maximumAllowedLevel;
for (int i = 0; i < timesToStepUp; i++)
{
uvScale *= 0.5;
uvOffset *= 0.5;
if (chunkIndex.isEastChild()) {
uvOffset.x += 0.5;
}
// In OpenGL, positive y direction is up
if (chunkIndex.isNorthChild()) {
uvOffset.y += 0.5;
}
Tile TileProvider::getHighestResolutionTile(ChunkIndex chunkIndex) {
TileUvTransform uvTransform;
uvTransform.uvOffset = glm::vec2(0, 0);
uvTransform.uvScale = glm::vec2(1, 1);
int numOverviews = _gdalDataSet->GetRasterBand(1)->GetOverviewCount();
int maximumLevel = numOverviews - 1 - _tileLevelDifference;
while(chunkIndex.level > maximumLevel){
transformFromParent(chunkIndex, uvTransform);
chunkIndex = chunkIndex.parent();
}
// We also need to check if the wanted texture is available. If not, go up a level
while (true) {
tex = getOrStartFetchingTile(chunkIndex);
if (tex != nullptr) {
break;
}
if (chunkIndex.level <= 1) {
tex = getDefaultTexture();
break;
}
// If we have a parent, calculate the UV offset and scale from the chunkIndex
else {
uvScale *= 0.5;
uvOffset *= 0.5;
if (chunkIndex.isEastChild()) {
uvOffset.x += 0.5;
}
// In OpenGL, positive y direction is up
if (chunkIndex.isNorthChild()) {
uvOffset.y += 0.5;
}
chunkIndex = chunkIndex.parent();
}
}
return{ tex, {uvOffset, uvScale } };
return getOrEnqueueHighestResolutionTile(chunkIndex, uvTransform);
}
Tile TileProvider::getOrEnqueueHighestResolutionTile(const ChunkIndex& chunkIndex,
TileUvTransform& uvTransform)
{
HashKey key = chunkIndex.hashKey();
if (_tileCache.exist(key)) {
return { _tileCache.get(key), uvTransform };
}
else if (chunkIndex.level <= 1) {
return { getDefaultTexture(), uvTransform };
}
else {
// We don't have the tile for the requested level
// --> check if the parent has a tile we can use
transformFromParent(chunkIndex, uvTransform);
Tile tile = getOrEnqueueHighestResolutionTile(chunkIndex.parent(), uvTransform);
// As we didn't have this tile, push it to the request queue
// post order enqueueing tiles --> enqueue tiles at low levels first
enqueueTileRequest(chunkIndex);
return tile;
}
}
void TileProvider::transformFromParent(const ChunkIndex& chunkIndex, TileUvTransform& uv) const {
uv.uvOffset *= 0.5;
uv.uvScale *= 0.5;
if (chunkIndex.isEastChild()) {
uv.uvOffset.x += 0.5;
}
// In OpenGL, positive y direction is up
if (chunkIndex.isNorthChild()) {
uv.uvOffset.y += 0.5;
}
}
std::shared_ptr<Texture> TileProvider::getOrStartFetchingTile(ChunkIndex chunkIndex) {
HashKey hashkey = chunkIndex.hashKey();
if (_tileCache.exist(hashkey)) {
return _tileCache.get(hashkey);
}
else {
enqueueTileRequest(chunkIndex);
return nullptr;
}
}
bool TileProvider::enqueueTileRequest(const ChunkIndex& chunkIndex) {
HashKey key = chunkIndex.hashKey();
bool tileHasBeenQueued = _queuedTileRequests.find(key) != _queuedTileRequests.end();
if (!tileHasBeenQueued) {
// enque load job
std::shared_ptr<TextureTileLoadJob> job = std::shared_ptr<TextureTileLoadJob>(
new TextureTileLoadJob(this, chunkIndex));
_tileLoadManager.enqueueJob(job);
// map key to nullptr while tile is loaded
_tileCache.put(hashkey, nullptr);
return nullptr;
_queuedTileRequests.insert(key);
}
return !tileHasBeenQueued;
}

View File

@@ -28,6 +28,7 @@
#include "gdal_priv.h"
#include <openspace/engine/downloadmanager.h>
#include <set>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h> // absPath
@@ -69,10 +70,11 @@ namespace openspace {
*/
class TileProvider {
public:
TileProvider(const std::string& fileName, int tileCacheSize, int minimumPixelSize);
TileProvider(const std::string& fileName, int tileCacheSize, int minimumPixelSize,
int framesUntilRequestFlush);
~TileProvider();
Tile getMostHiResTile(ChunkIndex chunkIndex);
Tile getHighestResolutionTile(ChunkIndex chunkIndex);
std::shared_ptr<Texture> getOrStartFetchingTile(ChunkIndex chunkIndex);
std::shared_ptr<Texture> getDefaultTexture();
@@ -84,6 +86,16 @@ namespace openspace {
friend class TextureTileLoadJob;
//////////////////////////////////////////////////////////////////////////////////
// Helper functions //
//////////////////////////////////////////////////////////////////////////////////
Tile getOrEnqueueHighestResolutionTile(const ChunkIndex& ci, TileUvTransform& uvTransform);
void transformFromParent(const ChunkIndex& ci, TileUvTransform& uv) const;
/**
Fetches all the needeed texture data from the GDAL dataset.
*/
@@ -96,9 +108,27 @@ namespace openspace {
std::shared_ptr<Texture> initializeTexture(
std::shared_ptr<UninitializedTextureTile> uninitedTexture);
LRUCache<HashKey, std::shared_ptr<Texture>> _tileCache;
bool enqueueTileRequest(const ChunkIndex& ci);
const std::string _filePath;
void clearRequestQueue();
void initTexturesFromLoadedData();
//////////////////////////////////////////////////////////////////////////////////
// Member variables //
//////////////////////////////////////////////////////////////////////////////////
LRUCache<HashKey, std::shared_ptr<Texture>> _tileCache;
std::set<HashKey> _queuedTileRequests;
int _framesSinceLastRequestFlush;
int _framesUntilRequestFlush;
const std::string _filePath;
static bool hasInitializedGDAL;
GDALDataset* _gdalDataSet;

View File

@@ -24,7 +24,6 @@
#include <modules/globebrowsing/rendering/culling.h>
#include <modules/globebrowsing/rendering/aabb.h>
#include <modules/globebrowsing/geodetics/ellipsoid.h>
@@ -48,6 +47,9 @@ namespace openspace {
}
const AABB3 FrustumCuller::viewFrustum(vec3(-1, -1, 0), vec3(1, 1, 1e35));
bool FrustumCuller::isVisible(
const RenderData& data,
const vec3& point) {
@@ -143,8 +145,8 @@ namespace openspace {
bounds.expand(cornerScreenSpace);
}
AABB3 viewFrustum(vec3(-1, -1, 0), vec3(1, 1, 1e35));
return bounds.intersects(viewFrustum);
return bounds.intersects(FrustumCuller::viewFrustum);
/*
vec2 center = bounds.center();

View File

@@ -34,6 +34,8 @@
#include <modules/globebrowsing/geodetics/geodetic2.h>
#include <modules/globebrowsing/geodetics/ellipsoid.h>
#include <modules/globebrowsing/rendering/aabb.h>
namespace openspace {
@@ -52,12 +54,11 @@ namespace openspace {
class FrustumCuller {
public:
FrustumCuller();
~FrustumCuller();
static const AABB3 viewFrustum;
/**
Returns true if the point is inside the view frustrum defined in RenderData.
The third argument marginScreenSpace is added to the default screen space

View File

@@ -176,7 +176,7 @@ namespace openspace {
texUnitHeight.push_back(ghoul::opengl::TextureUnit());
auto tileProvider = it->second;
// Get the texture that should be used for rendering
Tile tile = tileProvider->getMostHiResTile(chunk.index());
Tile tile = tileProvider->getHighestResolutionTile(chunk.index());
TileDepthTransform depthTransform = tileProvider->depthTransform();
// The texture needs a unit to sample from
@@ -211,7 +211,7 @@ namespace openspace {
{
auto tileProvider = it->second;
// Get the texture that should be used for rendering
Tile tile = tileProvider->getMostHiResTile(chunk.index());
Tile tile = tileProvider->getHighestResolutionTile(chunk.index());
// The texture needs a unit to sample from
texUnitColor[i].activate();
@@ -276,7 +276,7 @@ namespace openspace {
//auto tileProviderHeight = heightMapProviders.begin()->second;
// Get the textures that should be used for rendering
Tile heightTile = tileProviderHeight->getMostHiResTile(chunk.index());
Tile heightTile = tileProviderHeight->getHighestResolutionTile(chunk.index());
// Bind and use the texture
@@ -296,7 +296,7 @@ namespace openspace {
// Pick the first color texture
auto colorTextureProviders = _tileProviderManager->colorTextureProviders();
auto tileProviderColor = colorTextureProviders.begin()->second;
Tile colorTile = tileProviderColor->getMostHiResTile(chunk.index());
Tile colorTile = tileProviderColor->getHighestResolutionTile(chunk.index());
// Bind and use the texture
@@ -375,7 +375,7 @@ namespace openspace {
auto tileProvider = it->second;
// Get the texture that should be used for rendering
Tile tile = tileProvider->getMostHiResTile(chunk.index());
Tile tile = tileProvider->getHighestResolutionTile(chunk.index());
TileDepthTransform depthTransform = tileProvider->depthTransform();
// The texture needs a unit to sample from
@@ -410,7 +410,7 @@ namespace openspace {
auto tileProvider = it->second;
// Get the texture that should be used for rendering
Tile tile = tileProvider->getMostHiResTile(chunk.index());
Tile tile = tileProvider->getHighestResolutionTile(chunk.index());
// The texture needs a unit to sample from
texUnitColor[i].activate();
@@ -514,7 +514,7 @@ namespace openspace {
auto tileProviderHeight = heightMapProviders.begin()->second;
// Get the textures that should be used for rendering
Tile heightTile = tileProviderHeight->getMostHiResTile(chunk.index());
Tile heightTile = tileProviderHeight->getHighestResolutionTile(chunk.index());
// Bind and use the texture
ghoul::opengl::TextureUnit texUnitHeight;
@@ -531,7 +531,7 @@ namespace openspace {
// Pick the first color texture
auto colorTextureProviders = _tileProviderManager->colorTextureProviders();
auto tileProviderColor = colorTextureProviders.begin()->second;
Tile colorTile = tileProviderColor->getMostHiResTile(chunk.index());
Tile colorTile = tileProviderColor->getHighestResolutionTile(chunk.index());
// Bind and use the texture

View File

@@ -33,15 +33,16 @@
//#include <test_common.inl>
//#include <test_spicemanager.inl>
//#include <test_scenegraphloader.inl>
#include <test_chunknode.inl>
#include <test_lrucache.inl>
//#include <test_chunknode.inl>
//#include <test_lrucache.inl>
#include <test_threadpool.inl>
//#include <test_luaconversions.inl>
//#include <test_powerscalecoordinates.inl>
#include <test_angle.inl>
//#include <test_angle.inl>
//#include <test_latlonpatch.inl>
//#include <test_gdalwms.inl>
#include <test_patchcoverageprovider.inl>
//#include <test_patchcoverageprovider.inl>
//#include <test_concurrentqueue.inl>
//#include <test_concurrentjobmanager.inl>

View File

@@ -25,7 +25,7 @@
#include "gtest/gtest.h"
#include <openspace/scene/scenegraphnode.h>
#include <modules/globebrowsing/globes/chunklodglobe.h>
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
#include <modules/globebrowsing/globes/chunknode.h>
#include <fstream>

View File

@@ -1,143 +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 "gtest/gtest.h"
#include <modules/globebrowsing/other/texturetileset.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <glm/glm.hpp>
class TextureTileSetTest : public testing::Test {};
using namespace openspace;
TEST_F(TextureTileSetTest, getTileIndexLevel) {
// Create a tile set with maximum depth 0
TextureTileSet tileSet(Geodetic2(M_PI, M_PI * 2), Geodetic2(M_PI / 2, - M_PI), 0);
GeodeticPatch patch(Geodetic2(0, 0), Geodetic2(M_PI / 16, M_PI / 8));
GeodeticTileIndex tileIndex0 = tileSet.getTileIndex(patch);
// Maximum level is 0
ASSERT_EQ(tileIndex0.level, 0);
// Create a tile set with maximum depth 10
TextureTileSet tileSetDepth10(Geodetic2(M_PI, M_PI * 2), Geodetic2(M_PI / 2, - M_PI), 10);
// A big tile that covers the whole latlon space
GeodeticPatch patchBig(Geodetic2(0, 0), Geodetic2(M_PI / 2, M_PI));
tileIndex0 = tileSetDepth10.getTileIndex(patchBig);
// Should return 0 since the tile covers the whole latlon space
ASSERT_EQ(tileIndex0.level, 0);
// An edge case tile that covers a fourth of the latlon space
GeodeticPatch patchEdgeCase(Geodetic2(0, 0), Geodetic2(M_PI / 4, M_PI / 2));
GeodeticTileIndex tileIndex1 = tileSetDepth10.getTileIndex(patchEdgeCase);
// Now it can go up a level
ASSERT_EQ(tileIndex1.level, 1);
// Bigger than the edge case
GeodeticPatch patchEdgeCaseBigger(Geodetic2(0, 0), Geodetic2(M_PI / 4 + 0.001, M_PI / 2 + 0.001));
tileIndex0 = tileSetDepth10.getTileIndex(patchEdgeCaseBigger);
// Should return 0 again
ASSERT_EQ(tileIndex0.level, 0);
}
TEST_F(TextureTileSetTest, getTileIndexXY) {
// Create a tile set with maximum depth 0
TextureTileSet tileSet(Geodetic2(M_PI, M_PI * 2), Geodetic2(M_PI / 2, - M_PI), 0);
GeodeticPatch patch(Geodetic2(0, 0), Geodetic2(M_PI / 16, M_PI / 8));
GeodeticTileIndex tileIndex0 = tileSet.getTileIndex(patch);
// Maximum level is 0 so the x y indices should also be 0
ASSERT_EQ(tileIndex0.x, 0);
ASSERT_EQ(tileIndex0.y, 0);
// Create a tile set with maximum depth 10
TextureTileSet tileSetDepth10(Geodetic2(M_PI, M_PI * 2), Geodetic2(M_PI / 2, - M_PI), 10);
// A big tile that covers the whole latlon space
GeodeticPatch patchBig(Geodetic2(0, 0), Geodetic2(M_PI / 2, M_PI));
tileIndex0 = tileSetDepth10.getTileIndex(patchBig);
// Should return 0 in x and y since the tile covers the whole latlon space
ASSERT_EQ(tileIndex0.x, 0);
ASSERT_EQ(tileIndex0.y, 0);
// A tile that covers a fourth of the latlon space
GeodeticPatch patchEdgeCase(Geodetic2(0, 0), Geodetic2(M_PI / 4, M_PI / 2));
GeodeticTileIndex tileIndex1 = tileSetDepth10.getTileIndex(patchEdgeCase);
// Now it can go up a level (1)
// Since the position is 0, 0 it has 0, 0, in x, y index
ASSERT_EQ(tileIndex1.x, 0);
ASSERT_EQ(tileIndex1.y, 0);
// A smaller edge case tile
GeodeticPatch patchEdgeCase2(Geodetic2(0, 0), Geodetic2(M_PI / 8, M_PI / 4));
GeodeticTileIndex tileIndex11 = tileSetDepth10.getTileIndex(patchEdgeCase2);
// Now it can go up two levels (2)
// Since the position is 0, 0 it now has 1, 1, in x, y index
// (north west corner is in that tile)
ASSERT_EQ(tileIndex11.x, 1);
ASSERT_EQ(tileIndex11.y, 1);
}
TEST_F(TextureTileSetTest, getUvTransformationPatchToTile) {
// Create a tile set with maximum depth 0
TextureTileSet tileSet(Geodetic2(M_PI, M_PI * 2), Geodetic2(M_PI / 2, -M_PI), 0);
// Create a patch that covers the whole latlon space
GeodeticPatch patch(Geodetic2(0, 0), Geodetic2(M_PI / 2, M_PI));
// Should be a 1:1 mapping
glm::mat3 patchToTileTransform =
tileSet.getUvTransformationPatchToTile(patch, { 0, 0, 0 });
ASSERT_EQ(patchToTileTransform, glm::mat3(1));
// Create a smaller patch in the upper west side
patch = GeodeticPatch(Geodetic2(M_PI / 4, - M_PI / 2), Geodetic2(M_PI / 4, M_PI / 2));
patchToTileTransform =
tileSet.getUvTransformationPatchToTile(patch, { 0,0,0 });
glm::vec2 uvPatchSpace = glm::vec2(0, 0);
glm::vec2 uvTileSpace = glm::vec2(patchToTileTransform * glm::vec3(uvPatchSpace, 1));
}

View File

@@ -24,28 +24,36 @@
#include "gtest/gtest.h"
#include <modules/globebrowsing/other/twmstileprovider.h>
#include <thread>
#include <modules/globebrowsing/other/threadpool.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <glm/glm.hpp>
class TWMSTileProviderTest : public testing::Test {};
class ThreadPoolTest : public testing::Test {};
using namespace openspace;
using namespace std::chrono_literals;
TEST_F(TWMSTileProviderTest, Simple) {
TileProvider* tileProvider = new TileProvider();
GeodeticTileIndex tileIndex = { 0, 0, 0 };
tileProvider->getTile(tileIndex);
TEST_F(ThreadPoolTest, Basic) {
ThreadPool pool(5);
using namespace std::chrono_literals;
std::this_thread::sleep_for(2s);
int val = 0;
for (int i = 0; i < 10; ++i) {
pool.enqueue([&val, i]() {
std::this_thread::sleep_for(std::chrono::milliseconds(100 + 10*i));
val++;
});
}
std::cout << "exiting" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
EXPECT_EQ(10, val) << "10 tasks taking 100 to 190 ms on 5 threads should take less than 1000 ms";
}