Commented code to test tile loading with concurrent job manager. Texture Loader does not allow multithreading

This commit is contained in:
Erik Broberg
2016-04-28 12:42:58 -04:00
parent 4c133cdcce
commit 582c1044af
12 changed files with 788 additions and 633 deletions
+110 -105
View File
@@ -28,135 +28,140 @@
#include <math.h>
namespace {
const std::string _loggerCat = "Ellipsoid";
const std::string _loggerCat = "Ellipsoid";
}
namespace openspace {
Ellipsoid::Ellipsoid(Vec3 radii)
: _radii(radii)
, _cachedValues({
Vec3( // _radiiSquared
(_radii.x * _radii.x),
(_radii.y * _radii.y),
(_radii.z * _radii.z)),
Vec3( // _oneOverRadiiSquared
1.0 / (_radii.x * _radii.x),
1.0 / (_radii.y * _radii.y),
1.0 / (_radii.z * _radii.z)),
Vec3( // _radiiToTheFourth
_radii.x * _radii.x * _radii.x * _radii.x,
_radii.y * _radii.y * _radii.y * _radii.y,
_radii.z * _radii.z * _radii.z * _radii.z),
glm::min(_radii.x, glm::min(_radii.y, _radii.z))})
{
const Ellipsoid Ellipsoid::UnitSphere = Ellipsoid(1, 1, 1);
}
const Ellipsoid Ellipsoid::WGS84 = Ellipsoid(6378137.0, 6378137.0, 6356752.314245);
Ellipsoid::Ellipsoid(Scalar x, Scalar y, Scalar z)
: Ellipsoid(Vec3(x, y, z))
{
}
Ellipsoid::Ellipsoid(Vec3 radii)
: _radii(radii)
, _cachedValues({
Vec3( // _radiiSquared
(_radii.x * _radii.x),
(_radii.y * _radii.y),
(_radii.z * _radii.z)),
Vec3( // _oneOverRadiiSquared
1.0 / (_radii.x * _radii.x),
1.0 / (_radii.y * _radii.y),
1.0 / (_radii.z * _radii.z)),
Vec3( // _radiiToTheFourth
_radii.x * _radii.x * _radii.x * _radii.x,
_radii.y * _radii.y * _radii.y * _radii.y,
_radii.z * _radii.z * _radii.z * _radii.z),
glm::min(_radii.x, glm::min(_radii.y, _radii.z))})
{
Ellipsoid::~Ellipsoid()
{
}
}
Ellipsoid::Ellipsoid(Scalar x, Scalar y, Scalar z)
: Ellipsoid(Vec3(x, y, z))
{
Vec3 Ellipsoid::scaleToGeocentricSurface(const Vec3& p) const
{
Scalar beta = 1.0 / sqrt(dot(p * p, _cachedValues._oneOverRadiiSquared));
return beta * p;
}
}
Vec3 Ellipsoid::scaleToGeodeticSurface(const Vec3& p) const
{
Scalar beta = 1.0 / sqrt(dot(p * p, _cachedValues._oneOverRadiiSquared));
Scalar n = glm::length(beta * p * _cachedValues._oneOverRadiiSquared);
Scalar alpha = (1.0 - beta) * (glm::length(p) / n);
Vec3 p2 = p * p;
Vec3 d, d2, d3;
Ellipsoid::~Ellipsoid()
{
Scalar s = 0.0;
Scalar dSdA = 1.0;
}
Scalar epsilon = 1e-10;
do {
alpha -= (s / dSdA);
Vec3 Ellipsoid::scaleToGeocentricSurface(const Vec3& p) const
{
Scalar beta = 1.0 / sqrt(dot(p * p, _cachedValues._oneOverRadiiSquared));
return beta * p;
}
d = Vec3(1.0) + alpha * _cachedValues._oneOverRadiiSquared;
d2 = d * d;
d3 = d * d2;
s = glm::dot(p2 / (_cachedValues._radiiSquared * d2), Vec3(1.0)) - 1.0;
Vec3 Ellipsoid::scaleToGeodeticSurface(const Vec3& p) const
{
Scalar beta = 1.0 / sqrt(dot(p * p, _cachedValues._oneOverRadiiSquared));
Scalar n = glm::length(beta * p * _cachedValues._oneOverRadiiSquared);
Scalar alpha = (1.0 - beta) * (glm::length(p) / n);
Vec3 p2 = p * p;
Vec3 d, d2, d3;
dSdA = -2.0 * glm::dot(p2 / (_cachedValues._radiiToTheFourth * d3), Vec3(1.0));
}
while (abs(s) > epsilon);
return p / d;
}
Scalar s = 0.0;
Scalar dSdA = 1.0;
Vec3 Ellipsoid::geodeticSurfaceNormal(const Vec3& p) const
{
Vec3 normal = p * _cachedValues._oneOverRadiiSquared;
return glm::normalize(normal);
}
Scalar epsilon = 1e-10;
do {
alpha -= (s / dSdA);
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));
}
d = Vec3(1.0) + alpha * _cachedValues._oneOverRadiiSquared;
d2 = d * d;
d3 = d * d2;
s = glm::dot(p2 / (_cachedValues._radiiSquared * d2), Vec3(1.0)) - 1.0;
// TODO: IMPLEMENT THESE FUNCTIONS AND SEND RADIISQUARED TO THE SHADER PROGRAM
dSdA = -2.0 * glm::dot(p2 / (_cachedValues._radiiToTheFourth * d3), Vec3(1.0));
}
while (abs(s) > epsilon);
return p / d;
}
Vec3 Ellipsoid::radiiSquared() const
{
return _cachedValues._radiiSquared;
}
Vec3 Ellipsoid::geodeticSurfaceNormal(const Vec3& p) const
{
Vec3 normal = p * _cachedValues._oneOverRadiiSquared;
return glm::normalize(normal);
}
Vec3 Ellipsoid::oneOverRadiiSquared() const
{
return _cachedValues._oneOverRadiiSquared;
}
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));
}
Vec3 Ellipsoid::radiiToTheFourth() const
{
return _cachedValues._radiiToTheFourth;
}
// TODO: IMPLEMENT THESE FUNCTIONS AND SEND RADIISQUARED TO THE SHADER PROGRAM
Scalar Ellipsoid::minimumRadius() const
{
return _cachedValues._minimumRadius;
}
Vec3 Ellipsoid::radiiSquared() const
{
return _cachedValues._radiiSquared;
}
Geodetic2 Ellipsoid::cartesianToGeodetic2(const Vec3& p) const
{
Vec3 normal = geodeticSurfaceNormal(p);
return Geodetic2(
asin(normal.z / length(normal)), // Latitude
atan2(normal.y, normal.x)); // Longitude
}
Vec3 Ellipsoid::oneOverRadiiSquared() const
{
return _cachedValues._oneOverRadiiSquared;
}
Vec3 Ellipsoid::geodetic2ToCartesian(const Geodetic2& geodetic2) const
{
// Position on surface : height = 0
return geodetic3ToCartesian(Geodetic3({ geodetic2, 0 }));
}
Vec3 Ellipsoid::radiiToTheFourth() const
{
return _cachedValues._radiiToTheFourth;
}
Vec3 Ellipsoid::geodetic3ToCartesian(const Geodetic3& geodetic3) const
{
Vec3 normal = geodeticSurfaceNormal(geodetic3.geodetic2);
Vec3 k = _cachedValues._radiiSquared * normal;
Scalar gamma = sqrt(dot(k, normal));
Vec3 rSurface = k / gamma;
return rSurface + geodetic3.height * normal;
}
Scalar Ellipsoid::minimumRadius() const
{
return _cachedValues._minimumRadius;
}
Geodetic2 Ellipsoid::cartesianToGeodetic2(const Vec3& p) const
{
Vec3 normal = geodeticSurfaceNormal(p);
return Geodetic2(
asin(normal.z / length(normal)), // Latitude
atan2(normal.y, normal.x)); // Longitude
}
Vec3 Ellipsoid::geodetic2ToCartesian(const Geodetic2& geodetic2) const
{
// Position on surface : height = 0
return geodetic3ToCartesian(Geodetic3({ geodetic2, 0 }));
}
Vec3 Ellipsoid::geodetic3ToCartesian(const Geodetic3& geodetic3) const
{
Vec3 normal = geodeticSurfaceNormal(geodetic3.geodetic2);
Vec3 k = _cachedValues._radiiSquared * normal;
Scalar gamma = sqrt(dot(k, normal));
Vec3 rSurface = k / gamma;
return rSurface + geodetic3.height * normal;
}
} // namespace openspace
+66 -53
View File
@@ -29,67 +29,80 @@
namespace openspace {
/**
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
in 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.
*/
/**
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
in 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.
*/
class Ellipsoid {
public:
/**
\param radii defines three radii for the Ellipsoid
*/
Ellipsoid(Vec3 radii);
/**
\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 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 scaleToGeocentricSurface(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 scaleToGeodeticSurface(const Vec3& p) const;
/**
World Geodetic System 1984 coordinate system
*/
static const Ellipsoid WGS84;
Vec3 geodeticSurfaceNormal(const Vec3& p) const;
Vec3 geodeticSurfaceNormal(Geodetic2 geodetic2) const;
Vec3 radiiSquared() const;
Vec3 oneOverRadiiSquared() const;
Vec3 radiiToTheFourth() const;
Scalar minimumRadius() const;
static const Ellipsoid UnitSphere;
Geodetic2 cartesianToGeodetic2(const Vec3& p) const;
Vec3 geodetic2ToCartesian(const Geodetic2& geodetic2) const;
Vec3 geodetic3ToCartesian(const Geodetic3& geodetic3) const;
/**
\param radii defines three radii for the Ellipsoid
*/
Ellipsoid(Vec3 radii);
/**
\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 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 scaleToGeocentricSurface(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 scaleToGeodeticSurface(const Vec3& p) const;
Vec3 geodeticSurfaceNormal(const Vec3& p) const;
Vec3 geodeticSurfaceNormal(Geodetic2 geodetic2) const;
Vec3 radiiSquared() const;
Vec3 oneOverRadiiSquared() const;
Vec3 radiiToTheFourth() const;
Scalar minimumRadius() const;
Geodetic2 cartesianToGeodetic2(const Vec3& p) const;
Vec3 geodetic2ToCartesian(const Geodetic2& geodetic2) const;
Vec3 geodetic3ToCartesian(const Geodetic3& geodetic3) const;
private:
struct EllipsoidCache
{
const Vec3 _radiiSquared;
const Vec3 _oneOverRadiiSquared;
const Vec3 _radiiToTheFourth;
const Scalar _minimumRadius;
};
struct EllipsoidCache
{
const Vec3 _radiiSquared;
const Vec3 _oneOverRadiiSquared;
const Vec3 _radiiToTheFourth;
const Scalar _minimumRadius;
};
const Vec3 _radii;
const EllipsoidCache _cachedValues;
const Vec3 _radii;
const EllipsoidCache _cachedValues;
};
} // namespace openspace
+85 -81
View File
@@ -39,120 +39,124 @@
#include <math.h>
namespace {
const std::string _loggerCat = "ChunkLodGlobe";
const std::string _loggerCat = "ChunkLodGlobe";
const std::string keyFrame = "Frame";
const std::string keyGeometry = "Geometry";
const std::string keyShading = "PerformShading";
const std::string keyFrame = "Frame";
const std::string keyGeometry = "Geometry";
const std::string keyShading = "PerformShading";
const std::string keyBody = "Body";
const std::string keyBody = "Body";
}
namespace openspace {
const GeodeticPatch ChunkLodGlobe::LEFT_HEMISPHERE = GeodeticPatch(0, -M_PI/2, M_PI/2, M_PI/2);
const GeodeticPatch ChunkLodGlobe::RIGHT_HEMISPHERE = GeodeticPatch(0, M_PI/2, M_PI/2, M_PI/2);
const GeodeticPatch ChunkLodGlobe::LEFT_HEMISPHERE = GeodeticPatch(0, -M_PI/2, M_PI/2, M_PI/2);
const GeodeticPatch ChunkLodGlobe::RIGHT_HEMISPHERE = GeodeticPatch(0, M_PI/2, M_PI/2, M_PI/2);
ChunkLodGlobe::ChunkLodGlobe(
const ghoul::Dictionary& dictionary,
const Ellipsoid& ellipsoid)
: _ellipsoid(ellipsoid)
, _leftRoot(new ChunkNode(*this, LEFT_HEMISPHERE))
, _rightRoot(new ChunkNode(*this, RIGHT_HEMISPHERE))
, minSplitDepth(2)
, maxSplitDepth(22)
, _rotation("rotation", "Rotation", 0, 0, 360)
{
std::string name;
bool success = dictionary.getValue(SceneGraphNode::KeyName, name);
//ghoul_assert(success, "ChunkLodGlobe need the '" << SceneGraphNode::KeyName << "' be specified");
setName(name);
ChunkLodGlobe::ChunkLodGlobe(
const ghoul::Dictionary& dictionary,
const Ellipsoid& ellipsoid)
: _ellipsoid(ellipsoid)
, _leftRoot(new ChunkNode(*this, LEFT_HEMISPHERE))
, _rightRoot(new ChunkNode(*this, RIGHT_HEMISPHERE))
, minSplitDepth(2)
, maxSplitDepth(22)
, _rotation("rotation", "Rotation", 0, 0, 360)
{
std::string name;
bool success = dictionary.getValue(SceneGraphNode::KeyName, name);
//ghoul_assert(success, "ChunkLodGlobe need the '" << SceneGraphNode::KeyName << "' be specified");
setName(name);
dictionary.getValue(keyFrame, _frame);
dictionary.getValue(keyBody, _target);
if (_target != "")
setBody(_target);
dictionary.getValue(keyFrame, _frame);
dictionary.getValue(keyBody, _target);
if (_target != "")
setBody(_target);
// Mainly for debugging purposes @AA
addProperty(_rotation);
// Mainly for debugging purposes @AA
addProperty(_rotation);
//globeRadius = dictionary.value<double>("Radius");
//globeRadius = dictionary.value<double>("Radius");
// ---------
// init Renderer
auto geometry = std::shared_ptr<BasicGrid>(new BasicGrid(
10,
10,
TriangleSoup::Positions::No,
TriangleSoup::TextureCoordinates::Yes,
TriangleSoup::Normals::No));
// ---------
// init Renderer
auto geometry = std::shared_ptr<BasicGrid>(new BasicGrid(
10,
10,
TriangleSoup::Positions::No,
TriangleSoup::TextureCoordinates::Yes,
TriangleSoup::Normals::No));
_patchRenderer.reset(new LatLonPatchRenderer(geometry));
_patchRenderer.reset(new LatLonPatchRenderer(geometry));
_frustumCuller = std::shared_ptr<FrustumCuller>(new FrustumCuller());
_frustumCuller = std::shared_ptr<FrustumCuller>(new FrustumCuller());
}
}
ChunkLodGlobe::~ChunkLodGlobe() {
ChunkLodGlobe::~ChunkLodGlobe() {
}
}
bool ChunkLodGlobe::initialize() {
return isReady();
}
bool ChunkLodGlobe::initialize() {
return isReady();
}
bool ChunkLodGlobe::deinitialize() {
return true;
}
bool ChunkLodGlobe::deinitialize() {
return true;
}
bool ChunkLodGlobe::isReady() const {
bool ready = true;
return ready;
}
bool ChunkLodGlobe::isReady() const {
bool ready = true;
return ready;
}
LatLonPatchRenderer& ChunkLodGlobe::getPatchRenderer() {
return *_patchRenderer;
}
LatLonPatchRenderer& ChunkLodGlobe::getPatchRenderer() {
return *_patchRenderer;
}
FrustumCuller& ChunkLodGlobe::getFrustumCuller() {
return *_frustumCuller;
}
FrustumCuller& ChunkLodGlobe::getFrustumCuller() {
return *_frustumCuller;
}
void ChunkLodGlobe::render(const RenderData& data){
minDistToCamera = INFINITY;
ChunkNode::renderedPatches = 0;
void ChunkLodGlobe::render(const RenderData& data){
minDistToCamera = INFINITY;
ChunkNode::renderedPatches = 0;
ChunkIndex leftRootTileIndex = { 0, 0, 1 };
_leftRoot->render(data, leftRootTileIndex);
ChunkIndex rightRootTileIndex = { 1, 0, 1 };
_rightRoot->render(data, rightRootTileIndex);
ChunkIndex leftRootTileIndex = { 0, 0, 1 };
_leftRoot->render(data, leftRootTileIndex);
//LDEBUG("min distnace to camera: " << minDistToCamera);
ChunkIndex rightRootTileIndex = { 1, 0, 1 };
_rightRoot->render(data, rightRootTileIndex);
Vec3 cameraPos = data.camera.position().dvec3();
//LDEBUG("cam pos x: " << cameraPos.x << " y: " << cameraPos.y << " z: " << cameraPos.z);
//LDEBUG("min distnace to camera: " << minDistToCamera);
//LDEBUG("ChunkNode count: " << ChunkNode::instanceCount);
//LDEBUG("RenderedPatches count: " << ChunkNode::renderedPatches);
}
Vec3 cameraPos = data.camera.position().dvec3();
//LDEBUG("cam pos x: " << cameraPos.x << " y: " << cameraPos.y << " z: " << cameraPos.z);
void ChunkLodGlobe::update(const UpdateData& data) {
// set spice-orientation in accordance to timestamp
_stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time);
_time = data.time;
}
//LDEBUG("ChunkNode count: " << ChunkNode::instanceCount);
//LDEBUG("RenderedPatches count: " << ChunkNode::renderedPatches);
}
const Ellipsoid& ChunkLodGlobe::ellipsoid() const
{
return _ellipsoid;
}
void ChunkLodGlobe::update(const UpdateData& data) {
// set spice-orientation in accordance to timestamp
_stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time);
_time = data.time;
_patchRenderer->update();
}
const Ellipsoid& ChunkLodGlobe::ellipsoid() const
{
return _ellipsoid;
}
} // namespace openspace
+26 -26
View File
@@ -137,13 +137,13 @@ void ChunkNode::internalRender(const RenderData& data, ChunkIndex& traverseData)
}
int ChunkNode::calculateDesiredLevelAndUpdateIsVisible(
const RenderData& data,
const ChunkIndex& traverseData) {
const RenderData& data,
const ChunkIndex& traverseData) {
_isVisible = true;
Vec3 globePosition = data.position.dvec3();
Vec3 patchPosition =
globePosition +
_owner.ellipsoid().geodetic2ToCartesian(_patch.center());
Vec3 patchPosition =
globePosition +
_owner.ellipsoid().geodetic2ToCartesian(_patch.center());
Vec3 cameraPosition = data.camera.position().dvec3();
Vec3 cameraDirection = Vec3(data.camera.viewDirection());
@@ -156,23 +156,23 @@ int ChunkNode::calculateDesiredLevelAndUpdateIsVisible(
Vec3 globeToCamera = cameraPosition - globePosition;
Geodetic2 cameraPositionOnGlobe =
_owner.ellipsoid().cartesianToGeodetic2(globeToCamera);
Geodetic2 closestPatchPoint = _patch.closestPoint(cameraPositionOnGlobe);
Geodetic2 cameraPositionOnGlobe =
_owner.ellipsoid().cartesianToGeodetic2(globeToCamera);
Geodetic2 closestPatchPoint = _patch.closestPoint(cameraPositionOnGlobe);
Vec3 normalOfClosestPatchPoint =
_owner.ellipsoid().geodeticSurfaceNormal(closestPatchPoint);
Scalar cosPatchNormalNormalizedGlobeToCamera =
glm::dot(normalOfClosestPatchPoint, glm::normalize(globeToCamera));
Vec3 normalOfClosestPatchPoint =
_owner.ellipsoid().geodeticSurfaceNormal(closestPatchPoint);
Scalar cosPatchNormalNormalizedGlobeToCamera =
glm::dot(normalOfClosestPatchPoint, glm::normalize(globeToCamera));
//LDEBUG(cosPatchNormalCameraDirection);
// Get the minimum radius from the ellipsoid. The closer the ellipsoid is to a
// sphere, the better this will make the splitting. Using the minimum radius to
// be safe. This means that if the ellipsoid has high difference between radii,
// splitting might accur even though it is not needed.
Scalar minimumGlobeRadius = _owner.ellipsoid().minimumRadius();
double cosAngleToHorizon = minimumGlobeRadius / glm::length(globeToCamera);
// Get the minimum radius from the ellipsoid. The closer the ellipsoid is to a
// sphere, the better this will make the splitting. Using the minimum radius to
// be safe. This means that if the ellipsoid has high difference between radii,
// splitting might accur even though it is not needed.
Scalar minimumGlobeRadius = _owner.ellipsoid().minimumRadius();
double cosAngleToHorizon = minimumGlobeRadius / glm::length(globeToCamera);
if (cosPatchNormalNormalizedGlobeToCamera < cosAngleToHorizon) {
_isVisible = false;
return traverseData.level - 1;
@@ -181,20 +181,20 @@ int ChunkNode::calculateDesiredLevelAndUpdateIsVisible(
// Do frustrum culling
FrustumCuller& culler = _owner.getFrustumCuller();
if (!culler.isVisible(data, _patch, _owner.ellipsoid())) {
_isVisible = false;
return traverseData.level - 1;
}
if (!culler.isVisible(data, _patch, _owner.ellipsoid())) {
_isVisible = false;
return traverseData.level - 1;
}
// Calculate desired level based on distance
Scalar distance = glm::length(cameraToChunk);
_owner.minDistToCamera = fmin(_owner.minDistToCamera, distance);
Scalar scaleFactor = 100 * minimumGlobeRadius;
Scalar projectedScaleFactor = scaleFactor / distance;
int desiredLevel = floor( log2(projectedScaleFactor) );
return desiredLevel;
Scalar scaleFactor = 100 * minimumGlobeRadius;
Scalar projectedScaleFactor = scaleFactor / distance;
int desiredLevel = floor( log2(projectedScaleFactor) );
return desiredLevel;
}
@@ -50,8 +50,8 @@ namespace openspace {
virtual ~Job() { }
virtual void execute() = 0;
virtual P product() = 0;
virtual std::shared_ptr<P> product() = 0;
};
+19 -18
View File
@@ -35,31 +35,32 @@
namespace openspace {
// Templated class implementing a Least-Recently-Used Cache
template<typename KeyType, typename ValueType>
class LRUCache {
public:
LRUCache(size_t size);
~LRUCache();
// Templated class implementing a Least-Recently-Used Cache
template<typename KeyType, typename ValueType>
class LRUCache {
public:
LRUCache(size_t size);
~LRUCache();
void put(const KeyType& key, const ValueType& value);
bool exist(const KeyType& key) const;
ValueType get(const KeyType& key);
void put(const KeyType& key, const ValueType& value);
bool exist(const KeyType& key) const;
ValueType get(const KeyType& key);
size_t size() const;
private:
void clean();
private:
void clean();
// Member varialbes
private:
std::list<std::pair<KeyType, ValueType>> _itemList;
std::unordered_map<KeyType, decltype(_itemList.begin())> _itemMap;
size_t _cacheSize;
// Member varialbes
private:
std::list<std::pair<KeyType, ValueType>> _itemList;
std::unordered_map<KeyType, decltype(_itemList.begin())> _itemMap;
size_t _cacheSize;
};
};
} // namespace openspace
+55 -49
View File
@@ -32,66 +32,72 @@
namespace openspace {
template<typename KeyType, typename ValueType>
LRUCache<KeyType, ValueType>::LRUCache(size_t size)
: _cacheSize(size) { }
template<typename KeyType, typename ValueType>
LRUCache<KeyType, ValueType>::LRUCache(size_t size)
: _cacheSize(size) { }
template<typename KeyType, typename ValueType>
LRUCache<KeyType, ValueType>::~LRUCache() {
// Clean up list and map!
}
template<typename KeyType, typename ValueType>
LRUCache<KeyType, ValueType>::~LRUCache() {
// Clean up list and map!
}
//////////////////////////////
// PUBLIC INTERFACE //
//////////////////////////////
//////////////////////////////
// PUBLIC INTERFACE //
//////////////////////////////
template<typename KeyType, typename ValueType>
void LRUCache<KeyType, ValueType>::put(const KeyType& key, const ValueType& value)
{
auto it = _itemMap.find(key);
if (it != _itemMap.end()) {
_itemList.erase(it->second);
_itemMap.erase(it);
}
_itemList.push_front(std::make_pair(key, value));
_itemMap.insert(std::make_pair(key, _itemList.begin()));
clean();
}
template<typename KeyType, typename ValueType>
void LRUCache<KeyType, ValueType>::put(const KeyType& key, const ValueType& value)
{
auto it = _itemMap.find(key);
if (it != _itemMap.end()) {
_itemList.erase(it->second);
_itemMap.erase(it);
}
_itemList.push_front(std::make_pair(key, value));
_itemMap.insert(std::make_pair(key, _itemList.begin()));
clean();
}
template<typename KeyType, typename ValueType>
bool LRUCache<KeyType, ValueType>::exist(const KeyType& key) const
{
return _itemMap.count(key) > 0;
}
template<typename KeyType, typename ValueType>
bool LRUCache<KeyType, ValueType>::exist(const KeyType& key) const
{
return _itemMap.count(key) > 0;
}
template<typename KeyType, typename ValueType>
ValueType LRUCache<KeyType, ValueType>::get(const KeyType& key)
{
ghoul_assert(exist(key), "Key " << key << " must exist");
auto it = _itemMap.find(key);
// Move list iterator pointing to value
_itemList.splice(_itemList.begin(), _itemList, it->second);
return it->second->second;
}
template<typename KeyType, typename ValueType>
ValueType LRUCache<KeyType, ValueType>::get(const KeyType& key)
{
ghoul_assert(exist(key), "Key " << key << " must exist");
auto it = _itemMap.find(key);
// Move list iterator pointing to value
_itemList.splice(_itemList.begin(), _itemList, it->second);
return it->second->second;
}
template<typename KeyType, typename ValueType>
size_t LRUCache<KeyType, ValueType>::size() const
{
return _itemMap.size();
}
//////////////////////////////
// PRIVATE HELPERS //
//////////////////////////////
template<typename KeyType, typename ValueType>
void LRUCache<KeyType, ValueType>::clean()
{
while (_itemMap.size() > _cacheSize) {
auto last_it = _itemList.end(); last_it--;
_itemMap.erase(last_it->first);
_itemList.pop_back();
}
}
//////////////////////////////
// PRIVATE HELPERS //
//////////////////////////////
template<typename KeyType, typename ValueType>
void LRUCache<KeyType, ValueType>::clean()
{
while (_itemMap.size() > _cacheSize) {
auto last_it = _itemList.end(); last_it--;
_itemMap.erase(last_it->first);
_itemList.pop_back();
}
}
} // namespace openspace
+126 -101
View File
@@ -37,124 +37,149 @@
namespace {
const std::string _loggerCat = "TwmsTileProvider";
const std::string _loggerCat = "TwmsTileProvider";
}
namespace openspace {
TwmsTileProvider::TwmsTileProvider()
: _tileCache(5000) // setting cache size
, _fileFutureCache(5000) // setting cache size
{
int downloadApplicationVersion = 1;
if (!DownloadManager::isInitialized()) {
DownloadManager::initialize("../tmp_openspace_downloads/", downloadApplicationVersion);
}
}
TwmsTileProvider::~TwmsTileProvider(){
TwmsTileProvider::TwmsTileProvider()
: _tileCache(5000) // setting cache size
//, _fileFutureCache(5000) // setting cache size
{
int downloadApplicationVersion = 1;
if (!DownloadManager::isInitialized()) {
DownloadManager::initialize("../tmp_openspace_downloads/", downloadApplicationVersion);
}
}
}
TwmsTileProvider::~TwmsTileProvider(){
}
std::shared_ptr<Texture> TwmsTileProvider::getTile(const TileIndex& tileIndex) {
HashKey hashkey = tileIndex.hashKey();
if (_tileCache.exist(hashkey)) {
return _tileCache.get(hashkey);
}
else if (_fileFutureCache.exist(hashkey)) {
if (_fileFutureCache.get(hashkey)->isFinished) {
std::string fileName = _fileFutureCache.get(hashkey)->filePath;
std::string filePath = "tiles/" + fileName;
std::shared_ptr<Texture> texture = loadAndInitTextureDisk(filePath);
//LDEBUG("Downloaded " << fileName);
_tileCache.put(hashkey, texture);
}
}
else {
std::shared_ptr<DownloadManager::FileFuture> fileFuture = requestTile(tileIndex);
_fileFutureCache.put(hashkey, fileFuture);
}
return nullptr;
}
void TwmsTileProvider::prerender() {
std::shared_ptr<Texture> TwmsTileProvider::loadAndInitTextureDisk(std::string filePath) {
auto textureReader = ghoul::io::TextureReader::ref();
std::shared_ptr<Texture> texture = std::move(textureReader.loadTexture(absPath(filePath)));
// Remove filefutures that are inactive
auto it = _fileFutureMap.begin();
auto end = _fileFutureMap.end();
for (; it != end;){
if (it->second->isAborted ||
it->second->secondsRemaining > 20 ||
it->second->errorMessage.compare("") != 0 ||
it->second->isFinished)
{
it = _fileFutureMap.erase(it);
//LDEBUG("removnig filefuture");
}
else {
it++;
}
}
// upload to gpu
texture->uploadTexture();
texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
return texture;
}
// Move finished texture tiles to cache
while (_concurrentJobManager.numFinishedJobs() > 0) {
auto finishedJob = _concurrentJobManager.popFinishedJob();
TextureLoadJob* finishedTextureLoadJob = reinterpret_cast<TextureLoadJob*>(finishedJob.get());
ghoul_assert(finishedTextureLoadJob != nullptr, "unable to reinterpret cast to TextureLoadJob*");
auto texture = finishedTextureLoadJob->product();
// upload to gpu
texture->uploadTexture();
texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
//LDEBUG("uploaded texture " << finishedTextureLoadJob->hashKey());
HashKey hashkey = finishedTextureLoadJob->hashKey();
_tileCache.put(hashkey, texture);
_fileFutureMap.erase(hashkey);
}
}
std::shared_ptr<Texture> TwmsTileProvider::getTile(const TileIndex& tileIndex) {
HashKey hashkey = tileIndex.hashKey();
if (_tileCache.exist(hashkey)) {
return _tileCache.get(hashkey);
}
else if (_fileFutureMap.find(hashkey) != _fileFutureMap.end()) {
if (_fileFutureMap.find(hashkey)->second->isFinished) {
std::string fileName = _fileFutureMap.find(hashkey)->second->filePath;
std::string filePath = "tiles/" + fileName;
std::shared_ptr<Texture> texture = loadAndInitTextureDisk(filePath);
_tileCache.put(hashkey, texture);
_fileFutureMap.erase(hashkey);
//LDEBUG("Downloaded " << fileName);
//auto job = std::shared_ptr<TextureLoadJob>(new TextureLoadJob(filePath, hashkey));
//_concurrentJobManager.enqueueJob(job);
}
}
else if(_fileFutureMap.size() < 50){
std::shared_ptr<DownloadManager::FileFuture> fileFuture = requestTile(tileIndex);
_fileFutureMap.insert_or_assign(hashkey, fileFuture);
}
return nullptr;
}
std::shared_ptr<Texture> TwmsTileProvider::loadAndInitTextureDisk(std::string filePath) {
auto textureReader = ghoul::io::TextureReader::ref();
std::shared_ptr<Texture> texture = std::move(textureReader.loadTexture(absPath(filePath)));
// upload to gpu
texture->uploadTexture();
texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
return texture;
}
std::shared_ptr<DownloadManager::FileFuture> TwmsTileProvider::requestTile(const TileIndex& tileIndex) {
// download tile
std::stringstream ss;
//std::string baseUrl = "https://map1c.vis.earthdata.nasa.gov/wmts-geo/wmts.cgi?TIME=2016-04-17&layer=MODIS_Terra_CorrectedReflectance_TrueColor&tilematrixset=EPSG4326_250m&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image%2Fjpeg";
//ss << baseUrl;
//ss << "&TileMatrix=" << tileIndex.level;
//ss << "&TileCol=" << tileIndex.x;
//ss << "&TileRow=" << tileIndex.y;
// https://map1c.vis.earthdata.nasa.gov/wmts-geo/wmts.cgi?TIME=2016-04-17&layer=MODIS_Terra_CorrectedReflectance_TrueColor&tilematrixset=EPSG4326_250m&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image%2Fjpeg&TileMatrix=0&TileCol=0&TileRow=0
std::shared_ptr<DownloadManager::FileFuture> TwmsTileProvider::requestTile(const TileIndex& tileIndex) {
// download tile
std::stringstream ss;
//std::string baseUrl = "https://map1c.vis.earthdata.nasa.gov/wmts-geo/wmts.cgi?TIME=2016-04-17&layer=MODIS_Terra_CorrectedReflectance_TrueColor&tilematrixset=EPSG4326_250m&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image%2Fjpeg";
//ss << baseUrl;
//ss << "&TileMatrix=" << tileIndex.level;
//ss << "&TileCol=" << tileIndex.x;
//ss << "&TileRow=" << tileIndex.y;
// https://map1c.vis.earthdata.nasa.gov/wmts-geo/wmts.cgi?TIME=2016-04-17&layer=MODIS_Terra_CorrectedReflectance_TrueColor&tilematrixset=EPSG4326_250m&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image%2Fjpeg&TileMatrix=0&TileCol=0&TileRow=0
std::string baseUrl = "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913";
ss << baseUrl;
ss << "/" << tileIndex.level;
ss << "/" << tileIndex.x;
ss << "/" << tileIndex.y;
ss << ".png?1461277159335";
// http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/5/8/12.png?
std::string twmsRequestUrl = ss.str();
ss = std::stringstream();
ss << tileIndex.level;
ss << "_" << tileIndex.x;
ss << "_" << tileIndex.y;
std::string filePath = "tiles/tile" + ss.str() + ".png";
std::string baseUrl = "http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913";
ss << baseUrl;
ss << "/" << tileIndex.level;
ss << "/" << tileIndex.x;
ss << "/" << tileIndex.y;
ss << ".png?1461277159335";
// http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/5/8/12.png?
std::string twmsRequestUrl = ss.str();
ss = std::stringstream();
ss << tileIndex.level;
ss << "_" << tileIndex.x;
ss << "_" << tileIndex.y;
std::string filePath = "tiles/tile" + ss.str() + ".png";
using ghoul::filesystem::File;
File localTileFile(filePath);
bool overrideFile = true;
using ghoul::filesystem::File;
File localTileFile(filePath);
bool overrideFile = true;
std::shared_ptr<DownloadManager::FileFuture> fileFuture = DownloadManager::ref().downloadFile(twmsRequestUrl, localTileFile, overrideFile);
return fileFuture;
/*
struct OnTileDownloaded {
HashKey key;
LRUCache<HashKey, std::shared_ptr<Texture>> * tileCache;
OnTileDownloaded(HashKey key, LRUCache<HashKey, std::shared_ptr<Texture>> * tileCache)
: key(key)
, tileCache(tileCache)
{
}
void operator()(const DownloadManager::FileFuture& ff) const {
//LDEBUG("Download of tile with hashkey " << key << " done!");
auto textureReader = ghoul::io::TextureReader::ref();
std::string relFilePath = "tiles/" + ff.filePath;
std::shared_ptr<Texture> texture = std::move(textureReader.loadTexture(absPath(relFilePath)));
// upload to gpu
texture->uploadTexture();
texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
tileCache->put(key, texture);
LDEBUG("Cache updated");
}
};
OnTileDownloaded onTileDownloaded(tileIndex.hashKey(), &_tileCache);
*/
std::shared_ptr<DownloadManager::FileFuture> fileFuture = DownloadManager::ref().downloadFile(twmsRequestUrl, localTileFile, overrideFile);
return fileFuture;
}
}
} // namespace openspace
+66 -20
View File
@@ -26,9 +26,13 @@
#define __TWMS_TILE_PROVIDER_H__
#include <modules/globebrowsing/other/lrucache.h>
#include <modules/globebrowsing/other/concurrentjobmanager.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h> // absPath
#include <ghoul/opengl/texture.h>
#include <ghoul/io/texture/texturereader.h>
#include <openspace/engine/downloadmanager.h>
@@ -39,15 +43,52 @@
//////////////////////////////////////////////////////////////////////////////////////
namespace openspace {
using HashKey = unsigned long;
using HashKey = unsigned long;
struct TileIndex {
int x, y, level;
struct TileIndex {
int x, y, level;
HashKey hashKey() const {
return x ^ (y << 16) ^ (level << 21);
}
};
}
namespace openspace {
using namespace ghoul::opengl;
struct TextureLoadJob : public Job<Texture> {
TextureLoadJob(const std::string& filePath, HashKey hashkey)
: _filePath(filePath)
, _hashkey(hashkey){
}
virtual ~TextureLoadJob() { }
virtual void execute() {
auto textureReader = ghoul::io::TextureReader::ref();
_texture = std::move(textureReader.loadTexture(absPath(_filePath)));
}
virtual std::shared_ptr<Texture> product() {
return _texture;
}
HashKey hashKey() { return _hashkey; }
private:
std::string _filePath;
HashKey _hashkey;
std::shared_ptr<Texture> _texture;
};
HashKey hashKey() const {
return x ^ (y << 16) ^ (level << 21);
}
};
}
@@ -57,24 +98,29 @@ namespace openspace {
namespace openspace {
using namespace ghoul::opengl;
using namespace ghoul::opengl;
class TwmsTileProvider
{
public:
TwmsTileProvider();
~TwmsTileProvider();
class TwmsTileProvider
{
public:
TwmsTileProvider();
~TwmsTileProvider();
std::shared_ptr<Texture> getTile(const TileIndex& tileIndex);
std::shared_ptr<Texture> getTile(const TileIndex& tileIndex);
void prerender();
private:
std::shared_ptr<DownloadManager::FileFuture> requestTile(const TileIndex&);
std::shared_ptr<Texture> loadAndInitTextureDisk(std::string filePath);
private:
std::shared_ptr<DownloadManager::FileFuture> requestTile(const TileIndex&);
std::shared_ptr<Texture> loadAndInitTextureDisk(std::string filePath);
LRUCache<HashKey, std::shared_ptr<Texture>> _tileCache;
LRUCache<HashKey, std::shared_ptr<DownloadManager::FileFuture>> _fileFutureCache;
};
LRUCache<HashKey, std::shared_ptr<Texture>> _tileCache;
std::unordered_map<HashKey, std::shared_ptr<DownloadManager::FileFuture>> _fileFutureMap;
//LRUCache<HashKey, std::shared_ptr<DownloadManager::FileFuture>> _fileFutureCache;
ConcurrentJobManager<Texture> _concurrentJobManager;
};
} // namespace openspace
+169 -165
View File
@@ -41,217 +41,221 @@
#include <math.h>
namespace {
const std::string _loggerCat = "PatchRenderer";
const std::string _loggerCat = "PatchRenderer";
const std::string keyFrame = "Frame";
const std::string keyGeometry = "Geometry";
const std::string keyShading = "PerformShading";
const std::string keyFrame = "Frame";
const std::string keyGeometry = "Geometry";
const std::string keyShading = "PerformShading";
const std::string keyBody = "Body";
const std::string keyBody = "Body";
}
namespace openspace {
//////////////////////////////////////////////////////////////////////////////////////
// PATCH RENDERER //
//////////////////////////////////////////////////////////////////////////////////////
PatchRenderer::PatchRenderer()
: _tileSet(Geodetic2(M_PI, M_PI * 2), Geodetic2(M_PI / 2, -M_PI), 0)
{
//////////////////////////////////////////////////////////////////////////////////////
// PATCH RENDERER //
//////////////////////////////////////////////////////////////////////////////////////
PatchRenderer::PatchRenderer()
: _tileSet(Geodetic2(M_PI, M_PI * 2), Geodetic2(M_PI / 2, -M_PI), 0)
{
}
}
PatchRenderer::~PatchRenderer() {
if (_programObject) {
RenderEngine& renderEngine = OsEng.renderEngine();
renderEngine.removeRenderProgram(_programObject);
_programObject = nullptr;
}
}
PatchRenderer::~PatchRenderer() {
if (_programObject) {
RenderEngine& renderEngine = OsEng.renderEngine();
renderEngine.removeRenderProgram(_programObject);
_programObject = nullptr;
}
}
//////////////////////////////////////////////////////////////////////////////////////
// LATLON PATCH RENDERER //
//////////////////////////////////////////////////////////////////////////////////////
LatLonPatchRenderer::LatLonPatchRenderer(shared_ptr<Grid> grid)
: PatchRenderer()
, _grid(grid)
{
_programObject = OsEng.renderEngine().buildRenderProgram(
"LatLonSphereMappingProgram",
"${MODULE_GLOBEBROWSING}/shaders/latlonpatch_spheremapping_vs.glsl",
"${MODULE_GLOBEBROWSING}/shaders/simple_fs.glsl");
ghoul_assert(_programObject != nullptr, "Failed to initialize programObject!");
//////////////////////////////////////////////////////////////////////////////////////
// LATLON PATCH RENDERER //
//////////////////////////////////////////////////////////////////////////////////////
LatLonPatchRenderer::LatLonPatchRenderer(shared_ptr<Grid> grid)
: PatchRenderer()
, _grid(grid)
{
_programObject = OsEng.renderEngine().buildRenderProgram(
"LatLonSphereMappingProgram",
"${MODULE_GLOBEBROWSING}/shaders/latlonpatch_spheremapping_vs.glsl",
"${MODULE_GLOBEBROWSING}/shaders/simple_fs.glsl");
ghoul_assert(_programObject != nullptr, "Failed to initialize programObject!");
using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError;
_programObject->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes);
}
using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError;
_programObject->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes);
}
void LatLonPatchRenderer::renderPatch(
const GeodeticPatch& patch, const RenderData& data, const Ellipsoid& ellipsoid)
{
// Get the textures that should be used for rendering
TileIndex ti = _tileSet.getTileIndex(patch);
void LatLonPatchRenderer::update() {
tileProvider.prerender();
}
renderPatch(patch, data, ellipsoid, ti);
}
void LatLonPatchRenderer::renderPatch(
const GeodeticPatch& patch, const RenderData& data, const Ellipsoid& ellipsoid)
{
// Get the textures that should be used for rendering
TileIndex ti = _tileSet.getTileIndex(patch);
void LatLonPatchRenderer::renderPatch(
const GeodeticPatch& patch,
const RenderData& data,
const Ellipsoid& ellipsoid,
const TileIndex& tileIndex)
{
renderPatch(patch, data, ellipsoid, ti);
}
using namespace glm;
void LatLonPatchRenderer::renderPatch(
const GeodeticPatch& patch,
const RenderData& data,
const Ellipsoid& ellipsoid,
const TileIndex& tileIndex)
{
using namespace glm;
// TODO : Model transform should be fetched as a matrix directly.
mat4 modelTransform = translate(mat4(1), data.position.vec3());
mat4 viewTransform = data.camera.combinedViewMatrix();
mat4 modelViewProjectionTransform = data.camera.projectionMatrix()
* viewTransform * modelTransform;
// TODO : Model transform should be fetched as a matrix directly.
mat4 modelTransform = translate(mat4(1), data.position.vec3());
mat4 viewTransform = data.camera.combinedViewMatrix();
mat4 modelViewProjectionTransform = data.camera.projectionMatrix()
* viewTransform * modelTransform;
// activate shader
_programObject->activate();
// activate shader
_programObject->activate();
// Get the textures that should be used for rendering
std::shared_ptr<ghoul::opengl::Texture> tile00;
bool usingTile = true;
TileIndex ti;
ti.level =tileIndex.level;
ti.x = tileIndex.y;
ti.y = tileIndex.x;
tile00 = tileProvider.getTile(ti);
// Get the textures that should be used for rendering
std::shared_ptr<ghoul::opengl::Texture> tile00;
bool usingTile = true;
TileIndex ti;
ti.level =tileIndex.level;
ti.x = tileIndex.y;
ti.y = tileIndex.x;
tile00 = tileProvider.getTile(ti);
if (tile00 == nullptr) {
tile00 = _tileSet.getTile(tileIndex);
usingTile = false;
}
if (tile00 == nullptr) {
tile00 = _tileSet.getTile(tileIndex);
usingTile = false;
}
glm::mat3 uvTransform = usingTile ? glm::mat3(1) : _tileSet.getUvTransformationPatchToTile(patch, tileIndex);
glm::mat3 uvTransform = usingTile ? glm::mat3(1) : _tileSet.getUvTransformationPatchToTile(patch, tileIndex);
// Bind and use the texture
ghoul::opengl::TextureUnit texUnit;
texUnit.activate();
tile00->bind();
_programObject->setUniform("textureSampler", texUnit);
_programObject->setUniform("uvTransformPatchToTile", uvTransform);
// Bind and use the texture
ghoul::opengl::TextureUnit texUnit;
texUnit.activate();
tile00->bind();
_programObject->setUniform("textureSampler", texUnit);
_programObject->setUniform("uvTransformPatchToTile", uvTransform);
Geodetic2 swCorner = patch.southWestCorner();
_programObject->setUniform("segmentsPerPatch", _grid->xSegments());
_programObject->setUniform("modelViewProjectionTransform", modelViewProjectionTransform);
_programObject->setUniform("minLatLon", vec2(swCorner.toLonLatVec2()));
_programObject->setUniform("lonLatScalingFactor", vec2(patch.size().toLonLatVec2()));
_programObject->setUniform("radiiSquared", vec3(ellipsoid.radiiSquared()));
Geodetic2 swCorner = patch.southWestCorner();
_programObject->setUniform("segmentsPerPatch", _grid->xSegments());
_programObject->setUniform("modelViewProjectionTransform", modelViewProjectionTransform);
_programObject->setUniform("minLatLon", vec2(swCorner.toLonLatVec2()));
_programObject->setUniform("lonLatScalingFactor", vec2(patch.size().toLonLatVec2()));
_programObject->setUniform("radiiSquared", vec3(ellipsoid.radiiSquared()));
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// render
_grid->geometry().drawUsingActiveProgram();
// render
_grid->geometry().drawUsingActiveProgram();
// disable shader
_programObject->deactivate();
}
// disable shader
_programObject->deactivate();
}
//////////////////////////////////////////////////////////////////////////////////////
// CLIPMAP PATCH RENDERER //
//////////////////////////////////////////////////////////////////////////////////////
ClipMapPatchRenderer::ClipMapPatchRenderer(shared_ptr<ClipMapGrid> grid)
: PatchRenderer()
, _grid(grid)
{
_programObject = OsEng.renderEngine().buildRenderProgram(
"LatLonSphereMappingProgram",
"${MODULE_GLOBEBROWSING}/shaders/clipmappatch_spheremapping_vs.glsl",
"${MODULE_GLOBEBROWSING}/shaders/simple_fs.glsl");
ghoul_assert(_programObject != nullptr, "Failed to initialize programObject!");
//////////////////////////////////////////////////////////////////////////////////////
// CLIPMAP PATCH RENDERER //
//////////////////////////////////////////////////////////////////////////////////////
ClipMapPatchRenderer::ClipMapPatchRenderer(shared_ptr<ClipMapGrid> grid)
: PatchRenderer()
, _grid(grid)
{
_programObject = OsEng.renderEngine().buildRenderProgram(
"LatLonSphereMappingProgram",
"${MODULE_GLOBEBROWSING}/shaders/clipmappatch_spheremapping_vs.glsl",
"${MODULE_GLOBEBROWSING}/shaders/simple_fs.glsl");
ghoul_assert(_programObject != nullptr, "Failed to initialize programObject!");
using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError;
_programObject->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes);
}
using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError;
_programObject->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes);
}
void ClipMapPatchRenderer::renderPatch(
const Geodetic2& patchSize,
const RenderData& data,
const Ellipsoid& ellipsoid)
{
// activate shader
_programObject->activate();
using namespace glm;
void ClipMapPatchRenderer::renderPatch(
const Geodetic2& patchSize,
const RenderData& data,
const Ellipsoid& ellipsoid)
{
// activate shader
_programObject->activate();
using namespace glm;
mat4 viewTransform = data.camera.combinedViewMatrix();
mat4 viewTransform = data.camera.combinedViewMatrix();
// TODO : Model transform should be fetched as a matrix directly.
mat4 modelTransform = translate(mat4(1), data.position.vec3());
// TODO : Model transform should be fetched as a matrix directly.
mat4 modelTransform = translate(mat4(1), data.position.vec3());
// Snap patch position
int segmentsPerPatch = _grid->segments();
Geodetic2 stepSize = Geodetic2(
patchSize.lat / segmentsPerPatch,
patchSize.lon / segmentsPerPatch);
ivec2 patchesToCoverGlobe = ivec2(
M_PI / patchSize.lat + 0.5,
M_PI * 2 / patchSize.lon + 0.5);
Geodetic2 cameraPosLatLon = ellipsoid.cartesianToGeodetic2(data.camera.position().dvec3());
ivec2 intSnapCoord = ivec2(
cameraPosLatLon.lat / (M_PI * 2) * segmentsPerPatch * patchesToCoverGlobe.y,
cameraPosLatLon.lon / (M_PI) * segmentsPerPatch * patchesToCoverGlobe.x);
Geodetic2 newPatchCenter = Geodetic2(
stepSize.lat * intSnapCoord.x,
stepSize.lon * intSnapCoord.y);
GeodeticPatch newPatch(
newPatchCenter,
Geodetic2(patchSize.lat / 2, patchSize.lon / 2));
// Snap patch position
int segmentsPerPatch = _grid->segments();
Geodetic2 stepSize = Geodetic2(
patchSize.lat / segmentsPerPatch,
patchSize.lon / segmentsPerPatch);
ivec2 patchesToCoverGlobe = ivec2(
M_PI / patchSize.lat + 0.5,
M_PI * 2 / patchSize.lon + 0.5);
Geodetic2 cameraPosLatLon = ellipsoid.cartesianToGeodetic2(data.camera.position().dvec3());
ivec2 intSnapCoord = ivec2(
cameraPosLatLon.lat / (M_PI * 2) * segmentsPerPatch * patchesToCoverGlobe.y,
cameraPosLatLon.lon / (M_PI) * segmentsPerPatch * patchesToCoverGlobe.x);
Geodetic2 newPatchCenter = Geodetic2(
stepSize.lat * intSnapCoord.x,
stepSize.lon * intSnapCoord.y);
GeodeticPatch newPatch(
newPatchCenter,
Geodetic2(patchSize.lat / 2, patchSize.lon / 2));
ivec2 contraction = ivec2(intSnapCoord.y % 2, intSnapCoord.x % 2);
ivec2 contraction = ivec2(intSnapCoord.y % 2, intSnapCoord.x % 2);
//LDEBUG("patch.center = [ " << patch.center.lat << " , " << patch.center.lon << " ]");
//LDEBUG("intSnapCoord = [ " << intSnapCoord.x << " , " << intSnapCoord.y << " ]");
//LDEBUG("contraction = [ " << contraction.x << " , " << contraction.y << " ]");
//LDEBUG("patch.center = [ " << patch.center.lat << " , " << patch.center.lon << " ]");
//LDEBUG("intSnapCoord = [ " << intSnapCoord.x << " , " << intSnapCoord.y << " ]");
//LDEBUG("contraction = [ " << contraction.x << " , " << contraction.y << " ]");
// Get the textures that should be used for rendering
TileIndex tileIndex = _tileSet.getTileIndex(newPatch);
GeodeticPatch tilePatch = _tileSet.getTilePositionAndScale(tileIndex);
std::shared_ptr<ghoul::opengl::Texture> tile00 = _tileSet.getTile(tileIndex);
glm::mat3 uvTransform = _tileSet.getUvTransformationPatchToTile(newPatch, tileIndex);
// Get the textures that should be used for rendering
TileIndex tileIndex = _tileSet.getTileIndex(newPatch);
GeodeticPatch tilePatch = _tileSet.getTilePositionAndScale(tileIndex);
std::shared_ptr<ghoul::opengl::Texture> tile00 = _tileSet.getTile(tileIndex);
glm::mat3 uvTransform = _tileSet.getUvTransformationPatchToTile(newPatch, tileIndex);
// Bind and use the texture
ghoul::opengl::TextureUnit texUnit;
texUnit.activate();
tile00->bind();
_programObject->setUniform("textureSampler", texUnit);
_programObject->setUniform("uvTransformPatchToTile", mat3(uvTransform));
// Bind and use the texture
ghoul::opengl::TextureUnit texUnit;
texUnit.activate();
tile00->bind();
_programObject->setUniform("textureSampler", texUnit);
_programObject->setUniform("uvTransformPatchToTile", mat3(uvTransform));
_programObject->setUniform(
"modelViewProjectionTransform",
data.camera.projectionMatrix() * viewTransform * modelTransform);
_programObject->setUniform("segmentsPerPatch", segmentsPerPatch);
_programObject->setUniform("minLatLon", vec2(newPatch.southWestCorner().toLonLatVec2()));
_programObject->setUniform("lonLatScalingFactor", vec2(patchSize.toLonLatVec2()));
_programObject->setUniform("radiiSquared", vec3(ellipsoid.radiiSquared()));
_programObject->setUniform("contraction", contraction);
_programObject->setUniform(
"modelViewProjectionTransform",
data.camera.projectionMatrix() * viewTransform * modelTransform);
_programObject->setUniform("segmentsPerPatch", segmentsPerPatch);
_programObject->setUniform("minLatLon", vec2(newPatch.southWestCorner().toLonLatVec2()));
_programObject->setUniform("lonLatScalingFactor", vec2(patchSize.toLonLatVec2()));
_programObject->setUniform("radiiSquared", vec3(ellipsoid.radiiSquared()));
_programObject->setUniform("contraction", contraction);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// render
_grid->geometry().drawUsingActiveProgram();
// render
_grid->geometry().drawUsingActiveProgram();
// disable shader
_programObject->deactivate();
}
// disable shader
_programObject->deactivate();
}
} // namespace openspace
@@ -75,6 +75,8 @@ namespace openspace {
public:
LatLonPatchRenderer(shared_ptr<Grid> grid);
void update();
void renderPatch(
const GeodeticPatch& patch,
const RenderData& data,
@@ -85,9 +87,13 @@ namespace openspace {
const RenderData& data,
const Ellipsoid& ellipsoid,
const TileIndex& ti);
private:
shared_ptr<Grid> _grid;
TwmsTileProvider tileProvider;
shared_ptr<Grid> _grid;
};
+57 -12
View File
@@ -55,8 +55,8 @@ struct TestJob : public Job<int> {
std::cout << "Finished job" << std::endl;
}
virtual int product() {
return prod;
virtual std::shared_ptr<int> product() {
return std::make_shared<int>(prod);
}
private:
@@ -88,27 +88,68 @@ TEST_F(ConcurrentJobManagerTest, Basic) {
auto finishedJob = jobManager.popFinishedJob();
int product = finishedJob->product();
int product = *finishedJob->product();
EXPECT_EQ(product, 1337) << "Expecting product to be 1337";
}
struct VerboseTestJob : public TestJob {
VerboseTestJob(int jobExecutingTime)
: TestJob(jobExecutingTime) {
struct VerboseProduct {
VerboseProduct(int v)
: val(v){
std::cout << "VerboseProduct constructor" << std::endl;
}
~VerboseProduct() {
std::cout << "VerboseProduct destructor" << std::endl;
}
int val;
};
struct VerboseJob : public Job<VerboseProduct>{
VerboseJob(int jobExecutingTime)
: _jobExecutingTime(jobExecutingTime) {
std::cout << "VerboseTestJob constructor" << std::endl;
}
~VerboseTestJob() {
~VerboseJob() {
std::cout << "VerboseTestJob destructor" << std::endl;
}
virtual void execute() {
std::cout << " ** Executing job ... " << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(_jobExecutingTime));
_product = std::shared_ptr<VerboseProduct>(new VerboseProduct(1337));
std::cout << " ** Finished job" << std::endl;
}
virtual std::shared_ptr<VerboseProduct> product() {
return _product;
}
int _jobExecutingTime;
std::shared_ptr<VerboseProduct> _product;
};
TEST_F(ConcurrentJobManagerTest, JobCreation) {
ConcurrentJobManager<int> jobManager;
auto testJob1 = std::shared_ptr<TestJob>(new VerboseTestJob(20));
TEST_F(ConcurrentJobManagerTest, JobCreation) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
ConcurrentJobManager<VerboseProduct> jobManager;
auto testJob1 = std::shared_ptr<VerboseJob>(new VerboseJob(20));
jobManager.enqueueJob(testJob1);
@@ -121,8 +162,12 @@ TEST_F(ConcurrentJobManagerTest, JobCreation) {
auto finishedJob = jobManager.popFinishedJob();
{
auto product = finishedJob->product();
}
int product = finishedJob->product();
EXPECT_EQ(product, 1337) << "Expecting product to be 1337";
int a;
}