Planet.cpp   Planet.cpp 
skipping to change at line 20 skipping to change at line 20
* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*/ */
#include <QOpenGLFunctions_1_0>
#include "StelApp.hpp" #include "StelApp.hpp"
#include "StelCore.hpp" #include "StelCore.hpp"
#include "StelFileMgr.hpp" #include "StelFileMgr.hpp"
#include "StelTexture.hpp" #include "StelTexture.hpp"
#include "StelSkyDrawer.hpp" #include "StelSkyDrawer.hpp"
#include "SolarSystem.hpp" #include "SolarSystem.hpp"
#include "LandscapeMgr.hpp" #include "LandscapeMgr.hpp"
#include "Planet.hpp" #include "Planet.hpp"
#include "Orbit.hpp" #include "Orbit.hpp"
#include "planetsephems/precession.h" #include "planetsephems/precession.h"
skipping to change at line 41 skipping to change at line 42
#include "StelProjector.hpp" #include "StelProjector.hpp"
#include "sidereal_time.h" #include "sidereal_time.h"
#include "StelTextureMgr.hpp" #include "StelTextureMgr.hpp"
#include "StelModuleMgr.hpp" #include "StelModuleMgr.hpp"
#include "StarMgr.hpp" #include "StarMgr.hpp"
#include "StelMovementMgr.hpp" #include "StelMovementMgr.hpp"
#include "StelPainter.hpp" #include "StelPainter.hpp"
#include "StelTranslator.hpp" #include "StelTranslator.hpp"
#include "StelUtils.hpp" #include "StelUtils.hpp"
#include "StelOpenGL.hpp" #include "StelOpenGL.hpp"
#include "StelOBJ.hpp"
#include "StelOpenGLArray.hpp"
#include <iomanip>
#include <limits> #include <limits>
#include <QByteArray>
#include <QTextStream> #include <QTextStream>
#include <QString> #include <QString>
#include <QDebug> #include <QDebug>
#include <QVarLengthArray> #include <QVarLengthArray>
#include <QOpenGLBuffer>
#include <QOpenGLContext> #include <QOpenGLContext>
#ifdef DEBUG_SHADOWMAP
#include <QOpenGLFramebufferObject>
#endif
#include <QOpenGLShader> #include <QOpenGLShader>
#include <QtConcurrent>
const QString Planet::PLANET_TYPE = QStringLiteral("Planet");
bool Planet::shaderError = false;
Vec3f Planet::labelColor = Vec3f(0.4f,0.4f,0.8f); Vec3f Planet::labelColor = Vec3f(0.4f,0.4f,0.8f);
Vec3f Planet::orbitColor = Vec3f(1.0f,0.6f,1.0f); Vec3f Planet::orbitColor = Vec3f(1.0f,0.6f,1.0f);
Vec3f Planet::orbitMajorPlanetsColor = Vec3f(1.0f,0.6f,1.0f); Vec3f Planet::orbitMajorPlanetsColor = Vec3f(1.0f,0.6f,1.0f);
Vec3f Planet::orbitMoonsColor = Vec3f(1.0f,0.6f,1.0f); Vec3f Planet::orbitMoonsColor = Vec3f(1.0f,0.6f,1.0f);
Vec3f Planet::orbitMinorPlanetsColor = Vec3f(1.0f,0.6f,1.0f); Vec3f Planet::orbitMinorPlanetsColor = Vec3f(1.0f,0.6f,1.0f);
Vec3f Planet::orbitDwarfPlanetsColor = Vec3f(1.0f,0.6f,1.0f); Vec3f Planet::orbitDwarfPlanetsColor = Vec3f(1.0f,0.6f,1.0f);
Vec3f Planet::orbitCubewanosColor = Vec3f(1.0f,0.6f,1.0f); Vec3f Planet::orbitCubewanosColor = Vec3f(1.0f,0.6f,1.0f);
Vec3f Planet::orbitPlutinosColor = Vec3f(1.0f,0.6f,1.0f); Vec3f Planet::orbitPlutinosColor = Vec3f(1.0f,0.6f,1.0f);
Vec3f Planet::orbitScatteredDiscObjectsColor = Vec3f(1.0f,0.6f,1.0f); Vec3f Planet::orbitScatteredDiscObjectsColor = Vec3f(1.0f,0.6f,1.0f);
skipping to change at line 82 skipping to change at line 94
StelTextureSP Planet::texEarthShadow; StelTextureSP Planet::texEarthShadow;
bool Planet::permanentDrawingOrbits = false; bool Planet::permanentDrawingOrbits = false;
Planet::PlanetOrbitColorStyle Planet::orbitColorStyle = Planet::ocsOneColor ; Planet::PlanetOrbitColorStyle Planet::orbitColorStyle = Planet::ocsOneColor ;
bool Planet::flagCustomGrsSettings = false; bool Planet::flagCustomGrsSettings = false;
double Planet::customGrsJD = 2456901.5; double Planet::customGrsJD = 2456901.5;
double Planet::customGrsDrift = 15.; double Planet::customGrsDrift = 15.;
int Planet::customGrsLongitude = 216; int Planet::customGrsLongitude = 216;
QOpenGLShaderProgram* Planet::planetShaderProgram=NULL; QOpenGLShaderProgram* Planet::planetShaderProgram=Q_NULLPTR;
Planet::PlanetShaderVars Planet::planetShaderVars; Planet::PlanetShaderVars Planet::planetShaderVars;
QOpenGLShaderProgram* Planet::ringPlanetShaderProgram=NULL; QOpenGLShaderProgram* Planet::ringPlanetShaderProgram=Q_NULLPTR;
Planet::RingPlanetShaderVars Planet::ringPlanetShaderVars; Planet::PlanetShaderVars Planet::ringPlanetShaderVars;
QOpenGLShaderProgram* Planet::moonShaderProgram=NULL; QOpenGLShaderProgram* Planet::moonShaderProgram=Q_NULLPTR;
Planet::MoonShaderVars Planet::moonShaderVars; Planet::PlanetShaderVars Planet::moonShaderVars;
QOpenGLShaderProgram* Planet::objShaderProgram=Q_NULLPTR;
Planet::PlanetShaderVars Planet::objShaderVars;
QOpenGLShaderProgram* Planet::objShadowShaderProgram=Q_NULLPTR;
Planet::PlanetShaderVars Planet::objShadowShaderVars;
QOpenGLShaderProgram* Planet::transformShaderProgram=Q_NULLPTR;
Planet::PlanetShaderVars Planet::transformShaderVars;
bool Planet::shadowInitialized = false;
Vec2f Planet::shadowPolyOffset = Vec2f(0.0f, 0.0f);
#ifdef DEBUG_SHADOWMAP
QOpenGLFramebufferObject* Planet::shadowFBO = Q_NULLPTR;
#else
GLuint Planet::shadowFBO = 0;
#endif
GLuint Planet::shadowTex = 0;
QMap<Planet::PlanetType, QString> Planet::pTypeMap; QMap<Planet::PlanetType, QString> Planet::pTypeMap;
QMap<Planet::ApparentMagnitudeAlgorithm, QString> Planet::vMagAlgorithmMap; QMap<Planet::ApparentMagnitudeAlgorithm, QString> Planet::vMagAlgorithmMap;
Planet::ApparentMagnitudeAlgorithm Planet::vMagAlgorithm;
#define STRINGIFY2(a) #a
#define STRINGIFY(a) STRINGIFY2(a)
#define SM_SIZE 1024
Planet::PlanetOBJModel::PlanetOBJModel()
: needsRescale(true), projPosBuffer(new QOpenGLBuffer(QOpenGLBuffer:
:VertexBuffer)), obj(new StelOBJ()), arr(new StelOpenGLArray())
{
//The buffer is refreshed completely before each draw, so StreamDraw
should be ok
projPosBuffer->setUsagePattern(QOpenGLBuffer::StreamDraw);
}
Planet::PlanetOBJModel::~PlanetOBJModel()
{
delete projPosBuffer;
delete obj;
delete arr;
}
bool Planet::PlanetOBJModel::loadGL()
{
if(arr->load(obj,false))
{
//delete StelOBJ because the data is no longer needed
delete obj;
obj = Q_NULLPTR;
//make sure the vector has enough space to hold the projecte
d data
projectedPosArray.resize(posArray.size());
//create the GL buffer for the projection
return projPosBuffer->create();
}
return false;
}
void Planet::PlanetOBJModel::performScaling(double scale)
{
scaledArray = posArray;
//pre-scale the cpu-side array
for(int i = 0; i<posArray.size();++i)
{
scaledArray[i]*=scale;
}
needsRescale = false;
}
Planet::Planet(const QString& englishName, Planet::Planet(const QString& englishName,
int flagLighting,
double radius, double radius,
double oblateness, double oblateness,
Vec3f halocolor, Vec3f halocolor,
float albedo, float albedo,
float roughness,
const QString& atexMapName, const QString& atexMapName,
const QString& anormalMapName, const QString& anormalMapName,
const QString& aobjModelName,
posFuncType coordFunc, posFuncType coordFunc,
void* auserDataPtr, void* anOrbitPtr,
OsculatingFunctType *osculatingFunc, OsculatingFunctType *osculatingFunc,
bool acloseOrbit, bool acloseOrbit,
bool hidden, bool hidden,
bool hasAtmosphere, bool hasAtmosphere,
bool hasHalo, bool hasHalo,
const QString& pTypeStr) const QString& pTypeStr)
: flagNativeName(true), : flagNativeName(true),
flagTranslatedName(true), flagTranslatedName(true),
lastOrbitJDE(0.0), lastOrbitJDE(0.0),
deltaJDE(StelCore::JD_SECOND), deltaJDE(StelCore::JD_SECOND),
deltaOrbitJDE(0.0), deltaOrbitJDE(0.0),
orbitCached(false), orbitCached(false),
closeOrbit(acloseOrbit), closeOrbit(acloseOrbit),
englishName(englishName), englishName(englishName),
nameI18(englishName), nameI18(englishName),
nativeName(""), nativeName(""),
texMapName(atexMapName), texMapName(atexMapName),
normalMapName(anormalMapName), normalMapName(anormalMapName),
flagLighting(flagLighting),
radius(radius), radius(radius),
oneMinusOblateness(1.0-oblateness), oneMinusOblateness(1.0-oblateness),
eclipticPos(0.,0.,0.), eclipticPos(0.,0.,0.),
haloColor(halocolor), haloColor(halocolor),
albedo(albedo),
absoluteMagnitude(-99.0f), absoluteMagnitude(-99.0f),
albedo(albedo),
roughness(roughness),
outgas_intensity(0.f),
outgas_falloff(0.f),
rotLocalToParent(Mat4d::identity()), rotLocalToParent(Mat4d::identity()),
axisRotation(0.), axisRotation(0.),
rings(NULL), objModel(Q_NULLPTR),
objModelLoader(Q_NULLPTR),
rings(Q_NULLPTR),
distance(0.0), distance(0.0),
sphereScale(1.f), sphereScale(1.f),
lastJDE(J2000), lastJDE(J2000),
coordFunc(coordFunc), coordFunc(coordFunc),
userDataPtr(auserDataPtr), orbitPtr(anOrbitPtr),
osculatingFunc(osculatingFunc), osculatingFunc(osculatingFunc),
parent(NULL), parent(Q_NULLPTR),
flagLabels(true), flagLabels(true),
hidden(hidden), hidden(hidden),
atmosphere(hasAtmosphere), atmosphere(hasAtmosphere),
halo(hasHalo), halo(hasHalo),
vMagAlgorithm(Planet::UndefinedAlgorithm) gl(Q_NULLPTR)
{ {
// Initialize pType with the key found in pTypeMap, or mark planet t ype as undefined. // Initialize pType with the key found in pTypeMap, or mark planet t ype as undefined.
// The latter condition should obviously never happen. // The latter condition should obviously never happen.
pType = pTypeMap.key(pTypeStr, Planet::isUNDEFINED); pType = pTypeMap.key(pTypeStr, Planet::isUNDEFINED);
// 0.16: Ensure type is always given!
// AW: I've commented the code to the allow flying on spaceship (imp
lemented as an artificial planet)!
if (pType==Planet::isUNDEFINED)
{
qCritical() << "Planet " << englishName << "has no type. Ple
ase edit one of ssystem_major.ini or ssystem_minor.ini to ensure operation.
";
exit(-1);
}
Q_ASSERT(pType != Planet::isUNDEFINED);
//only try loading textures when there is actually something to load
!
//prevents some overhead when starting
if(!texMapName.isEmpty())
{
// TODO: use StelFileMgr::findFileInAllPaths() after introdu
cing an Add-On Manager
QString texMapFile = StelFileMgr::findFile("textures/"+texMa
pName, StelFileMgr::File);
if (!texMapFile.isEmpty())
texMap = StelApp::getInstance().getTextureManager().
createTextureThread(texMapFile, StelTexture::StelTextureParams(true, GL_LIN
EAR, GL_REPEAT));
else
qWarning()<<"Cannot resolve path to texture file"<<t
exMapName<<"of object"<<englishName;
}
texMap = StelApp::getInstance().getTextureManager().createTextureThr if(!normalMapName.isEmpty())
ead(StelFileMgr::getInstallationDir()+"/textures/"+texMapName, StelTexture: {
:StelTextureParams(true, GL_LINEAR, GL_REPEAT)); // TODO: use StelFileMgr::findFileInAllPaths() after introdu
normalMap = StelApp::getInstance().getTextureManager().createTexture cing an Add-On Manager
Thread(StelFileMgr::getInstallationDir()+"/textures/"+normalMapName, StelTe QString normalMapFile = StelFileMgr::findFile("textures/"+no
xture::StelTextureParams(true, GL_LINEAR, GL_REPEAT)); rmalMapName, StelFileMgr::File);
if (!normalMapFile.isEmpty())
if (englishName!="Pluto") normalMap = StelApp::getInstance().getTextureManager
().createTextureThread(normalMapFile, StelTexture::StelTextureParams(true,
GL_LINEAR, GL_REPEAT));
}
//the OBJ is lazily loaded when first required
if(!aobjModelName.isEmpty())
{
// TODO: use StelFileMgr::findFileInAllPaths() after introdu
cing an Add-On Manager
objModelPath = StelFileMgr::findFile("models/"+aobjModelName
, StelFileMgr::File);
if(objModelPath.isEmpty())
{
qWarning()<<"Cannot resolve path to model file"<<aob
jModelName<<"of object"<<englishName;
}
}
if (englishName!="Pluto") // TODO: add some far-out slow object type
s: other Plutoids, KBO, SDO, OCO, ...
{ {
deltaJDE = 0.001*StelCore::JD_SECOND; deltaJDE = 0.001*StelCore::JD_SECOND;
} }
} }
// called in SolarSystem::init() before first planet is created. Loads pTyp eMap. // called in SolarSystem::init() before first planet is created. Loads pTyp eMap.
void Planet::init() void Planet::init()
{ {
if (pTypeMap.count() > 0 ) if (pTypeMap.count() > 0 )
{ {
// This should never happen. But it's uncritical. // This should never happen. But it's uncritical.
qDebug() << "Planet::init(): Non-empty static map. This is a programming error, but we can fix that."; qDebug() << "Planet::init(): Non-empty static map. This is a programming error, but we can fix that.";
pTypeMap.clear(); pTypeMap.clear();
} }
pTypeMap.insert(Planet::isStar, "star"); pTypeMap.insert(Planet::isStar, "star");
pTypeMap.insert(Planet::isPlanet, "planet"); pTypeMap.insert(Planet::isPlanet, "planet");
pTypeMap.insert(Planet::isMoon, "moon"); pTypeMap.insert(Planet::isMoon, "moon");
pTypeMap.insert(Planet::isObserver, "observer");
pTypeMap.insert(Planet::isArtificial, "artificial");
pTypeMap.insert(Planet::isAsteroid, "asteroid"); pTypeMap.insert(Planet::isAsteroid, "asteroid");
pTypeMap.insert(Planet::isPlutino, "plutino"); pTypeMap.insert(Planet::isPlutino, "plutino");
pTypeMap.insert(Planet::isComet, "comet"); pTypeMap.insert(Planet::isComet, "comet");
pTypeMap.insert(Planet::isDwarfPlanet, "dwarf planet"); pTypeMap.insert(Planet::isDwarfPlanet, "dwarf planet");
pTypeMap.insert(Planet::isCubewano, "cubewano"); pTypeMap.insert(Planet::isCubewano, "cubewano");
pTypeMap.insert(Planet::isSDO, "scattered disc object"); pTypeMap.insert(Planet::isSDO, "scattered disc object");
pTypeMap.insert(Planet::isOCO, "Oort cloud object"); pTypeMap.insert(Planet::isOCO, "Oort cloud object");
pTypeMap.insert(Planet::isSednoid, "sednoid"); pTypeMap.insert(Planet::isSednoid, "sednoid");
pTypeMap.insert(Planet::isUNDEFINED, "UNDEFINED"); // something m ust be broken before we ever see this! pTypeMap.insert(Planet::isUNDEFINED, "UNDEFINED"); // something m ust be broken before we ever see this!
if (vMagAlgorithmMap.count() > 0) if (vMagAlgorithmMap.count() > 0)
{ {
qDebug() << "Planet::init(): Non-empty static map. This is a programming error, but we can fix that."; qDebug() << "Planet::init(): Non-empty static map. This is a programming error, but we can fix that.";
vMagAlgorithmMap.clear(); vMagAlgorithmMap.clear();
} }
vMagAlgorithmMap.insert(Planet::Expl_Sup_2013, "ExpSup2013"); vMagAlgorithmMap.insert(Planet::Expl_Sup_2013, "ExpSup2013");
vMagAlgorithmMap.insert(Planet::Expl_Sup_1992, "planesas"); // depr ecate in 0.16, remove later. TODO: Rename the other strings. BETTER: Use th e metaobject!
vMagAlgorithmMap.insert(Planet::Expl_Sup_1992, "ExpSup1992"); vMagAlgorithmMap.insert(Planet::Expl_Sup_1992, "ExpSup1992");
vMagAlgorithmMap.insert(Planet::Mueller_1893, "mueller"); // d eprecate in 0.16, remove later.
vMagAlgorithmMap.insert(Planet::Mueller_1893, "Mueller1893"); // b etter name vMagAlgorithmMap.insert(Planet::Mueller_1893, "Mueller1893"); // b etter name
vMagAlgorithmMap.insert(Planet::Astr_Alm_1984, "harris"); // d eprecate in 0.16, remove later
vMagAlgorithmMap.insert(Planet::Astr_Alm_1984, "AstrAlm1984"); // c onsistent name vMagAlgorithmMap.insert(Planet::Astr_Alm_1984, "AstrAlm1984"); // c onsistent name
vMagAlgorithmMap.insert(Planet::Generic, "generic"), vMagAlgorithmMap.insert(Planet::Generic, "Generic"),
vMagAlgorithmMap.insert(Planet::UndefinedAlgorithm, ""); vMagAlgorithmMap.insert(Planet::UndefinedAlgorithm, "");
} }
Planet::~Planet() Planet::~Planet()
{ {
if (rings) delete rings;
delete rings; delete objModel;
} }
void Planet::translateName(const StelTranslator& trans) void Planet::translateName(const StelTranslator& trans)
{ {
if (!nativeName.isEmpty() && getFlagNativeName()) if (!nativeName.isEmpty() && getFlagNativeName())
{ {
if (getFlagTranslatedName()) if (getFlagTranslatedName())
nameI18 = trans.qtranslate(nativeName); nameI18 = trans.qtranslate(nativeName);
else else
nameI18 = nativeName; nameI18 = nativeName;
skipping to change at line 259 skipping to change at line 370
if (flags&ObjectType && getPlanetType()!=isUNDEFINED) if (flags&ObjectType && getPlanetType()!=isUNDEFINED)
{ {
oss << q_("Type: <b>%1</b>").arg(q_(getPlanetTypeString())) << "<br />"; oss << q_("Type: <b>%1</b>").arg(q_(getPlanetTypeString())) << "<br />";
} }
if (flags&Magnitude && getVMagnitude(core)!=std::numeric_limits<floa t>::infinity()) if (flags&Magnitude && getVMagnitude(core)!=std::numeric_limits<floa t>::infinity())
{ {
if (core->getSkyDrawer()->getFlagHasAtmosphere() && (alt_app >-3.0*M_PI/180.0)) // Don't show extincted magnitude much below horizon whe re model is meaningless. if (core->getSkyDrawer()->getFlagHasAtmosphere() && (alt_app >-3.0*M_PI/180.0)) // Don't show extincted magnitude much below horizon whe re model is meaningless.
oss << q_("Magnitude: <b>%1</b> (after extinction: < b>%2</b>)").arg(QString::number(getVMagnitude(core), 'f', 2), oss << q_("Magnitude: <b>%1</b> (after extinction: < b>%2</b>)").arg(QString::number(getVMagnitude(core), 'f', 2),
QString::number(getVMagnitudeWithExtinction(core), 'f', 2)) << "<br>"; QString::number(getVMagnitudeWithExtinction(core), 'f', 2)) << "<br>";
else else
oss << q_("Magnitude: <b>%1</b>").arg(getVMagnitude( core), 0, 'f', 2) << "<br>"; oss << q_("Magnitude: <b>%1</b>").arg(getVMagnitude( core), 0, 'f', 2) << "<br>";
} }
if (flags&AbsoluteMagnitude && (getAbsoluteMagnitude() > -99.)) if (flags&AbsoluteMagnitude && (getAbsoluteMagnitude() > -99.))
{ {
oss << q_("Absolute Magnitude: %1").arg(getAbsoluteMagnitude (), 0, 'f', 2) << "<br>"; oss << q_("Absolute Magnitude: %1").arg(getAbsoluteMagnitude (), 0, 'f', 2) << "<br>";
const float moMag=getMeanOppositionMagnitude(); const float moMag=getMeanOppositionMagnitude();
if (moMag<50.f) if (moMag<50.f)
oss << q_("Mean Opposition Magnitude: %1").arg(moMag , 0, 'f', 2) << "<br>"; oss << q_("Mean Opposition Magnitude: %1").arg(moMag , 0, 'f', 2) << "<br>";
} }
oss << getPositionInfoString(core, flags); oss << getPositionInfoString(core, flags);
// Debug help.
//oss << "Apparent Magnitude Algorithm: " << getApparentMagnitudeAlg
orithmString() << " " << vMagAlgorithm << "<br>";
// GZ This is mostly for debugging. Maybe also useful for letting pe ople use our results to cross-check theirs, but we should not act as refere nce, currently... // GZ This is mostly for debugging. Maybe also useful for letting pe ople use our results to cross-check theirs, but we should not act as refere nce, currently...
// TODO: maybe separate this out into: // TODO: maybe separate this out into:
//if (flags&EclipticCoordXYZ) //if (flags&EclipticCoordXYZ)
// For now: add to EclipticCoord // For now: add to EclipticCoord
//if (flags&EclipticCoord) //if (flags&EclipticCoord)
// oss << q_("Ecliptical XYZ (VSOP87A): %1/%2/%3").arg(QString: :number(eclipticPos[0], 'f', 3), QString::number(eclipticPos[1], 'f', 3), Q String::number(eclipticPos[2], 'f', 3)) << "<br>"; // oss << q_("Ecliptical XYZ (VSOP87A): %1/%2/%3").arg(QString: :number(eclipticPos[0], 'f', 3), QString::number(eclipticPos[1], 'f', 3), Q String::number(eclipticPos[2], 'f', 3)) << "<br>";
if (flags&Distance) if (flags&Distance)
{ {
double hdistanceAu = getHeliocentricEclipticPos().length(); double hdistanceAu = getHeliocentricEclipticPos().length();
skipping to change at line 307 skipping to change at line 421
.arg(hdistanceAu, 0, 'f', 3) .arg(hdistanceAu, 0, 'f', 3)
.arg(hdistanceKm / 1.0e6, 0, 'f', 3); .arg(hdistanceKm / 1.0e6, 0, 'f', 3);
} }
oss << "<br>"; oss << "<br>";
} }
double distanceKm = AU * distanceAu; double distanceKm = AU * distanceAu;
if (distanceAu < 0.1) if (distanceAu < 0.1)
{ {
// xgettext:no-c-format // xgettext:no-c-format
oss << QString(q_("Distance: %1AU (%2 km)")) oss << QString(q_("Distance: %1AU (%2 km)"))
.arg(distanceAu, 0, 'f', 6) .arg(distanceAu, 0, 'f', 6)
.arg(distanceKm, 0, 'f', 3); .arg(distanceKm, 0, 'f', 3);
} }
else else
{ {
// xgettext:no-c-format // xgettext:no-c-format
oss << QString(q_("Distance: %1AU (%2 Mio km)")) oss << QString(q_("Distance: %1AU (%2 Mio km)"))
.arg(distanceAu, 0, 'f', 3) .arg(distanceAu, 0, 'f', 3)
.arg(distanceKm / 1.0e6, 0, 'f', 3); .arg(distanceKm / 1.0e6, 0, 'f', 3);
} }
oss << "<br>"; oss << "<br>";
} }
if (flags&Size) if (flags&Size)
{ {
double angularSize = 2.*getAngularSize(core)*M_PI/180.; double angularSize = 2.*getAngularSize(core)*M_PI/180.;
if (rings) if (rings)
{ {
double withoutRings = 2.*getSpheroidAngularSize(core )*M_PI/180.; double withoutRings = 2.*getSpheroidAngularSize(core )*M_PI/180.;
skipping to change at line 437 skipping to change at line 551
oss << " (" << moonPhase << ")"; oss << " (" << moonPhase << ")";
oss << "<br>"; oss << "<br>";
oss << QString(q_("Illuminated: %1%")).arg(getPhase( observerHelioPos) * 100, 0, 'f', 1) << "<br>"; oss << QString(q_("Illuminated: %1%")).arg(getPhase( observerHelioPos) * 100, 0, 'f', 1) << "<br>";
oss << QString(q_("Albedo: %1")).arg(QString::number (getAlbedo(), 'f', 3)) << "<br>"; oss << QString(q_("Albedo: %1")).arg(QString::number (getAlbedo(), 'f', 3)) << "<br>";
} }
if (englishName=="Sun") if (englishName=="Sun")
{ {
// Only show during eclipse, show percent? // Only show during eclipse, show percent?
static SolarSystem *ssystem=GETSTELMODULE(SolarSyste m); static SolarSystem *ssystem=GETSTELMODULE(SolarSyste m);
// Debug solution: // Debug solution:
// float eclipseFactor = ssystem->getEclipseFactor(core // float eclipseFactor = ssyste
); m->getEclipseFactor(core);
// oss << QString(q_("Eclipse Factor: %1 alpha: %2")).a // oss << QString(q_("Eclipse F
rg(eclipseFactor).arg(-0.1f*qMax(-10.0f, (float) std::log10(eclipseFactor)) actor: %1 alpha: %2")).arg(eclipseFactor).arg(-0.1f*qMax(-10.0f, (float) st
) << "<br>"; d::log10(eclipseFactor))) << "<br>";
// Release version: // Release version:
float eclipseFactor = 100.f*(1.f-ssystem->getEclipse Factor(core)); float eclipseFactor = 100.f*(1.f-ssystem->getEclipse Factor(core));
if (eclipseFactor>1.e-7) // needed to avoid false di splay of 1e-14 or so. if (eclipseFactor>1.e-7) // needed to avoid false di splay of 1e-14 or so.
oss << QString(q_("Eclipse Factor: %1%")).ar g(eclipseFactor) << "<br>"; oss << QString(q_("Eclipse Factor: %1%")).ar g(eclipseFactor) << "<br>";
} }
} }
postProcessInfoString(str, flags); postProcessInfoString(str, flags);
skipping to change at line 483 skipping to change at line 597
} }
return map; return map;
} }
//! Get sky label (sky translation) //! Get sky label (sky translation)
QString Planet::getSkyLabel(const StelCore*) const QString Planet::getSkyLabel(const StelCore*) const
{ {
QString str; QString str;
QTextStream oss(&str); QTextStream oss(&str);
oss.setRealNumberPrecision(2); oss.setRealNumberPrecision(3);
oss << getNameI18n(); oss << getNameI18n();
if (sphereScale != 1.f) if (sphereScale != 1.f)
{ {
oss << QString::fromUtf8(" (\xC3\x97") << sphereScale << ")" ; oss << QString::fromUtf8(" (\xC3\x97") << sphereScale << ")" ;
} }
return str; return str;
} }
float Planet::getSelectPriority(const StelCore* core) const float Planet::getSelectPriority(const StelCore* core) const
{ {
if( ((SolarSystem*)StelApp::getInstance().getModuleMgr().getModule(" SolarSystem"))->getFlagHints() ) if( ((SolarSystem*)StelApp::getInstance().getModuleMgr().getModule(" SolarSystem"))->getFlagHints() )
{ {
// easy to select, especially pluto // easy to select, especially pluto
return getVMagnitudeWithExtinction(core)-15.f; return getVMagnitudeWithExtinction(core)-15.f;
} }
else else
{ {
return getVMagnitudeWithExtinction(core) - 8.f; return getVMagnitudeWithExtinction(core) - 8.f;
} }
} }
Vec3f Planet::getInfoColor(void) const Vec3f Planet::getInfoColor(void) const
{ {
skipping to change at line 557 skipping to change at line 671
{ {
return StelCore::matVsop87ToJ2000.multiplyWithoutTranslation(getHeli ocentricEclipticPos() - core->getObserverHeliocentricEclipticPos()); return StelCore::matVsop87ToJ2000.multiplyWithoutTranslation(getHeli ocentricEclipticPos() - core->getObserverHeliocentricEclipticPos());
} }
// Compute the position in the parent Planet coordinate system // Compute the position in the parent Planet coordinate system
// Actually call the provided function to compute the ecliptical position // Actually call the provided function to compute the ecliptical position
void Planet::computePositionWithoutOrbits(const double dateJDE) void Planet::computePositionWithoutOrbits(const double dateJDE)
{ {
if (fabs(lastJDE-dateJDE)>deltaJDE) if (fabs(lastJDE-dateJDE)>deltaJDE)
{ {
coordFunc(dateJDE, eclipticPos, userDataPtr); coordFunc(dateJDE, eclipticPos, orbitPtr);
lastJDE = dateJDE; lastJDE = dateJDE;
} }
} }
// return value in radians! // return value in radians!
// For Earth, this is epsilon_A, the angle between earth's rotational axis and mean ecliptic of date. // For Earth, this is epsilon_A, the angle between earth's rotational axis and mean ecliptic of date.
// Details: e.g. Hilton etal, Report on Precession and the Ecliptic, Cel.Me ch.Dyn.Astr.94:351-67 (2006), Fig1. // Details: e.g. Hilton etal, Report on Precession and the Ecliptic, Cel.Me ch.Dyn.Astr.94:351-67 (2006), Fig1.
double Planet::getRotObliquity(double JDE) const double Planet::getRotObliquity(double JDE) const
{ {
// JDay=2451545.0 for J2000.0 // JDay=2451545.0 for J2000.0
skipping to change at line 673 skipping to change at line 787
calc_date = new_date + (d-ORBIT_SEGM ENTS/2)*deltaOrbitJDE; calc_date = new_date + (d-ORBIT_SEGM ENTS/2)*deltaOrbitJDE;
// date increments between points wi ll not be completely constant though // date increments between points wi ll not be completely constant though
computeTransMatrix(calc_date-core->c omputeDeltaT(calc_date)/86400.0, calc_date); computeTransMatrix(calc_date-core->c omputeDeltaT(calc_date)/86400.0, calc_date);
if (osculatingFunc) if (osculatingFunc)
{ {
(*osculatingFunc)(dateJDE,ca lc_date,eclipticPos); (*osculatingFunc)(dateJDE,ca lc_date,eclipticPos);
} }
else else
{ {
coordFunc(calc_date, eclipti cPos, userDataPtr); coordFunc(calc_date, eclipti cPos, orbitPtr);
} }
orbitP[d] = eclipticPos; orbitP[d] = eclipticPos;
orbit[d] = getHeliocentricEclipticPo s(); orbit[d] = getHeliocentricEclipticPo s();
} }
else else
{ {
orbitP[d] = orbitP[d+delta_points]; orbitP[d] = orbitP[d+delta_points];
orbit[d] = getHeliocentricPos(orbitP [d]); orbit[d] = getHeliocentricPos(orbitP [d]);
} }
} }
skipping to change at line 703 skipping to change at line 817
{ {
// calculate new points // calculate new points
calc_date = new_date + (d-ORBIT_SEGM ENTS/2)*deltaOrbitJDE; calc_date = new_date + (d-ORBIT_SEGM ENTS/2)*deltaOrbitJDE;
computeTransMatrix(calc_date-core->c omputeDeltaT(calc_date)/86400.0, calc_date); computeTransMatrix(calc_date-core->c omputeDeltaT(calc_date)/86400.0, calc_date);
if (osculatingFunc) { if (osculatingFunc) {
(*osculatingFunc)(dateJDE,ca lc_date,eclipticPos); (*osculatingFunc)(dateJDE,ca lc_date,eclipticPos);
} }
else else
{ {
coordFunc(calc_date, eclipti cPos, userDataPtr); coordFunc(calc_date, eclipti cPos, orbitPtr);
} }
orbitP[d] = eclipticPos; orbitP[d] = eclipticPos;
orbit[d] = getHeliocentricEclipticPo s(); orbit[d] = getHeliocentricEclipticPo s();
} }
else else
{ {
orbitP[d] = orbitP[d+delta_points]; orbitP[d] = orbitP[d+delta_points];
orbit[d] = getHeliocentricPos(orbitP [d]); orbit[d] = getHeliocentricPos(orbitP [d]);
} }
} }
skipping to change at line 732 skipping to change at line 846
for( int d=0; d<ORBIT_SEGMENTS; d++ ) for( int d=0; d<ORBIT_SEGMENTS; d++ )
{ {
calc_date = dateJDE + (d-ORBIT_SEGMENTS/2)*d eltaOrbitJDE; calc_date = dateJDE + (d-ORBIT_SEGMENTS/2)*d eltaOrbitJDE;
computeTransMatrix(calc_date-core->computeDe ltaT(calc_date)/86400.0, calc_date); computeTransMatrix(calc_date-core->computeDe ltaT(calc_date)/86400.0, calc_date);
if (osculatingFunc) if (osculatingFunc)
{ {
(*osculatingFunc)(dateJDE,calc_date, eclipticPos); (*osculatingFunc)(dateJDE,calc_date, eclipticPos);
} }
else else
{ {
coordFunc(calc_date, eclipticPos, us erDataPtr); coordFunc(calc_date, eclipticPos, or bitPtr);
} }
orbitP[d] = eclipticPos; orbitP[d] = eclipticPos;
orbit[d] = getHeliocentricEclipticPos(); orbit[d] = getHeliocentricEclipticPos();
} }
lastOrbitJDE = dateJDE; lastOrbitJDE = dateJDE;
if (!osculatingFunc) orbitCached = 1; if (!osculatingFunc) orbitCached = 1;
} }
// calculate actual Planet position // calculate actual Planet position
coordFunc(dateJDE, eclipticPos, userDataPtr); coordFunc(dateJDE, eclipticPos, orbitPtr);
lastJDE = dateJDE; lastJDE = dateJDE;
} }
else if (fabs(lastJDE-dateJDE)>deltaJDE) else if (fabs(lastJDE-dateJDE)>deltaJDE)
{ {
// calculate actual Planet position // calculate actual Planet position
coordFunc(dateJDE, eclipticPos, userDataPtr); coordFunc(dateJDE, eclipticPos, orbitPtr);
if (orbitFader.getInterstate()>0.000001) if (orbitFader.getInterstate()>0.000001)
for( int d=0; d<ORBIT_SEGMENTS; d++ ) for( int d=0; d<ORBIT_SEGMENTS; d++ )
orbit[d]=getHeliocentricPos(orbitP[d]); orbit[d]=getHeliocentricPos(orbitP[d]);
lastJDE = dateJDE; lastJDE = dateJDE;
} }
} }
// Compute the transformation matrix from the local Planet coordinate syste m to the parent Planet coordinate system. // Compute the transformation matrix from the local Planet coordinate syste m to the parent Planet coordinate system.
// In case of the planets, this makes the axis point to their respective ce lestial poles. // In case of the planets, this makes the axis point to their respective ce lestial poles.
skipping to change at line 956 skipping to change at line 1070
} }
} }
// Compute the distance to the given position in heliocentric coordinate (i n AU) // Compute the distance to the given position in heliocentric coordinate (i n AU)
// This is called by SolarSystem::draw() // This is called by SolarSystem::draw()
double Planet::computeDistance(const Vec3d& obsHelioPos) double Planet::computeDistance(const Vec3d& obsHelioPos)
{ {
distance = (obsHelioPos-getHeliocentricEclipticPos()).length(); distance = (obsHelioPos-getHeliocentricEclipticPos()).length();
// improve fps by juggling updates for asteroids and other minor bod ies. They must be fast if close to observer, but can be slow if further awa y. // improve fps by juggling updates for asteroids and other minor bod ies. They must be fast if close to observer, but can be slow if further awa y.
if (pType >= Planet::isAsteroid) if (pType >= Planet::isAsteroid)
deltaJDE=distance*StelCore::JD_SECOND; deltaJDE=distance*StelCore::JD_SECOND;
return distance; return distance;
} }
// Get the phase angle (radians) for an observer at pos obsPos in heliocent ric coordinates (dist in AU) // Get the phase angle (radians) for an observer at pos obsPos in heliocent ric coordinates (dist in AU)
double Planet::getPhaseAngle(const Vec3d& obsPos) const double Planet::getPhaseAngle(const Vec3d& obsPos) const
{ {
const double observerRq = obsPos.lengthSquared(); const double observerRq = obsPos.lengthSquared();
const Vec3d& planetHelioPos = getHeliocentricEclipticPos(); const Vec3d& planetHelioPos = getHeliocentricEclipticPos();
const double planetRq = planetHelioPos.lengthSquared(); const double planetRq = planetHelioPos.lengthSquared();
const double observerPlanetRq = (obsPos - planetHelioPos).lengthSqua red(); const double observerPlanetRq = (obsPos - planetHelioPos).lengthSqua red();
return std::acos((observerPlanetRq + planetRq - observerRq)/(2.0*std ::sqrt(observerPlanetRq*planetRq))); return std::acos((observerPlanetRq + planetRq - observerRq)/(2.0*std ::sqrt(observerPlanetRq*planetRq)));
} }
// Get the planet phase for an observer at pos obsPos in heliocentric coord inates (in AU) // Get the planet phase[0..1] for an observer at pos obsPos in heliocentric coordinates (in AU)
float Planet::getPhase(const Vec3d& obsPos) const float Planet::getPhase(const Vec3d& obsPos) const
{ {
const double observerRq = obsPos.lengthSquared(); const double observerRq = obsPos.lengthSquared();
const Vec3d& planetHelioPos = getHeliocentricEclipticPos(); const Vec3d& planetHelioPos = getHeliocentricEclipticPos();
const double planetRq = planetHelioPos.lengthSquared(); const double planetRq = planetHelioPos.lengthSquared();
const double observerPlanetRq = (obsPos - planetHelioPos).lengthSqua red(); const double observerPlanetRq = (obsPos - planetHelioPos).lengthSqua red();
const double cos_chi = (observerPlanetRq + planetRq - observerRq)/(2 .0*std::sqrt(observerPlanetRq*planetRq)); const double cos_chi = (observerPlanetRq + planetRq - observerRq)/(2 .0*std::sqrt(observerPlanetRq*planetRq));
return 0.5f * qAbs(1.f + cos_chi); return 0.5f * qAbs(1.f + cos_chi);
} }
skipping to change at line 1036 skipping to change at line 1150
else if (parent->englishName=="Saturn") else if (parent->englishName=="Saturn")
semimajorAxis=9.53667594; semimajorAxis=9.53667594;
else if (parent->englishName=="Uranus") else if (parent->englishName=="Uranus")
semimajorAxis=19.18916464; semimajorAxis=19.18916464;
else if (parent->englishName=="Neptune") else if (parent->englishName=="Neptune")
semimajorAxis=30.06992276; semimajorAxis=30.06992276;
else if (parent->englishName=="Pluto") else if (parent->englishName=="Pluto")
semimajorAxis=39.48211675; semimajorAxis=39.48211675;
else if (pType>= isAsteroid) else if (pType>= isAsteroid)
{ {
if (userDataPtr) if (orbitPtr)
semimajorAxis=((CometOrbit*)userDataPtr)->getSemimaj semimajorAxis=((CometOrbit*)orbitPtr)->getSemimajorA
orAxis(); xis();
} }
if (semimajorAxis>0.) if (semimajorAxis>0.)
return absoluteMagnitude+5*log10(semimajorAxis*(semimajorAxi s-1)); return absoluteMagnitude+5*log10(semimajorAxis*(semimajorAxi s-1));
return 100.; return 100.;
} }
// Computation of the visual magnitude (V band) of the planet. // Computation of the visual magnitude (V band) of the planet.
float Planet::getVMagnitude(const StelCore* core) const float Planet::getVMagnitude(const StelCore* core) const
skipping to change at line 1135 skipping to change at line 1249
// (2) Astronomical Almanac 1984 and later. These give V (in strumental) magnitudes. // (2) Astronomical Almanac 1984 and later. These give V (in strumental) magnitudes.
// The structure is almost identical, just the numbers are d ifferent! // The structure is almost identical, just the numbers are d ifferent!
// I activate (1) for now, because we want to simulate the e ye's impression. (Esp. Venus!) // I activate (1) for now, because we want to simulate the e ye's impression. (Esp. Venus!)
// AW: (2) activated by default // AW: (2) activated by default
// GZ Note that calling (2) "Harris" is an absolute misnomer . Meeus clearly describes this in AstrAlg1998 p.286. // GZ Note that calling (2) "Harris" is an absolute misnomer . Meeus clearly describes this in AstrAlg1998 p.286.
// The values should likely be named: // The values should likely be named:
// Planesas --> Expl_Suppl_1992 AND THIS SHOULD BECOME DEFA ULT // Planesas --> Expl_Suppl_1992 AND THIS SHOULD BECOME DEFA ULT
// Mueller --> Mueller_1893 // Mueller --> Mueller_1893
// Harris --> Astr_Eph_1984 // Harris --> Astr_Eph_1984
switch (core->getCurrentPlanet()->getApparentMagnitudeAlgori thm()) switch (Planet::getApparentMagnitudeAlgorithm())
{ {
case UndefinedAlgorithm: // The most recent s olution should be activated by default case UndefinedAlgorithm: // The most recent s olution should be activated by default
case Expl_Sup_2013: case Expl_Sup_2013:
{ {
// GZ2017: This is taken straight from the E xplanatory Supplement to the Astronomical Ephemeris 2013 (chap. 10.3) // GZ2017: This is taken straight from the E xplanatory Supplement to the Astronomical Ephemeris 2013 (chap. 10.3)
// AW2017: Updated data from Errata in The E xplanatory Supplement to the Astronomical Almanac (3rd edition, 1st printin g) // AW2017: Updated data from Errata in The E xplanatory Supplement to the Astronomical Almanac (3rd edition, 1st printin g)
// http://aa.usno.navy.mil/publicati ons/docs/exp_supp_errata.pdf (Last update: 1 December 2016) // http://aa.usno.navy.mil/publicati ons/docs/exp_supp_errata.pdf (Last update: 1 December 2016)
if (englishName=="Mercury") if (englishName=="Mercury")
return -0.6 + d + (((3.02e-6*phaseDe g - 0.000488)*phaseDeg + 0.0498)*phaseDeg); return -0.6 + d + (((3.02e-6*phaseDe g - 0.000488)*phaseDeg + 0.0498)*phaseDeg);
if (englishName=="Venus") if (englishName=="Venus")
skipping to change at line 1399 skipping to change at line 1513
// Compute the 2D position and check if in the screen // Compute the 2D position and check if in the screen
const StelProjectorP prj = core->getProjection(transfo); const StelProjectorP prj = core->getProjection(transfo);
float screenSz = getAngularSize(core)*M_PI/180.*prj->getPixelPerRadA tCenter(); float screenSz = getAngularSize(core)*M_PI/180.*prj->getPixelPerRadA tCenter();
float viewportBufferSz=screenSz; float viewportBufferSz=screenSz;
// enlarge if this is sun with its huge halo. // enlarge if this is sun with its huge halo.
if (englishName=="Sun") if (englishName=="Sun")
viewportBufferSz+=125.f; viewportBufferSz+=125.f;
float viewport_left = prj->getViewportPosX(); float viewport_left = prj->getViewportPosX();
float viewport_bottom = prj->getViewportPosY(); float viewport_bottom = prj->getViewportPosY();
if ((prj->project(Vec3d(0), screenPos)
if ((prj->project(Vec3d(0.), screenPos)
&& screenPos[1]>viewport_bottom - viewportBufferSz && screenPos [1] < viewport_bottom + prj->getViewportHeight()+viewportBufferSz && screenPos[1]>viewport_bottom - viewportBufferSz && screenPos [1] < viewport_bottom + prj->getViewportHeight()+viewportBufferSz
&& screenPos[0]>viewport_left - viewportBufferSz && screenPos[0 && screenPos[0]>viewport_left - viewportBufferSz && screenPos[0
] < viewport_left + prj->getViewportWidth() + viewportBufferSz) ] < viewport_left + prj->getViewportWidth() + viewportBufferSz))
|| permanentDrawingOrbits)
{ {
// Draw the name, and the circle if it's not too close from the body it's turning around // Draw the name, and the circle if it's not too close from the body it's turning around
// this prevents name overlapping (e.g. for Jupiter's satell ites) // this prevents name overlapping (e.g. for Jupiter's satell ites)
float ang_dist = 300.f*atan(getEclipticPos().length()/getEqu inoxEquatorialPos(core).length())/core->getMovementMgr()->getCurrentFov(); float ang_dist = 300.f*atan(getEclipticPos().length()/getEqu inoxEquatorialPos(core).length())/core->getMovementMgr()->getCurrentFov();
if (ang_dist==0.f) if (ang_dist==0.f)
ang_dist = 1.f; // if ang_dist == 0, the Planet is s un.. ang_dist = 1.f; // if ang_dist == 0, the Planet is s un..
// by putting here, only draw orbit if Planet is visible for clarity // by putting here, only draw orbit if Planet is visible for clarity
drawOrbit(core); // TODO - fade in here also... drawOrbit(core); // TODO - fade in here also...
skipping to change at line 1425 skipping to change at line 1539
labelsFader=true; labelsFader=true;
} }
else else
{ {
labelsFader=false; labelsFader=false;
} }
drawHints(core, planetNameFont); drawHints(core, planetNameFont);
draw3dModel(core,transfo,screenSz); draw3dModel(core,transfo,screenSz);
} }
else if (permanentDrawingOrbits) // A special case for demos
drawOrbit(core);
return; return;
} }
class StelPainterLight class StelPainterLight
{ {
public: public:
Vec3f position; Vec3d position;
Vec3f diffuse; Vec3f diffuse;
Vec3f ambient; Vec3f ambient;
}; };
static StelPainterLight light; static StelPainterLight light;
void Planet::PlanetShaderVars::initLocations(QOpenGLShaderProgram* p) void Planet::PlanetShaderVars::initLocations(QOpenGLShaderProgram* p)
{ {
GL(projectionMatrix = p->uniformLocation("projectionMatrix")); GL(p->bind());
//attributes
GL(texCoord = p->attributeLocation("texCoord")); GL(texCoord = p->attributeLocation("texCoord"));
GL(unprojectedVertex = p->attributeLocation("unprojectedVertex")); GL(unprojectedVertex = p->attributeLocation("unprojectedVertex"));
GL(vertex = p->attributeLocation("vertex")); GL(vertex = p->attributeLocation("vertex"));
GL(texture = p->uniformLocation("tex")); GL(normalIn = p->attributeLocation("normalIn"));
//common uniforms
GL(projectionMatrix = p->uniformLocation("projectionMatrix"));
GL(tex = p->uniformLocation("tex"));
GL(lightDirection = p->uniformLocation("lightDirection")); GL(lightDirection = p->uniformLocation("lightDirection"));
GL(eyeDirection = p->uniformLocation("eyeDirection")); GL(eyeDirection = p->uniformLocation("eyeDirection"));
GL(diffuseLight = p->uniformLocation("diffuseLight")); GL(diffuseLight = p->uniformLocation("diffuseLight"));
GL(ambientLight = p->uniformLocation("ambientLight")); GL(ambientLight = p->uniformLocation("ambientLight"));
GL(shadowCount = p->uniformLocation("shadowCount")); GL(shadowCount = p->uniformLocation("shadowCount"));
GL(shadowData = p->uniformLocation("shadowData")); GL(shadowData = p->uniformLocation("shadowData"));
GL(sunInfo = p->uniformLocation("sunInfo")); GL(sunInfo = p->uniformLocation("sunInfo"));
GL(skyBrightness = p->uniformLocation("skyBrightness")); GL(skyBrightness = p->uniformLocation("skyBrightness"));
GL(orenNayarParameters = p->uniformLocation("orenNayarParameters"));
GL(outgasParameters = p->uniformLocation("outgasParameters"));
// Moon-specific variables
GL(earthShadow = p->uniformLocation("earthShadow"));
GL(normalMap = p->uniformLocation("normalMap"));
// Rings-specific variables
GL(isRing = p->uniformLocation("isRing"));
GL(ring = p->uniformLocation("ring"));
GL(outerRadius = p->uniformLocation("outerRadius"));
GL(innerRadius = p->uniformLocation("innerRadius"));
GL(ringS = p->uniformLocation("ringS"));
// Shadowmap variables
GL(shadowMatrix = p->uniformLocation("shadowMatrix"));
GL(shadowTex = p->uniformLocation("shadowTex"));
GL(poissonDisk = p->uniformLocation("poissonDisk"));
GL(p->release());
}
QOpenGLShaderProgram* Planet::createShader(const QString& name, PlanetShade
rVars& vars, const QByteArray& vSrc, const QByteArray& fSrc, const QByteArr
ay& prefix, const QMap<QByteArray, int> &fixedAttributeLocations)
{
QOpenGLShaderProgram* program = new QOpenGLShaderProgram();
if(!program->create())
{
qCritical()<<"Planet: Cannot create shader program object fo
r"<<name;
delete program;
return Q_NULLPTR;
}
// We HAVE to create QOpenGLShader on the heap (with automatic QObje
ct memory management), or the shader may be destroyed before the program ha
s been linked
// This was FUN to debug - OGL simply accepts an empty shader, no er
rors generated but funny colors drawn :)
// We could also use QOpenGLShaderProgram::addShaderFromSourceCode d
irectly, but this would prevent having access to warnings (because log is c
opied only on errors there...)
if(!vSrc.isEmpty())
{
QOpenGLShader* shd = new QOpenGLShader(QOpenGLShader::Vertex
, program);
bool ok = shd->compileSourceCode(prefix + vSrc);
QString log = shd->log();
if (!log.isEmpty() && !log.contains("no warnings", Qt::CaseI
nsensitive)) { qWarning() << "Planet: Warnings/Errors while compiling" << n
ame << "vertex shader: " << log; }
if(!ok)
{
qCritical()<<name<<"vertex shader could not be compi
led";
delete program;
return Q_NULLPTR;
}
if(!program->addShader(shd))
{
qCritical()<<name<<"vertex shader could not be added
to program";
delete program;
return Q_NULLPTR;
}
}
if(!fSrc.isEmpty())
{
QOpenGLShader* shd = new QOpenGLShader(QOpenGLShader::Fragme
nt, program);
bool ok = shd->compileSourceCode(prefix + fSrc);
QString log = shd->log();
if (!log.isEmpty() && !log.contains("no warnings", Qt::CaseI
nsensitive)) { qWarning() << "Planet: Warnings/Errors while compiling" << n
ame << "fragment shader: " << log; }
if(!ok)
{
qCritical()<<name<<"fragment shader could not be com
piled";
delete program;
return Q_NULLPTR;
}
if(!program->addShader(shd))
{
qCritical()<<name<<"fragment shader could not be add
ed to program";
delete program;
return Q_NULLPTR;
}
}
//process fixed attribute locations
QMap<QByteArray,int>::const_iterator it = fixedAttributeLocations.be
gin();
while(it!=fixedAttributeLocations.end())
{
program->bindAttributeLocation(it.key(),it.value());
++it;
}
if(!StelPainter::linkProg(program,name))
{
delete program;
return Q_NULLPTR;
}
vars.initLocations(program);
return program;
} }
void Planet::initShader() void Planet::initShader()
{ {
qDebug() << "Initializing planets GL shaders... "; qDebug() << "Initializing planets GL shaders... ";
shaderError = true;
const char *vsrc = QSettings* settings = StelApp::getInstance().getSettings();
"attribute highp vec3 vertex;\n" settings->sync();
"attribute highp vec3 unprojectedVertex;\n" shadowPolyOffset = StelUtils::strToVec2f(settings->value("astro/plan
"attribute mediump vec2 texCoord;\n" et_shadow_polygonoffset", StelUtils::vec2fToStr(Vec2f(0.0f, 0.0f))).toStrin
"uniform highp mat4 projectionMatrix;\n" g());
"uniform highp vec3 lightDirection;\n" //qDebug()<<"Shadow poly offset"<<shadowPolyOffset;
"uniform highp vec3 eyeDirection;\n"
"varying mediump vec2 texc;\n"
"varying highp vec3 P;\n"
"#ifdef IS_MOON\n"
" varying highp vec3 normalX;\n"
" varying highp vec3 normalY;\n"
" varying highp vec3 normalZ;\n"
"#else\n"
" varying mediump float lum_;\n"
"#endif\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = projectionMatrix * vec4(vertex, 1.);\n"
" texc = texCoord;\n"
" highp vec3 normal = normalize(unprojectedVertex);\n"
"#ifdef IS_MOON\n"
" normalX = normalize(cross(vec3(0,0,1), normal));\n"
" normalY = normalize(cross(normal, normalX));\n"
" normalZ = normal;\n"
"#else\n"
" mediump float c = dot(lightDirection, normal);\n"
" lum_ = clamp(c, 0.0, 1.0);\n"
"#endif\n"
"\n"
" P = unprojectedVertex;\n"
"}\n"
"\n";
const char *fsrc =
"varying mediump vec2 texc;\n"
"uniform sampler2D tex;\n"
"uniform mediump vec3 ambientLight;\n"
"uniform mediump vec3 diffuseLight;\n"
"uniform highp vec4 sunInfo;\n"
"uniform mediump float skyBrightness;\n"
"varying highp vec3 P;\n"
"\n"
"uniform int shadowCount;\n"
"uniform highp mat4 shadowData;\n"
"\n"
"#ifdef RINGS_SUPPORT\n"
"uniform bool ring;\n"
"uniform highp float outerRadius;\n"
"uniform highp float innerRadius;\n"
"uniform sampler2D ringS;\n"
"uniform bool isRing;\n"
"#endif\n"
"\n"
"#ifdef IS_MOON\n"
"uniform sampler2D earthShadow;\n"
"uniform sampler2D normalMap;\n"
"uniform highp vec3 lightDirection;\n"
"uniform highp vec3 eyeDirection;\n"
"varying highp vec3 normalX;\n"
"varying highp vec3 normalY;\n"
"varying highp vec3 normalZ;\n"
"#else\n"
"varying mediump float lum_;\n"
"#endif\n"
"\n"
"void main()\n"
"{\n"
" mediump float final_illumination = 1.0;\n"
"#ifdef IS_MOON\n"
" mediump float lum = 1.;\n"
"#else\n"
" mediump float lum = lum_;\n"
"#endif\n"
"#ifdef RINGS_SUPPORT\n"
" if(isRing)"
" lum=1.0;\n"
"#endif\n"
" if(lum > 0.0)\n"
" {\n"
" highp vec3 sunPosition = sunInfo.xyz;\n"
"#ifdef RINGS_SUPPORT\n"
" if(ring && !isRing)\n"
" {\n"
" highp vec3 ray = normalize(sunPosition);\n"
" highp float u = - P.z / ray.z;\n"
" if(u > 0.0 && u < 1e10)\n"
" {\n"
" mediump float ring_radius = length(P + u *
ray);\n"
" if(ring_radius > innerRadius && ring_radius
< outerRadius)\n"
" {\n"
" ring_radius = (ring_radius - innerRadiu
s) / (outerRadius - innerRadius);\n"
" lowp float ringAlpha = texture2D(ringS,
vec2(ring_radius, 0.5)).w;\n"
" final_illumination = 1.0 - ringAlpha;\n
"
" }\n"
" }\n"
" }\n"
"#endif\n"
"\n"
" highp float sunRadius = sunInfo.w;\n"
" highp float L = length(sunPosition - P);\n"
" highp float R = asin(sunRadius / L);\n"
" for (int i = 0; i < 4; ++i)\n"
" {\n"
" if (shadowCount>i)\n"
" {\n"
" highp vec3 satellitePosition = shadowData[i
].xyz;\n"
" highp float satelliteRadius = shadowData[i]
.w;\n"
" highp float l = length(satellitePosition -
P);\n"
" highp float r = asin(satelliteRadius / l);\
n"
" highp float d = acos(min(1.0, dot(normalize
(sunPosition - P), normalize(satellitePosition - P))));\n"
"\n"
" mediump float illumination = 1.0;\n"
" if(d >= R + r)\n"
" {\n"
" // distance too far\n"
" illumination = 1.0;\n"
" }\n"
" else if(r >= R + d)\n"
" {\n"
" // umbra\n"
"#ifdef IS_MOON\n"
" illumination = d / (r - R) * 0.6;\n"
"#else\n"
" illumination = 0.0;\n"
"#endif\n"
" }\n"
" else if(d + r <= R)\n"
" {\n"
" // penumbra completely inside\n"
" illumination = 1.0 - r * r / (R * R);\n
"
" }\n"
" else\n"
" {\n"
" // penumbra partially inside\n"
"#ifdef IS_MOON\n"
" illumination = ((d - abs(R-r)) / (R + r
- abs(R-r))) * 0.4 + 0.6;\n"
"#else\n"
" mediump float x = (R * R + d * d - r *
r) / (2.0 * d);\n"
" mediump float alpha = acos(x / R);\n"
" mediump float beta = acos((d - x) / r);
\n"
" mediump float AR = R * R * (alpha - 0.5
* sin(2.0 * alpha));\n"
" mediump float Ar = r * r * (beta - 0.5
* sin(2.0 * beta));\n"
" mediump float AS = R * R * 2.0 * 1.5707
9633;\n"
" illumination = 1.0 - (AR + Ar) / AS;\n"
"#endif\n"
" }\n"
" final_illumination = min(illumination, fina
l_illumination);\n"
" }\n"
" }\n"
" }\n"
"\n"
"#ifdef IS_MOON\n"
" mediump vec3 normal = texture2D(normalMap, texc).rgb-ve
c3(0.5, 0.5, 0);\n"
" normal = normalize(normalX*normal.x+normalY*normal.y+no
rmalZ*normal.z);\n"
" // normal now contains the real surface normal taking n
ormal map into account\n"
" // Use an Oren-Nayar model for rough surfaces\n"
" // Ref: http://content.gpwiki.org/index.php/D3DBook:(Li
ghting)_Oren-Nayar\n"
// GZ next 2 don't require highp IMHO
" mediump float cosAngleLightNormal = dot(normal, lightDi
rection);\n"
" mediump float cosAngleEyeNormal = dot(normal, eyeDirect
ion);\n"
" mediump float angleLightNormal = acos(cosAngleLightNorm
al);\n"
" mediump float angleEyeNormal = acos(cosAngleEyeNormal);
\n"
" mediump float alpha = max(angleEyeNormal, angleLightNor
mal);\n"
" mediump float beta = min(angleEyeNormal, angleLightNorm
al);\n"
" mediump float gamma = dot(eyeDirection - normal * cosAn
gleEyeNormal, lightDirection - normal * cosAngleLightNormal);\n"
// GZ next 5 can be lowp instead of mediump. Roughness origi
nal 1.0, then 0.8 in 0.14.0.
" lowp float roughness = 0.9;\n"
" lowp float roughnessSquared = roughness * roughness;\n"
" lowp float A = 1.0 - 0.5 * (roughnessSquared / (roughne
ssSquared + 0.57));\n"
" lowp float B = 0.45 * (roughnessSquared / (roughnessSqu
ared + 0.09));\n"
" lowp float C = sin(alpha) * tan(beta);\n"
// GZ final number was 2, but this causes overly bright moon
. was 1.5 in 0.14.0.
" lum = max(0.0, cosAngleLightNormal) * (A + B * max(0.0,
gamma) * C) * 1.85;\n"
"#endif\n"
//Reduce lum if sky is bright, to avoid burnt-out look in da
ylight sky.
" lum *= (1.0-0.4*skyBrightness);\n"
" mediump vec4 litColor = vec4(lum * final_illumination *
diffuseLight + ambientLight, 1.0);\n"
"#ifdef IS_MOON\n"
" if(final_illumination < 0.99)\n"
" {\n"
" lowp vec4 shadowColor = texture2D(earthShadow, vec2
(final_illumination, 0.5));\n"
" gl_FragColor = mix(texture2D(tex, texc) * litColor,
shadowColor, shadowColor.a);\n"
" }\n"
" else\n"
"#endif\n"
" {\n"
" gl_FragColor = texture2D(tex, texc) * litColor;\n"
" }\n"
"}\n";
// Default planet shader program // Shader text is loaded from file
QOpenGLShader vshader(QOpenGLShader::Vertex); QString vFileName = StelFileMgr::findFile("data/shaders/planet.vert"
vshader.compileSourceCode(vsrc); ,StelFileMgr::File);
if (!vshader.log().isEmpty()) { qWarning() << "Planet: Warnings whil QString fFileName = StelFileMgr::findFile("data/shaders/planet.frag"
e compiling vshader: " << vshader.log(); } ,StelFileMgr::File);
QOpenGLShader fshader(QOpenGLShader::Fragment);
fshader.compileSourceCode(fsrc);
if (!fshader.log().isEmpty()) { qWarning() << "Planet: Warnings whil
e compiling fshader: " << fshader.log(); }
planetShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::curre
ntContext());
planetShaderProgram->addShader(&vshader);
planetShaderProgram->addShader(&fshader);
GL(StelPainter::linkProg(planetShaderProgram, "planetShaderProgram")
);
GL(planetShaderProgram->bind());
planetShaderVars.initLocations(planetShaderProgram);
GL(planetShaderProgram->release());
// Planet with ring shader program if(vFileName.isEmpty())
QByteArray arr = "#define RINGS_SUPPORT\n\n"; {
arr+=fsrc; qCritical()<<"Cannot find 'data/shaders/planet.vert', can't
QOpenGLShader ringFragmentShader(QOpenGLShader::Fragment); use planet rendering!";
ringFragmentShader.compileSourceCode(arr.constData()); return;
if (!ringFragmentShader.log().isEmpty()) { qWarning() << "Planet: Wa }
rnings while compiling ringFragmentShader: " << ringFragmentShader.log(); } if(fFileName.isEmpty())
{
ringPlanetShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::c qCritical()<<"Cannot find 'data/shaders/planet.frag', can't
urrentContext()); use planet rendering!";
ringPlanetShaderProgram->addShader(&vshader); return;
ringPlanetShaderProgram->addShader(&ringFragmentShader); }
GL(StelPainter::linkProg(ringPlanetShaderProgram, "ringPlanetShaderP
rogram")); QFile vFile(vFileName);
GL(ringPlanetShaderProgram->bind()); QFile fFile(fFileName);
ringPlanetShaderVars.initLocations(ringPlanetShaderProgram);
GL(ringPlanetShaderVars.isRing = ringPlanetShaderProgram->uniformLoc if(!vFile.open(QIODevice::ReadOnly | QIODevice::Text))
ation("isRing")); {
GL(ringPlanetShaderVars.ring = ringPlanetShaderProgram->uniformLocat qCritical()<<"Cannot load planet vertex shader file"<<vFileN
ion("ring")); ame<<vFile.errorString();
GL(ringPlanetShaderVars.outerRadius = ringPlanetShaderProgram->unifo return;
rmLocation("outerRadius")); }
GL(ringPlanetShaderVars.innerRadius = ringPlanetShaderProgram->unifo QByteArray vsrc = vFile.readAll();
rmLocation("innerRadius")); vFile.close();
GL(ringPlanetShaderVars.ringS = ringPlanetShaderProgram->uniformLoca
tion("ringS")); if(!fFile.open(QIODevice::ReadOnly | QIODevice::Text))
GL(ringPlanetShaderProgram->release()); {
qCritical()<<"Cannot load planet fragment shader file"<<fFil
eName<<fFile.errorString();
return;
}
QByteArray fsrc = fFile.readAll();
fFile.close();
shaderError = false;
// Default planet shader program
planetShaderProgram = createShader("planetShaderProgram",planetShade
rVars,vsrc,fsrc);
// Planet with ring shader program
ringPlanetShaderProgram = createShader("ringPlanetShaderProgram",rin
gPlanetShaderVars,vsrc,fsrc,"#define RINGS_SUPPORT\n\n");
// Moon shader program // Moon shader program
arr = "#define IS_MOON\n\n"; moonShaderProgram = createShader("moonShaderProgram",moonShaderVars,
arr+=vsrc; vsrc,fsrc,"#define IS_MOON\n\n");
QOpenGLShader moonVertexShader(QOpenGLShader::Vertex); // OBJ model shader program
moonVertexShader.compileSourceCode(arr.constData()); // we REQUIRE some fixed attribute locations here
if (!moonVertexShader.log().isEmpty()) { qWarning() << "Planet: Warn QMap<QByteArray,int> attrLoc;
ings while compiling moonVertexShader: " << moonVertexShader.log(); } attrLoc.insert("unprojectedVertex", StelOpenGLArray::ATTLOC_VERTEX);
attrLoc.insert("texCoord", StelOpenGLArray::ATTLOC_TEXCOORD);
arr = "#define IS_MOON\n\n"; attrLoc.insert("normalIn", StelOpenGLArray::ATTLOC_NORMAL);
arr+=fsrc; objShaderProgram = createShader("objShaderProgram",objShaderVars,vsr
QOpenGLShader moonFragmentShader(QOpenGLShader::Fragment); c,fsrc,"#define IS_OBJ\n\n",attrLoc);
moonFragmentShader.compileSourceCode(arr.constData()); //OBJ shader with shadowmap support
if (!moonFragmentShader.log().isEmpty()) { qWarning() << "Planet: Wa objShadowShaderProgram = createShader("objShadowShaderProgram",objSh
rnings while compiling moonFragmentShader: " << moonFragmentShader.log(); } adowShaderVars,vsrc,fsrc,
"#define IS_OBJ\n"
moonShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::current "#define SHADOWMAP\n"
Context()); "#define SM_SIZE " STRINGIFY(S
moonShaderProgram->addShader(&moonVertexShader); M_SIZE) "\n"
moonShaderProgram->addShader(&moonFragmentShader);
GL(StelPainter::linkProg(moonShaderProgram, "moonPlanetShaderProgram "\n",attrLoc);
"));
GL(moonShaderProgram->bind()); //set the poisson disk as uniform, this seems to be the only way to
moonShaderVars.initLocations(moonShaderProgram); get an (const) array into GLSL 110 on all drivers
GL(moonShaderVars.earthShadow = moonShaderProgram->uniformLocation(" if(objShadowShaderProgram)
earthShadow")); {
GL(moonShaderVars.normalMap = moonShaderProgram->uniformLocation("no objShadowShaderProgram->bind();
rmalMap")); const float poissonDisk[] ={
GL(moonShaderProgram->release()); -0.610470f, -0.702763f,
0.609267f, 0.765488f,
-0.817537f, -0.412950f,
0.777710f, -0.446717f,
-0.668764f, -0.524195f,
0.425181f, 0.797780f,
-0.766728f, -0.065185f,
0.266692f, 0.917346f,
-0.578028f, -0.268598f,
0.963767f, 0.079058f,
-0.968971f, -0.039291f,
0.174263f, -0.141862f,
-0.348933f, -0.505110f,
0.837686f, -0.083142f,
-0.462722f, -0.072878f,
0.701887f, -0.281632f,
-0.377209f, -0.247278f,
0.765589f, 0.642157f,
-0.678950f, 0.128138f,
0.418512f, -0.186050f,
-0.442419f, 0.242444f,
0.442748f, -0.456745f,
-0.196461f, 0.084314f,
0.536558f, -0.770240f,
-0.190154f, -0.268138f,
0.643032f, -0.584872f,
-0.160193f, -0.457076f,
0.089220f, 0.855679f,
-0.200650f, -0.639838f,
0.220825f, 0.710969f,
-0.330313f, -0.812004f,
-0.046886f, 0.721859f,
0.070102f, -0.703208f,
-0.161384f, 0.952897f,
0.034711f, -0.432054f,
-0.508314f, 0.638471f,
-0.026992f, -0.163261f,
0.702982f, 0.089288f,
-0.004114f, -0.901428f,
0.656819f, 0.387131f,
-0.844164f, 0.526829f,
0.843124f, 0.220030f,
-0.802066f, 0.294509f,
0.863563f, 0.399832f,
0.268762f, -0.576295f,
0.465623f, 0.517930f,
0.340116f, -0.747385f,
0.223493f, 0.516709f,
0.240980f, -0.942373f,
-0.689804f, 0.649927f,
0.272309f, -0.297217f,
0.378957f, 0.162593f,
0.061461f, 0.067313f,
0.536957f, 0.249192f,
-0.252331f, 0.265096f,
0.587532f, -0.055223f,
0.034467f, 0.289122f,
0.215271f, 0.278700f,
-0.278059f, 0.615201f,
-0.369530f, 0.791952f,
-0.026918f, 0.542170f,
0.274033f, 0.010652f,
-0.561495f, 0.396310f,
-0.367752f, 0.454260f
};
objShadowShaderProgram->setUniformValueArray(objShadowShader
Vars.poissonDisk,poissonDisk,64,2);
objShadowShaderProgram->release();
}
//this is a simple transform-only shader (used for filling the depth
map for OBJ shadows)
QByteArray transformVShader(
"uniform mat4 projectionMatrix;\n"
"attribute vec4 unprojectedVertex;\n"
#ifdef DEBUG_SHADOWMAP
"attribute mediump vec2 texCoord;\n"
"varying mediump vec2 texc; //texture coord\
n"
"varying highp vec4 pos; //projected pos\n"
#endif
"void main()\n"
"{\n"
#ifdef DEBUG_SHADOWMAP
" texc = texCoord;\n"
" pos = projectionMatrix * unprojectedVert
ex;\n"
#endif
" gl_Position = projectionMatrix * unproje
ctedVertex;\n"
"}\n"
);
#ifdef DEBUG_SHADOWMAP
const QByteArray transformFShader(
"uniform lowp sampler2D tex;\n"
"varying mediump vec2 texc; //texture coord\
n"
"varying highp vec4 pos; //projected pos\n"
"void main()\n"
"{\n"
" lowp vec4 texCol = texture2D(tex,texc);\
n"
" highp float zNorm = (pos.z + 1.0) / 2.0;
\n" //from [-1,1] to [0,1]
" gl_FragColor = vec4(texCol.rgb,zNorm);\n
"
"}\n"
);
#else
//On ES2, we have to create an empty dummy FShader or the compiler m
ay complain
//but don't do this on desktop, at least my Intel fails linking with
this (with no log message, yay...)
QByteArray transformFShader;
if(QOpenGLContext::currentContext()->isOpenGLES())
{
transformFShader = "void main()\n{ }\n";
}
#endif
GL(transformShaderProgram = createShader("transformShaderProgam", tr
ansformShaderVars, transformVShader, transformFShader,QByteArray(),attrLoc)
);
//check if ALL shaders have been created correctly
shaderError = !(planetShaderProgram&&
ringPlanetShaderProgram&&
moonShaderProgram&&
objShaderProgram&&
objShadowShaderProgram&&
transformShaderProgram);
} }
void Planet::deinitShader() void Planet::deinitShader()
{ {
//note that it is not necessary to check for Q_NULLPTR before delete
delete planetShaderProgram; delete planetShaderProgram;
planetShaderProgram = NULL; planetShaderProgram = Q_NULLPTR;
delete ringPlanetShaderProgram; delete ringPlanetShaderProgram;
ringPlanetShaderProgram = NULL; ringPlanetShaderProgram = Q_NULLPTR;
delete moonShaderProgram; delete moonShaderProgram;
moonShaderProgram = NULL; moonShaderProgram = Q_NULLPTR;
delete objShaderProgram;
objShaderProgram = Q_NULLPTR;
delete objShadowShaderProgram;
objShadowShaderProgram = Q_NULLPTR;
delete transformShaderProgram;
transformShaderProgram = Q_NULLPTR;
}
bool Planet::initFBO()
{
if(shadowInitialized)
return false;
QOpenGLContext* ctx = QOpenGLContext::currentContext();
QOpenGLFunctions* gl = ctx->functions();
bool isGLESv2 = false;
bool error = false;
//check if support for the required features is available
if(!ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::Framebuffer
s))
{
qWarning()<<"Your GL driver does not support framebuffer obj
ects, OBJ model self-shadows will not be available";
error = true;
}
else if(ctx->isOpenGLES() &&
ctx->format().majorVersion()<3)
{
isGLESv2 = true;
//GLES v2 requires extensions for depth textures
if(!(ctx->hasExtension("GL_OES_depth_texture") || ctx->hasEx
tension("GL_ANGLE_depth_texture")))
{
qWarning()<<"Your GL driver has no support for depth
textures, OBJ model self-shadows will not be available";
error = true;
}
}
//on desktop, depth textures should be available on all GL >= 1.4 co
ntexts, so no check should be required
if(!error)
{
//all seems ok, create our objects
GL(gl->glGenTextures(1, &shadowTex));
GL(gl->glActiveTexture(GL_TEXTURE1));
GL(gl->glBindTexture(GL_TEXTURE_2D, shadowTex));
#ifndef QT_OPENGL_ES_2
if(!isGLESv2)
{
GL(gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BAS
E_LEVEL, 0));
GL(gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX
_LEVEL, 0));
GL(gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRA
P_S, GL_CLAMP_TO_BORDER));
GL(gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRA
P_T, GL_CLAMP_TO_BORDER));
const float ones[] = {1.0f, 1.0f, 1.0f, 1.0f};
GL(gl->glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BO
RDER_COLOR, ones));
}
#endif
GL(gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST));
GL(gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST));
#ifndef DEBUG_SHADOWMAP
//create the texture
//note that the 'type' must be GL_UNSIGNED_SHORT or GL_UNSIG
NED_INT for ES2 compatibility, even if the 'pixels' are Q_NULLPTR
GL(gl->glTexImage2D(GL_TEXTURE_2D, 0, isGLESv2?GL_DEPTH_COMP
ONENT:GL_DEPTH_COMPONENT16, SM_SIZE, SM_SIZE, 0, GL_DEPTH_COMPONENT, GL_UNS
IGNED_SHORT, Q_NULLPTR));
//we dont use QOpenGLFramebuffer because we dont want a colo
r buffer...
GL(gl->glGenFramebuffers(1, &shadowFBO));
GL(gl->glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO));
//attach shadow tex to FBO
gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHME
NT, GL_TEXTURE_2D, shadowTex, 0);
//on desktop, we must disable the read/draw buffer because w
e have no color buffer
//else, it would be an FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER er
ror
//see GL_EXT_framebuffer_object and GL_ARB_framebuffer_objec
t
//on ES 2, this seems to be allowed (there are no glDrawBuff
ers/glReadBuffer functions there), see GLES spec section 4.4.4
//probably same on ES 3: though it has glDrawBuffers/glReadB
uffer but no mention of it in section 4.4.4 and no FRAMEBUFFER_INCOMPLETE_D
RAW_BUFFER is defined
#ifndef QT_OPENGL_ES_2
if(!ctx->isOpenGLES())
{
QOpenGLFunctions_1_0* gl10 = ctx->versionFunctions<Q
OpenGLFunctions_1_0>();
if(Q_LIKELY(gl10))
{
//use DrawBuffer instead of DrawBuffers
//because it is available since GL 1.0 inste
ad of only on 3+
gl10->glDrawBuffer(GL_NONE);
gl10->glReadBuffer(GL_NONE);
}
else
{
//something is probably not how we want it
Q_ASSERT(0);
}
}
#endif
//check for completeness
GLenum status = gl->glCheckFramebufferStatus(GL_FRAMEBUFFER)
;
if(status != GL_FRAMEBUFFER_COMPLETE)
{
error = true;
qWarning()<<"Planet self-shadow framebuffer is incom
plete, cannot use. Status:"<<status;
}
GL(gl->glBindFramebuffer(GL_FRAMEBUFFER, StelApp::getInstanc
e().getDefaultFBO()));
gl->glActiveTexture(GL_TEXTURE0);
#else
GL(shadowFBO = new QOpenGLFramebufferObject(SM_SIZE,SM_SIZE,
QOpenGLFramebufferObject::Depth));
error = !shadowFBO->isValid();
#endif
qDebug()<<"Planet self-shadow framebuffer initialized";
}
shadowInitialized = true;
return !error;
}
void Planet::deinitFBO()
{
if(!shadowInitialized)
return;
QOpenGLFunctions* gl = QOpenGLContext::currentContext()->functions()
;
#ifndef DEBUG_SHADOWMAP
//zeroed names are ignored by GL
gl->glDeleteFramebuffers(1,&shadowFBO);
shadowFBO = 0;
#else
delete shadowFBO;
shadowFBO = Q_NULLPTR;
#endif
gl->glDeleteTextures(1,&shadowTex);
shadowTex = 0;
shadowInitialized = false;
} }
void Planet::draw3dModel(StelCore* core, StelProjector::ModelViewTranformP transfo, float screenSz, bool drawOnlyRing) void Planet::draw3dModel(StelCore* core, StelProjector::ModelViewTranformP transfo, float screenSz, bool drawOnlyRing)
{ {
// This is the main method drawing a planet 3d model // This is the main method drawing a planet 3d model
// Some work has to be done on this method to make the rendering nic er // Some work has to be done on this method to make the rendering nic er
SolarSystem* ssm = GETSTELMODULE(SolarSystem); SolarSystem* ssm = GETSTELMODULE(SolarSystem);
// Find extinction settings to change colors. The method is rather a d-hoc. // Find extinction settings to change colors. The method is rather a d-hoc.
float extinctedMag=getVMagnitudeWithExtinction(core)-getVMagnitude(c ore); // this is net value of extinction, in mag. float extinctedMag=getVMagnitudeWithExtinction(core)-getVMagnitude(c ore); // this is net value of extinction, in mag.
float magFactorGreen=pow(0.85f, 0.6f*extinctedMag); float magFactorGreen=pow(0.85f, 0.6f*extinctedMag);
float magFactorBlue=pow(0.6f, 0.5f*extinctedMag); float magFactorBlue=pow(0.6f, 0.5f*extinctedMag);
if (screenSz>1.) if (screenSz>1.)
{ {
//make better use of depth buffer by adjusting clipping plan
es
//must be done before creating StelPainter
//depth buffer is used for object with rings or with OBJ mod
els
//it is not used for normal spherical object rendering witho
ut rings!
//but it does not hurt to adjust it in all cases
double n,f;
core->getClippingPlanes(&n,&f); // Save clipping planes
//determine the minimum size of the clip space
double r = radius*sphereScale;
if(rings)
r+=rings->getSize();
const double dist = getEquinoxEquatorialPos(core).length();
double z_near = (dist - r); //near Z should be as close as p
ossible to the actual geometry
double z_far = (dist + 10*r); //far Z should be quite a bit
further behind (Z buffer accuracy is worse near the far plane)
if (z_near < 0.0) z_near = 0.0;
core->setClippingPlanes(z_near,z_far);
StelProjector::ModelViewTranformP transfo2 = transfo->clone( ); StelProjector::ModelViewTranformP transfo2 = transfo->clone( );
transfo2->combine(Mat4d::zrotation(M_PI/180*(axisRotation + 90.))); transfo2->combine(Mat4d::zrotation(M_PI/180*(axisRotation + 90.)));
StelPainter* sPainter = new StelPainter(core->getProjection( transfo2)); StelPainter* sPainter = new StelPainter(core->getProjection( transfo2));
gl = sPainter->glFuncs();
if (flagLighting) // Set the main source of light to be the sun
{ Vec3d sunPos(0.);
// Set the main source of light to be the sun core->getHeliocentricEclipticModelViewTransform()->forward(s
Vec3d sunPos(0); unPos);
core->getHeliocentricEclipticModelViewTransform()->f light.position=Vec4d(sunPos);
orward(sunPos);
light.position=Vec4f(sunPos[0],sunPos[1],sunPos[2],1 // Set the light parameters taking sun as the light source
.f); light.diffuse = Vec4f(1.f,magFactorGreen*1.f,magFactorBlue*1
.f);
// Set the light parameters taking sun as the light light.ambient = Vec4f(0.02f,magFactorGreen*0.02f,magFactorBl
source ue*0.02f);
light.diffuse = Vec4f(1.f,magFactorGreen*1.f,magFact
orBlue*1.f); if (this==ssm->getMoon())
light.ambient = Vec4f(0.02f,magFactorGreen*0.02f,mag {
FactorBlue*0.02f); // ambient for the moon can provide the Ashen light!
// TODO: ambient for the moon should provide the Ash // during daylight, this still should not make moon
en light! visible. We grab sky brightness and dim the moon.
// This approach here is again pretty ad-hoc.
if (this==ssm->getMoon()) // We have 5000cd/m^2 at sunset returned (Note this
{ may be unnaturally much. Should be rather 10, but the 5000 may include the
float fov=core->getProjection(transfo)->getF sun).
ov(); // When atm.brightness has fallen to 2000cd/m^2, we
float fovFactor=1.6f; allow ashen light to appear visible. Its impact is full when atm.brightness
// scale brightness to reduce if fov smaller is below 1000.
than 5 degrees. Min brightness (to avoid glare) if fov=2deg. LandscapeMgr* lmgr = GETSTELMODULE(LandscapeMgr);
if (fov<5.0f) Q_ASSERT(lmgr);
{ float atmLum=(lmgr->getFlagAtmosphere() ? lmgr->getA
fovFactor -= 0.1f*(5.0f-qMax(2.0f, f tmosphereAverageLuminance() : 0.0f);
ov)); if (atmLum<2000.0f)
} {
// Special case for the Moon. Was 1.6, but t float atmScaling=1.0f- (qMax(1000.0f, atmLum
his often is too bright. )-1000.0f)*0.001f; // full impact when atmLum<1000.
light.diffuse = Vec4f(fovFactor,magFactorGre float ashenFactor=(1.0f-getPhase(ssm->getEar
en*fovFactor,magFactorBlue*fovFactor,1.f); th()->getHeliocentricEclipticPos())); // We really mean the Earth for this!
(Try observing from Mars ;-)
ashenFactor*=ashenFactor*0.15f*atmScaling;
light.ambient = Vec4f(ashenFactor,magFactorG
reen*ashenFactor,magFactorBlue*ashenFactor);
}
float fov=core->getProjection(transfo)->getFov();
float fovFactor=1.6f;
// scale brightness to reduce if fov smaller than 5
degrees. Min brightness (to avoid glare) if fov=2deg.
if (fov<5.0f)
{
fovFactor -= 0.1f*(5.0f-qMax(2.0f, fov));
} }
} // Special case for the Moon. Was 1.6, but this ofte
else n is too bright.
{ light.diffuse = Vec4f(fovFactor,magFactorGreen*fovFa
sPainter->setColor(albedo,magFactorGreen*albedo,magF ctor,magFactorBlue*fovFactor,1.f);
actorBlue*albedo);
} }
// possibly tint sun's color from extinction. This should de liberately cause stronger reddening than for the other objects. // possibly tint sun's color from extinction. This should de liberately cause stronger reddening than for the other objects.
if (this==ssm->getSun()) if (this==ssm->getSun())
{ {
// when we zoom in, reduce the overbrightness. (LP:# 1421173) // when we zoom in, reduce the overbrightness. (LP:# 1421173)
const float fov=core->getProjection(transfo)->getFov (); const float fov=core->getProjection(transfo)->getFov ();
const float overbright=qMin(2.0f, qMax(0.85f,0.5f*fo v)); // scale full brightness to 0.85...2. (<2 when fov gets under 4 degree s) const float overbright=qBound(0.85f, 0.5f*fov, 2.0f) ; // scale full brightness to 0.85...2. (<2 when fov gets under 4 degrees)
sPainter->setColor(overbright, pow(0.75f, extinctedM ag)*overbright, pow(0.42f, 0.9f*extinctedMag)*overbright); sPainter->setColor(overbright, pow(0.75f, extinctedM ag)*overbright, pow(0.42f, 0.9f*extinctedMag)*overbright);
} }
if (rings) //if (rings) /// GZ This was the previous condition. Not sur
e why rings were dropped?
if(ssm->getFlagUseObjModels() && !objModelPath.isEmpty())
{ {
// The planet has rings, we need to use depth buffer if(!drawObjModel(sPainter, screenSz))
and adjust the clipping planes to avoid {
// reaching the maximum resolution of the depth buff drawSphere(sPainter, screenSz, drawOnlyRing)
er ;
const double dist = getEquinoxEquatorialPos(core).le }
ngth();
double z_near = 0.9*(dist - rings->getSize());
double z_far = 1.1*(dist + rings->getSize());
if (z_near < 0.0) z_near = 0.0;
double n,f;
core->getClippingPlanes(&n,&f); // Save clipping pla
nes
core->setClippingPlanes(z_near,z_far);
drawSphere(sPainter, screenSz, drawOnlyRing);
core->setClippingPlanes(n,f); // Restore old clippi
ng planes
} }
else else
{ drawSphere(sPainter, screenSz, drawOnlyRing);
// Normal planet
drawSphere(sPainter, screenSz); core->setClippingPlanes(n,f); // Restore old clipping plane
} s
delete sPainter; delete sPainter;
sPainter=NULL; sPainter=Q_NULLPTR;
} }
bool allowDrawHalo = true; bool allowDrawHalo = true;
if ((this!=ssm->getSun()) && ((this !=ssm->getMoon() && core->getCur rentLocation().planetName=="Earth" ))) if ((this!=ssm->getSun()) && ((this !=ssm->getMoon() && core->getCur rentLocation().planetName=="Earth" )))
{ {
// Let's hide halo when inner planet between Sun and observe r (or moon between planet and observer). // Let's hide halo when inner planet between Sun and observe r (or moon between planet and observer).
// Do not hide Earth's moon's halo below ~-45degrees when ob serving from earth. // Do not hide Earth's moon's halo below ~-45degrees when ob serving from earth.
Vec3d obj = getJ2000EquatorialPos(core); Vec3d obj = getJ2000EquatorialPos(core);
Vec3d par = getParent()->getJ2000EquatorialPos(core); Vec3d par = getParent()->getJ2000EquatorialPos(core);
double angle = obj.angle(par)*180.f/M_PI; double angle = obj.angle(par)*180.f/M_PI;
skipping to change at line 1957 skipping to change at line 2260
{ {
result = Mat4d::translation(eclipticPos) * rotLocalToParent * Mat4d: :zrotation(M_PI/180*(axisRotation + 90.)); result = Mat4d::translation(eclipticPos) * rotLocalToParent * Mat4d: :zrotation(M_PI/180*(axisRotation + 90.));
PlanetP p = parent; PlanetP p = parent;
while (p && p->parent) while (p && p->parent)
{ {
result = Mat4d::translation(p->eclipticPos) * result * p->ro tLocalToParent; result = Mat4d::translation(p->eclipticPos) * result * p->ro tLocalToParent;
p = p->parent; p = p->parent;
} }
} }
Planet::RenderData Planet::setCommonShaderUniforms(const StelPainter& paint
er, QOpenGLShaderProgram* shader, const PlanetShaderVars& shaderVars) const
{
RenderData data;
const PlanetP sun = GETSTELMODULE(SolarSystem)->getSun();
const StelProjectorP& projector = painter.getProjector();
const Mat4f& m = projector->getProjectionMatrix();
const QMatrix4x4 qMat = m.convertToQMatrix();
computeModelMatrix(data.modelMatrix);
// used to project from solar system into local space
data.mTarget = data.modelMatrix.inverse();
data.shadowCandidates = getCandidatesForShadow();
// Our shader doesn't support more than 4 planets creating shadow
if (data.shadowCandidates.size()>4)
{
qDebug() << "Too many satellite shadows, some won't be displ
ayed";
data.shadowCandidates.resize(4);
}
Mat4d shadowModelMatrix;
for (int i=0;i<data.shadowCandidates.size();++i)
{
data.shadowCandidates.at(i)->computeModelMatrix(shadowModelM
atrix);
const Vec4d position = data.mTarget * shadowModelMatrix.getC
olumn(3);
data.shadowCandidatesData(0, i) = position[0];
data.shadowCandidatesData(1, i) = position[1];
data.shadowCandidatesData(2, i) = position[2];
data.shadowCandidatesData(3, i) = data.shadowCandidates.at(i
)->getRadius();
}
Vec3f lightPos3(light.position[0], light.position[1], light.position
[2]);
projector->getModelViewTransform()->backward(lightPos3);
lightPos3.normalize();
data.eyePos = StelApp::getInstance().getCore()->getObserverHeliocent
ricEclipticPos();
//qDebug() << eyePos[0] << " " << eyePos[1] << " " << eyePos[2] << "
--> ";
// Use refractionOff for avoiding flickering Moon. (Bug #1411958)
StelApp::getInstance().getCore()->getHeliocentricEclipticModelViewTr
ansform(StelCore::RefractionOff)->forward(data.eyePos);
//qDebug() << "-->" << eyePos[0] << " " << eyePos[1] << " " << eyePo
s[2];
projector->getModelViewTransform()->backward(data.eyePos);
data.eyePos.normalize();
//qDebug() << " -->" << eyePos[0] << " " << eyePos[1] << " " << eyeP
os[2];
LandscapeMgr* lmgr=GETSTELMODULE(LandscapeMgr);
Q_ASSERT(lmgr);
GL(shader->setUniformValue(shaderVars.projectionMatrix, qMat));
GL(shader->setUniformValue(shaderVars.lightDirection, lightPos3[0],
lightPos3[1], lightPos3[2]));
GL(shader->setUniformValue(shaderVars.eyeDirection, data.eyePos[0],
data.eyePos[1], data.eyePos[2]));
GL(shader->setUniformValue(shaderVars.diffuseLight, light.diffuse[0]
, light.diffuse[1], light.diffuse[2]));
GL(shader->setUniformValue(shaderVars.ambientLight, light.ambient[0]
, light.ambient[1], light.ambient[2]));
GL(shader->setUniformValue(shaderVars.tex, 0));
GL(shader->setUniformValue(shaderVars.shadowCount, data.shadowCandid
ates.size()));
GL(shader->setUniformValue(shaderVars.shadowData, data.shadowCandida
tesData));
GL(shader->setUniformValue(shaderVars.sunInfo, data.mTarget[12], dat
a.mTarget[13], data.mTarget[14], sun->getRadius()));
GL(shader->setUniformValue(shaderVars.skyBrightness, lmgr->getLumina
nce()));
if(shaderVars.orenNayarParameters>=0)
{
//calculate and set oren-nayar parameters
float roughnessSq = roughness * roughness;
QVector3D vec(
1.0f - 0.5f * roughnessSq / (roughne
ssSq + 0.57f), //x = A
0.45f * roughnessSq / (roughnessSq +
0.09f), //y = B
1.85f //z = scale factor
);
GL(shader->setUniformValue(shaderVars.orenNayarParameters, v
ec));
}
float outgas_intensity_distanceScaled=outgas_intensity/getHeliocentr
icEclipticPos().lengthSquared(); // ad-hoc function: assume square falloff
by distance.
GL(shader->setUniformValue(shaderVars.outgasParameters, QVector2D(ou
tgas_intensity_distanceScaled, outgas_falloff)));
return data;
}
void Planet::drawSphere(StelPainter* painter, float screenSz, bool drawOnly Ring) void Planet::drawSphere(StelPainter* painter, float screenSz, bool drawOnly Ring)
{ {
if (texMap) if (texMap)
{ {
// For lazy loading, return if texture not yet loaded // For lazy loading, return if texture not yet loaded
if (!texMap->bind(0)) if (!texMap->bind(0))
{ {
return; return;
} }
} }
skipping to change at line 1981 skipping to change at line 2361
// Draw the spheroid itself // Draw the spheroid itself
// Adapt the number of facets according with the size of the sphere for optimization // Adapt the number of facets according with the size of the sphere for optimization
int nb_facet = (int)(screenSz * 40.f/50.f); // 40 facets for 102 4 pixels diameter on screen int nb_facet = (int)(screenSz * 40.f/50.f); // 40 facets for 102 4 pixels diameter on screen
if (nb_facet<10) nb_facet = 10; if (nb_facet<10) nb_facet = 10;
if (nb_facet>100) nb_facet = 100; if (nb_facet>100) nb_facet = 100;
// Generates the vertice // Generates the vertice
Planet3DModel model; Planet3DModel model;
sSphere(&model, radius*sphereScale, oneMinusOblateness, nb_facet, nb _facet); sSphere(&model, radius*sphereScale, oneMinusOblateness, nb_facet, nb _facet);
QVector<float> projectedVertexArr; QVector<float> projectedVertexArr(model.vertexArr.size());
projectedVertexArr.resize(model.vertexArr.size());
for (int i=0;i<model.vertexArr.size()/3;++i) for (int i=0;i<model.vertexArr.size()/3;++i)
painter->getProjector()->project(*((Vec3f*)(model.vertexArr. constData()+i*3)), *((Vec3f*)(projectedVertexArr.data()+i*3))); painter->getProjector()->project(*((Vec3f*)(model.vertexArr. constData()+i*3)), *((Vec3f*)(projectedVertexArr.data()+i*3)));
const SolarSystem* ssm = GETSTELMODULE(SolarSystem); const SolarSystem* ssm = GETSTELMODULE(SolarSystem);
if (this==ssm->getSun()) if (this==ssm->getSun())
{ {
texMap->bind(); texMap->bind();
//painter->setColor(2, 2, 0.2); // This is now in draw3dMode l() to apply extinction //painter->setColor(2, 2, 0.2); // This is now in draw3dMode l() to apply extinction
painter->setArrays((Vec3f*)projectedVertexArr.constData(), ( Vec2f*)model.texCoordArr.constData()); painter->setArrays((Vec3f*)projectedVertexArr.constData(), ( Vec2f*)model.texCoordArr.constData());
painter->drawFromArray(StelPainter::Triangles, model.indiceA rr.size(), 0, false, model.indiceArr.constData()); painter->drawFromArray(StelPainter::Triangles, model.indiceA rr.size(), 0, false, model.indiceArr.constData());
return; return;
} }
if (planetShaderProgram==NULL) //cancel out if shaders are invalid
Planet::initShader(); if(shaderError)
Q_ASSERT(planetShaderProgram!=NULL); return;
Q_ASSERT(ringPlanetShaderProgram!=NULL);
Q_ASSERT(moonShaderProgram!=NULL);
QOpenGLShaderProgram* shader = planetShaderProgram; QOpenGLShaderProgram* shader = planetShaderProgram;
const PlanetShaderVars* shaderVars = &planetShaderVars; const PlanetShaderVars* shaderVars = &planetShaderVars;
if (rings) if (rings)
{ {
shader = ringPlanetShaderProgram; shader = ringPlanetShaderProgram;
shaderVars = &ringPlanetShaderVars; shaderVars = &ringPlanetShaderVars;
} }
if (this==ssm->getMoon()) if (this==ssm->getMoon())
{ {
shader = moonShaderProgram; shader = moonShaderProgram;
shaderVars = &moonShaderVars; shaderVars = &moonShaderVars;
} }
GL(shader->bind()); //check if shaders are loaded
if(!shader)
const Mat4f& m = painter->getProjector()->getProjectionMatrix();
const QMatrix4x4 qMat(m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[1
3], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]);
Mat4d modelMatrix;
computeModelMatrix(modelMatrix);
// TODO explain this
const Mat4d mTarget = modelMatrix.inverse();
QMatrix4x4 shadowCandidatesData;
QVector<const Planet*> shadowCandidates = getCandidatesForShadow();
// Our shader doesn't support more than 4 planets creating shadow
if (shadowCandidates.size()>4)
{ {
qDebug() << "Too many satellite shadows, some won't be displ Planet::initShader();
ayed";
shadowCandidates.resize(4);
}
for (int i=0;i<shadowCandidates.size();++i)
{
shadowCandidates.at(i)->computeModelMatrix(modelMatrix);
const Vec4d position = mTarget * modelMatrix.getColumn(3);
shadowCandidatesData(0, i) = position[0];
shadowCandidatesData(1, i) = position[1];
shadowCandidatesData(2, i) = position[2];
shadowCandidatesData(3, i) = shadowCandidates.at(i)->getRadi
us();
}
const StelProjectorP& projector = painter->getProjector(); if(shaderError)
{
qCritical()<<"Can't use planet drawing, shaders inva
lid!";
return;
}
Vec3f lightPos3(light.position[0], light.position[1], light.position shader = planetShaderProgram;
[2]); if (rings)
projector->getModelViewTransform()->backward(lightPos3); {
lightPos3.normalize(); shader = ringPlanetShaderProgram;
}
if (this==ssm->getMoon())
{
shader = moonShaderProgram;
}
}
Vec3d eyePos = StelApp::getInstance().getCore()->getObserverHeliocen GL(shader->bind());
tricEclipticPos();
//qDebug() << eyePos[0] << " " << eyePos[1] << " " << eyePos[2] << "
--> ";
// Use refractionOff for avoiding flickering Moon. (Bug #1411958)
StelApp::getInstance().getCore()->getHeliocentricEclipticModelViewTr
ansform(StelCore::RefractionOff)->forward(eyePos);
//qDebug() << "-->" << eyePos[0] << " " << eyePos[1] << " " << eyePo
s[2];
projector->getModelViewTransform()->backward(eyePos);
eyePos.normalize();
//qDebug() << " -->" << eyePos[0] << " " << eyePos[1] << " " << eyeP
os[2];
LandscapeMgr* lmgr=GETSTELMODULE(LandscapeMgr);
Q_ASSERT(lmgr);
GL(shader->setUniformValue(shaderVars->projectionMatrix, qMat)); RenderData rData = setCommonShaderUniforms(*painter,shader,*shaderVa
GL(shader->setUniformValue(shaderVars->lightDirection, lightPos3[0], rs);
lightPos3[1], lightPos3[2]));
GL(shader->setUniformValue(shaderVars->eyeDirection, eyePos[0], eyeP
os[1], eyePos[2]));
GL(shader->setUniformValue(shaderVars->diffuseLight, light.diffuse[0
], light.diffuse[1], light.diffuse[2]));
GL(shader->setUniformValue(shaderVars->ambientLight, light.ambient[0
], light.ambient[1], light.ambient[2]));
GL(shader->setUniformValue(shaderVars->texture, 0));
GL(shader->setUniformValue(shaderVars->shadowCount, shadowCandidates
.size()));
GL(shader->setUniformValue(shaderVars->shadowData, shadowCandidatesD
ata));
GL(shader->setUniformValue(shaderVars->sunInfo, mTarget[12], mTarget
[13], mTarget[14], ssm->getSun()->getRadius()));
GL(texMap->bind(1));
GL(shader->setUniformValue(shaderVars->skyBrightness, lmgr->getLumin
ance()));
if (rings!=NULL) if (rings!=Q_NULLPTR)
{ {
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.isRing, false)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.isRing, false));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.ring, true)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.ring, true));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.outerRadius, rings->radiusMax)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.outerRadius, rings->radiusMax));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.innerRadius, rings->radiusMin)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.innerRadius, rings->radiusMin));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.ringS, 2)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.ringS, 2));
rings->tex->bind(2); rings->tex->bind(2);
} }
if (this==ssm->getMoon()) if (this==ssm->getMoon())
{ {
GL(normalMap->bind(2)); GL(normalMap->bind(2));
GL(moonShaderProgram->setUniformValue(moonShaderVars.normalM ap, 2)); GL(moonShaderProgram->setUniformValue(moonShaderVars.normalM ap, 2));
if (!shadowCandidates.isEmpty()) if (!rData.shadowCandidates.isEmpty())
{ {
GL(texEarthShadow->bind(3)); GL(texEarthShadow->bind(3));
GL(moonShaderProgram->setUniformValue(moonShaderVars .earthShadow, 3)); GL(moonShaderProgram->setUniformValue(moonShaderVars .earthShadow, 3));
} }
} }
GL(shader->setAttributeArray(shaderVars->vertex, (const GLfloat*)pro jectedVertexArr.constData(), 3)); GL(shader->setAttributeArray(shaderVars->vertex, (const GLfloat*)pro jectedVertexArr.constData(), 3));
GL(shader->enableAttributeArray(shaderVars->vertex)); GL(shader->enableAttributeArray(shaderVars->vertex));
GL(shader->setAttributeArray(shaderVars->unprojectedVertex, (const G Lfloat*)model.vertexArr.constData(), 3)); GL(shader->setAttributeArray(shaderVars->unprojectedVertex, (const G Lfloat*)model.vertexArr.constData(), 3));
GL(shader->enableAttributeArray(shaderVars->unprojectedVertex)); GL(shader->enableAttributeArray(shaderVars->unprojectedVertex));
GL(shader->setAttributeArray(shaderVars->texCoord, (const GLfloat*)m odel.texCoordArr.constData(), 2)); GL(shader->setAttributeArray(shaderVars->texCoord, (const GLfloat*)m odel.texCoordArr.constData(), 2));
GL(shader->enableAttributeArray(shaderVars->texCoord)); GL(shader->enableAttributeArray(shaderVars->texCoord));
QOpenGLFunctions* gl = painter->glFuncs();
if (rings) if (rings)
{ {
painter->setDepthMask(true); painter->setDepthMask(true);
painter->setDepthTest(true); painter->setDepthTest(true);
gl->glClear(GL_DEPTH_BUFFER_BIT); gl->glClear(GL_DEPTH_BUFFER_BIT);
} }
if (!drawOnlyRing) if (!drawOnlyRing)
GL(gl->glDrawElements(GL_TRIANGLES, model.indiceArr.size(), GL_UNSIGNED_SHORT, model.indiceArr.constData())); GL(gl->glDrawElements(GL_TRIANGLES, model.indiceArr.size(), GL_UNSIGNED_SHORT, model.indiceArr.constData()));
skipping to change at line 2124 skipping to change at line 2468
// Draw the rings just after the planet // Draw the rings just after the planet
painter->setDepthMask(false); painter->setDepthMask(false);
// Normal transparency mode // Normal transparency mode
painter->setBlending(true); painter->setBlending(true);
Ring3DModel ringModel; Ring3DModel ringModel;
sRing(&ringModel, rings->radiusMin, rings->radiusMax, 128, 3 2); sRing(&ringModel, rings->radiusMin, rings->radiusMax, 128, 3 2);
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.isRing, true)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.isRing, true));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.texture, 2)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.tex, 2));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.ringS, 1)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.ringS, 1));
computeModelMatrix(modelMatrix); QMatrix4x4 shadowCandidatesData;
const Vec4d position = mTarget * modelMatrix.getColumn(3); const Vec4d position = rData.mTarget * rData.modelMatrix.get
Column(3);
shadowCandidatesData(0, 0) = position[0]; shadowCandidatesData(0, 0) = position[0];
shadowCandidatesData(1, 0) = position[1]; shadowCandidatesData(1, 0) = position[1];
shadowCandidatesData(2, 0) = position[2]; shadowCandidatesData(2, 0) = position[2];
shadowCandidatesData(3, 0) = getRadius(); shadowCandidatesData(3, 0) = getRadius();
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.shadowCount, 1)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.shadowCount, 1));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.shadowData, shadowCandidatesData)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader Vars.shadowData, shadowCandidatesData));
projectedVertexArr.resize(ringModel.vertexArr.size()); projectedVertexArr.resize(ringModel.vertexArr.size());
for (int i=0;i<ringModel.vertexArr.size()/3;++i) for (int i=0;i<ringModel.vertexArr.size()/3;++i)
painter->getProjector()->project(*((Vec3f*)(ringMode l.vertexArr.constData()+i*3)), *((Vec3f*)(projectedVertexArr.data()+i*3))); painter->getProjector()->project(*((Vec3f*)(ringMode l.vertexArr.constData()+i*3)), *((Vec3f*)(projectedVertexArr.data()+i*3)));
GL(ringPlanetShaderProgram->setAttributeArray(ringPlanetShad erVars.vertex, (const GLfloat*)projectedVertexArr.constData(), 3)); GL(ringPlanetShaderProgram->setAttributeArray(ringPlanetShad erVars.vertex, (const GLfloat*)projectedVertexArr.constData(), 3));
GL(ringPlanetShaderProgram->enableAttributeArray(ringPlanetS haderVars.vertex)); GL(ringPlanetShaderProgram->enableAttributeArray(ringPlanetS haderVars.vertex));
GL(ringPlanetShaderProgram->setAttributeArray(ringPlanetShad erVars.unprojectedVertex, (const GLfloat*)ringModel.vertexArr.constData(), 3)); GL(ringPlanetShaderProgram->setAttributeArray(ringPlanetShad erVars.unprojectedVertex, (const GLfloat*)ringModel.vertexArr.constData(), 3));
GL(ringPlanetShaderProgram->enableAttributeArray(ringPlanetS haderVars.unprojectedVertex)); GL(ringPlanetShaderProgram->enableAttributeArray(ringPlanetS haderVars.unprojectedVertex));
GL(ringPlanetShaderProgram->setAttributeArray(ringPlanetShad erVars.texCoord, (const GLfloat*)ringModel.texCoordArr.constData(), 2)); GL(ringPlanetShaderProgram->setAttributeArray(ringPlanetShad erVars.texCoord, (const GLfloat*)ringModel.texCoordArr.constData(), 2));
GL(ringPlanetShaderProgram->enableAttributeArray(ringPlanetS haderVars.texCoord)); GL(ringPlanetShaderProgram->enableAttributeArray(ringPlanetS haderVars.texCoord));
if (eyePos[2]<0) if (rData.eyePos[2]<0)
gl->glCullFace(GL_FRONT); gl->glCullFace(GL_FRONT);
GL(gl->glDrawElements(GL_TRIANGLES, ringModel.indiceArr.size (), GL_UNSIGNED_SHORT, ringModel.indiceArr.constData())); GL(gl->glDrawElements(GL_TRIANGLES, ringModel.indiceArr.size (), GL_UNSIGNED_SHORT, ringModel.indiceArr.constData()));
if (eyePos[2]<0) if (rData.eyePos[2]<0)
gl->glCullFace(GL_BACK); gl->glCullFace(GL_BACK);
painter->setDepthTest(false); painter->setDepthTest(false);
} }
GL(shader->release()); GL(shader->release());
painter->setCullFace(false); painter->setCullFace(false);
} }
Planet::PlanetOBJModel* Planet::loadObjModel() const
{
PlanetOBJModel* mdl = new PlanetOBJModel();
if(!mdl->obj->load(objModelPath))
{
//object loading failed
qCritical()<<"Could not load planet OBJ model for"<<englishN
ame;
delete mdl;
return Q_NULLPTR;
}
//ideally, all planet OBJs should only have a single object with a s
ingle material
if(mdl->obj->getObjectList().size()>1)
qWarning()<<"Planet OBJ model has more than one object defin
ed, this may cause problems ...";
if(mdl->obj->getMaterialList().size()>1)
qWarning()<<"Planet OBJ model has more than one material def
ined, this may cause problems ...";
//start texture loading
const StelOBJ::Material& mat = mdl->obj->getMaterialList().at(mdl->o
bj->getObjectList().first().groups.first().materialIndex);
if(mat.map_Kd.isEmpty())
{
//we use a custom 1x1 pixel texture in this case
qWarning()<<"Planet OBJ model for"<<englishName<<"has no dif
fuse texture";
}
else
{
//this call starts loading the tex in background
mdl->texture = StelApp::getInstance().getTextureManager().cr
eateTextureThread(mat.map_Kd,StelTexture::StelTextureParams(true,GL_LINEAR,
GL_REPEAT,true),false);
}
//extract the pos array into separate vector, it is the only one we
need on CPU side for drawing
mdl->obj->splitVertexData(&mdl->posArray);
mdl->bbox = mdl->obj->getAABBox();
return mdl;
}
bool Planet::ensureObjLoaded()
{
if(!objModel && !objModelLoader)
{
qDebug()<<"Queueing aysnc load of OBJ model for"<<englishNam
e;
//create the async OBJ model loader
objModelLoader = new QFuture<PlanetOBJModel*>(QtConcurrent::
run(this,&Planet::loadObjModel));
}
if(objModelLoader)
{
if(objModelLoader->isFinished())
{
//the model loading has just finished, save the resu
lt
objModel = objModelLoader->result();
delete objModelLoader; //we dont need the result any
more
objModelLoader = Q_NULLPTR;
if(!objModel)
{
//model load failed, fall back to sphere mod
e
objModelPath.clear();
qWarning()<<"Cannot load OBJ model for solar
system object"<<getEnglishName();
return false;
}
else
{
//load model data into GL
if(!objModel->loadGL())
{
delete objModel;
objModel = Q_NULLPTR;
objModelPath.clear();
qWarning()<<"Cannot load OBJ model i
nto OpenGL for solar system object"<<getEnglishName();
return false;
}
GL(;);
}
}
else
{
//we are still loading, use the sphere method for dr
awing
return false;
}
}
//OBJ model is valid!
return true;
}
bool Planet::drawObjModel(StelPainter *painter, float screenSz)
{
Q_UNUSED(screenSz); //screen size unused for now, use it for LOD or
something?
//make sure the OBJ is loaded, or start loading it
if(!ensureObjLoaded())
return false;
if(shaderError)
{
qDebug() << "Planet::drawObjModel: Something went wrong with
shader initialisation. Cannot draw OBJs, using spheres instead.";
return false;
}
const SolarSystem* ssm = GETSTELMODULE(SolarSystem);
QMatrix4x4 shadowMatrix;
bool shadowmapping = false;
if(ssm->getFlagShowObjSelfShadows())
shadowmapping = drawObjShadowMap(painter,shadowMatrix);
if(objModel->texture)
{
if(!objModel->texture->bind())
{
//the texture is still loading, use the sphere metho
d
return false;
}
}
else
{
//HACK: there is no texture defined, we create a 1x1 pixel t
exture with color*albedo
//this is not the most efficient method, but prevents having
to rewrite the shader to work without a texture
//removing some complexity in managing this use-case
Vec3f texCol = haloColor * albedo * 255.0f + Vec3f(0.5f);
//convert to byte
Vector3<GLubyte> colByte(texCol[0],texCol[1],texCol[2]);
GLuint tex;
gl->glActiveTexture(GL_TEXTURE0);
gl->glGenTextures(1, &tex);
gl->glBindTexture(GL_TEXTURE_2D,tex);
GLint oldalignment;
gl->glGetIntegerv(GL_UNPACK_ALIGNMENT,&oldalignment);
gl->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB,
GL_UNSIGNED_BYTE, colByte.v );
gl->glPixelStorei(GL_UNPACK_ALIGNMENT, oldalignment);
gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL
_NEAREST);
gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL
_NEAREST);
gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REP
EAT);
gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REP
EAT);
// create a StelTexture from this
objModel->texture = StelApp::getInstance().getTextureManager
().wrapperForGLTexture(tex);
}
if(objModel->needsRescale)
objModel->performScaling(AU_KM * sphereScale);
//the model is ready to draw!
painter->setBlending(false);
painter->setCullFace(true);
gl->glCullFace(GL_BACK);
//depth testing is required here
painter->setDepthTest(true);
painter->setDepthMask(true);
gl->glClear(GL_DEPTH_BUFFER_BIT);
// Bind the array
GL(objModel->arr->bind());
//set up shader
QOpenGLShaderProgram* shd = objShaderProgram;
PlanetShaderVars* shdVars = &objShaderVars;
if(shadowmapping)
{
shd = objShadowShaderProgram;
shdVars = &objShadowShaderVars;
gl->glActiveTexture(GL_TEXTURE1);
gl->glBindTexture(GL_TEXTURE_2D,shadowTex);
GL(shd->bind());
GL(shd->setUniformValue(shdVars->shadowMatrix, shadowMatrix)
);
GL(shd->setUniformValue(shdVars->shadowTex, 1));
}
else
shd->bind();
//project the data
//because the StelOpenGLArray might use a VAO, we have to use a OGL
buffer here in all cases
objModel->projPosBuffer->bind();
const int vtxCount = objModel->posArray.size();
const StelProjectorP& projector = painter->getProjector();
// I tested buffer orphaning (https://www.opengl.org/wiki/Buffer_Obj
ect_Streaming#Buffer_re-specification),
// but it seems there is not really much of a effect here (probably
because we are already pretty CPU-bound).
// Also, map()-ing the buffer directly, like:
// Vec3f* bufPtr = static_cast<Vec3f*>(objModel->projPosBuffer-
>map(QOpenGLBuffer::WriteOnly));
// projector->project(vtxCount,objModel->posArray.constData(),b
ufPtr);
// objModel->projPosBuffer->unmap();
// caused a 40% FPS drop for some reason!
// (in theory, this should be faster because it should avoid copying
the array)
// So, lets not do that and just use this simple way in all cases:
projector->project(vtxCount, objModel->scaledArray.constData(),objMo
del->projectedPosArray.data());
objModel->projPosBuffer->allocate(objModel->projectedPosArray.constD
ata(),vtxCount * sizeof(Vec3f));
//unprojectedVertex, normalIn and texCoord are set by the StelOpenGL
Array
//we only need to set the freshly projected data
GL(shd->setAttributeArray("vertex",GL_FLOAT,Q_NULLPTR,3,0));
GL(shd->enableAttributeArray("vertex"));
objModel->projPosBuffer->release();
setCommonShaderUniforms(*painter,shd,*shdVars);
//draw that model using the array wrapper
objModel->arr->draw();
shd->disableAttributeArray("vertex");
shd->release();
objModel->arr->release();
painter->setCullFace(false);
painter->setDepthTest(false);
return true;
}
bool Planet::drawObjShadowMap(StelPainter *painter, QMatrix4x4& shadowMatri
x)
{
if(!shadowInitialized)
if(!initFBO())
{
qDebug()<<"Cannot draw OBJ self-shadow";
return false;
}
const StelProjectorP projector = painter->getProjector();
//find the light direction in model space
//Mat4d modelMatrix;
//computeModelMatrix(modelMatrix);
//Mat4d worldToModel = modelMatrix.inverse();
Vec3d lightDir = light.position.toVec3d();
projector->getModelViewTransform()->backward(lightDir);
//Vec3d lightDir(worldToModel[12], worldToModel[13], worldToModel[14
]);
lightDir.normalize();
//use a distance of 1km to the origin for additional precision, inst
ead of 1AU
Vec3d lightPosScaled = lightDir;
//the camera looks to the origin
QMatrix4x4 modelView;
modelView.lookAt(QVector3D(lightPosScaled[0],lightPosScaled[1],light
PosScaled[2]), QVector3D(), QVector3D(0,0,1));
//create an orthographic projection encompassing the AABB
double maxZ = -std::numeric_limits<double>::max();
double minZ = std::numeric_limits<double>::max();
double maxUp = -std::numeric_limits<double>::max();
double minUp = std::numeric_limits<double>::max();
double maxRight = -std::numeric_limits<double>::max();
double minRight = std::numeric_limits<double>::max();
//create an orthonormal system using 2-step Gram-Schmidt + cross pro
duct
// https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process
Vec3d vDir = -lightDir; //u1/e1, view direction
Vec3d up = Vec3d(0.0, 0.0, 1.0); //v2
up = up - up.dot(vDir) * vDir; //u2 = v2 - proj_u1(v2)
up.normalize(); //e2
Vec3d right = vDir^up;
right.normalize();
for(unsigned int i=0; i<AABBox::CORNERCOUNT; i++)
{
Vec3d v = objModel->bbox.getCorner(static_cast<AABBox::Corne
r>(i)).toVec3d();
Vec3d fromCam = v - lightPosScaled; //vector from cam to ver
tex
//project the fromCam vector onto the 3 vectors of the ortho
normal system
double dist = fromCam.dot(vDir);
maxZ = std::max(dist, maxZ);
minZ = std::min(dist, minZ);
dist = fromCam.dot(right);
minRight = std::min(dist, minRight);
maxRight = std::max(dist, maxRight);
dist = fromCam.dot(up);
minUp = std::min(dist, minUp);
maxUp = std::max(dist, maxUp);
}
QMatrix4x4 proj;
proj.ortho(minRight,maxRight,minUp,maxUp,minZ,maxZ);
QMatrix4x4 mvp = proj * modelView;
//bias matrix for lookup
static const QMatrix4x4 biasMatrix(0.5f, 0.0f, 0.0f, 0.5f,
0.0f, 0.5f, 0.0f, 0.5f,
0.0f, 0.0f, 0.5f, 0.5f,
0.0f, 0.0f, 0.0f, 1.0f);
shadowMatrix = biasMatrix * mvp;
painter->setDepthTest(true);
painter->setDepthMask(true);
painter->setCullFace(true);
gl->glCullFace(GL_BACK);
bool useOffset = !qFuzzyIsNull(shadowPolyOffset.lengthSquared());
if(useOffset)
{
gl->glEnable(GL_POLYGON_OFFSET_FILL);
gl->glPolygonOffset(shadowPolyOffset[0], shadowPolyOffset[1]
);
}
gl->glViewport(0,0,SM_SIZE,SM_SIZE);
GL(objModel->arr->bind());
GL(transformShaderProgram->bind());
GL(transformShaderProgram->setUniformValue(transformShaderVars.proje
ctionMatrix, mvp));
#ifdef DEBUG_SHADOWMAP
shadowFBO->bind();
objModel->texture->bind();
transformShaderProgram->setUniformValue(transformShaderVars.tex, 0);
gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
#else
gl->glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);
gl->glClear(GL_DEPTH_BUFFER_BIT);
#endif
GL(objModel->arr->draw());
transformShaderProgram->release();
objModel->arr->release();
#ifdef DEBUG_SHADOWMAP
//copy depth buffer into shadowTex
gl->glActiveTexture(GL_TEXTURE1);
gl->glBindTexture(GL_TEXTURE_2D,shadowTex);
//this is probably unsupported on an OGL ES2 context! just don't use
DEBUG_SHADOWMAP here...
GL(QOpenGLContext::currentContext()->functions()->glCopyTexImage2D(G
L_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, SM_SIZE, SM_SIZE, 0));
#endif
gl->glBindFramebuffer(GL_FRAMEBUFFER, StelApp::getInstance().getDefa
ultFBO());
//reset viewport (see StelPainter::setProjector)
const Vec4i& vp = projector->getViewport();
gl->glViewport(vp[0], vp[1], vp[2], vp[3]);
if(useOffset)
{
gl->glDisable(GL_POLYGON_OFFSET_FILL);
GL(gl->glPolygonOffset(0.0f,0.0f));
}
#ifdef DEBUG_SHADOWMAP
//display the FB contents on-screen
QOpenGLFramebufferObject::blitFramebuffer(Q_NULLPTR,shadowFBO);
#endif
return true;
}
void Planet::drawHints(const StelCore* core, const QFont& planetNameFont) void Planet::drawHints(const StelCore* core, const QFont& planetNameFont)
{ {
if (labelsFader.getInterstate()<=0.f) if (labelsFader.getInterstate()<=0.f)
return; return;
const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000) ; const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000) ;
StelPainter sPainter(prj); StelPainter sPainter(prj);
sPainter.setFont(planetNameFont); sPainter.setFont(planetNameFont);
// Draw nameI18 + scaling if it's not == 1. // Draw nameI18 + scaling if it's not == 1.
float tmp = (hintFader.getInterstate()<=0 ? 7.f : 10.f) + getAngular Size(core)*M_PI/180.f*prj->getPixelPerRadAtCenter()/1.44f; // Shift for nam eI18 printing float tmp = (hintFader.getInterstate()<=0 ? 7.f : 10.f) + getAngular Size(core)*M_PI/180.f*prj->getPixelPerRadAtCenter()/1.44f; // Shift for nam eI18 printing
skipping to change at line 2190 skipping to change at line 2886
if (tmp<1) tmp=1; if (tmp<1) tmp=1;
sPainter.setColor(labelColor[0], labelColor[1], labelColor[2],labels Fader.getInterstate()*hintFader.getInterstate()/tmp*0.7f); sPainter.setColor(labelColor[0], labelColor[1], labelColor[2],labels Fader.getInterstate()*hintFader.getInterstate()/tmp*0.7f);
// Draw the 2D small circle // Draw the 2D small circle
sPainter.setBlending(true); sPainter.setBlending(true);
Planet::hintCircleTex->bind(); Planet::hintCircleTex->bind();
sPainter.drawSprite2dMode(screenPos[0], screenPos[1], 11); sPainter.drawSprite2dMode(screenPos[0], screenPos[1], 11);
} }
Ring::Ring(float radiusMin, float radiusMax, const QString &texname) Ring::Ring(float radiusMin, float radiusMax, const QString &texname)
:radiusMin(radiusMin),radiusMax(radiusMax) :radiusMin(radiusMin),radiusMax(radiusMax)
{ {
tex = StelApp::getInstance().getTextureManager().createTexture(StelF ileMgr::getInstallationDir()+"/textures/"+texname); tex = StelApp::getInstance().getTextureManager().createTexture(StelF ileMgr::getInstallationDir()+"/textures/"+texname);
} }
Vec3f Planet::getCurrentOrbitColor() Vec3f Planet::getCurrentOrbitColor() const
{ {
Vec3f orbColor = orbitColor; Vec3f orbColor = orbitColor;
switch(orbitColorStyle) switch(orbitColorStyle)
{ {
case ocsGroups: case ocsGroups:
{ {
switch (pType) switch (pType)
{ {
case isMoon: case isMoon:
orbColor = orbitMoonsColor; orbColor = orbitMoonsColor;
skipping to change at line 2333 skipping to change at line 3029
void Planet::update(int deltaTime) void Planet::update(int deltaTime)
{ {
hintFader.update(deltaTime); hintFader.update(deltaTime);
labelsFader.update(deltaTime); labelsFader.update(deltaTime);
orbitFader.update(deltaTime); orbitFader.update(deltaTime);
} }
void Planet::setApparentMagnitudeAlgorithm(QString algorithm) void Planet::setApparentMagnitudeAlgorithm(QString algorithm)
{ {
vMagAlgorithm = vMagAlgorithmMap.key(algorithm.toLower(), Planet::Un // sync default value with ViewDialog and SolarSystem!
definedAlgorithm); vMagAlgorithm = vMagAlgorithmMap.key(algorithm, Planet::Expl_Sup_201
3);
} }
 End of changes. 93 change blocks. 
518 lines changed or deleted 1323 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/