mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-03-09 23:08:49 -05:00
Merge branch 'feature/globebrowsing' of github.com:OpenSpace/OpenSpace-Development into feature/globebrowsing
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ using HashKey = unsigned long;
|
||||
|
||||
|
||||
struct ChunkIndex {
|
||||
|
||||
|
||||
|
||||
int x, y, level;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
120
modules/globebrowsing/other/threadpool.cpp
Normal file
120
modules/globebrowsing/other/threadpool.cpp
Normal 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
|
||||
81
modules/globebrowsing/other/threadpool.h
Normal file
81
modules/globebrowsing/other/threadpool.h
Normal 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__
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
Reference in New Issue
Block a user