Landscape.cpp   Landscape.cpp 
/* /*
* Stellarium * Stellarium
* Copyright (C) 2003 Fabien Chereau * Copyright (C) 2003 Fabien Chereau
* Copyright (C) 2011 Bogdan Marinov * Copyright (C) 2011 Bogdan Marinov
* Copyright (C) 2014-17 Georg Zotti
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
* *
* 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.
skipping to change at line 40 skipping to change at line 41
#include <QDebug> #include <QDebug>
#include <QSettings> #include <QSettings>
#include <QVarLengthArray> #include <QVarLengthArray>
#include <QFile> #include <QFile>
#include <QDir> #include <QDir>
#include <QtAlgorithms> #include <QtAlgorithms>
Landscape::Landscape(float _radius) Landscape::Landscape(float _radius)
: radius(_radius) : radius(_radius)
, id("uninitialized")
, minBrightness(-1.) , minBrightness(-1.)
, landscapeBrightness(1.) , landscapeBrightness(1.)
, lightScapeBrightness(0.) , lightScapeBrightness(0.)
, validLandscape(false) , validLandscape(false)
, rows(20) , rows(20)
, cols(40) , cols(40)
, angleRotateZ(0.) , angleRotateZ(0.)
, angleRotateZOffset(0.) , angleRotateZOffset(0.)
, sinMinAltitudeLimit(-0.035) //sin(-2 degrees)) , sinMinAltitudeLimit(-0.035) //sin(-2 degrees))
, defaultBortleIndex(-1) , defaultBortleIndex(-1)
skipping to change at line 65 skipping to change at line 67
, fontSize(18) , fontSize(18)
{ {
} }
Landscape::~Landscape() Landscape::~Landscape()
{} {}
// Load attributes common to all landscapes // Load attributes common to all landscapes
void Landscape::loadCommon(const QSettings& landscapeIni, const QString& la ndscapeId) void Landscape::loadCommon(const QSettings& landscapeIni, const QString& la ndscapeId)
{ {
id = landscapeId;
name = landscapeIni.value("landscape/name").toString(); name = landscapeIni.value("landscape/name").toString();
author = landscapeIni.value("landscape/author").toString(); author = landscapeIni.value("landscape/author").toString();
description = landscapeIni.value("landscape/description").toString() ; description = landscapeIni.value("landscape/description").toString() ;
description = description.replace(QRegExp("\\\\n\\s*\\\\n"), "<br /> "); description = description.replace(QRegExp("\\\\n\\s*\\\\n"), "<br /> ");
description = description.replace("\\n", " "); description = description.replace("\\n", " ");
if (name.isEmpty()) if (name.isEmpty())
{ {
qWarning() << "No valid landscape definition (no name) found for landscape ID " qWarning() << "No valid landscape definition (no name) found for landscape ID "
<< landscapeId << ". No landscape in use." << endl; << landscapeId << ". No landscape in use." << endl;
validLandscape = false; validLandscape = false;
skipping to change at line 286 skipping to change at line 289
// We have found some file now. // We have found some file now.
QFile file(descFileName); QFile file(descFileName);
if(file.open(QIODevice::ReadOnly | QIODevice::Text)) if(file.open(QIODevice::ReadOnly | QIODevice::Text))
{ {
QTextStream in(&file); QTextStream in(&file);
in.setCodec("UTF-8"); in.setCodec("UTF-8");
while (!in.atEnd()) while (!in.atEnd())
{ {
QString line=in.readLine(); QString line=in.readLine();
// TODO: Read entries, construct vectors, put in lis // Skip comments and all-empty lines (space allowed
t. and ignored)
if (line.startsWith('#')) if (line.startsWith('#') || line.trimmed().isEmpty()
)
continue; continue;
// Read entries, construct vectors, put in list.
QStringList parts=line.split('|'); QStringList parts=line.split('|');
if (parts.count() != 5) if (parts.count() != 5)
{ {
qWarning() << "Invalid line in landscape" << descFileName << ":" << line; qWarning() << "Invalid line in landscape gaz etteer" << descFileName << ":" << line;
continue; continue;
} }
LandscapeLabel newLabel; LandscapeLabel newLabel;
newLabel.name=parts.at(4).trimmed(); newLabel.name=parts.at(4).trimmed();
StelUtils::spheToRect((180.0f-parts.at(0).toFloat()) *M_PI/180.0, parts.at(1).toFloat()*M_PI/180.0, newLabel.featurePoint); StelUtils::spheToRect((180.0f-parts.at(0).toFloat()) *M_PI/180.0, parts.at(1).toFloat()*M_PI/180.0, newLabel.featurePoint);
StelUtils::spheToRect((180.0f-parts.at(0).toFloat() - parts.at(3).toFloat())*M_PI/180.0, (parts.at(1).toFloat() + parts.at(2).t oFloat())*M_PI/180.0, newLabel.labelPoint); StelUtils::spheToRect((180.0f-parts.at(0).toFloat() - parts.at(3).toFloat())*M_PI/180.0, (parts.at(1).toFloat() + parts.at(2).t oFloat())*M_PI/180.0, newLabel.labelPoint);
landscapeLabels.append(newLabel); landscapeLabels.append(newLabel);
//qDebug() << "Added landscape label " << newLabel.n ame; //qDebug() << "Added landscape label " << newLabel.n ame;
} }
file.close(); file.close();
skipping to change at line 322 skipping to change at line 326
// We must reset painter to pure altaz coordinates without pano-base d rotation // We must reset painter to pure altaz coordinates without pano-base d rotation
const StelProjectorP prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff); const StelProjectorP prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
painter->setProjector(prj); painter->setProjector(prj);
QFont font; QFont font;
font.setPixelSize(fontSize); font.setPixelSize(fontSize);
painter->setFont(font); painter->setFont(font);
QFontMetrics fm(font); QFontMetrics fm(font);
painter->setColor(labelColor[0], labelColor[1], labelColor[2], label Fader.getInterstate()*landFader.getInterstate()); painter->setColor(labelColor[0], labelColor[1], labelColor[2], label Fader.getInterstate()*landFader.getInterstate());
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); painter->setBlending(true);
glEnable(GL_BLEND); painter->setLineSmooth(true);
glDisable(GL_TEXTURE_2D);
// OpenGL ES 2.0 doesn't have GL_LINE_SMOOTH. But it looks much bett
er.
#ifdef GL_LINE_SMOOTH
if (QOpenGLContext::currentContext()->format().renderableType()==QSu
rfaceFormat::OpenGL)
glEnable(GL_LINE_SMOOTH);
#endif
for (int i = 0; i < landscapeLabels.size(); ++i) for (int i = 0; i < landscapeLabels.size(); ++i)
{ {
// in case of gravityLabels, we cannot shift-adjust centered placename, sorry! // in case of gravityLabels, we cannot shift-adjust centered placename, sorry!
if (prj->getFlagGravityLabels()) if (prj->getFlagGravityLabels())
{ {
painter->drawText(landscapeLabels.at(i).labelPoint, landscapeLabels.at(i).name, 0, 0, 0, false); painter->drawText(landscapeLabels.at(i).labelPoint, landscapeLabels.at(i).name, 0, 0, 0, false);
} }
else else
{ {
int textWidth=fm.width(landscapeLabels.at(i).name); int textWidth=fm.width(landscapeLabels.at(i).name);
painter->drawText(landscapeLabels.at(i).labelPoint, landscapeLabels.at(i).name, 0, -textWidth/2, 2, true); painter->drawText(landscapeLabels.at(i).labelPoint, landscapeLabels.at(i).name, 0, -textWidth/2, 2, true);
} }
painter->drawGreatCircleArc(landscapeLabels.at(i).featurePoi nt, landscapeLabels.at(i).labelPoint, NULL); painter->drawGreatCircleArc(landscapeLabels.at(i).featurePoi nt, landscapeLabels.at(i).labelPoint, NULL);
} }
#ifdef GL_LINE_SMOOTH painter->setLineSmooth(false);
if (QOpenGLContext::currentContext()->format().renderableType()==QSu painter->setBlending(false);
rfaceFormat::OpenGL)
glDisable(GL_LINE_SMOOTH);
#endif
glDisable(GL_BLEND);
} }
LandscapeOldStyle::LandscapeOldStyle(float _radius) LandscapeOldStyle::LandscapeOldStyle(float _radius)
: Landscape(_radius) : Landscape(_radius)
, sideTexs(NULL) , sideTexs(NULL)
, nbSideTexs(0) , nbSideTexs(0)
, nbSide(0) , nbSide(0)
, sides(NULL) , sides(NULL)
, nbDecorRepeat(0) , nbDecorRepeat(0)
, fogAltAngle(0.) , fogAltAngle(0.)
, fogAngleShift(0.) , fogAngleShift(0.)
, decorAltAngle(0.) , decorAltAngle(0.)
, decorAngleShift(0.) , decorAngleShift(0.)
, groundAngleShift(0.) , groundAngleShift(0.)
, groundAngleRotateZ(0.) , groundAngleRotateZ(0.)
, drawGroundFirst(0) , drawGroundFirst(0)
, tanMode(false) , tanMode(false)
, calibrated(false) , calibrated(false)
, memorySize(sizeof(LandscapeOldStyle)) // start with just the known entries.
{} {}
LandscapeOldStyle::~LandscapeOldStyle() LandscapeOldStyle::~LandscapeOldStyle()
{ {
if (sideTexs) if (sideTexs)
{ {
delete [] sideTexs; delete [] sideTexs;
sideTexs = NULL; sideTexs = NULL;
} }
skipping to change at line 401 skipping to change at line 397
loadCommon(landscapeIni, landscapeId); loadCommon(landscapeIni, landscapeId);
// rows, cols have been loaded already, but with different defaults. // rows, cols have been loaded already, but with different defaults.
// GZ Hey, they are not used altogether! Resolution is constant, bel ow! // GZ Hey, they are not used altogether! Resolution is constant, bel ow!
//rows = landscapeIni.value("landscape/tesselate_rows", 8).toInt(); //rows = landscapeIni.value("landscape/tesselate_rows", 8).toInt();
//cols = landscapeIni.value("landscape/tesselate_cols", 16).toInt(); //cols = landscapeIni.value("landscape/tesselate_cols", 16).toInt();
QString type = landscapeIni.value("landscape/type").toString(); QString type = landscapeIni.value("landscape/type").toString();
if(type != "old_style") if(type != "old_style")
{ {
qWarning() << "Landscape type mismatch for landscape " << la ndscapeId qWarning() << "Landscape type mismatch for landscape " << la ndscapeId
<< ", expected old_style, found " << type << ". No landscape in use."; << ", expected old_style, found " << type << ". No landscape in use.";
validLandscape = 0; validLandscape = false;
return; return;
} }
nbDecorRepeat = landscapeIni.value("landscape/nb_decor_repeat", 1).toInt(); nbDecorRepeat = landscapeIni.value("landscape/nb_decor_repeat", 1).toInt();
fogAltAngle = landscapeIni.value("landscape/fog_alt_angle", 0 .).toFloat(); fogAltAngle = landscapeIni.value("landscape/fog_alt_angle", 0 .).toFloat();
fogAngleShift = landscapeIni.value("landscape/fog_angle_shift", 0.).toFloat(); fogAngleShift = landscapeIni.value("landscape/fog_angle_shift", 0.).toFloat();
decorAltAngle = landscapeIni.value("landscape/decor_alt_angle", 0.).toFloat(); decorAltAngle = landscapeIni.value("landscape/decor_alt_angle", 0.).toFloat();
decorAngleShift = landscapeIni.value("landscape/decor_angle_shift ", 0.).toFloat(); decorAngleShift = landscapeIni.value("landscape/decor_angle_shift ", 0.).toFloat();
angleRotateZ = landscapeIni.value("landscape/decor_angle_rotat ez", 0.).toFloat() * M_PI/180.f; angleRotateZ = landscapeIni.value("landscape/decor_angle_rotat ez", 0.).toFloat() * M_PI/180.f;
groundAngleShift = landscapeIni.value("landscape/ground_angle_shif t", 0.).toFloat() * M_PI/180.f; groundAngleShift = landscapeIni.value("landscape/ground_angle_shif t", 0.).toFloat() * M_PI/180.f;
skipping to change at line 431 skipping to change at line 427
{ {
QString textureKey = QString("landscape/tex%1").arg(i); QString textureKey = QString("landscape/tex%1").arg(i);
QString textureName = landscapeIni.value(textureKey).toStrin g(); QString textureName = landscapeIni.value(textureKey).toStrin g();
const QString texturePath = getTexturePath(textureName, land scapeId); const QString texturePath = getTexturePath(textureName, land scapeId);
sideTexs[i] = StelApp::getInstance().getTextureManager().cre ateTexture(texturePath); sideTexs[i] = StelApp::getInstance().getTextureManager().cre ateTexture(texturePath);
// GZ: To query the textures, also keep an array of QImage*, but only // GZ: To query the textures, also keep an array of QImage*, but only
// if that query is not going to be prevented by the polygon that already has been loaded at that point... // if that query is not going to be prevented by the polygon that already has been loaded at that point...
if ( (!horizonPolygon) && calibrated ) { // for uncalibrated landscapes the texture is currently never queried, so no need to store. if ( (!horizonPolygon) && calibrated ) { // for uncalibrated landscapes the texture is currently never queried, so no need to store.
QImage *image = new QImage(texturePath); QImage *image = new QImage(texturePath);
sidesImages.append(image); // indices identical to t hose in sideTexs sidesImages.append(image); // indices identical to t hose in sideTexs
memorySize+=image->byteCount();
} }
// Also allow light textures. The light textures must cover the same geometry as the sides. It is allowed that not all or even any ligh t textures are present! // Also allow light textures. The light textures must cover the same geometry as the sides. It is allowed that not all or even any ligh t textures are present!
textureKey = QString("landscape/light%1").arg(i); textureKey = QString("landscape/light%1").arg(i);
textureName = landscapeIni.value(textureKey).toString(); textureName = landscapeIni.value(textureKey).toString();
if (textureName.length()) if (textureName.length())
{ {
const QString lightTexturePath = getTexturePath(text ureName, landscapeId); const QString lightTexturePath = getTexturePath(text ureName, landscapeId);
sideTexs[nbSideTexs+i] = StelApp::getInstance().getT extureManager().createTexture(lightTexturePath); sideTexs[nbSideTexs+i] = StelApp::getInstance().getT extureManager().createTexture(lightTexturePath);
if(sideTexs[nbSideTexs+i])
memorySize+=sideTexs[nbSideTexs+i].data()->g
etGlSize();
} }
else else
sideTexs[nbSideTexs+i].clear(); sideTexs[nbSideTexs+i].clear();
} }
if ( (!horizonPolygon) && calibrated ) if ( (!horizonPolygon) && calibrated )
{ {
Q_ASSERT(sidesImages.size()==nbSideTexs); Q_ASSERT(sidesImages.size()==nbSideTexs);
} }
QMap<int, int> texToSide; QMap<int, int> texToSide;
// Init sides parameters // Init sides parameters
skipping to change at line 481 skipping to change at line 480
// old_style landscapes which had a z rotation on the side t extures // old_style landscapes which had a z rotation on the side t extures
// and where side0 did not map to tex0 // and where side0 did not map to tex0
// texToSide is a nasty hack to replace the old behaviour. // texToSide is a nasty hack to replace the old behaviour.
// GZ for V0.13: I put the zrotation to the draw call (like for all other landscapes). // GZ for V0.13: I put the zrotation to the draw call (like for all other landscapes).
// Maybe this can be again simplified? // Maybe this can be again simplified?
texToSide[i] = texnum; texToSide[i] = texnum;
} }
QString groundTexName = landscapeIni.value("landscape/groundtex").to String(); QString groundTexName = landscapeIni.value("landscape/groundtex").to String();
QString groundTexPath = getTexturePath(groundTexName, landscapeId); QString groundTexPath = getTexturePath(groundTexName, landscapeId);
groundTex = StelApp::getInstance().getTextureManager().createTexture (groundTexPath, StelTexture::StelTextureParams(true)); groundTex = StelApp::getInstance().getTextureManager().createTexture (groundTexPath, StelTexture::StelTextureParams(true));
// GZ 2013/11: I don't see any use of this: if (groundTex)
// QString description = landscapeIni.value("landscape/ground").toStrin memorySize+=groundTex.data()->getGlSize();
g();
// //sscanf(description.toLocal8Bit(),"groundtex:%f:%f:%f:%f",&a,&b,&c,
&d);
// QStringList parameters = description.split(':');
// groundTexCoord.tex = groundTex;
// groundTexCoord.texCoords[0] = parameters.at(1).toFloat();
// groundTexCoord.texCoords[1] = parameters.at(2).toFloat();
// groundTexCoord.texCoords[2] = parameters.at(3).toFloat();
// groundTexCoord.texCoords[3] = parameters.at(4).toFloat();
QString fogTexName = landscapeIni.value("landscape/fogtex").toString (); QString fogTexName = landscapeIni.value("landscape/fogtex").toString ();
QString fogTexPath = getTexturePath(fogTexName, landscapeId); QString fogTexPath = getTexturePath(fogTexName, landscapeId);
fogTex = StelApp::getInstance().getTextureManager().createTexture(fo gTexPath, StelTexture::StelTextureParams(true, GL_LINEAR, GL_REPEAT)); fogTex = StelApp::getInstance().getTextureManager().createTexture(fo gTexPath, StelTexture::StelTextureParams(true, GL_LINEAR, GL_REPEAT));
// GZ 2013/11: I don't see any use of this: if (fogTex)
// QString description = landscapeIni.value("landscape/fog").toString() memorySize+=fogTex.data()->getGlSize();
;
// //sscanf(description.toLocal8Bit(),"fogtex:%f:%f:%f:%f",&a,&b,&c,&d)
;
// QStringList parameters = description.split(':');
// fogTexCoord.tex = fogTex;
// fogTexCoord.texCoords[0] = parameters.at(1).toFloat();
// fogTexCoord.texCoords[1] = parameters.at(2).toFloat();
// fogTexCoord.texCoords[2] = parameters.at(3).toFloat();
// fogTexCoord.texCoords[3] = parameters.at(4).toFloat();
// Precompute the vertex arrays for ground display // Precompute the vertex arrays for ground display
// Make slices_per_side=(3<<K) so that the innermost polygon of the fandisk becomes a triangle: // Make slices_per_side=(3<<K) so that the innermost polygon of the fandisk becomes a triangle:
//const int slices_per_side = 3*64/(nbDecorRepeat*nbSide); //const int slices_per_side = 3*64/(nbDecorRepeat*nbSide);
//if (slices_per_side<=0) // GZ: How can negative ever happen? //if (slices_per_side<=0) // GZ: How can negative ever happen?
// slices_per_side = 1; // slices_per_side = 1;
const int slices_per_side = qMax(3*64/(nbDecorRepeat*nbSide), 1); const int slices_per_side = qMax(3*64/(nbDecorRepeat*nbSide), 1);
// draw a fan disk instead of a ordinary disk to that the inner slic es // draw a fan disk instead of a ordinary disk to that the inner slic es
// are not so slender. When they are too slender, culling errors occ ur // are not so slender. When they are too slender, culling errors occ ur
skipping to change at line 529 skipping to change at line 514
slices_inside>>=1; slices_inside>>=1;
} }
StelPainter::computeFanDisk(radius, slices_inside, level, groundVert exArr, groundTexCoordArr); StelPainter::computeFanDisk(radius, slices_inside, level, groundVert exArr, groundTexCoordArr);
// Precompute the vertex arrays for side display. The geometry of th e sides is always a cylinder. // Precompute the vertex arrays for side display. The geometry of th e sides is always a cylinder.
// The texture is split into regular quads. // The texture is split into regular quads.
// GZ: the original code for vertical placement makes unfortunately no sense. There are many approximately-fitted landscapes, though. // GZ: the original code for vertical placement makes unfortunately no sense. There are many approximately-fitted landscapes, though.
// I added a switch "calibrated" for the ini file. If true, it works as this landscape apparently was originally intended, // I added a switch "calibrated" for the ini file. If true, it works as this landscape apparently was originally intended,
// if false (or missing) it uses the original code. // if false (or missing) it uses the original code.
// So I corrected the texture coordinates so that decorAltAngle is t he total vertical angle, decorAngleShift the lower angle, // I corrected the texture coordinates so that decorAltAngle is the total vertical angle, decorAngleShift the lower angle,
// and the texture in between is correctly stretched. // and the texture in between is correctly stretched.
// I located an undocumented switch tan_mode, maybe tan_mode=true me ans cylindrical panorama projection. // I located an undocumented switch tan_mode, maybe tan_mode=true me ans cylindrical panorama projection instead of equirectangular.
// Since V0.13, calibrated&&tanMode also works! // Since V0.13, calibrated&&tanMode also works!
// In calibrated && !tan_mode, the vertical position is computed cor rectly, so that quads off the horizon are larger. // In calibrated && !tan_mode, the vertical position is computed cor rectly, so that quads off the horizon are larger.
// in calibrated && tan_mode, d_z can become a constant because the texture is already predistorted in cylindrical projection. // in calibrated && tan_mode, d_z can become a constant because the texture is already predistorted in cylindrical projection.
static const int stacks = (calibrated ? 16 : 8); // GZ: 8->16, I nee d better precision. static const int stacks = (calibrated ? 16 : 8); // GZ: 8->16, I nee d better precision.
float z0, d_z; float z0, d_z;
if (calibrated) if (calibrated)
{ {
if (tanMode) // cylindrical pano: linear in d_z, simpler. if (tanMode) // cylindrical pano: linear in d_z, simpler.
{ {
z0=radius*std::tan(decorAngleShift*M_PI/180.0f); z0=radius*std::tan(decorAngleShift*M_PI/180.0f);
skipping to change at line 628 skipping to change at line 613
precomputedSides.append(precompSide); precomputedSides.append(precompSide);
if (sideTexs[ti+nbSide]) if (sideTexs[ti+nbSide])
{ {
precompSide.light=true; precompSide.light=true;
precompSide.tex=sideTexs[ti+nbSide]; precompSide.tex=sideTexs[ti+nbSide];
precomputedSides.append(precompSide); // T hese sides are not called by strict index! precomputedSides.append(precompSide); // T hese sides are not called by strict index!
// M ay be 9 for 8 sidetexs plus 1-only light panel // M ay be 9 for 8 sidetexs plus 1-only light panel
} }
} }
} }
//qDebug() << "OldStyleLandscape" << landscapeId << "loaded, mem siz e:" << memorySize;
} }
void LandscapeOldStyle::draw(StelCore* core) void LandscapeOldStyle::draw(StelCore* core)
{ {
StelPainter painter(core->getProjection(StelCore::FrameAltAz, StelCo re::RefractionOff)); StelPainter painter(core->getProjection(StelCore::FrameAltAz, StelCo re::RefractionOff));
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); painter.setBlending(true);
glEnable(GL_BLEND); painter.setCullFace(true);
painter.enableTexture2d(true);
glEnable(GL_CULL_FACE);
if (!validLandscape) if (!validLandscape)
return; return;
if (drawGroundFirst) if (drawGroundFirst)
drawGround(core, painter); drawGround(core, painter);
drawDecor(core, painter, false); drawDecor(core, painter, false);
if (!drawGroundFirst) if (!drawGroundFirst)
drawGround(core, painter); drawGround(core, painter);
drawFog(core, painter); drawFog(core, painter);
// Self-luminous layer (Light pollution etc). This looks striking! // Self-luminous layer (Light pollution etc). This looks striking!
if (lightScapeBrightness>0.0f && illumFader.getInterstate()) if (lightScapeBrightness>0.0f && illumFader.getInterstate())
{ {
glBlendFunc(GL_SRC_ALPHA, GL_ONE); painter.setBlending(true, GL_SRC_ALPHA, GL_ONE);
drawDecor(core, painter, true); drawDecor(core, painter, true);
} }
// If a horizon line also has been defined, draw it. // If a horizon line also has been defined, draw it.
if (horizonPolygon && (horizonPolygonLineColor[0] >= 0)) if (horizonPolygon && (horizonPolygonLineColor[0] >= 0))
{ {
//qDebug() << "drawing line"; //qDebug() << "drawing line";
StelProjector::ModelViewTranformP transfo = core->getAltAzMo delViewTransform(StelCore::RefractionOff); StelProjector::ModelViewTranformP transfo = core->getAltAzMo delViewTransform(StelCore::RefractionOff);
transfo->combine(Mat4d::zrotation(-angleRotateZOffset)); transfo->combine(Mat4d::zrotation(-angleRotateZOffset));
const StelProjectorP prj = core->getProjection(transfo); const StelProjectorP prj = core->getProjection(transfo);
painter.setProjector(prj); painter.setProjector(prj);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); painter.setBlending(true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALP HA);
painter.setColor(horizonPolygonLineColor[0], horizonPolygonL ineColor[1], horizonPolygonLineColor[2], landFader.getInterstate()); painter.setColor(horizonPolygonLineColor[0], horizonPolygonL ineColor[1], horizonPolygonLineColor[2], landFader.getInterstate());
painter.drawSphericalRegion(horizonPolygon.data(), StelPaint er::SphericalPolygonDrawModeBoundary); painter.drawSphericalRegion(horizonPolygon.data(), StelPaint er::SphericalPolygonDrawModeBoundary);
} }
//else qDebug() << "no polygon defined"; //else qDebug() << "no polygon defined";
drawLabels(core, &painter); drawLabels(core, &painter);
} }
// Draw the horizon fog // Draw the horizon fog
void LandscapeOldStyle::drawFog(StelCore* core, StelPainter& sPainter) cons t void LandscapeOldStyle::drawFog(StelCore* core, StelPainter& sPainter) cons t
skipping to change at line 689 skipping to change at line 673
return; return;
const float vpos = (tanMode||calibrated) ? radius*std::tan(fogAngleS hift*M_PI/180.) : radius*std::sin(fogAngleShift*M_PI/180.); const float vpos = (tanMode||calibrated) ? radius*std::tan(fogAngleS hift*M_PI/180.) : radius*std::sin(fogAngleShift*M_PI/180.);
StelProjector::ModelViewTranformP transfo = core->getAltAzModelViewT ransform(StelCore::RefractionOff); StelProjector::ModelViewTranformP transfo = core->getAltAzModelViewT ransform(StelCore::RefractionOff);
if (calibrated) // new in V0.13: take proper care of the fog layer. This will work perfectly only for calibrated&&tanMode. if (calibrated) // new in V0.13: take proper care of the fog layer. This will work perfectly only for calibrated&&tanMode.
transfo->combine(Mat4d::zrotation(-(angleRotateZ+angleRotate ZOffset))); transfo->combine(Mat4d::zrotation(-(angleRotateZ+angleRotate ZOffset)));
transfo->combine(Mat4d::translation(Vec3d(0.,0.,vpos))); transfo->combine(Mat4d::translation(Vec3d(0.,0.,vpos)));
sPainter.setProjector(core->getProjection(transfo)); sPainter.setProjector(core->getProjection(transfo));
glBlendFunc(GL_ONE, GL_ONE); sPainter.setBlending(true, GL_ONE, GL_ONE);
sPainter.setColor(landFader.getInterstate()*fogFader.getInterstate() *(0.1f+0.1f*landscapeBrightness), sPainter.setColor(landFader.getInterstate()*fogFader.getInterstate() *(0.1f+0.1f*landscapeBrightness),
landFader.getInterstate()*fogFader.getInterstate() *(0.1f+0.1f*landscapeBrightness), landFader.getInterstate()*fogFader.getInterstate() *(0.1f+0.1f*landscapeBrightness),
landFader.getInterstate()*fogFader.getInterstate() *(0.1f+0.1f*landscapeBrightness), landFader.getInterstate()); landFader.getInterstate()*fogFader.getInterstate() *(0.1f+0.1f*landscapeBrightness), landFader.getInterstate());
fogTex->bind(); fogTex->bind();
const float height = (calibrated? const float height = (calibrated?
radius*(std::tan((fogAltAngle+fogAngleShift) *M_PI/180.) - std::tan(fogAngleShift*M_PI/180.)) radius*(std::tan((fogAltAngle+fogAngleShift) *M_PI/180.) - std::tan(fogAngleShift*M_PI/180.))
: ((tanMode) ? radius*std::tan(fogAltAngle*M _PI/180.) : radius*std::sin(fogAltAngle*M_PI/180.))); : ((tanMode) ? radius*std::tan(fogAltAngle*M _PI/180.) : radius*std::sin(fogAltAngle*M_PI/180.)));
sPainter.sCylinder(radius, height, 64, 1); sPainter.sCylinder(radius, height, 64, 1);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); sPainter.setBlending(true);
} }
// Draw the side textures // Draw the side textures
void LandscapeOldStyle::drawDecor(StelCore* core, StelPainter& sPainter, co nst bool drawLight) const void LandscapeOldStyle::drawDecor(StelCore* core, StelPainter& sPainter, co nst bool drawLight) const
{ {
StelProjector::ModelViewTranformP transfo = core->getAltAzModelViewT ransform(StelCore::RefractionOff); StelProjector::ModelViewTranformP transfo = core->getAltAzModelViewT ransform(StelCore::RefractionOff);
transfo->combine(Mat4d::zrotation(-(angleRotateZ+angleRotateZOffset) )); transfo->combine(Mat4d::zrotation(-(angleRotateZ+angleRotateZOffset) ));
sPainter.setProjector(core->getProjection(transfo)); sPainter.setProjector(core->getProjection(transfo));
if (!landFader.getInterstate()) if (!landFader.getInterstate())
skipping to change at line 757 skipping to change at line 741
} }
float LandscapeOldStyle::getOpacity(Vec3d azalt) const float LandscapeOldStyle::getOpacity(Vec3d azalt) const
{ {
if (angleRotateZOffset!=0.0f) if (angleRotateZOffset!=0.0f)
azalt.transfo4d(Mat4d::zrotation(angleRotateZOffset)); azalt.transfo4d(Mat4d::zrotation(angleRotateZOffset));
// in case we also have a horizon polygon defined, this is trivial a nd fast. // in case we also have a horizon polygon defined, this is trivial a nd fast.
if (horizonPolygon) if (horizonPolygon)
{ {
if (horizonPolygon->contains(azalt) ) return 1.0f; else return 0.0f; if (horizonPolygon->contains(azalt)) return 1.0f; else retur n 0.0f;
} }
// Else, sample the images... // Else, sample the images...
const float alt_rad = std::asin(azalt[2]); // sampled altitude, rad float az, alt_rad;
ians StelUtils::rectToSphe(&az, &alt_rad, azalt);
if (alt_rad < decorAngleShift*M_PI/180.0f) return 1.0f; // below dec or, i.e. certainly opaque ground. if (alt_rad < decorAngleShift*M_PI/180.0f) return 1.0f; // below dec or, i.e. certainly opaque ground.
if (alt_rad > (decorAltAngle+decorAngleShift)*M_PI/180.0f) return 0. 0f; // above decor, i.e. certainly free sky. if (alt_rad > (decorAltAngle+decorAngleShift)*M_PI/180.0f) return 0. 0f; // above decor, i.e. certainly free sky.
if (!calibrated) // the result of this function has no real use here : just complain and return result for math. horizon. if (!calibrated) // the result of this function has no real use here : just complain and return result for math. horizon.
{ {
static QString lastLandscapeName; static QString lastLandscapeName;
if (lastLandscapeName != name) if (lastLandscapeName != name)
{ {
qWarning() << "Dubious result: Landscape " << name < < " not calibrated. Opacity test represents mathematical horizon only."; qWarning() << "Dubious result: Landscape " << name < < " not calibrated. Opacity test represents mathematical horizon only.";
lastLandscapeName=name; lastLandscapeName=name;
} }
return (azalt[2] > 0 ? 0.0f : 1.0f); return (azalt[2] > 0 ? 0.0f : 1.0f);
} }
float az=atan2(azalt[0], azalt[1]) / M_PI + 0.5f; // -0.5..+1.5 az = (M_PI-az) / M_PI; // 0..2 = N.E.S.
if (az<0) az+=2.0f; // 0..2 = N.E.S. W.N
W.N
// we go to 0..1 domain, it's easier to think. // we go to 0..1 domain, it's easier to think.
const float xShift=angleRotateZ /(2.0f*M_PI); // shift value in -1.. 1 const float xShift=angleRotateZ /(2.0f*M_PI); // shift value in -1.. 1 domain
Q_ASSERT(xShift >= -1.0f); Q_ASSERT(xShift >= -1.0f);
Q_ASSERT(xShift <= 1.0f); Q_ASSERT(xShift <= 1.0f);
float az_phot=az*0.5f - 0.25f - xShift; // The 0.25 is caused b y regular pano left edge being East. The xShift compensates any configured angleRotateZ float az_phot=az*0.5f - 0.25f - xShift; // The 0.25 is caused b y regular pano left edge being East. The xShift compensates any configured angleRotateZ
az_phot=fmodf(az_phot, 1.0f); az_phot=fmodf(az_phot, 1.0f);
if (az_phot<0) az_phot+=1.0f; // 0.. 1 = image-X for a non-repeating pano photo if (az_phot<0) az_phot+=1.0f; // 0.. 1 = image-X for a non-repeating pano photo
float az_panel = nbSide*nbDecorRepeat * az_phot; // azimuth in "pan el space". Ex for nbS=4, nbDR=3: [0..[12, say 11.4 float az_panel = nbSide*nbDecorRepeat * az_phot; // azimuth in "pan el space". Ex for nbS=4, nbDR=3: [0..[12, say 11.4
float x_in_panel=fmodf(az_panel, 1.0f); float x_in_panel=fmodf(az_panel, 1.0f);
int currentSide = (int) floor(fmodf(az_panel, nbSide)); int currentSide = (int) floor(fmodf(az_panel, nbSide));
Q_ASSERT(currentSide>=0); Q_ASSERT(currentSide>=0);
Q_ASSERT(currentSide<nbSideTexs); Q_ASSERT(currentSide<nbSideTexs);
skipping to change at line 810 skipping to change at line 795
} }
else else
{ // adapted from spherical... { // adapted from spherical...
const float alt_pm1 = 2.0f * alt_rad / M_PI; // sampled al titude, -1...+1 linear in altitude angle const float alt_pm1 = 2.0f * alt_rad / M_PI; // sampled al titude, -1...+1 linear in altitude angle
const float img_top_pm1 = 1.0f-( (90.0f-decorAltAngle-decorA ngleShift) / 90.0f); // the top line in -1..+1 (angular) const float img_top_pm1 = 1.0f-( (90.0f-decorAltAngle-decorA ngleShift) / 90.0f); // the top line in -1..+1 (angular)
if (alt_pm1>img_top_pm1) { Q_ASSERT(0); return 0.0f; } // sh ould have been caught above with alt_rad tests if (alt_pm1>img_top_pm1) { Q_ASSERT(0); return 0.0f; } // sh ould have been caught above with alt_rad tests
const float img_bot_pm1 = 1.0f-((90.0f-decorAngleShift) / 90 .0f); // the bottom line in -1..+1 (angular) const float img_bot_pm1 = 1.0f-((90.0f-decorAngleShift) / 90 .0f); // the bottom line in -1..+1 (angular)
if (alt_pm1<img_bot_pm1) { Q_ASSERT(0); return 1.0f; } // sh ould have been caught above with alt_rad tests if (alt_pm1<img_bot_pm1) { Q_ASSERT(0); return 1.0f; } // sh ould have been caught above with alt_rad tests
y_img_1=(alt_pm1-img_bot_pm1)/(img_top_pm1-img_bot_pm1); // the sampled altitude in 0..1 visible image height from bottom y_img_1=(alt_pm1-img_bot_pm1)/(img_top_pm1-img_bot_pm1); // the sampled altitude in 0..1 visible image height from bottom
Q_ASSERT(y_img_1<=1.f);
Q_ASSERT(y_img_1>=0.f);
} }
// x0/y0 is lower left, x1/y1 upper right corner. // x0/y0 is lower left, x1/y1 upper right corner.
float y_baseImg_1 = sides[currentSide].texCoords[1]+ y_img_1*(sides[ currentSide].texCoords[3]-sides[currentSide].texCoords[1]); float y_baseImg_1 = sides[currentSide].texCoords[1]+ y_img_1*(sides[ currentSide].texCoords[3]-sides[currentSide].texCoords[1]);
int y=(1.0-y_baseImg_1)*sidesImages[currentSide]->height(); // pixel Y from top. int y=(1.0-y_baseImg_1)*sidesImages[currentSide]->height(); // pixel Y from top.
QRgb pixVal=sidesImages[currentSide]->pixel(x, y); QRgb pixVal=sidesImages[currentSide]->pixel(x, y);
/* /*
#ifndef NDEBUG #ifndef NDEBUG
// GZ: please leave the comment available for further development! // GZ: please leave the comment available for further development!
qDebug() << "Oldstyle Landscape sampling: az=" << az*180.0 << "° alt =" << alt_rad*180.0f/M_PI qDebug() << "Oldstyle Landscape sampling: az=" << az*180.0 << "° alt =" << alt_rad*180.0f/M_PI
<< "°, xShift[-1..+1]=" << xShift << " az_phot[0..1 ]=" << az_phot << "°, xShift[-1..+1]=" << xShift << " az_phot[0..1 ]=" << az_phot
skipping to change at line 846 skipping to change at line 833
} }
void LandscapePolygonal::load(const QSettings& landscapeIni, const QString& landscapeId) void LandscapePolygonal::load(const QSettings& landscapeIni, const QString& landscapeId)
{ {
// loading the polygon has been moved to Landscape::loadCommon(), so that all Landscape classes can use a polygon line. // loading the polygon has been moved to Landscape::loadCommon(), so that all Landscape classes can use a polygon line.
loadCommon(landscapeIni, landscapeId); loadCommon(landscapeIni, landscapeId);
QString type = landscapeIni.value("landscape/type").toString(); QString type = landscapeIni.value("landscape/type").toString();
if(type != "polygonal") if(type != "polygonal")
{ {
qWarning() << "Landscape type mismatch for landscape "<< lan dscapeId << ", expected polygonal, found " << type << ". No landscape in u se.\n"; qWarning() << "Landscape type mismatch for landscape "<< lan dscapeId << ", expected polygonal, found " << type << ". No landscape in u se.\n";
validLandscape = 0; validLandscape = false;
return; return;
} }
if (horizonPolygon.isNull()) if (horizonPolygon.isNull())
{ {
qWarning() << "Landscape " << landscapeId << " does not decl are a valid polygonal_horizon_list. No landscape in use.\n"; qWarning() << "Landscape " << landscapeId << " does not decl are a valid polygonal_horizon_list. No landscape in use.\n";
validLandscape = 0; validLandscape = false;
return; return;
} }
groundColor=StelUtils::strToVec3f( landscapeIni.value("landscape/gro und_color", "0,0,0" ).toString() ); groundColor=StelUtils::strToVec3f( landscapeIni.value("landscape/gro und_color", "0,0,0" ).toString() );
validLandscape = 1; // assume ok... validLandscape = true; // assume ok...
//qDebug() << "PolygonalLandscape" << landscapeId << "loaded, mem si
ze:" << getMemorySize();
} }
void LandscapePolygonal::draw(StelCore* core) void LandscapePolygonal::draw(StelCore* core)
{ {
if(!validLandscape) return; if(!validLandscape) return;
if(!landFader.getInterstate()) return; if(!landFader.getInterstate()) return;
StelProjector::ModelViewTranformP transfo = core->getAltAzModelViewT ransform(StelCore::RefractionOff); StelProjector::ModelViewTranformP transfo = core->getAltAzModelViewT ransform(StelCore::RefractionOff);
transfo->combine(Mat4d::zrotation(-angleRotateZOffset)); transfo->combine(Mat4d::zrotation(-angleRotateZOffset));
const StelProjectorP prj = core->getProjection(transfo); const StelProjectorP prj = core->getProjection(transfo);
StelPainter sPainter(prj); StelPainter sPainter(prj);
// Normal transparency mode for the transition blending // Normal transparency mode for the transition blending
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); sPainter.setBlending(true);
glEnable(GL_CULL_FACE); sPainter.setCullFace(true);
glEnable(GL_BLEND);
//#ifdef GL_POLYGON_SMOOTH
// OpenGL ES 2.0 doesn't have GL_LINE_SMOOTH. Anyway, Polygon smooth
ing makes the triangles visible. May be Interesting for debugging only.
//if (QOpenGLContext::currentContext()->format().renderableType()==Q
SurfaceFormat::OpenGL)
// glEnable(GL_POLYGON_SMOOTH);
//#endif
sPainter.setColor(landscapeBrightness*groundColor[0], landscapeBrigh tness*groundColor[1], landscapeBrightness*groundColor[2], landFader.getInte rstate()); sPainter.setColor(landscapeBrightness*groundColor[0], landscapeBrigh tness*groundColor[1], landscapeBrightness*groundColor[2], landFader.getInte rstate());
sPainter.drawSphericalRegion(horizonPolygon.data(), StelPainter::Sph ericalPolygonDrawModeFill); sPainter.drawSphericalRegion(horizonPolygon.data(), StelPainter::Sph ericalPolygonDrawModeFill);
//#ifdef GL_POLYGON_SMOOTH
//if (QOpenGLContext::currentContext()->format().renderableType()==Q
SurfaceFormat::OpenGL)
// glDisable(GL_POLYGON_SMOOTH);
//#endif
if (horizonPolygonLineColor[0] >= 0) if (horizonPolygonLineColor[0] >= 0)
{ {
// OpenGL ES 2.0 doesn't have GL_LINE_SMOOTH sPainter.setLineSmooth(true);
#ifdef GL_LINE_SMOOTH
if (QOpenGLContext::currentContext()->format().renderableTyp
e()==QSurfaceFormat::OpenGL)
glEnable(GL_LINE_SMOOTH);
#endif
sPainter.setColor(horizonPolygonLineColor[0], horizonPolygon LineColor[1], horizonPolygonLineColor[2], landFader.getInterstate()); sPainter.setColor(horizonPolygonLineColor[0], horizonPolygon LineColor[1], horizonPolygonLineColor[2], landFader.getInterstate());
sPainter.drawSphericalRegion(horizonPolygon.data(), StelPain ter::SphericalPolygonDrawModeBoundary); sPainter.drawSphericalRegion(horizonPolygon.data(), StelPain ter::SphericalPolygonDrawModeBoundary);
#ifdef GL_LINE_SMOOTH sPainter.setLineSmooth(false);
if (QOpenGLContext::currentContext()->format().renderableTyp
e()==QSurfaceFormat::OpenGL)
glDisable(GL_LINE_SMOOTH);
#endif
} }
glDisable(GL_CULL_FACE); sPainter.setCullFace(false);
drawLabels(core, &sPainter); drawLabels(core, &sPainter);
} }
float LandscapePolygonal::getOpacity(Vec3d azalt) const float LandscapePolygonal::getOpacity(Vec3d azalt) const
{ {
if (angleRotateZOffset!=0.0f) if (angleRotateZOffset!=0.0f)
azalt.transfo4d(Mat4d::zrotation(angleRotateZOffset)); azalt.transfo4d(Mat4d::zrotation(angleRotateZOffset));
if (horizonPolygon->contains(azalt) ) return 1.0f; else return 0 .0f; if (horizonPolygon->contains(azalt)) return 1.0f; else return 0.0f;
} }
/////////////////////////////////////////////////////////////////////////// ///////////// /////////////////////////////////////////////////////////////////////////// /////////////
// LandscapeFisheye // LandscapeFisheye
// //
LandscapeFisheye::LandscapeFisheye(float _radius) LandscapeFisheye::LandscapeFisheye(float _radius)
: Landscape(_radius) : Landscape(_radius)
, mapTex(StelTextureSP())
, mapTexFog(StelTextureSP())
, mapTexIllum(StelTextureSP())
, mapImage(NULL) , mapImage(NULL)
, texFov(360.) , texFov(360.)
, memorySize(0)
{} {}
LandscapeFisheye::~LandscapeFisheye() LandscapeFisheye::~LandscapeFisheye()
{ {
if (mapImage) delete mapImage; if (mapImage) delete mapImage;
landscapeLabels.clear(); landscapeLabels.clear();
} }
void LandscapeFisheye::load(const QSettings& landscapeIni, const QString& l andscapeId) void LandscapeFisheye::load(const QSettings& landscapeIni, const QString& l andscapeId)
{ {
loadCommon(landscapeIni, landscapeId); loadCommon(landscapeIni, landscapeId);
QString type = landscapeIni.value("landscape/type").toString(); QString type = landscapeIni.value("landscape/type").toString();
if(type != "fisheye") if(type != "fisheye")
{ {
qWarning() << "Landscape type mismatch for landscape "<< lan dscapeId << ", expected fisheye, found " << type << ". No landscape in use .\n"; qWarning() << "Landscape type mismatch for landscape "<< lan dscapeId << ", expected fisheye, found " << type << ". No landscape in use .\n";
validLandscape = 0; validLandscape = false;
return; return;
} }
create(name, create(name,
landscapeIni.value("landscape/texturefov", 360).toFloat(), landscapeIni.value("landscape/texturefov", 360).toFloat(),
getTexturePath(landscapeIni.value("landscape/maptex").toStrin g(), landscapeId), getTexturePath(landscapeIni.value("landscape/maptex").toStrin g(), landscapeId),
getTexturePath(landscapeIni.value("landscape/maptex_fog").toS tring(), landscapeId), getTexturePath(landscapeIni.value("landscape/maptex_fog").toS tring(), landscapeId),
getTexturePath(landscapeIni.value("landscape/maptex_illum").t oString(), landscapeId), getTexturePath(landscapeIni.value("landscape/maptex_illum").t oString(), landscapeId),
landscapeIni.value("landscape/angle_rotatez", 0.f).toFloat()) ; landscapeIni.value("landscape/angle_rotatez", 0.f).toFloat()) ;
//qDebug() << "FisheyeLandscape" << landscapeId << "loaded, mem size :" << memorySize;
} }
void LandscapeFisheye::create(const QString _name, float _texturefov, const QString& _maptex, const QString &_maptexFog, const QString& _maptexIllum, const float _angleRotateZ) void LandscapeFisheye::create(const QString _name, float _texturefov, const QString& _maptex, const QString &_maptexFog, const QString& _maptexIllum, const float _angleRotateZ)
{ {
// qDebug() << _name << " " << _fullpath << " " << _maptex << " " << _texturefov; // qDebug() << _name << " " << _fullpath << " " << _maptex << " " << _texturefov;
validLandscape = 1; // assume ok... validLandscape = true; // assume ok...
name = _name; name = _name;
texFov = _texturefov*M_PI/180.f; texFov = _texturefov*M_PI/180.f;
angleRotateZ = _angleRotateZ*M_PI/180.f; angleRotateZ = _angleRotateZ*M_PI/180.f;
if (!horizonPolygon) if (!horizonPolygon)
{
mapImage = new QImage(_maptex); mapImage = new QImage(_maptex);
memorySize+=mapImage->byteCount();
}
mapTex = StelApp::getInstance().getTextureManager().createTexture(_m aptex, StelTexture::StelTextureParams(true)); mapTex = StelApp::getInstance().getTextureManager().createTexture(_m aptex, StelTexture::StelTextureParams(true));
memorySize+=mapTex.data()->getGlSize();
if (_maptexIllum.length()) if (_maptexIllum.length() && (!_maptexIllum.endsWith("/")))
{
mapTexIllum = StelApp::getInstance().getTextureManager().cre ateTexture(_maptexIllum, StelTexture::StelTextureParams(true)); mapTexIllum = StelApp::getInstance().getTextureManager().cre ateTexture(_maptexIllum, StelTexture::StelTextureParams(true));
if (_maptexFog.length()) if (mapTexIllum)
memorySize+=mapTexIllum.data()->getGlSize();
}
if (_maptexFog.length() && (!_maptexFog.endsWith("/")))
{
mapTexFog = StelApp::getInstance().getTextureManager().creat eTexture(_maptexFog, StelTexture::StelTextureParams(true)); mapTexFog = StelApp::getInstance().getTextureManager().creat eTexture(_maptexFog, StelTexture::StelTextureParams(true));
if (mapTexFog)
memorySize+=mapTexFog.data()->getGlSize();
}
} }
void LandscapeFisheye::draw(StelCore* core) void LandscapeFisheye::draw(StelCore* core)
{ {
if(!validLandscape) return; if(!validLandscape) return;
if(!landFader.getInterstate()) return; if(!landFader.getInterstate()) return;
StelProjector::ModelViewTranformP transfo = core->getAltAzModelViewT ransform(StelCore::RefractionOff); StelProjector::ModelViewTranformP transfo = core->getAltAzModelViewT ransform(StelCore::RefractionOff);
transfo->combine(Mat4d::zrotation(-(angleRotateZ+angleRotateZOffset) )); transfo->combine(Mat4d::zrotation(-(angleRotateZ+angleRotateZOffset) ));
const StelProjectorP prj = core->getProjection(transfo); const StelProjectorP prj = core->getProjection(transfo);
StelPainter sPainter(prj); StelPainter sPainter(prj);
// Normal transparency mode // Normal transparency mode
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); sPainter.setBlending(true);
sPainter.setCullFace(true);
sPainter.setColor(landscapeBrightness, landscapeBrightness, landscap eBrightness, landFader.getInterstate()); sPainter.setColor(landscapeBrightness, landscapeBrightness, landscap eBrightness, landFader.getInterstate());
glEnable(GL_CULL_FACE);
sPainter.enableTexture2d(true);
glEnable(GL_BLEND);
mapTex->bind(); mapTex->bind();
sPainter.sSphereMap(radius,cols,rows,texFov,1); sPainter.sSphereMap(radius,cols,rows,texFov,1);
// NEW since 0.13: Fog also for fisheye... // NEW since 0.13: Fog also for fisheye...
if ((mapTexFog) && (core->getSkyDrawer()->getFlagHasAtmosphere())) if ((mapTexFog) && (core->getSkyDrawer()->getFlagHasAtmosphere()))
{ {
//glBlendFunc(GL_ONE, GL_ONE); // GZ: Take blending mode as found in the old_style landscapes... //glBlendFunc(GL_ONE, GL_ONE); // GZ: Take blending mode as found in the old_style landscapes...
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); // GZ: better? sPainter.setBlending(true, GL_ONE, GL_ONE_MINUS_SRC_COLOR); // GZ: better?
sPainter.setColor(landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness), sPainter.setColor(landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness),
landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness), landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness),
landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness), landFader.getInterstate()); landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness), landFader.getInterstate());
mapTexFog->bind(); mapTexFog->bind();
sPainter.sSphereMap(radius,cols,rows,texFov,1); sPainter.sSphereMap(radius,cols,rows,texFov,1);
} }
if (mapTexIllum && lightScapeBrightness>0.0f && illumFader.getInters tate()) if (mapTexIllum && lightScapeBrightness>0.0f && illumFader.getInters tate())
{ {
glBlendFunc(GL_SRC_ALPHA, GL_ONE); sPainter.setBlending(true, GL_SRC_ALPHA, GL_ONE);
sPainter.setColor(illumFader.getInterstate()*lightScapeBrigh tness, sPainter.setColor(illumFader.getInterstate()*lightScapeBrigh tness,
illumFader.getInterstate()*lightScapeBrigh tness, illumFader.getInterstate()*lightScapeBrigh tness,
illumFader.getInterstate()*lightScapeBrigh tness, landFader.getInterstate()); illumFader.getInterstate()*lightScapeBrigh tness, landFader.getInterstate());
mapTexIllum->bind(); mapTexIllum->bind();
sPainter.sSphereMap(radius, cols, rows, texFov, 1); sPainter.sSphereMap(radius, cols, rows, texFov, 1);
} }
glDisable(GL_CULL_FACE); sPainter.setCullFace(false);
drawLabels(core, &sPainter); drawLabels(core, &sPainter);
} }
float LandscapeFisheye::getOpacity(Vec3d azalt) const float LandscapeFisheye::getOpacity(Vec3d azalt) const
{ {
if (angleRotateZOffset!=0.0f) if (angleRotateZOffset!=0.0f)
azalt.transfo4d(Mat4d::zrotation(angleRotateZOffset)); azalt.transfo4d(Mat4d::zrotation(angleRotateZOffset));
// in case we also have a horizon polygon defined, this is trivial a nd fast. // in case we also have a horizon polygon defined, this is trivial a nd fast.
if (horizonPolygon) if (horizonPolygon)
{ {
if (horizonPolygon->contains(azalt) ) return 1.0f; else return 0.0f; if (horizonPolygon->contains(azalt)) return 1.0f; else retur n 0.0f;
} }
// Else, sample the image... // Else, sample the image...
float az, alt_rad;
StelUtils::rectToSphe(&az, &alt_rad, azalt);
// QImage has pixel 0/0 in top left corner. // QImage has pixel 0/0 in top left corner.
// The texture is taken from the center circle in the square texture . // The texture is taken from the center circle in the square texture .
// It is possible that sample position is outside. in this case, ass ume full opacity and exit early. // It is possible that sample position is outside. in this case, ass ume full opacity and exit early.
const float alt_rad = std::asin(azalt[2]); // sampled altitude, rad if (M_PI/2-alt_rad > texFov/2.0f ) return 1.0f; // outside fov, in t
ians he clamped texture zone: always opaque.
if (M_PI/2-alt_rad > texFov/2.0 ) return 1.0; // outside fov, in the
clamped texture zone: always opaque.
float radius=(M_PI/2-alt_rad)*2.0f/texFov; // radius in units of map Image.height/2 float radius=(M_PI/2-alt_rad)*2.0f/texFov; // radius in units of map Image.height/2
float az=atan2(azalt[0], azalt[1]) + M_PI/2 - angleRotateZ; // -pi/2 ..+3pi/2, real azimuth. NESW az = (M_PI-az) - angleRotateZ; // 0..+2pi -angleRotateZ, real azimut h. NESW
// The texture map has south on top, east at right (if anglerotateZ =0) // The texture map has south on top, east at right (if anglerotateZ =0)
int x= mapImage->height()/2*(1 + radius*std::sin(az)); int x= mapImage->height()/2*(1 + radius*std::sin(az));
int y= mapImage->height()/2*(1 + radius*std::cos(az)); int y= mapImage->height()/2*(1 + radius*std::cos(az));
QRgb pixVal=mapImage->pixel(x, y); QRgb pixVal=mapImage->pixel(x, y);
/* /*
#ifndef NDEBUG #ifndef NDEBUG
// GZ: please leave the comment available for further development! // GZ: please leave the comment available for further development!
qDebug() << "Landscape sampling: az=" << (az+angleRotateZ)/M_PI*180. 0f << "° alt=" << alt_rad/M_PI*180.f qDebug() << "Landscape sampling: az=" << (az+angleRotateZ)/M_PI*180. 0f << "° alt=" << alt_rad/M_PI*180.f
<< "°, w=" << mapImage->width() << " h=" << mapImag e->height() << "°, w=" << mapImage->width() << " h=" << mapImag e->height()
skipping to change at line 1050 skipping to change at line 1038
#endif #endif
*/ */
return qAlpha(pixVal)/255.0f; return qAlpha(pixVal)/255.0f;
} }
/////////////////////////////////////////////////////////////////////////// ////////////////////// /////////////////////////////////////////////////////////////////////////// //////////////////////
// spherical panoramas // spherical panoramas
LandscapeSpherical::LandscapeSpherical(float _radius) LandscapeSpherical::LandscapeSpherical(float _radius)
: Landscape(_radius) : Landscape(_radius)
, mapTex(StelTextureSP())
, mapTexFog(StelTextureSP())
, mapTexIllum(StelTextureSP())
, mapTexTop(0.) , mapTexTop(0.)
, mapTexBottom(0.) , mapTexBottom(0.)
, fogTexTop(0.) , fogTexTop(0.)
, fogTexBottom(0.) , fogTexBottom(0.)
, illumTexTop(0.) , illumTexTop(0.)
, illumTexBottom(0.) , illumTexBottom(0.)
, mapImage(NULL) , mapImage(NULL)
, memorySize(sizeof(LandscapeSpherical))
{} {}
LandscapeSpherical::~LandscapeSpherical() LandscapeSpherical::~LandscapeSpherical()
{ {
if (mapImage) delete mapImage; if (mapImage) delete mapImage;
landscapeLabels.clear(); landscapeLabels.clear();
} }
void LandscapeSpherical::load(const QSettings& landscapeIni, const QString& landscapeId) void LandscapeSpherical::load(const QSettings& landscapeIni, const QString& landscapeId)
{ {
skipping to change at line 1079 skipping to change at line 1071
// qDebug() << "This landscape, " << landscapeId << ", has a po lygon defined!" ; // qDebug() << "This landscape, " << landscapeId << ", has a po lygon defined!" ;
// else // else
// qDebug() << "This landscape, " << landscapeId << ", has no p olygon defined!" ; // qDebug() << "This landscape, " << landscapeId << ", has no p olygon defined!" ;
QString type = landscapeIni.value("landscape/type").toString(); QString type = landscapeIni.value("landscape/type").toString();
if (type != "spherical") if (type != "spherical")
{ {
qWarning() << "Landscape type mismatch for landscape "<< lan dscapeId qWarning() << "Landscape type mismatch for landscape "<< lan dscapeId
<< ", expected spherical, found " << type << ", expected spherical, found " << type
<< ". No landscape in use.\n"; << ". No landscape in use.\n";
validLandscape = 0; validLandscape = false;
return; return;
} }
create(name, create(name,
getTexturePath(landscapeIni.value("landscape/maptex").toStrin g(), landscapeId), getTexturePath(landscapeIni.value("landscape/maptex").toStrin g(), landscapeId),
getTexturePath(landscapeIni.value("landscape/maptex_fog").toS tring(), landscapeId), getTexturePath(landscapeIni.value("landscape/maptex_fog").toS tring(), landscapeId),
getTexturePath(landscapeIni.value("landscape/maptex_illum").t oString(), landscapeId), getTexturePath(landscapeIni.value("landscape/maptex_illum").t oString(), landscapeId),
landscapeIni.value("landscape/angle_rotatez" , 0.f).to Float(), landscapeIni.value("landscape/angle_rotatez" , 0.f).to Float(),
landscapeIni.value("landscape/maptex_top" , 90.f).to Float(), landscapeIni.value("landscape/maptex_top" , 90.f).to Float(),
landscapeIni.value("landscape/maptex_bottom" , -90.f).to Float(), landscapeIni.value("landscape/maptex_bottom" , -90.f).to Float(),
landscapeIni.value("landscape/maptex_fog_top" , 90.f).to Float(), landscapeIni.value("landscape/maptex_fog_top" , 90.f).to Float(),
landscapeIni.value("landscape/maptex_fog_bottom" , -90.f).to Float(), landscapeIni.value("landscape/maptex_fog_bottom" , -90.f).to Float(),
landscapeIni.value("landscape/maptex_illum_top" , 90.f).to Float(), landscapeIni.value("landscape/maptex_illum_top" , 90.f).to Float(),
landscapeIni.value("landscape/maptex_illum_bottom", -90.f).to Float()); landscapeIni.value("landscape/maptex_illum_bottom", -90.f).to Float());
//qDebug() << "SphericalLandscape" << landscapeId << "loaded, mem si ze:" << memorySize;
} }
//// create a spherical landscape from basic parameters (no ini file needed ) //// create a spherical landscape from basic parameters (no ini file needed )
void LandscapeSpherical::create(const QString _name, const QString& _maptex , const QString& _maptexFog, const QString& _maptexIllum, const float _angl eRotateZ, void LandscapeSpherical::create(const QString _name, const QString& _maptex , const QString& _maptexFog, const QString& _maptexIllum, const float _angl eRotateZ,
const float _mapTexTop, const float _mapTexBottom, const float _mapTexTop, const float _mapTexBottom,
const float _fogTexTop, const float _fogTexBottom, const float _fogTexTop, const float _fogTexBottom,
const float _illumTexTop, const float _illumTexBottom) const float _illumTexTop, const float _illumTexBottom)
{ {
//qDebug() << "LandscapeSpherical::create():"<< _name << " : " << _m aptex << " : " << _maptexFog << " : " << _maptexIllum << " : " << _angleRot ateZ; //qDebug() << "LandscapeSpherical::create():"<< _name << " : " << _m aptex << " : " << _maptexFog << " : " << _maptexIllum << " : " << _angleRot ateZ;
validLandscape = 1; // assume ok... validLandscape = true; // assume ok...
name = _name; name = _name;
angleRotateZ = _angleRotateZ *M_PI/180.f; // Defined in ini --> internal prg value angleRotateZ = _angleRotateZ *M_PI/180.f; // Defined in ini --> internal prg value
mapTexTop = (90.f-_mapTexTop) *M_PI/180.f; // top 90 --> 0 mapTexTop = (90.f-_mapTexTop) *M_PI/180.f; // top 90 --> 0
mapTexBottom = (90.f-_mapTexBottom) *M_PI/180.f; // bottom -90 --> pi mapTexBottom = (90.f-_mapTexBottom) *M_PI/180.f; // bottom -90 --> pi
fogTexTop = (90.f-_fogTexTop) *M_PI/180.f; fogTexTop = (90.f-_fogTexTop) *M_PI/180.f;
fogTexBottom = (90.f-_fogTexBottom) *M_PI/180.f; fogTexBottom = (90.f-_fogTexBottom) *M_PI/180.f;
illumTexTop = (90.f-_illumTexTop) *M_PI/180.f; illumTexTop = (90.f-_illumTexTop) *M_PI/180.f;
illumTexBottom= (90.f-_illumTexBottom)*M_PI/180.f; illumTexBottom= (90.f-_illumTexBottom)*M_PI/180.f;
if (!horizonPolygon) if (!horizonPolygon)
{
mapImage = new QImage(_maptex); mapImage = new QImage(_maptex);
memorySize+=mapImage->byteCount();
}
mapTex = StelApp::getInstance().getTextureManager().createTexture(_m aptex, StelTexture::StelTextureParams(true)); mapTex = StelApp::getInstance().getTextureManager().createTexture(_m aptex, StelTexture::StelTextureParams(true));
memorySize+=mapTex.data()->getGlSize();
if (_maptexIllum.length()) if (_maptexIllum.length() && (!_maptexIllum.endsWith("/")))
{
mapTexIllum = StelApp::getInstance().getTextureManager().cre ateTexture(_maptexIllum, StelTexture::StelTextureParams(true)); mapTexIllum = StelApp::getInstance().getTextureManager().cre ateTexture(_maptexIllum, StelTexture::StelTextureParams(true));
if (_maptexFog.length()) if (mapTexIllum)
memorySize+=mapTexIllum.data()->getGlSize();
}
if (_maptexFog.length() && (!_maptexFog.endsWith("/")))
{
mapTexFog = StelApp::getInstance().getTextureManager().creat eTexture(_maptexFog, StelTexture::StelTextureParams(true)); mapTexFog = StelApp::getInstance().getTextureManager().creat eTexture(_maptexFog, StelTexture::StelTextureParams(true));
if (mapTexFog)
memorySize+=mapTexFog.data()->getGlSize();
}
} }
void LandscapeSpherical::draw(StelCore* core) void LandscapeSpherical::draw(StelCore* core)
{ {
if(!validLandscape) return; if(!validLandscape) return;
if(!landFader.getInterstate()) return; if(!landFader.getInterstate()) return;
StelProjector::ModelViewTranformP transfo = core->getAltAzModelViewT ransform(StelCore::RefractionOff); StelProjector::ModelViewTranformP transfo = core->getAltAzModelViewT ransform(StelCore::RefractionOff);
transfo->combine(Mat4d::zrotation(-(angleRotateZ+angleRotateZOffset) )); transfo->combine(Mat4d::zrotation(-(angleRotateZ+angleRotateZOffset) ));
const StelProjectorP prj = core->getProjection(transfo); const StelProjectorP prj = core->getProjection(transfo);
StelPainter sPainter(prj); StelPainter sPainter(prj);
// Normal transparency mode // Normal transparency mode
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
sPainter.setColor(landscapeBrightness, landscapeBrightness, landscap eBrightness, landFader.getInterstate()); sPainter.setColor(landscapeBrightness, landscapeBrightness, landscap eBrightness, landFader.getInterstate());
sPainter.setBlending(true);
sPainter.setCullFace(true);
glEnable(GL_CULL_FACE);
sPainter.enableTexture2d(true);
glEnable(GL_BLEND);
mapTex->bind(); mapTex->bind();
// TODO: verify that this works correctly for custom projections [co mment not by GZ] // TODO: verify that this works correctly for custom projections [co mment not by GZ]
// seam is at East, except if angleRotateZ has been given. // seam is at East, except if angleRotateZ has been given.
sPainter.sSphere(radius, 1.0, cols, rows, 1, true, mapTexTop, mapTex Bottom); sPainter.sSphere(radius, 1.0, cols, rows, 1, true, mapTexTop, mapTex Bottom);
// Since 0.13: Fog also for sphericals... // Since 0.13: Fog also for sphericals...
if ((mapTexFog) && (core->getSkyDrawer()->getFlagHasAtmosphere())) if ((mapTexFog) && (core->getSkyDrawer()->getFlagHasAtmosphere()))
{ {
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); sPainter.setBlending(true, GL_ONE, GL_ONE_MINUS_SRC_COLOR);
sPainter.setColor(landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness), sPainter.setColor(landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness),
landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness), landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness),
landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness), landFader.getInterstate()); landFader.getInterstate()*fogFader.getInte rstate()*(0.1f+0.1f*landscapeBrightness), landFader.getInterstate());
mapTexFog->bind(); mapTexFog->bind();
sPainter.sSphere(radius, 1.0, cols, (int) ceil(rows*(fogTexT op-fogTexBottom)/(mapTexTop-mapTexBottom)), 1, true, fogTexTop, fogTexBotto m); sPainter.sSphere(radius, 1.0, cols, (int) ceil(rows*(fogTexT op-fogTexBottom)/(mapTexTop-mapTexBottom)), 1, true, fogTexTop, fogTexBotto m);
} }
// Self-luminous layer (Light pollution etc). This looks striking! // Self-luminous layer (Light pollution etc). This looks striking!
if (mapTexIllum && (lightScapeBrightness>0.0f) && illumFader.getInte rstate()) if (mapTexIllum && (lightScapeBrightness>0.0f) && illumFader.getInte rstate())
{ {
glBlendFunc(GL_SRC_ALPHA, GL_ONE); sPainter.setBlending(true, GL_SRC_ALPHA, GL_ONE);
sPainter.setColor(lightScapeBrightness*illumFader.getInterst ate(), sPainter.setColor(lightScapeBrightness*illumFader.getInterst ate(),
lightScapeBrightness*illumFader.getInterst ate(), lightScapeBrightness*illumFader.getInterst ate(),
lightScapeBrightness*illumFader.getInterst ate(), landFader.getInterstate()); lightScapeBrightness*illumFader.getInterst ate(), landFader.getInterstate());
mapTexIllum->bind(); mapTexIllum->bind();
sPainter.sSphere(radius, 1.0, cols, (int) ceil(rows*(illumTe xTop-illumTexBottom)/(mapTexTop-mapTexBottom)), 1, true, illumTexTop, illum TexBottom); sPainter.sSphere(radius, 1.0, cols, (int) ceil(rows*(illumTe xTop-illumTexBottom)/(mapTexTop-mapTexBottom)), 1, true, illumTexTop, illum TexBottom);
} }
//qDebug() << "before drawing line"; //qDebug() << "before drawing line";
// If a horizon line also has been defined, draw it. // If a horizon line also has been defined, draw it.
if (horizonPolygon && (horizonPolygonLineColor[0] >= 0)) if (horizonPolygon && (horizonPolygonLineColor[0] >= 0))
{ {
//qDebug() << "drawing line"; //qDebug() << "drawing line";
transfo = core->getAltAzModelViewTransform(StelCore::Refract ionOff); transfo = core->getAltAzModelViewTransform(StelCore::Refract ionOff);
transfo->combine(Mat4d::zrotation(-angleRotateZOffset)); transfo->combine(Mat4d::zrotation(-angleRotateZOffset));
const StelProjectorP prj = core->getProjection(transfo); const StelProjectorP prj = core->getProjection(transfo);
sPainter.setProjector(prj); sPainter.setProjector(prj);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); sPainter.setBlending(true);
sPainter.setColor(horizonPolygonLineColor[0], horizonPolygon LineColor[1], horizonPolygonLineColor[2], landFader.getInterstate()); sPainter.setColor(horizonPolygonLineColor[0], horizonPolygon LineColor[1], horizonPolygonLineColor[2], landFader.getInterstate());
sPainter.drawSphericalRegion(horizonPolygon.data(), StelPain ter::SphericalPolygonDrawModeBoundary); sPainter.drawSphericalRegion(horizonPolygon.data(), StelPain ter::SphericalPolygonDrawModeBoundary);
} }
//else qDebug() << "no polygon defined"; //else qDebug() << "no polygon defined";
glDisable(GL_CULL_FACE); sPainter.setCullFace(false);
drawLabels(core, &sPainter); drawLabels(core, &sPainter);
} }
//! Sample landscape texture for transparency. May be used for advanced vis ibility computation like sunrise on the visible horizon etc. //! Sample landscape texture for transparency. May be used for advanced vis ibility computation like sunrise on the visible horizon etc.
//! @param azalt: normalized direction in alt-az frame //! @param azalt: normalized direction in alt-az frame
//! @retval alpha (0..1), where 0=fully transparent. //! @retval alpha (0..1), where 0=fully transparent.
float LandscapeSpherical::getOpacity(Vec3d azalt) const float LandscapeSpherical::getOpacity(Vec3d azalt) const
{ {
if (angleRotateZOffset!=0.0f) if (angleRotateZOffset!=0.0f)
azalt.transfo4d(Mat4d::zrotation(angleRotateZOffset)); azalt.transfo4d(Mat4d::zrotation(angleRotateZOffset));
// in case we also have a horizon polygon defined, this is trivial a nd fast. // in case we also have a horizon polygon defined, this is trivial a nd fast.
if (horizonPolygon) if (horizonPolygon)
{ {
if (horizonPolygon->contains(azalt) ) return 1.0f; else return 0.0f; if (horizonPolygon->contains(azalt)) return 1.0f; else retur n 0.0f;
} }
// Else, sample the image... // Else, sample the image...
float az, alt_rad;
StelUtils::rectToSphe(&az, &alt_rad, azalt);
// QImage has pixel 0/0 in top left corner. We must first find image Y for optionally cropped images. // QImage has pixel 0/0 in top left corner. We must first find image Y for optionally cropped images.
// It is possible that sample position is outside cropped texture. i n this case, assume full transparency and exit early. // It is possible that sample position is outside cropped texture. i n this case, assume full transparency and exit early.
const float alt_pm1 = 2.0f * std::asin(azalt[2]) / M_PI; // sample
d altitude, -1...+1 linear in altitude angle const float alt_pm1 = 2.0f * alt_rad / M_PI; // sample
d altitude, -1...+1 linear in altitude angle
const float img_top_pm1 = 1.0f-2.0f*(mapTexTop / M_PI); // the to p line in -1..+1 const float img_top_pm1 = 1.0f-2.0f*(mapTexTop / M_PI); // the to p line in -1..+1
if (alt_pm1>img_top_pm1) return 0.0f; if (alt_pm1>img_top_pm1) return 0.0f;
const float img_bot_pm1 = 1.0f-2.0f*(mapTexBottom / M_PI); // the bo ttom line in -1..+1 const float img_bot_pm1 = 1.0f-2.0f*(mapTexBottom / M_PI); // the bo ttom line in -1..+1
if (alt_pm1<img_bot_pm1) return 1.0f; // rare case of a hole in the ground. Even though there is a visible hole, play opaque. if (alt_pm1<img_bot_pm1) return 1.0f; // rare case of a hole in the ground. Even though there is a visible hole, play opaque.
float y_img_1=(alt_pm1-img_bot_pm1)/(img_top_pm1-img_bot_pm1); // th e sampled altitude in 0..1 image height from bottom float y_img_1=(alt_pm1-img_bot_pm1)/(img_top_pm1-img_bot_pm1); // th e sampled altitude in 0..1 image height from bottom
Q_ASSERT(y_img_1<=1.f);
Q_ASSERT(y_img_1>=0.f);
int y=(1.0-y_img_1)*mapImage->height(); // pixel Y from to p. int y=(1.0-y_img_1)*mapImage->height(); // pixel Y from to p.
float az=atan2(azalt[0], azalt[1]) / M_PI + 0.5f; // -0.5..+1.5 az = (M_PI-az) / M_PI; // 0..2 = N.E.S.W
if (az<0) az+=2.0f; // 0..2 = N.E.S. .N
W.N
const float xShift=(angleRotateZ) /M_PI; // shift value in -2..2 const float xShift=(angleRotateZ) /M_PI; // shift value in -2..2
float az_phot=az - 0.5f - xShift; // The 0.5 is caused by regul ar pano left edge being East. The xShift compensates any configured angleRo tateZ float az_phot=az - 0.5f - xShift; // The 0.5 is caused by regul ar pano left edge being East. The xShift compensates any configured angleRo tateZ
az_phot=fmodf(az_phot, 2.0f); az_phot=fmodf(az_phot, 2.0f);
if (az_phot<0) az_phot+=2.0f; // 0.. 2 = image-X if (az_phot<0) az_phot+=2.0f; // 0.. 2 = image-X
int x=(az_phot/2.0f) * mapImage->width(); // pixel X from left. int x=(az_phot/2.0f) * mapImage->width(); // pixel X from left.
QRgb pixVal=mapImage->pixel(x, y); QRgb pixVal=mapImage->pixel(x, y);
/* /*
 End of changes. 80 change blocks. 
127 lines changed or deleted 123 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/