SkyImageTile.cpp   StelSkyImageTile.cpp 
skipping to change at line 19 skipping to change at line 19
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, U SA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, U SA.
*/ */
#include "SkyImageTile.hpp" #include "StelSkyImageTile.hpp"
#include "QtJsonParser.hpp"
#include "StelApp.hpp" #include "StelApp.hpp"
#include "StelFileMgr.hpp" #include "StelFileMgr.hpp"
#include "StelUtils.hpp" #include "StelUtils.hpp"
#include "STexture.hpp" #include "StelTexture.hpp"
#include "Projector.hpp" #include "StelProjector.hpp"
#include "ToneReproducer.hpp" #include "StelToneReproducer.hpp"
#include "StelCore.hpp" #include "StelCore.hpp"
#include "StelTextureMgr.hpp" #include "StelTextureMgr.hpp"
#include "SkyDrawer.hpp" #include "StelSkyDrawer.hpp"
#include "StelPainter.hpp"
#include <QDebug> #include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QHttp>
#include <QUrl>
#include <QBuffer>
#include <QThread>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <stdexcept>
#ifdef DEBUG_SKYIMAGE_TILE #ifdef DEBUG_STELSKYIMAGE_TILE
#include "SFont.hpp" #include "StelFont.hpp"
#include "StelFontMgr.hpp" #include "StelFontMgr.hpp"
#include "StelLocaleMgr.hpp" #include "StelLocaleMgr.hpp"
SFont* SkyImageTile::debugFont = NULL; StelFont* StelSkyImageTile::debugFont = NULL;
#endif #endif
/************************************************************************* void StelSkyImageTile::initCtor()
Class used to load a JSON file in a thread
*************************************************************************/
class JsonLoadThread : public QThread
{
public:
JsonLoadThread(SkyImageTile* atile, QByteArray content, bool
acompressed=false) : QThread((QObject*)atile),
tile(atile), data(content), compressed(acompressed)
{;}
virtual void run();
private:
SkyImageTile* tile;
QByteArray data;
const bool compressed;
};
void JsonLoadThread::run()
{
try
{
QBuffer buf(&data);
buf.open(QIODevice::ReadOnly);
tile->temporaryResultMap = SkyImageTile::loadFromJSON(buf, c
ompressed);
}
catch (std::runtime_error e)
{
qWarning() << "WARNING : Can't parse loaded JSON Image Tile
description: " << e.what();
tile->errorOccured = true;
}
}
void SkyImageTile::initCtor()
{ {
minResolution = -1;
luminance = -1; luminance = -1;
alphaBlend = false; alphaBlend = false;
noTexture = false; noTexture = false;
errorOccured = false;
httpReply = NULL;
downloading = false;
loadThread = NULL;
texFader = NULL; texFader = NULL;
loadingState = false;
lastPercent = 0;
} }
// Constructor // Constructor
SkyImageTile::SkyImageTile(const QString& url, SkyImageTile* parent) : QObj ect(parent) StelSkyImageTile::StelSkyImageTile(const QString& url, StelSkyImageTile* pa rent) : MultiLevelJsonBase(parent)
{ {
initCtor(); initCtor();
if (parent!=NULL) if (parent!=NULL)
{ {
luminance = parent->luminance; luminance = parent->luminance;
alphaBlend = parent->alphaBlend; alphaBlend = parent->alphaBlend;
} }
if (!url.startsWith("http://") && (parent==NULL || !parent->getBaseU initFromUrl(url);
rl().startsWith("http://")))
{
// Assume a local file
QString fileName;
try
{
fileName = StelApp::getInstance().getFileMgr().findF
ile(url);
}
catch (std::exception e)
{
try
{
if (parent==NULL)
throw std::runtime_error("NULL paren
t");
fileName = StelApp::getInstance().getFileMgr
().findFile(parent->getBaseUrl()+url);
}
catch (std::runtime_error e)
{
qWarning() << "WARNING : Can't find JSON Ima
ge Tile description: " << url << ": " << e.what();
errorOccured = true;
return;
}
}
QFileInfo finf(fileName);
baseUrl = finf.absolutePath()+'/';
QFile f(fileName);
f.open(QIODevice::ReadOnly);
const bool compressed = fileName.endsWith(".qZ");
try
{
loadFromQVariantMap(loadFromJSON(f, compressed));
}
catch (std::runtime_error e)
{
qWarning() << "WARNING : Can't parse JSON Image Tile
description: " << fileName << ": " << e.what();
errorOccured = true;
f.close();
return;
}
f.close();
lastTimeDraw = StelApp::getInstance().getTotalRunTime();
}
else
{
QUrl qurl;
if (url.startsWith("http://"))
{
qurl.setUrl(url);
}
else
{
assert(parent->getBaseUrl().startsWith("http://"));
qurl.setUrl(parent->getBaseUrl()+url);
}
assert(httpReply==NULL);
httpReply = StelApp::getInstance().getNetworkAccessManager()
->get(QNetworkRequest(qurl));
connect(httpReply, SIGNAL(finished()), this, SLOT(downloadFi
nished()));
downloading = true;
QString turl = qurl.toString();
baseUrl = turl.left(turl.lastIndexOf('/')+1);
}
} }
// Constructor from a map used for JSON files with more than 1 level // Constructor from a map used for JSON files with more than 1 level
SkyImageTile::SkyImageTile(const QVariantMap& map, SkyImageTile* parent) : QObject(parent) StelSkyImageTile::StelSkyImageTile(const QVariantMap& map, StelSkyImageTile * parent) : MultiLevelJsonBase(parent)
{ {
initCtor(); initCtor();
if (parent!=NULL) if (parent!=NULL)
{ {
baseUrl = parent->getBaseUrl();
luminance = parent->luminance; luminance = parent->luminance;
alphaBlend = parent->alphaBlend; alphaBlend = parent->alphaBlend;
} }
loadFromQVariantMap(map); initFromQVariantMap(map);
lastTimeDraw = StelApp::getInstance().getTotalRunTime();
} }
// Destructor // Destructor
SkyImageTile::~SkyImageTile() StelSkyImageTile::~StelSkyImageTile()
{ {
if (httpReply)
{
httpReply->abort();
delete httpReply;
httpReply = NULL;
}
if (loadThread && loadThread->isRunning())
{
disconnect(loadThread, SIGNAL(finished()), this, SLOT(JsonLo
adFinished()));
// The thread is currently running, it needs to be properly
stopped
if (loadThread->wait(500)==false)
{
loadThread->terminate();
//loadThread->wait(2000);
}
}
foreach (SkyImageTile* tile, subTiles)
{
delete tile;
}
} }
void SkyImageTile::draw(StelCore* core) void StelSkyImageTile::draw(StelCore* core, const StelPainter& sPainter)
{ {
Projector* prj = core->getProjection(); const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000) ;
const float limitLuminance = core->getSkyDrawer()->getLimitLuminance (); const float limitLuminance = core->getSkyDrawer()->getLimitLuminance ();
QMultiMap<double, SkyImageTile*> result; QMultiMap<double, StelSkyImageTile*> result;
getTilesToDraw(result, core, prj->getViewportConvexPolygon(0, 0), li mitLuminance, true); getTilesToDraw(result, core, prj->getViewportConvexPolygon(0, 0), li mitLuminance, true);
int numToBeLoaded=0; int numToBeLoaded=0;
foreach (StelSkyImageTile* t, result)
if (t->isReadyToDisplay()==false)
++numToBeLoaded;
updatePercent(result.size(), numToBeLoaded);
// Draw in the good order
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_ONE, GL_ONE); glBlendFunc(GL_ONE, GL_ONE);
//glDisable(GL_CULL_FACE); QMap<double, StelSkyImageTile*>::Iterator i = result.end();
QMap<double, SkyImageTile*>::Iterator i = result.end();
while (i!=result.begin()) while (i!=result.begin())
{ {
--i; --i;
if (i.value()->drawTile(core)==false) i.value()->drawTile(core, sPainter);
++numToBeLoaded;
} }
updatePercent(result.size(), numToBeLoaded);
deleteUnusedTiles(); deleteUnusedSubTiles();
} }
// Return the list of tiles which should be drawn. // Return the list of tiles which should be drawn.
void SkyImageTile::getTilesToDraw(QMultiMap<double, SkyImageTile*>& result, StelCore* core, const StelGeom::ConvexPolygon& viewPortPoly, float limitLu minance, bool recheckIntersect) void StelSkyImageTile::getTilesToDraw(QMultiMap<double, StelSkyImageTile*>& result, StelCore* core, const StelGeom::ConvexPolygon& viewPortPoly, float limitLuminance, bool recheckIntersect)
{ {
#ifndef NDEBUG
// When this method is called, we can assume that:
// - the parent tile min resolution was reached
// - the parent tile is intersecting FOV
// - the parent tile is not scheduled for deletion
Q_ASSERT(isDeletionScheduled()==false);
const StelSkyImageTile* parent = qobject_cast<StelSkyImageTile*>(QOb
ject::parent());
if (parent!=NULL)
{
const double degPerPixel = 1./core->getProjection(StelCore::
FrameJ2000)->getPixelPerRadAtCenter()*180./M_PI;
Q_ASSERT(degPerPixel<parent->minResolution);
Q_ASSERT(parent->isDeletionScheduled()==false);
}
#endif
// An error occured during loading // An error occured during loading
if (errorOccured) if (errorOccured)
return; return;
// The JSON file is currently being downloaded // The JSON file is currently being downloaded
if (downloading) if (downloading)
{ {
// Avoid the tile to be deleted by telling that it was drawn //qDebug() << "Downloading " << contructorUrl;
lastTimeDraw = StelApp::getInstance().getTotalRunTime();
return; return;
} }
if (luminance>0 && luminance<limitLuminance) if (luminance>0 && luminance<limitLuminance)
{
// Schedule a deletion
scheduleChildsDeletion();
return; return;
}
// Check that we are in the screen // Check that we are in the screen
bool fullInScreen = true; bool fullInScreen = true;
bool intersectScreen = false; bool intersectScreen = false;
if (recheckIntersect) if (recheckIntersect)
{ {
if (skyConvexPolygons.isEmpty()) if (skyConvexPolygons.isEmpty())
{ {
// If no polygon is defined, we assume that the tile covers the whole sky // If no polygon is defined, we assume that the tile covers the whole sky
fullInScreen=false; fullInScreen=false;
skipping to change at line 276 skipping to change at line 173
{ {
fullInScreen = false; fullInScreen = false;
if (intersect(viewPortPoly, poly)) if (intersect(viewPortPoly, poly))
intersectScreen = true; intersectScreen = true;
} }
} }
} }
} }
// The tile is outside screen // The tile is outside screen
if (fullInScreen==false && intersectScreen==false) if (fullInScreen==false && intersectScreen==false)
{
// Schedule a deletion
scheduleChildsDeletion();
return; return;
}
lastTimeDraw = StelApp::getInstance().getTotalRunTime(); // The tile is in screen, and it is a precondition that its resoluti
on is higher than the limit
// make sure that it's not going to be deleted
cancelDeletion();
if (noTexture==false) if (noTexture==false)
{ {
if (!tex) if (!tex)
{ {
// The tile has an associated texture, but it is not yet loaded: load it now // The tile has an associated texture, but it is not yet loaded: load it now
StelTextureMgr& texMgr=StelApp::getInstance().getTex tureManager(); StelTextureMgr& texMgr=StelApp::getInstance().getTex tureManager();
texMgr.setDefaultParams(); texMgr.setDefaultParams();
texMgr.setMipmapsMode(true); texMgr.setMipmapsMode(true);
texMgr.setMinFilter(GL_LINEAR); texMgr.setMinFilter(GL_LINEAR);
texMgr.setMagFilter(GL_LINEAR); texMgr.setMagFilter(GL_LINEAR);
// static int countG=0; texMgr.setWrapMode(GL_CLAMP_TO_EDGE);
// qWarning() << countG++;
tex = texMgr.createTextureThread(absoluteImageURI); tex = texMgr.createTextureThread(absoluteImageURI);
if (!tex) if (!tex)
{ {
qWarning() << "WARNING : Can't create tile: " << absoluteImageURI; qWarning() << "WARNING : Can't create tile: " << absoluteImageURI;
errorOccured = true; errorOccured = true;
return; return;
} }
} }
// Every test passed :) The tile will be displayed // The tile is in screen and has a texture: every test passe d :) The tile will be displayed
result.insert(minResolution, this); result.insert(minResolution, this);
// Check that the texture is now fully loaded before trying
to load sub tiles
if (tex->canBind()==false)
return;
} }
// Check if we reach the resolution limit // Check if we reach the resolution limit
Projector* prj = core->getProjection(); const double degPerPixel = 1./core->getProjection(StelCore::FrameJ20
const double degPerPixel = 1./prj->getPixelPerRadAtCenter()*180./M_P 00)->getPixelPerRadAtCenter()*180./M_PI;
I; if (degPerPixel < minResolution)
if (degPerPixel < minResolution*0.8)
{ {
if (subTiles.isEmpty()) if (subTiles.isEmpty() && !subTilesUrls.isEmpty())
{ {
if (!subTilesUrls.isEmpty()) // Load the sub tiles because we reached the maximum
resolution and they are not yet loaded
foreach (QVariant s, subTilesUrls)
{ {
// Load the sub tiles because we reached the StelSkyImageTile* nt;
maximum resolution if (s.type()==QVariant::Map)
// and they are not yet loaded nt = new StelSkyImageTile(s.toMap(),
foreach (QString url, subTilesUrls) this);
else
{ {
subTiles.append(new SkyImageTile(url Q_ASSERT(s.type()==QVariant::String)
, this)); ;
nt = new StelSkyImageTile(s.toString
(), this);
} }
subTiles.append(nt);
} }
} }
else // Try to add the subtiles
foreach (MultiLevelJsonBase* tile, subTiles)
{ {
// Try to add the subtiles qobject_cast<StelSkyImageTile*>(tile)->getTilesToDra
foreach (SkyImageTile* tile, subTiles) w(result, core, viewPortPoly, limitLuminance, !fullInScreen);
{
tile->getTilesToDraw(result, core, viewPortP
oly, limitLuminance, !fullInScreen);
}
} }
} }
else
{
// The subtiles should not be displayed because their resolu
tion is too high
scheduleChildsDeletion();
}
} }
// Draw the image on the screen. // Draw the image on the screen.
// Assume GL_TEXTURE_2D is enabled // Assume GL_TEXTURE_2D is enabled
bool SkyImageTile::drawTile(StelCore* core) bool StelSkyImageTile::drawTile(StelCore* core, const StelPainter& sPainter )
{ {
const float ad_lum = (luminance>0) ? core->getToneReproducer()->adap
tLuminanceScaled(luminance) : 1.f;
if (!tex->bind()) if (!tex->bind())
{ {
return false; return false;
} }
if (!texFader) if (!texFader)
{ {
texFader = new QTimeLine(1000, this); texFader = new QTimeLine(1000, this);
texFader->start(); texFader->start();
} }
const Projector* prj = core->getProjection(); const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000)
;
const float factorX = tex->getCoordinates()[2][0]; const float factorX = tex->getCoordinates()[2][0];
const float factorY = tex->getCoordinates()[2][1]; const float factorY = tex->getCoordinates()[2][1];
// Draw the real texture for this image // Draw the real texture for this image
const float ad_lum = (luminance>0) ? core->getToneReproducer()->adap tLuminanceScaled(luminance) : 1.f;
if (alphaBlend==true || texFader->state()==QTimeLine::Running) if (alphaBlend==true || texFader->state()==QTimeLine::Running)
{ {
if (!alphaBlend) if (!alphaBlend)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); / / Normal transparency mode glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); / / Normal transparency mode
glEnable(GL_BLEND); glEnable(GL_BLEND);
glColor4f(ad_lum,ad_lum,ad_lum, texFader->currentValue()); glColor4f(ad_lum,ad_lum,ad_lum, texFader->currentValue());
} }
else else
{ {
glDisable(GL_BLEND); glDisable(GL_BLEND);
glColor3f(ad_lum,ad_lum,ad_lum); glColor3f(ad_lum,ad_lum,ad_lum);
} }
for (int p=0;p<skyConvexPolygons.size();++p) for (int p=0;p<skyConvexPolygons.size();++p)
{ {
const StelGeom::Polygon& poly = skyConvexPolygons.at(p).asPo lygon(); const StelGeom::Polygon& poly = skyConvexPolygons.at(p).asPo lygon();
const QList<Vec2f>& texCoords = textureCoords.at(p); const QList<Vec2f>& texCoords = textureCoords.at(p);
assert((int)poly.size()==texCoords.size()); Q_ASSERT((int)poly.size()==texCoords.size());
Vec3d win; Vec3d win;
const int N=poly.size()-1; const int N=poly.size()-1;
int idx=N; int idx=N;
int diff = 0; int diff = 0;
// Using TRIANGLE STRIP requires to use the following vertex order N-0,0,N-1,1,N-2,2 etc.. // Using TRIANGLE STRIP requires to use the following vertex order N-0,0,N-1,1,N-2,2 etc..
glBegin(GL_TRIANGLE_STRIP); glBegin(GL_TRIANGLE_STRIP);
for (int i=0;i<=N;++i) for (int i=0;i<=N;++i)
{ {
idx = (diff==0 ? N-i/2 : i/2); idx = (diff==0 ? N-i/2 : i/2);
++diff; ++diff;
if (diff>1) diff=0; if (diff>1) diff=0;
glTexCoord2d(texCoords[idx][0]*factorX, texCoords[id x][1]*factorY); glTexCoord2d(texCoords[idx][0]*factorX, texCoords[id x][1]*factorY);
prj->project(poly[idx],win); prj->project(poly[idx],win);
glVertex3dv(win); glVertex3dv(win);
} }
glEnd(); glEnd();
} }
#ifdef DEBUG_SKYIMAGE_TILE #ifdef DEBUG_STELSKYIMAGE_TILE
if (debugFont==NULL) if (debugFont==NULL)
{ {
debugFont = &StelApp::getInstance().getFontManager().getStan dardFont(StelApp::getInstance().getLocaleMgr().getSkyLanguage(), 12); debugFont = &StelApp::getInstance().getFontManager().getStan dardFont(StelApp::getInstance().getLocaleMgr().getSkyLanguage(), 12);
} }
glColor3f(1.0,0.5,0.5); glColor3f(1.0,0.5,0.5);
foreach (const StelGeom::ConvexPolygon& poly, skyConvexPolygons) foreach (const StelGeom::ConvexPolygon& poly, skyConvexPolygons)
{ {
Vec3d win; Vec3d win;
Vec3d bary = poly.getBarycenter(); Vec3d bary = poly.getBarycenter();
prj->project(bary,win); prj->project(bary,win);
prj->drawText(debugFont, win[0], win[1], getAbsoluteImageURI ()); sPainter.drawText(debugFont, win[0], win[1], getAbsoluteImag eURI());
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
prj->drawPolygon(poly); sPainter.drawPolygon(poly);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
} }
#endif #endif
if (!alphaBlend) if (!alphaBlend)
glBlendFunc(GL_ONE, GL_ONE); // Revert glBlendFunc(GL_ONE, GL_ONE); // Revert
return true; return true;
} }
// Return true if the tile is fully loaded and can be displayed // Return true if the tile is fully loaded and can be displayed
bool SkyImageTile::isReadyToDisplay() const bool StelSkyImageTile::isReadyToDisplay() const
{ {
return tex && tex->canBind(); return tex && tex->canBind();
} }
// Load the tile information from a JSON file
QVariantMap SkyImageTile::loadFromJSON(QIODevice& input, bool compressed)
{
QtJsonParser parser;
QVariantMap map;
if (compressed && input.size()>0)
{
QByteArray ar = qUncompress(input.readAll());
input.close();
QBuffer buf(&ar);
buf.open(QIODevice::ReadOnly);
map = parser.parse(buf).toMap();
buf.close();
}
else
{
map = parser.parse(input).toMap();
}
if (map.isEmpty())
throw std::runtime_error("empty JSON file, cannot load image
tile");
return map;
}
// Load the tile from a valid QVariantMap // Load the tile from a valid QVariantMap
void SkyImageTile::loadFromQVariantMap(const QVariantMap& map) void StelSkyImageTile::loadFromQVariantMap(const QVariantMap& map)
{ {
if (map.contains("imageCredits")) if (map.contains("imageCredits"))
{ {
QVariantMap dsCredits = map.value("imageCredits").toMap(); QVariantMap dsCredits = map.value("imageCredits").toMap();
dataSetCredits.shortCredits = dsCredits.value("short").toStr ing(); dataSetCredits.shortCredits = dsCredits.value("short").toStr ing();
dataSetCredits.fullCredits = dsCredits.value("full").toStrin g(); dataSetCredits.fullCredits = dsCredits.value("full").toStrin g();
dataSetCredits.infoURL = dsCredits.value("infoUrl").toString (); dataSetCredits.infoURL = dsCredits.value("infoUrl").toString ();
} }
if (map.contains("serverCredits")) if (map.contains("serverCredits"))
{ {
skipping to change at line 516 skipping to change at line 392
QList<Vec3d> vertices; QList<Vec3d> vertices;
foreach (QVariant vRaDec, polyRaDec.toList()) foreach (QVariant vRaDec, polyRaDec.toList())
{ {
const QVariantList vl = vRaDec.toList(); const QVariantList vl = vRaDec.toList();
Vec3d v; Vec3d v;
StelUtils::spheToRect(vl.at(0).toDouble(&ok)*M_PI/18 0., vl.at(1).toDouble(&ok)*M_PI/180., v); StelUtils::spheToRect(vl.at(0).toDouble(&ok)*M_PI/18 0., vl.at(1).toDouble(&ok)*M_PI/180., v);
if (!ok) if (!ok)
throw std::runtime_error("wrong Ra and Dec, expect a double value"); throw std::runtime_error("wrong Ra and Dec, expect a double value");
vertices.append(v); vertices.append(v);
} }
assert(vertices.size()==4); Q_ASSERT(vertices.size()==4);
skyConvexPolygons.append(StelGeom::ConvexPolygon(vertices[0] , vertices[1], vertices[2], vertices[3])); skyConvexPolygons.append(StelGeom::ConvexPolygon(vertices[0] , vertices[1], vertices[2], vertices[3]));
} }
// Load the matching textures positions (if any) // Load the matching textures positions (if any)
polyList = map.value("textureCoords").toList(); polyList = map.value("textureCoords").toList();
foreach (const QVariant& polyXY, polyList) foreach (const QVariant& polyXY, polyList)
{ {
QList<Vec2f> vertices; QList<Vec2f> vertices;
foreach (QVariant vXY, polyXY.toList()) foreach (QVariant vXY, polyXY.toList())
{ {
const QVariantList vl = vXY.toList(); const QVariantList vl = vXY.toList();
vertices.append(Vec2f(vl.at(0).toDouble(&ok), vl.at( 1).toDouble(&ok))); vertices.append(Vec2f(vl.at(0).toDouble(&ok), vl.at( 1).toDouble(&ok)));
if (!ok) if (!ok)
throw std::runtime_error("wrong X and Y, exp ect a double value"); throw std::runtime_error("wrong X and Y, exp ect a double value");
} }
assert(vertices.size()==4); Q_ASSERT(vertices.size()==4);
textureCoords.append(vertices); textureCoords.append(vertices);
} }
if (map.contains("imageUrl")) if (map.contains("imageUrl"))
{ {
QString imageUrl = map.value("imageUrl").toString(); QString imageUrl = map.value("imageUrl").toString();
if (baseUrl.startsWith("http://")) if (baseUrl.startsWith("http://"))
{ {
absoluteImageURI = baseUrl+imageUrl; absoluteImageURI = baseUrl+imageUrl;
} }
skipping to change at line 561 skipping to change at line 437
// Maybe the user meant a file in stellarium local files // Maybe the user meant a file in stellarium local files
absoluteImageURI = imageUrl; absoluteImageURI = imageUrl;
} }
} }
if (skyConvexPolygons.size()!=textureCoords.size()) if (skyConvexPolygons.size()!=textureCoords.size())
throw std::runtime_error("the number of convex polyg ons does not match the number of texture space polygon"); throw std::runtime_error("the number of convex polyg ons does not match the number of texture space polygon");
} }
else else
noTexture = true; noTexture = true;
QVariantList subTilesl = map.value("subTiles").toList(); // This is a list of URLs to the child tiles or a list of already lo
// if (subTilesl.size()>10) aded map containing child information
// { // (in this later case, the StelSkyImageTile objects will be created
// qWarning() << "Large tiles number for " << shortName << ": " later)
<< subTilesl.size(); subTilesUrls = map.value("subTiles").toList();
// } for (QVariantList::Iterator i=subTilesUrls.begin(); i!=subTilesUrls.
foreach (QVariant subTile, subTilesl) end();++i)
{ {
// The JSON file contains a nested tile structure if (i->type()==QVariant::Map)
if (subTile.type()==QVariant::Map) {
{ // Check if the JSON object is a reference, i.e. if
subTiles.append(new SkyImageTile(subTile.toMap(), th it contains a $ref key
is)); QVariantMap m = i->toMap();
} if (m.size()==1 && m.contains("$ref"))
else {
{ *i=QString(m["$ref"].toString());
// This is an URL to the child tile }
subTilesUrls.append(subTile.toString());
} }
} }
// if (subTilesUrls.size()>10)
// {
// qWarning() << "Large tiles number for " << shortName << ": "
<< subTilesUrls.size();
// }
} }
// Called when the download for the JSON file terminated // Convert the image informations to a map following the JSON structure.
void SkyImageTile::downloadFinished() QVariantMap StelSkyImageTile::toQVariantMap() const
{
//qDebug() << "Download finished for " << httpReply->request().url()
.path() << ((httpReply->error()!=QNetworkReply::NoError) ? httpReply->error
String() : QString(""));
if (httpReply->error()!=QNetworkReply::NoError)
{
if (httpReply->error()!=QNetworkReply::OperationCanceledErro
r)
qWarning() << "WARNING : Problem while downloading J
SON Image Tile description for " << httpReply->request().url().path() << ":
"<< httpReply->errorString();
errorOccured = true;
httpReply->deleteLater();
httpReply=NULL;
downloading=false;
return;
}
QByteArray content = httpReply->readAll();
if (content.isEmpty())
{
errorOccured = true;
httpReply->deleteLater();
httpReply=NULL;
downloading=false;
return;
}
const bool compressed = httpReply->request().url().path().endsWith("
.qZ");
httpReply->deleteLater();
httpReply=NULL;
assert(loadThread==NULL);
loadThread = new JsonLoadThread(this, content, compressed);
connect(loadThread, SIGNAL(finished()), this, SLOT(JsonLoadFinished(
)));
loadThread->start(QThread::LowestPriority);
}
// Called when the tile is fully loaded from the JSON file
void SkyImageTile::JsonLoadFinished()
{ {
loadThread->wait(); QVariantMap res;
delete loadThread;
loadThread = NULL;
downloading = false;
if (errorOccured)
return;
loadFromQVariantMap(temporaryResultMap);
lastTimeDraw = StelApp::getInstance().getTotalRunTime();
}
// Delete all the subtiles which were not displayed since more than lastDra // Image credits
wTrigger seconds QVariantMap imCredits;
void SkyImageTile::deleteUnusedTiles(double lastDrawTrigger) if (!dataSetCredits.shortCredits.isEmpty())
{ imCredits["short"]=dataSetCredits.shortCredits;
if (subTiles.isEmpty()) if (!dataSetCredits.fullCredits.isEmpty())
return; imCredits["full"]=dataSetCredits.fullCredits;
if (!dataSetCredits.infoURL.isEmpty())
imCredits["infoUrl"]=dataSetCredits.infoURL;
if (!imCredits.empty())
res["imageCredits"]=imCredits;
// Server credits
QVariantMap serCredits;
if (!serverCredits.shortCredits.isEmpty())
imCredits["short"]=serverCredits.shortCredits;
if (!serverCredits.fullCredits.isEmpty())
imCredits["full"]=serverCredits.fullCredits;
if (!serverCredits.infoURL.isEmpty())
imCredits["infoUrl"]=serverCredits.infoURL;
if (!serCredits.empty())
res["serverCredits"]=serCredits;
// Misc
if (!shortName.isEmpty())
res["shortName"] = shortName;
if (minResolution>0)
res["minResolution"]=minResolution;
if (luminance>0)
res["maxBrightness"]=StelApp::getInstance().getCore()->getSk
yDrawer()->luminanceToSurfacebrightness(luminance);
if (alphaBlend)
res["alphaBlend"]=true;
if (noTexture==false)
res["imageUrl"]=absoluteImageURI;
double now = StelApp::getInstance().getTotalRunTime(); // Polygons
bool deleteAll = true; if (!skyConvexPolygons.isEmpty())
foreach (SkyImageTile* tile, subTiles)
{ {
// At least one of the subtiles is displayed QVariantList polygsL;
if (now-tile->getLastTimeDraw()<lastDrawTrigger || tile->dow foreach (const StelGeom::ConvexPolygon& poly, skyConvexPolyg
nloading) // || (tile->tex && tile->tex->isLoading()) ons)
{ {
deleteAll = false; QVariantList polyL;
break; for (size_t i=0;i<poly.asPolygon().size();++i)
{
double ra, dec;
StelUtils::rectToSphe(&ra, &dec, poly[i]);
QVariantList vL;
vL.append(ra);
vL.append(dec);
polyL.append(vL);
}
polygsL.append(polyL);
} }
res["worldCoords"]=polygsL;
} }
if (deleteAll==true) // textures positions
if (!textureCoords.empty())
{ {
// If there is no subTilesUrls stored it means that the tile QVariantList polygsL;
description was foreach (const QList<Vec2f>& poly, textureCoords)
// embeded into the same JSON file as the parent. Therefore
it cannot be deleted
// without deleting also the parent because it couldn't be r
eloaded alone.
const bool removeOnlyTextures = subTilesUrls.isEmpty();
if (removeOnlyTextures)
{ {
foreach (SkyImageTile* tile, subTiles) QVariantList polyL;
foreach (Vec2f v, poly)
{ {
tile->deleteTexture(); QVariantList vL;
if (tile->texFader) vL.append(v[0]);
{ vL.append(v[1]);
tile->texFader->deleteLater(); polyL.append(vL);
tile->texFader = NULL;
}
tile->deleteUnusedTiles(lastDrawTrigger);
} }
polygsL.append(polyL);
} }
else res["textureCoords"]=polygsL;
{
// None of the subtiles are displayed: delete all
foreach (SkyImageTile* tile, subTiles)
{
tile->deleteLater();
}
subTiles.clear();
}
return;
}
// Propagate
foreach (SkyImageTile* tile, subTiles)
{
tile->deleteUnusedTiles(lastDrawTrigger);
} }
}
void SkyImageTile::updatePercent(int tot, int toBeLoaded) if (!subTilesUrls.empty())
{
if (tot+toBeLoaded==0)
{ {
if (loadingState==true) res["subTiles"] = subTilesUrls;
{
loadingState=false;
emit(loadingStateChanged(false));
}
return;
} }
int p = (int)(100.f*tot/(tot+toBeLoaded)); return res;
if (p>100)
p=100;
if (p<0)
p=0;
if (p==100 || p==0)
{
if (loadingState==true)
{
loadingState=false;
emit(loadingStateChanged(false));
}
return;
}
else
{
if (loadingState==false)
{
loadingState=true;
emit(loadingStateChanged(true));
}
}
if (p==lastPercent)
return;
lastPercent=p;
emit(percentLoadedChanged(p));
} }
 End of changes. 77 change blocks. 
393 lines changed or deleted 194 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/