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 <iomanip>
#include <QTextStream>
#include <QString>
#include <QDebug>
#include <QVarLengthArray>
#include "StelApp.hpp" #include "StelApp.hpp"
#include "StelCore.hpp" #include "StelCore.hpp"
#include "renderer/GenericVertexTypes.hpp" #include "StelFileMgr.hpp"
#include "renderer/StelGeometryBuilder.hpp" #include "StelTexture.hpp"
#include "renderer/StelRenderer.hpp"
#include "renderer/StelTextureNew.hpp"
#include "StelSkyDrawer.hpp" #include "StelSkyDrawer.hpp"
#include "SolarSystem.hpp" #include "SolarSystem.hpp"
#include "Planet.hpp" #include "Planet.hpp"
#include "StelProjector.hpp" #include "StelProjector.hpp"
#include "sideral_time.h" #include "sidereal_time.h"
#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 "StelTranslator.hpp" #include "StelTranslator.hpp"
#include "StelUtils.hpp" #include "StelUtils.hpp"
#include "StelOpenGL.hpp"
#include <iomanip>
#include <QTextStream>
#include <QString>
#include <QDebug>
#include <QVarLengthArray>
#include <QOpenGLContext>
#include <QOpenGLShader>
Vec3f Planet::labelColor = Vec3f(0.4,0.4,0.8); Vec3f Planet::labelColor = Vec3f(0.4,0.4,0.8);
Vec3f Planet::orbitColor = Vec3f(1,0.6,1); Vec3f Planet::orbitColor = Vec3f(1,0.6,1);
StelTextureSP Planet::hintCircleTex;
StelTextureSP Planet::texEarthShadow;
Planet::SharedPlanetGraphics::~SharedPlanetGraphics() QOpenGLShaderProgram* Planet::planetShaderProgram=NULL;
{ Planet::PlanetShaderVars Planet::planetShaderVars;
if(!initialized){return;} QOpenGLShaderProgram* Planet::ringPlanetShaderProgram=NULL;
delete texEarthShadow; Planet::RingPlanetShaderVars Planet::ringPlanetShaderVars;
delete texHintCircle; QOpenGLShaderProgram* Planet::moonShaderProgram=NULL;
Planet::MoonShaderVars Planet::moonShaderVars;
if(NULL != simplePlanetShader)
delete simplePlanetShader;
if(NULL != shadowPlanetShader)
delete shadowPlanetShader;
initialized = false;
}
void Planet::SharedPlanetGraphics::lazyInit(StelRenderer* renderer)
{
if(initialized){return;}
texHintCircle = renderer->createTexture("textures/planet-indicator.
png");
texEarthShadow = renderer->createTexture("textures/earth-shadow.png"
);
planetShader = simplePlanetShader = shadowPlanetShader = NULL;
if(renderer->isGLSLSupported())
{
if(!loadPlanetShaders(renderer))
{
qWarning() << "Failed to load planet shaders, fallin
g back to CPU implementation";
simplePlanetShader = shadowPlanetShader = NULL;
}
}
initialized = true;
}
bool Planet::SharedPlanetGraphics::loadPlanetShaders(StelRenderer* renderer
)
{
Q_ASSERT_X(renderer->isGLSLSupported(), Q_FUNC_INFO,
"Trying to load planet shaders but GLSL is not supported"
);
simplePlanetShader = renderer->createGLSLShader();
if(!simplePlanetShader->addVertexShader(
"vec4 project(in vec4 v);\n"
"attribute mediump vec4 vertex;\n"
"attribute mediump vec4 unprojectedVertex;\n"
"attribute mediump vec2 texCoord;\n"
"uniform mediump mat4 projectionMatrix;\n"
"uniform highp vec3 lightPos;\n"
"uniform highp float oneMinusOblateness;\n"
"uniform highp float radius;\n"
"uniform mediump vec4 ambientLight;\n"
"uniform mediump vec4 diffuseLight;\n"
"varying mediump vec2 texc;\n"
"varying mediump vec4 litColor;\n"
"void main(void)\n"
"{\n"
" gl_Position = projectionMatrix * project(vertex);\n"
" texc = texCoord;\n"
" // Must be a separate variable due to Intel drivers\n"
" vec4 normal = unprojectedVertex / radius;\n"
" float c = lightPos.x * normal.x * oneMinusOblateness +\n"
" lightPos.y * normal.y * oneMinusOblateness +\n"
" lightPos.z * normal.z / oneMinusOblateness;\n"
" litColor = clamp(c, 0.0, 0.5) * diffuseLight + ambientLight;\
n"
"}\n"))
{
qWarning() << "Error adding simple planet vertex shader: " <
< simplePlanetShader->log();
delete simplePlanetShader;
return false;
}
if(!simplePlanetShader->addFragmentShader(
"varying mediump vec2 texc;\n"
"varying mediump vec4 litColor;\n"
"uniform sampler2D tex;\n"
"uniform mediump vec4 globalColor;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(tex, texc) * litColor;\n"
"}\n"))
{
qWarning() << "Error adding simple planet fragment shader: "
<< simplePlanetShader->log();
delete simplePlanetShader;
return false;
}
if(!simplePlanetShader->build())
{
qWarning() << "Error building shader: " << simplePlanetShade
r->log();
delete simplePlanetShader;
return false;
}
qDebug() << "Simple planet shader build log: " << simplePlanetShader
->log();
shadowPlanetShader = renderer->createGLSLShader();
if(!shadowPlanetShader->addVertexShader(
"vec4 project(in vec4 v);\n"
"attribute mediump vec4 vertex;\n"
"attribute mediump vec4 unprojectedVertex;\n"
"attribute mediump vec2 texCoord;\n"
"uniform mediump mat4 projectionMatrix;\n"
"uniform highp vec3 lightPos;\n"
"uniform highp float oneMinusOblateness;\n"
"uniform highp float radius;\n"
"varying mediump vec2 texc;\n"
"varying mediump float lambert;\n"
"varying highp vec3 P;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = projectionMatrix * project(vertex);\n"
" texc = texCoord;\n"
" // Must be a separate variable due to Intel drivers\n"
" vec4 normal = unprojectedVertex / radius;\n"
" float c = lightPos.x * normal.x * oneMinusOblateness +\n"
" lightPos.y * normal.y * oneMinusOblateness +\n"
" lightPos.z * normal.z / oneMinusOblateness;\n"
" lambert = clamp(c, 0.0, 0.5);\n"
"\n"
" P = vec3(unprojectedVertex);\n"
"}\n"
"\n"))
{
qWarning() << "Error adding shadow planet vertex shader: " <
< shadowPlanetShader->log();
delete shadowPlanetShader;
return false;
}
if(!shadowPlanetShader->addFragmentShader(
"varying mediump vec2 texc;\n"
"varying mediump float lambert;\n"
"uniform sampler2D tex;\n"
"uniform mediump vec4 globalColor;\n"
"uniform mediump vec4 ambientLight;\n"
"uniform mediump vec4 diffuseLight;\n"
"\n"
"varying highp vec3 P;\n"
"\n"
"uniform sampler2D info;\n"
"uniform int current;\n"
"uniform int infoCount;\n"
"uniform float infoSize;\n"
"\n"
"uniform bool ring;\n"
"uniform highp float outerRadius;\n"
"uniform highp float innerRadius;\n"
"uniform sampler2D ringS;\n"
"uniform bool isRing;\n"
"\n"
"uniform bool isMoon;\n"
"uniform sampler2D earthShadow;\n"
"\n"
"bool visible(vec3 normal, vec3 light)\n"
"{\n"
" return (dot(light, normal) > 0.0);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" float final_illumination = 1.0;\n"
" vec4 diffuse = diffuseLight;\n"
" vec4 data = texture2D(info, vec2(0.0, current) / infoSize);\n
"
" float RS = data.w;\n"
" vec3 Lp = data.xyz;\n"
"\n"
" vec3 P3;\n"
"\n"
" if(isRing)\n"
" P3 = P;\n"
" else\n"
" {\n"
" data = texture2D(info, vec2(current, current) / infoSize)
;\n"
" P3 = normalize(P) * data.w;\n"
" }\n"
"\n"
" float L = length(Lp - P3);\n"
" RS = L * tan(asin(RS / L));\n"
" float R = atan(RS / L); //RS / L;\n"
"\n"
" if((lambert > 0.0) || isRing)\n"
" {\n"
" if(ring && !isRing)\n"
" {\n"
" vec3 ray = normalize(Lp);\n"
" vec3 normal = normalize(vec3(0.0, 0.0, 1.0));\n"
" float u = - dot(P3, normal) / dot(ray, normal);\n"
"\n"
" if(u > 0.0 && u < 1e10)\n"
" {\n"
" float ring_radius = length(P3 + u * ray);\n"
"\n"
" if(ring_radius > innerRadius && ring_radius < out
erRadius)\n"
" {\n"
" ring_radius = (ring_radius - innerRadius) / (
outerRadius - innerRadius);\n"
" data = texture2D(ringS, vec2(ring_radius, 0.5
));\n"
"\n"
" final_illumination = 1.0 - data.w;\n"
" }\n"
" }\n"
" }\n"
"\n"
" for(int i = 1; i < infoCount; i++)\n"
" {\n"
" if(current == i && !isRing)\n"
" continue;\n"
"\n"
" data = texture2D(info, vec2(i, current) / infoSize);\
n"
" vec3 C = data.rgb;\n"
" float radius = data.a;\n"
"\n"
" float l = length(C - P3);\n"
" radius = l * tan(asin(radius / l));\n"
" float r = atan(radius / l); //radius / l;\n"
" float d = acos(min(1.0, dot(normalize(Lp - P3), norma
lize(C - P3)))); //length( (Lp - P3) / L - (C - P3) / l );\n"
"\n"
" float illumination = 1.0;\n"
"\n"
" // distance too far\n"
" if(d >= R + r)\n"
" {\n"
" illumination = 1.0;\n"
" }\n"
" // umbra\n"
" else if(r >= R + d)\n"
" {\n"
" if(isMoon)\n"
" illumination = d / (r - R) * 0.6;\n"
" else"
" illumination = 0.0;\n"
" }\n"
" // penumbra completely inside\n"
" else if(d + r <= R)\n"
" {\n"
" illumination = 1.0 - r * r / (R * R);\n"
" }\n"
" // penumbra partially inside\n"
" else\n"
" {\n"
" if(isMoon)\n"
" illumination = ((d - abs(R-r)) / (R + r - abs
(R-r))) * 0.4 + 0.6;\n"
" else\n"
" {\n"
" float x = (R * R + d * d - r * r) / (2.0 * d)
;\n"
"\n"
" float alpha = acos(x / R);\n"
" float beta = acos((d - x) / r);\n"
"\n"
" float AR = R * R * (alpha - 0.5 * sin(2.0 * a
lpha));\n"
" float Ar = r * r * (beta - 0.5 * sin(2.0 * be
ta));\n"
" float AS = R * R * 2.0 * asin(1.0);\n"
"\n"
" illumination = 1.0 - (AR + Ar) / AS;\n"
" }\n"
" }\n"
"\n"
" if(illumination < final_illumination)\n"
" final_illumination = illumination;\n"
" }\n"
" }\n"
"\n"
" vec4 litColor = (isRing ? 1.0 : lambert) * final_illumination
* diffuse + ambientLight;\n"
" if(isMoon && final_illumination < 1.0)\n"
" {\n"
" vec4 shadowColor = texture2D(earthShadow, vec2(final_illu
mination, 0.5));\n"
" gl_FragColor = mix(texture2D(tex, texc) * litColor, shado
wColor, shadowColor.a);\n"
" }\n"
" else\n"
" gl_FragColor = texture2D(tex, texc) * litColor;\n"
"}\n"
"\n"))
{
qWarning() << "Error adding shadow planet fragment shader: "
<< shadowPlanetShader->log();
delete shadowPlanetShader;
return false;
}
if(!shadowPlanetShader->build())
{
qWarning() << "Error building shader: " << shadowPlanetShade
r->log();
delete shadowPlanetShader;
return false;
}
qDebug() << "Shadow planet shader build log: " << shadowPlanetShader
->log();
return true;
}
Planet::Planet(const QString& englishName, Planet::Planet(const QString& englishName,
int flagLighting, int flagLighting,
double radius, double radius,
double oblateness, double oblateness,
Vec3f color, Vec3f color,
float albedo, float albedo,
const QString& atexMapName, const QString& atexMapName,
posFuncType coordFunc, const QString& anormalMapName,
void* auserDataPtr, posFuncType coordFunc,
OsculatingFunctType *osculatingFunc, void* auserDataPtr,
bool acloseOrbit, OsculatingFunctType *osculatingFunc,
bool hidden, bool acloseOrbit,
bool hidden,
bool hasAtmosphere, bool hasAtmosphere,
bool hasHalo,
const QString& pType) const QString& pType)
: englishName(englishName), : englishName(englishName),
flagLighting(flagLighting), flagLighting(flagLighting),
radius(radius), oneMinusOblateness(1.0-oblateness), radius(radius),
color(color), albedo(albedo), axisRotation(0.), oneMinusOblateness(1.0-oblateness),
texture(NULL), color(color),
albedo(albedo),
axisRotation(0.),
rings(NULL), rings(NULL),
sphereScale(1.f), sphereScale(1.f),
lastJD(J2000), lastJD(J2000),
coordFunc(coordFunc), coordFunc(coordFunc),
userDataPtr(auserDataPtr), userDataPtr(auserDataPtr),
osculatingFunc(osculatingFunc), osculatingFunc(osculatingFunc),
parent(NULL), parent(NULL),
hidden(hidden), hidden(hidden),
atmosphere(hasAtmosphere), atmosphere(hasAtmosphere),
pType(pType), halo(hasHalo),
unlitSphere(NULL), pType(pType)
litSphere(NULL)
{ {
texMapName = atexMapName; texMapName = atexMapName;
normalMapName = anormalMapName;
lastOrbitJD =0; lastOrbitJD =0;
deltaJD = StelCore::JD_SECOND; deltaJD = StelCore::JD_SECOND;
orbitCached = 0; orbitCached = 0;
orbitVertices = NULL;
closeOrbit = acloseOrbit; closeOrbit = acloseOrbit;
deltaOrbitJD = 0;
distance = 0;
eclipticPos=Vec3d(0.,0.,0.); eclipticPos=Vec3d(0.,0.,0.);
rotLocalToParent = Mat4d::identity(); rotLocalToParent = Mat4d::identity();
texMap = StelApp::getInstance().getTextureManager().createTextureThr
ead(StelFileMgr::getInstallationDir()+"/textures/"+texMapName, StelTexture:
:StelTextureParams(true, GL_LINEAR, GL_REPEAT));
normalMap = StelApp::getInstance().getTextureManager().createTexture
Thread(StelFileMgr::getInstallationDir()+"/textures/"+normalMapName, StelTe
xture::StelTextureParams(true, GL_LINEAR, GL_REPEAT));
nameI18 = englishName; nameI18 = englishName;
if (englishName!="Pluto") if (englishName!="Pluto")
{ {
deltaJD = 0.001*StelCore::JD_SECOND; deltaJD = 0.001*StelCore::JD_SECOND;
} }
flagLabels = true; flagLabels = true;
} }
Planet::~Planet() Planet::~Planet()
{ {
if(NULL != rings) if (rings)
{
delete rings; delete rings;
rings = NULL;
}
if(NULL != orbitVertices)
{
delete orbitVertices;
orbitVertices = NULL;
}
if(NULL != litSphere)
{
Q_ASSERT_X(NULL == unlitSphere, Q_FUNC_INFO,
"Both lit and unlit spheres have been generated")
;
delete litSphere;
litSphere = NULL;
}
if(NULL != unlitSphere)
{
Q_ASSERT_X(NULL == litSphere, Q_FUNC_INFO,
"Both lit and unlit spheres have been generated")
;
delete unlitSphere;
unlitSphere = NULL;
}
if(NULL != texture)
{
delete texture;
texture = NULL;
}
} }
void Planet::translateName(StelTranslator& trans) void Planet::translateName(const StelTranslator& trans)
{ {
nameI18 = trans.qtranslate(englishName); nameI18 = trans.qtranslate(englishName);
} }
// Return the information string "ready to print" :) // Return the information string "ready to print" :)
QString Planet::getInfoString(const StelCore* core, const InfoStringGroup& flags) const QString Planet::getInfoString(const StelCore* core, const InfoStringGroup& flags) const
{ {
QString str; QString str;
QTextStream oss(&str); QTextStream oss(&str);
if (flags&Name) if (flags&Name)
{ {
oss << "<h2>" << q_(englishName); // UI translation can dif fer from sky translation oss << "<h2>" << q_(englishName); // UI translation can dif fer from sky translation
oss.setRealNumberNotation(QTextStream::FixedNotation); oss.setRealNumberNotation(QTextStream::FixedNotation);
oss.setRealNumberPrecision(1); oss.setRealNumberPrecision(1);
if (sphereScale != 1.f) if (sphereScale != 1.f)
oss << QString::fromUtf8(" (\xC3\x97") << sphereScal e << ")"; oss << QString::fromUtf8(" (\xC3\x97") << sphereScal e << ")";
oss << "</h2>"; oss << "</h2>";
} }
if (flags&Extra1) if (flags&ObjectType)
{ {
if (pType.length()>0) if (pType.length()>0)
oss << q_("Type: <b>%1</b>").arg(q_(pType)) << "<br />"; oss << q_("Type: <b>%1</b>").arg(q_(pType)) << "<br />";
} }
if (flags&Magnitude) if (flags&Magnitude)
{ {
if (core->getSkyDrawer()->getFlagHasAtmosphere()) if (core->getSkyDrawer()->getFlagHasAtmosphere())
oss << q_("Magnitude: <b>%1</b> (extincted to: <b>%2</b> oss << q_("Magnitude: <b>%1</b> (extincted to: <b>%2</b>
)").arg(QString::number(getVMagnitude(core, false), 'f', 2), )").arg(QString::number(getVMagnitude(core), 'f', 2),
QString::number(getVMagnitude(core, true), 'f', 2)) << "<br>"; QString::number(getVMagnitudeWithExtinction(core), 'f', 2)) << "<br
>";
else else
oss << q_("Magnitude: <b>%1</b>").arg(getVMagnitude(core , false), 0, 'f', 2) << "<br>"; oss << q_("Magnitude: <b>%1</b>").arg(getVMagnitude(core ), 0, 'f', 2) << "<br>";
} }
if (flags&AbsoluteMagnitude) if (flags&AbsoluteMagnitude)
oss << q_("Absolute Magnitude: %1").arg(getVMagnitude(core, false)-5.*(std::log10(getJ2000EquatorialPos(core).length()*AU/PARSEC)-1.), 0, 'f', 2) << "<br>"; oss << q_("Absolute Magnitude: %1").arg(getVMagnitude(core)- 5.*(std::log10(getJ2000EquatorialPos(core).length()*AU/PARSEC)-1.), 0, 'f', 2) << "<br>";
oss << getPositionInfoString(core, flags); oss << getPositionInfoString(core, flags);
if ((flags&Extra1) && (core->getCurrentLocation().planetName=="Earth ")) if (flags&Extra)
{ {
//static SolarSystem *ssystem=GETSTELMODULE(SolarSystem); static SolarSystem *ssystem=GETSTELMODULE(SolarSystem);
//double ecl= -(ssystem->getEarth()->getRotObliquity()); // double ecl= ssystem->getEarth()->getRotObliquity(core->getJD
BUG DETECTED! Earth's obliquity is apparently reported constant. ay());
double ra_equ, dec_equ, lambda, beta; if (core->getCurrentLocation().planetName=="Earth")
double ecl= get_mean_ecliptical_obliquity(core->getJDay()) * oss << q_("Obliquity (of date, for Earth): %1").arg(
M_PI/180.0; StelUtils::radToDmsStr(ecl, true)) << "<br>";
StelUtils::rectToSphe(&ra_equ,&dec_equ,getEquinoxEquatorialP //if (englishName!="Sun")
os(core)); // oss << q_("Obliquity (of date): %1").arg(StelUtils::
StelUtils::ctRadec2Ecl(ra_equ, dec_equ, ecl, &lambda, &beta) radToDmsStr(getRotObliquity(core->getJDay()), true)) << "<br>";
;
if (lambda<0) lambda+=2.0*M_PI;
oss << q_("Ecliptic Topocentric (of date): %1/%2").arg(StelU
tils::radToDmsStr(lambda, true), StelUtils::radToDmsStr(beta, true)) << "<b
r>";
oss << q_("Obliquity (of date, for Earth): %1").arg(StelUtil
s::radToDmsStr(ecl, true)) << "<br>";
} }
if (flags&Distance) if (flags&Distance)
{ {
double distanceAu = getJ2000EquatorialPos(core).length(); double distanceAu = getJ2000EquatorialPos(core).length();
double distanceKm = AU * distanceAu;
if (distanceAu < 0.1) if (distanceAu < 0.1)
{ {
double distanceKm = AU * distanceAu;
// 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', 8) .arg(distanceAu, 0, 'f', 6)
.arg(distanceKm, 0, 'f', 0); .arg(distanceKm, 0, 'f', 3);
} }
else else
{ {
// xgettext:no-c-format // xgettext:no-c-format
oss << q_("Distance: %1AU").arg(distanceAu, 0, 'f', oss << QString(q_("Distance: %1AU (%2 Mio km)"))
8); .arg(distanceAu, 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 507 skipping to change at line 212
} }
else else
{ {
oss << q_("Apparent diameter: %1").arg(StelUtils::ra dToDmsStr(angularSize, true)); oss << q_("Apparent diameter: %1").arg(StelUtils::ra dToDmsStr(angularSize, true));
} }
oss << "<br>"; oss << "<br>";
} }
double siderealPeriod = getSiderealPeriod(); double siderealPeriod = getSiderealPeriod();
double siderealDay = getSiderealDay(); double siderealDay = getSiderealDay();
if ((flags&Extra1) && (siderealPeriod>0)) if (flags&Extra)
{ {
// TRANSLATORS: Sidereal (orbital) period for solar system b if (siderealPeriod>0)
odies in days and in Julian years (symbol: a)
oss << q_("Sidereal period: %1 days (%2 a)").arg(QString::nu
mber(siderealPeriod, 'f', 2)).arg(QString::number(siderealPeriod/365.25, 'f
', 3)) << "<br>";
if (std::abs(siderealDay)>0)
{ {
oss << q_("Sidereal day: %1").arg(StelUtils::hoursTo // TRANSLATORS: Sidereal (orbital) period for solar
HmsStr(std::abs(siderealDay*24))) << "<br>"; system bodies in days and in Julian years (symbol: a)
oss << q_("Mean solar day: %1").arg(StelUtils::hours oss << q_("Sidereal period: %1 days (%2 a)").arg(QSt
ToHmsStr(std::abs(getMeanSolarDay()*24))) << "<br>"; ring::number(siderealPeriod, 'f', 2)).arg(QString::number(siderealPeriod/36
5.25, 'f', 3)) << "<br>";
if (std::abs(siderealDay)>0)
{
oss << q_("Sidereal day: %1").arg(StelUtils:
:hoursToHmsStr(std::abs(siderealDay*24))) << "<br>";
oss << q_("Mean solar day: %1").arg(StelUtil
s::hoursToHmsStr(std::abs(getMeanSolarDay()*24))) << "<br>";
}
}
if (englishName.compare("Sun")!=0)
{
const Vec3d& observerHelioPos = core->getObserverHel
iocentricEclipticPos();
oss << QString(q_("Phase Angle: %1")).arg(StelUtils:
:radToDmsStr(getPhaseAngle(observerHelioPos))) << "<br>";
oss << QString(q_("Elongation: %1")).arg(StelUtils::
radToDmsStr(getElongation(observerHelioPos))) << "<br>";
oss << QString(q_("Phase: %1")).arg(getPhase(observe
rHelioPos), 0, 'f', 2) << "<br>";
oss << QString(q_("Illuminated: %1%")).arg(getPhase(
observerHelioPos) * 100, 0, 'f', 1) << "<br>";
} }
}
if ((flags&Extra2) && (englishName.compare("Sun")!=0))
{
const Vec3d& observerHelioPos = core->getObserverHeliocentri
cEclipticPos();
oss << QString(q_("Phase Angle: %1")).arg(StelUtils::radToDm
sStr(getPhaseAngle(observerHelioPos))) << "<br>";
oss << QString(q_("Elongation: %1")).arg(StelUtils::radToDms
Str(getElongation(observerHelioPos))) << "<br>";
oss << QString(q_("Phase: %1")).arg(getPhase(observerHelioPo
s), 0, 'f', 2) << "<br>";
oss << QString(q_("Illuminated: %1%")).arg(getPhase(observer
HelioPos) * 100, 0, 'f', 1) << "<br>";
} }
postProcessInfoString(str, flags); postProcessInfoString(str, flags);
return str; return str;
} }
//! Get sky label (sky translation) //! Get sky label (sky translation)
QString Planet::getSkyLabel(const StelCore*) const QString Planet::getSkyLabel(const StelCore*) const
{ {
skipping to change at line 552 skipping to change at line 259
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 getVMagnitude(core, false)-15.f; return getVMagnitudeWithExtinction(core)-15.f;
} }
else else
{ {
return getVMagnitude(core, false) - 8.f; return getVMagnitudeWithExtinction(core) - 8.f;
} }
} }
Vec3f Planet::getInfoColor(void) const Vec3f Planet::getInfoColor(void) const
{ {
Vec3f col = ((SolarSystem*)StelApp::getInstance().getModuleMgr().get return ((SolarSystem*)StelApp::getInstance().getModuleMgr().getModul
Module("SolarSystem"))->getLabelsColor(); e("SolarSystem"))->getLabelsColor();
if (StelApp::getInstance().getVisionModeNight())
col = StelUtils::getNightColor(col);
return col;
} }
double Planet::getCloseViewFov(const StelCore* core) const double Planet::getCloseViewFov(const StelCore* core) const
{ {
return std::atan(radius*sphereScale*2.f/getEquinoxEquatorialPos(core ).length())*180./M_PI * 4; return std::atan(radius*sphereScale*2.f/getEquinoxEquatorialPos(core ).length())*180./M_PI * 4;
} }
double Planet::getSatellitesFov(const StelCore* core) const double Planet::getSatellitesFov(const StelCore* core) const
{ {
// TODO: calculate from satellite orbits rather than hard code // TODO: calculate from satellite orbits rather than hard code
skipping to change at line 589 skipping to change at line 293
if (englishName=="Uranus") return std::atan(0.002f/getEquinoxEquator ialPos(core).length())*180./M_PI * 4; if (englishName=="Uranus") return std::atan(0.002f/getEquinoxEquator ialPos(core).length())*180./M_PI * 4;
return -1.; return -1.;
} }
double Planet::getParentSatellitesFov(const StelCore* core) const double Planet::getParentSatellitesFov(const StelCore* core) const
{ {
if (parent && parent->parent) return parent->getSatellitesFov(core); if (parent && parent->parent) return parent->getSatellitesFov(core);
return -1.0; return -1.0;
} }
// Set the orbital elements // Set the rotational elements of the planet body.
void Planet::setRotationElements(float _period, float _offset, double _epoc h, float _obliquity, float _ascendingNode, float _precessionRate, double _s iderealPeriod ) void Planet::setRotationElements(float _period, float _offset, double _epoc h, float _obliquity, float _ascendingNode, float _precessionRate, double _s iderealPeriod )
{ {
re.period = _period; re.period = _period;
re.offset = _offset; re.offset = _offset;
re.epoch = _epoch; re.epoch = _epoch;
re.obliquity = _obliquity; re.obliquity = _obliquity;
re.ascendingNode = _ascendingNode; re.ascendingNode = _ascendingNode;
re.precessionRate = _precessionRate; re.precessionRate = _precessionRate;
re.siderealPeriod = _siderealPeriod; // used for drawing orbit line s re.siderealPeriod = _siderealPeriod; // used for drawing orbit line s
skipping to change at line 619 skipping to change at line 323
// 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 date) void Planet::computePositionWithoutOrbits(const double date)
{ {
if (fabs(lastJD-date)>deltaJD) if (fabs(lastJD-date)>deltaJD)
{ {
coordFunc(date, eclipticPos, userDataPtr); coordFunc(date, eclipticPos, userDataPtr);
lastJD = date; lastJD = date;
} }
} }
double Planet::getRotObliquity(double JDay) const
{
// JDay=2451545.0 for J2000.0
if (englishName=="Earth")
return get_mean_ecliptical_obliquity(JDay) *M_PI/180.0;
else
return re.obliquity;
}
bool willCastShadow(const Planet* thisPlanet, const Planet* p)
{
Vec3d thisPos = thisPlanet->getHeliocentricEclipticPos();
Vec3d planetPos = p->getHeliocentricEclipticPos();
// If the planet p is farther from the sun than this planet, it can'
t cast shadow on it.
if (planetPos.lengthSquared()>thisPos.lengthSquared())
return false;
Vec3d ppVector = planetPos;
ppVector.normalize();
double shadowDistance = ppVector * thisPos;
static const double sunRadius = 696000./AU;
double d = planetPos.length() / (p->getRadius()/sunRadius+1);
double penumbraRadius = (shadowDistance-d)/d*sunRadius;
double penumbraCenterToThisPlanetCenterDistance = (ppVector*shadowDi
stance-thisPos).length();
if (penumbraCenterToThisPlanetCenterDistance<penumbraRadius+thisPlan
et->getRadius())
return true;
return false;
}
QVector<const Planet*> Planet::getCandidatesForShadow() const
{
QVector<const Planet*> res;
const SolarSystem *ssystem=GETSTELMODULE(SolarSystem);
const Planet* sun = ssystem->getSun().data();
if (this==sun || (parent.data()==sun && satellites.empty()))
return res;
foreach (const PlanetP& planet, satellites)
{
if (willCastShadow(this, planet.data()))
res.append(planet.data());
}
if (willCastShadow(this, parent.data()))
res.append(parent.data());
return res;
}
void Planet::computePosition(const double date) void Planet::computePosition(const double date)
{ {
if (orbitFader.getInterstate()>0.000001 && deltaOrbitJD > 0 && (fabs (lastOrbitJD-date)>deltaOrbitJD || !orbitCached)) if (orbitFader.getInterstate()>0.000001 && deltaOrbitJD > 0 && (fabs (lastOrbitJD-date)>deltaOrbitJD || !orbitCached))
{ {
double calc_date; double calc_date;
// int delta_points = (int)(0.5 + (date - lastOrbitJD)/date_ increment); // int delta_points = (int)(0.5 + (date - lastOrbitJD)/date_ increment);
int delta_points; int delta_points;
if( date > lastOrbitJD ) if( date > lastOrbitJD )
skipping to change at line 737 skipping to change at line 493
// calculate actual Planet position // calculate actual Planet position
coordFunc(date, eclipticPos, userDataPtr); coordFunc(date, eclipticPos, userDataPtr);
lastJD = date; lastJD = date;
} }
else if (fabs(lastJD-date)>deltaJD) else if (fabs(lastJD-date)>deltaJD)
{ {
// calculate actual Planet position // calculate actual Planet position
coordFunc(date, eclipticPos, userDataPtr); coordFunc(date, eclipticPos, userDataPtr);
// XXX: do we need to do that even when the orbit is not vis ible?
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]);
lastJD = date; lastJD = date;
} }
} }
// Compute the transformation matrix from the local Planet coordinate to th e parent Planet coordinate // Compute the transformation matrix from the local Planet coordinate to th e parent Planet coordinate
void Planet::computeTransMatrix(double jd) void Planet::computeTransMatrix(double jd)
{ {
axisRotation = getSiderealTime(jd); axisRotation = getSiderealTime(jd);
// Special case - heliocentric coordinates are on ecliptic, // Special case - heliocentric coordinates are on ecliptic,
// not solar equator... // not solar equator...
if (parent) if (parent)
{ {
rotLocalToParent = Mat4d::zrotation(re.ascendingNode - re.pr ecessionRate*(jd-re.epoch)) * Mat4d::xrotation(re.obliquity); rotLocalToParent = Mat4d::zrotation(re.ascendingNode - re.pr ecessionRate*(jd-re.epoch)) * Mat4d::xrotation(re.obliquity);
} }
} }
void Planet::computeModelMatrix(Mat4d &result) const
{
result = Mat4d::translation(eclipticPos) * rotLocalToParent * Mat4d:
:zrotation(M_PI/180*(axisRotation + 90.));
PlanetP p = parent;
while (p && p->parent)
{
result = Mat4d::translation(p->eclipticPos) * result * p->ro
tLocalToParent;
p = p->parent;
}
}
Mat4d Planet::getRotEquatorialToVsop87(void) const Mat4d Planet::getRotEquatorialToVsop87(void) const
{ {
Mat4d rval = rotLocalToParent; Mat4d rval = rotLocalToParent;
if (parent) if (parent)
{ {
for (PlanetP p=parent;p->parent;p=p->parent) for (PlanetP p=parent;p->parent;p=p->parent)
rval = p->rotLocalToParent * rval; rval = p->rotLocalToParent * rval;
} }
return rval; return rval;
} }
skipping to change at line 803 skipping to change at line 549
if (englishName=="Earth") if (englishName=="Earth")
{ {
return get_apparent_sidereal_time(jd); return get_apparent_sidereal_time(jd);
} }
double t = jd - re.epoch; double t = jd - re.epoch;
double rotations = t / (double) re.period; double rotations = t / (double) re.period;
double wholeRotations = floor(rotations); double wholeRotations = floor(rotations);
double remainder = rotations - wholeRotations; double remainder = rotations - wholeRotations;
// TODO: This block need rewrite
if (englishName=="Jupiter") if (englishName=="Jupiter")
{ {
// use semi-empirical coefficient for GRS drift // use semi-empirical coefficient for GRS drift
// TODO: need improved return remainder * 360. + re.offset - 0.2483 * std::abs(jd -
return remainder * 360. + re.offset - 0.2483 * std::abs(Stel 2456172);
App::getInstance().getCore()->getJDay() - 2456172);
} }
else else
return remainder * 360. + re.offset; return remainder * 360. + re.offset;
} }
double Planet::getMeanSolarDay() const double Planet::getMeanSolarDay() const
{ {
double msd = 0.; double msd = 0.;
if (englishName=="Sun")
return msd;
double sday = getSiderealDay(); double sday = getSiderealDay();
double coeff = std::abs(sday/getSiderealPeriod()); double coeff = std::abs(sday/getSiderealPeriod());
float sign = 1; float sign = 1;
// planets with retrograde rotation // planets with retrograde rotation
if (englishName=="Venus" || englishName=="Uranus" || englishName=="P luto") if (englishName=="Venus" || englishName=="Uranus" || englishName=="P luto")
sign = -1; sign = -1;
if (pType.contains("moon")) if (pType.contains("moon"))
{ {
// duration of mean solar day on moon are same as synodic mo nth on this moon // duration of mean solar day on moon are same as synodic mo nth on this moon
skipping to change at line 860 skipping to change at line 610
pos += pp->eclipticPos; pos += pp->eclipticPos;
pp = pp->parent; pp = pp->parent;
} }
} }
return pos; return pos;
} }
// Return heliocentric coordinate of p // Return heliocentric coordinate of p
Vec3d Planet::getHeliocentricPos(Vec3d p) const Vec3d Planet::getHeliocentricPos(Vec3d p) const
{ {
// Optimization: // Note: using shared copies is too slow here. So we use direct acc
// ess
// This code used about 8% of runtime before, // instead.
// this is an optimized version - avoiding smart pointer checks
// (this function doesn't own any of the parents - planets
// and solar system do, so we're OK)
//
// This is the equivalent (previous) unoptimized code:
// (update this if you make any functionality changes)
// PlanetP pp = parent;
// if (pp)
// {
// while (pp->parent)
// {
// pos += pp->eclipticPos;
// pp = pp->parent;
// }
// }
Vec3d pos = p; Vec3d pos = p;
const Planet* ourParent = &(*parent); const Planet* pp = parent.data();
const Planet* parentsParent; if (pp)
// int i = 0;
if (NULL != ourParent)
{ {
// const Planet* const parentsParent = &(*(ourParent->parent while (pp->parent.data())
));
while (NULL != (parentsParent = &(*(ourParent->parent))))
{ {
pos += ourParent->eclipticPos; pos += pp->eclipticPos;
ourParent = parentsParent; pp = pp->parent.data();
} }
} }
return pos; return pos;
} }
void Planet::setHeliocentricEclipticPos(const Vec3d &pos) void Planet::setHeliocentricEclipticPos(const Vec3d &pos)
{ {
eclipticPos = pos; eclipticPos = pos;
PlanetP p = parent; PlanetP p = parent;
if (p) if (p)
skipping to change at line 922 skipping to change at line 653
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*sq rt(observerPlanetRq*planetRq));
return std::acos((observerPlanetRq + planetRq - observerRq)/(2.0*sqr t(observerPlanetRq*planetRq))); return std::acos((observerPlanetRq + planetRq - observerRq)/(2.0*sqr t(observerPlanetRq*planetRq)));
} }
// Get the planet phase for an observer at pos obsPos in heliocentric coord inates (in AU) // Get the planet phase for an observer at pos obsPos in heliocentric coord inates (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();
skipping to change at line 948 skipping to change at line 678
double Planet::getElongation(const Vec3d& obsPos) const double Planet::getElongation(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 + observerRq - planetRq)/(2.0*sq rt(observerPlanetRq*observerRq))); return std::acos((observerPlanetRq + observerRq - planetRq)/(2.0*sq rt(observerPlanetRq*observerRq)));
} }
// 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, bool withExtinction) cons t float Planet::getVMagnitude(const StelCore* core) const
{ {
float extinctionMag=0.0; // track magnitude loss
if (withExtinction && core->getSkyDrawer()->getFlagHasAtmosphere())
{
Vec3d altAz=getAltAzPosApparent(core);
altAz.normalize();
core->getSkyDrawer()->getExtinction().forward(&altAz[2], &extinc
tionMag);
}
if (parent == 0) if (parent == 0)
{ {
// sun, compute the apparent magnitude for the absolute mag (4.83) and observer's distance // sun, compute the apparent magnitude for the absolute mag (4.83) and observer's distance
const double distParsec = std::sqrt(core->getObserverHelioce ntricEclipticPos().lengthSquared())*AU/PARSEC; const double distParsec = std::sqrt(core->getObserverHelioce ntricEclipticPos().lengthSquared())*AU/PARSEC;
return 4.83 + 5.*(std::log10(distParsec)-1.);
// check how much of it is visible
const SolarSystem* ssm = GETSTELMODULE(SolarSystem);
double shadowFactor = ssm->getEclipseFactor(core);
if(shadowFactor < 1e-11)
shadowFactor = 1e-11;
return 4.83 + 5.*(std::log10(distParsec)-1.) - 2.5*(std::log
10(shadowFactor)) + extinctionMag;
} }
// Compute the angular phase // Compute the angular phase
const Vec3d& observerHelioPos = core->getObserverHeliocentricEclipti cPos(); const Vec3d& observerHelioPos = core->getObserverHeliocentricEclipti cPos();
const double observerRq = observerHelioPos.lengthSquared(); const double observerRq = observerHelioPos.lengthSquared();
const Vec3d& planetHelioPos = getHeliocentricEclipticPos(); const Vec3d& planetHelioPos = getHeliocentricEclipticPos();
const double planetRq = planetHelioPos.lengthSquared(); const double planetRq = planetHelioPos.lengthSquared();
const double observerPlanetRq = (observerHelioPos - planetHelioPos). lengthSquared(); const double observerPlanetRq = (observerHelioPos - planetHelioPos). lengthSquared();
const double cos_chi = (observerPlanetRq + planetRq - observerRq)/(2 .0*sqrt(observerPlanetRq*planetRq)); const double cos_chi = (observerPlanetRq + planetRq - observerRq)/(2 .0*sqrt(observerPlanetRq*planetRq));
double phase = std::acos(cos_chi); double phase = std::acos(cos_chi);
skipping to change at line 1025 skipping to change at line 740
{ {
const double phaseDeg=phase*180./M_PI; const double phaseDeg=phase*180./M_PI;
const double d = 5. * log10(sqrt(observerPlanetRq*planetRq)) ; const double d = 5. * log10(sqrt(observerPlanetRq*planetRq)) ;
//double f1 = phaseDeg/100.; //double f1 = phaseDeg/100.;
/* /*
// Algorithm provided by Pere Planesas (Observatorio Astrono mico Nacional) // Algorithm provided by Pere Planesas (Observatorio Astrono mico Nacional)
if (englishName=="Mercury") if (englishName=="Mercury")
{ {
if ( phaseDeg > 150. ) f1 = 1.5; if ( phaseDeg > 150. ) f1 = 1.5;
return -0.36 + d + 3.8*f1 - 2.73*f1*f1 + 2*f1*f1*f1 + extinctionMag; return -0.36 + d + 3.8*f1 - 2.73*f1*f1 + 2*f1*f1*f1;
} }
if (englishName=="Venus") if (englishName=="Venus")
return -4.29 + d + 0.09*f1 + 2.39*f1*f1 - 0.65*f1*f1 *f1 + extinctionMag; return -4.29 + d + 0.09*f1 + 2.39*f1*f1 - 0.65*f1*f1 *f1;
if (englishName=="Mars") if (englishName=="Mars")
return -1.52 + d + 0.016*phaseDeg + extinctionMag; return -1.52 + d + 0.016*phaseDeg;
if (englishName=="Jupiter") if (englishName=="Jupiter")
return -9.25 + d + 0.005*phaseDeg + extinctionMag; return -9.25 + d + 0.005*phaseDeg;
if (englishName=="Saturn") if (englishName=="Saturn")
{ {
// TODO re-add rings computation // TODO re-add rings computation
// double rings = -2.6*sinx + 1.25*sinx*sinx; // double rings = -2.6*sinx + 1.25*sinx*sinx;
return -8.88 + d + 0.044*phaseDeg + extinctionMag;// + rings; return -8.88 + d + 0.044*phaseDeg;// + rings;
} }
if (englishName=="Uranus") if (englishName=="Uranus")
return -7.19 + d + 0.0028*phaseDeg + extinctionMag; return -7.19 + d + 0.0028*phaseDeg;
if (englishName=="Neptune") if (englishName=="Neptune")
return -6.87 + d + extinctionMag; return -6.87 + d;
if (englishName=="Pluto") if (englishName=="Pluto")
return -1.01 + d + 0.041*phaseDeg + extinctionMag; return -1.01 + d + 0.041*phaseDeg;
*/ */
// GZ: I prefer the values given by Meeus, Astronomical Algo rithms (1992). // GZ: I prefer the values given by Meeus, Astronomical Algo rithms (1992).
// There are two solutions: // There are two solutions:
// (1) G. Mueller, based on visual observations 1877-91. [Ex pl.Suppl.1961] // (1) G. Mueller, based on visual observations 1877-91. [Ex pl.Suppl.1961]
// (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!)
// (1) // (1)
if (englishName=="Mercury") if (englishName=="Mercury")
{ {
double ph50=phaseDeg-50.0; double ph50=phaseDeg-50.0;
return 1.16 + d + 0.02838*ph50 + 0.0001023*ph50*ph50 + extinctionMag; return 1.16 + d + 0.02838*ph50 + 0.0001023*ph50*ph50 ;
} }
if (englishName=="Venus") if (englishName=="Venus")
return -4.0 + d + 0.01322*phaseDeg + 0.0000004247*ph aseDeg*phaseDeg*phaseDeg + extinctionMag; return -4.0 + d + 0.01322*phaseDeg + 0.0000004247*ph aseDeg*phaseDeg*phaseDeg;
if (englishName=="Mars") if (englishName=="Mars")
return -1.3 + d + 0.01486*phaseDeg + extinctionMag; return -1.3 + d + 0.01486*phaseDeg;
if (englishName=="Jupiter") if (englishName=="Jupiter")
return -8.93 + d + extinctionMag; return -8.93 + d;
if (englishName=="Saturn") if (englishName=="Saturn")
{ {
// add rings computation // add rings computation
// GZ: implemented from Meeus, Astr.Alg.1992 // GZ: implemented from Meeus, Astr.Alg.1992
const double jd=core->getJDay(); const double jd=core->getJDay();
const double T=(jd-2451545.0)/36525.0; const double T=(jd-2451545.0)/36525.0;
const double i=((0.000004*T-0.012998)*T+28.075216)*M _PI/180.0; const double i=((0.000004*T-0.012998)*T+28.075216)*M _PI/180.0;
const double Omega=((0.000412*T+1.394681)*T+169.5084 70)*M_PI/180.0; const double Omega=((0.000412*T+1.394681)*T+169.5084 70)*M_PI/180.0;
static SolarSystem *ssystem=GETSTELMODULE(SolarSyste m); SolarSystem *ssystem=GETSTELMODULE(SolarSystem);
const Vec3d saturnEarth=getHeliocentricEclipticPos() - ssystem->getEarth()->getHeliocentricEclipticPos(); const Vec3d saturnEarth=getHeliocentricEclipticPos() - ssystem->getEarth()->getHeliocentricEclipticPos();
double lambda=atan2(saturnEarth[1], saturnEarth[0]); double lambda=atan2(saturnEarth[1], saturnEarth[0]);
double beta=atan2(saturnEarth[2], sqrt(saturnEarth[0 ]*saturnEarth[0]+saturnEarth[1]*saturnEarth[1])); double beta=atan2(saturnEarth[2], sqrt(saturnEarth[0 ]*saturnEarth[0]+saturnEarth[1]*saturnEarth[1]));
const double sinB=sin(i)*cos(beta)*sin(lambda-Omega) -cos(i)*sin(beta); const double sinB=sin(i)*cos(beta)*sin(lambda-Omega) -cos(i)*sin(beta);
double rings = -2.6*fabs(sinB) + 1.25*sinB*sinB; // sinx=sinB, saturnicentric latitude of earth. longish, see Meeus. double rings = -2.6*fabs(sinB) + 1.25*sinB*sinB; // sinx=sinB, saturnicentric latitude of earth. longish, see Meeus.
return -8.68 + d + 0.044*phaseDeg + rings + extincti onMag; return -8.68 + d + 0.044*phaseDeg + rings;
} }
if (englishName=="Uranus") if (englishName=="Uranus")
return -6.85 + d + extinctionMag; return -6.85 + d;
if (englishName=="Neptune") if (englishName=="Neptune")
return -7.05 + d + extinctionMag; return -7.05 + d;
if (englishName=="Pluto") if (englishName=="Pluto")
return -1.0 + d + extinctionMag; return -1.0 + d;
/* /*
// (2) // (2)
if (englishName=="Mercury") if (englishName=="Mercury")
return 0.42 + d + .038*phaseDeg - 0.000273*phaseDeg* phaseDeg + 0.000002*phaseDeg*phaseDeg*phaseDeg + extinctionMag; return 0.42 + d + .038*phaseDeg - 0.000273*phaseDeg* phaseDeg + 0.000002*phaseDeg*phaseDeg*phaseDeg;
if (englishName=="Venus") if (englishName=="Venus")
return -4.40 + d + 0.0009*phaseDeg + 0.000239*phaseD eg*phaseDeg - 0.00000065*phaseDeg*phaseDeg*phaseDeg + extinctionMag; return -4.40 + d + 0.0009*phaseDeg + 0.000239*phaseD eg*phaseDeg - 0.00000065*phaseDeg*phaseDeg*phaseDeg;
if (englishName=="Mars") if (englishName=="Mars")
return -1.52 + d + 0.016*phaseDeg + extinctionMag; return -1.52 + d + 0.016*phaseDeg;
if (englishName=="Jupiter") if (englishName=="Jupiter")
return -9.40 + d + 0.005*phaseDeg + extinctionMag; return -9.40 + d + 0.005*phaseDeg;
if (englishName=="Saturn") if (englishName=="Saturn")
{ {
// add rings computation // add rings computation
// GZ: implemented from Meeus, Astr.Alg.1992 // GZ: implemented from Meeus, Astr.Alg.1992
const double jd=core->getJDay(); const double jd=core->getJDay();
const double T=(jd-2451545.0)/36525.0; const double T=(jd-2451545.0)/36525.0;
const double i=((0.000004*T-0.012998)*T+28.075216)*M _PI/180.0; const double i=((0.000004*T-0.012998)*T+28.075216)*M _PI/180.0;
const double Omega=((0.000412*T+1.394681)*T+169.5084 70)*M_PI/180.0; const double Omega=((0.000412*T+1.394681)*T+169.5084 70)*M_PI/180.0;
static SolarSystem *ssystem=GETSTELMODULE(SolarSyste m); static SolarSystem *ssystem=GETSTELMODULE(SolarSyste m);
const Vec3d saturnEarth=getHeliocentricEclipticPos() - ssystem->getEarth()->getHeliocentricEclipticPos(); const Vec3d saturnEarth=getHeliocentricEclipticPos() - ssystem->getEarth()->getHeliocentricEclipticPos();
double lambda=atan2(saturnEarth[1], saturnEarth[0]); double lambda=atan2(saturnEarth[1], saturnEarth[0]);
double beta=atan2(saturnEarth[2], sqrt(saturnEarth[0 ]*saturnEarth[0]+saturnEarth[1]*saturnEarth[1])); double beta=atan2(saturnEarth[2], sqrt(saturnEarth[0 ]*saturnEarth[0]+saturnEarth[1]*saturnEarth[1]));
const double sinB=sin(i)*cos(beta)*sin(lambda-Omega) -cos(i)*sin(beta); const double sinB=sin(i)*cos(beta)*sin(lambda-Omega) -cos(i)*sin(beta);
double rings = -2.6*fabs(sinB) + 1.25*sinB*sinB; // sinx=sinB, saturnicentric latitude of earth. longish, see Meeus. double rings = -2.6*fabs(sinB) + 1.25*sinB*sinB; // sinx=sinB, saturnicentric latitude of earth. longish, see Meeus.
return -8.88 + d + 0.044*phaseDeg + rings + extincti onMag; return -8.88 + d + 0.044*phaseDeg + rings;
} }
if (englishName=="Uranus") if (englishName=="Uranus")
return -7.19f + d + extinctionMag; return -7.19f + d;
if (englishName=="Neptune") if (englishName=="Neptune")
return -6.87f + d + extinctionMag; return -6.87f + d;
if (englishName=="Pluto") if (englishName=="Pluto")
return -1.00f + d + extinctionMag; return -1.00f + d;
*/ */
// TODO: decide which set of formulae is best? // TODO: decide which set of formulae is best?
} }
// This formula seems to give wrong results // This formula seems to give wrong results
const double p = (1.0 - phase/M_PI) * cos_chi + std::sqrt(1.0 - cos_ chi*cos_chi) / M_PI; const double p = (1.0 - phase/M_PI) * cos_chi + std::sqrt(1.0 - cos_ chi*cos_chi) / M_PI;
double F = 2.0 * albedo * radius * radius * p / (3.0*observerPlanetR q*planetRq) * shadowFactor; double F = 2.0 * albedo * radius * radius * p / (3.0*observerPlanetR q*planetRq) * shadowFactor;
return -26.73 - 2.5 * std::log10(F) + extinctionMag; return -26.73 - 2.5 * std::log10(F);
} }
double Planet::getAngularSize(const StelCore* core) const double Planet::getAngularSize(const StelCore* core) const
{ {
double rad = radius; double rad = radius;
if (rings) if (rings)
rad = rings->getSize(); rad = rings->getSize();
return std::atan2(rad*sphereScale,getJ2000EquatorialPos(core).length ()) * 180./M_PI; return std::atan2(rad*sphereScale,getJ2000EquatorialPos(core).length ()) * 180./M_PI;
} }
double Planet::getSpheroidAngularSize(const StelCore* core) const double Planet::getSpheroidAngularSize(const StelCore* core) const
{ {
return std::atan2(radius*sphereScale,getJ2000EquatorialPos(core).len gth()) * 180./M_PI; return std::atan2(radius*sphereScale,getJ2000EquatorialPos(core).len gth()) * 180./M_PI;
} }
// Draw the Planet and all the related infos : name, circle etc.. // Draw the Planet and all the related infos : name, circle etc..
void Planet::draw(StelCore* core, StelRenderer* renderer, float maxMagLabel void Planet::draw(StelCore* core, float maxMagLabels, const QFont& planetNa
s, meFont)
const QFont& planetNameFont,
SharedPlanetGraphics& planetGraphics)
{ {
if (hidden) if (hidden)
return; return;
Mat4d mat = Mat4d::translation(eclipticPos) * rotLocalToParent; Mat4d mat = Mat4d::translation(eclipticPos) * rotLocalToParent;
PlanetP p = parent; PlanetP p = parent;
while (p && p->parent) while (p && p->parent)
{ {
mat = Mat4d::translation(p->eclipticPos) * mat * p->rotLocal ToParent; mat = Mat4d::translation(p->eclipticPos) * mat * p->rotLocal ToParent;
p = p->parent; p = p->parent;
} }
// This removed totally the Planet shaking bug!!! // This removed totally the Planet shaking bug!!!
StelProjector::ModelViewTranformP transfo = core->getHeliocentricEcl ipticModelViewTransform(); StelProjector::ModelViewTranformP transfo = core->getHeliocentricEcl ipticModelViewTransform();
transfo->combine(mat); transfo->combine(mat);
if (getEnglishName() == core->getCurrentLocation().planetName) if (getEnglishName() == core->getCurrentLocation().planetName)
{ {
// Draw the rings if we are located on a planet with rings, but not the planet itself. // Draw the rings if we are located on a planet with rings, but not the planet itself.
if (rings) if (rings)
{ {
rings->draw(core->getProjection(transfo), renderer, draw3dModel(core, transfo, 1024, true);
transfo, planetGraphics.planetShader, 1000.0,
planetGraphics.planetShader
== planetGraphics.shadowPlanetShader ? &planetGraphics.info : NULL);
} }
return; return;
} }
// 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 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 - screenSz && screenPos[1] < vie wport_bottom + prj->getViewportHeight()+screenSz && screenPos[1]>viewport_bottom - screenSz && screenPos[1] < vie wport_bottom + prj->getViewportHeight()+screenSz
&& screenPos[0]>viewport_left - screenSz && screenPos[0] < viewp ort_left + prj->getViewportWidth() + screenSz) && screenPos[0]>viewport_left - screenSz && screenPos[0] < viewp ort_left + prj->getViewportWidth() + screenSz)
{ {
// 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 overlaping (ie for jupiter satellites) // this prevents name overlaping (ie for jupiter satellites)
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, renderer); // TODO - fade in here also... drawOrbit(core); // TODO - fade in here also...
if (flagLabels && ang_dist>0.25 && maxMagLabels>getVMagnitud e(core)) if (flagLabels && ang_dist>0.25 && maxMagLabels>getVMagnitud e(core))
{ {
labelsFader=true; labelsFader=true;
} }
else else
{ {
labelsFader=false; labelsFader=false;
} }
drawHints(core, renderer, planetNameFont, planetGraphics); drawHints(core, planetNameFont);
draw3dModel(core, renderer, planetGraphics, transfo, screenS z); draw3dModel(core,transfo,screenSz);
} }
return; return;
} }
void Planet::draw3dModel(StelCore* core, StelRenderer* renderer, class StelPainterLight
SharedPlanetGraphics& planetGraphics, {
StelProjector::ModelViewTranformP transfo, float s public:
creenSz) Vec3f position;
Vec3f diffuse;
Vec3f ambient;
};
static StelPainterLight light;
void Planet::PlanetShaderVars::initLocations(QOpenGLShaderProgram* p)
{
GL(projectionMatrix = p->uniformLocation("projectionMatrix"));
GL(texCoord = p->attributeLocation("texCoord"));
GL(unprojectedVertex = p->attributeLocation("unprojectedVertex"));
GL(vertex = p->attributeLocation("vertex"));
GL(texture = p->uniformLocation("tex"));
GL(lightDirection = p->uniformLocation("lightDirection"));
GL(eyeDirection = p->uniformLocation("eyeDirection"));
GL(diffuseLight = p->uniformLocation("diffuseLight"));
GL(ambientLight = p->uniformLocation("ambientLight"));
GL(shadowCount = p->uniformLocation("shadowCount"));
GL(shadowData = p->uniformLocation("shadowData"));
GL(sunInfo = p->uniformLocation("sunInfo"));
}
void Planet::initShader()
{
qWarning() << "Intializing planets GL shaders... ";
const char *vsrc =
"attribute highp vec3 vertex;\n"
"attribute highp vec3 unprojectedVertex;\n"
"attribute mediump vec2 texCoord;\n"
"uniform highp mat4 projectionMatrix;\n"
"uniform highp vec3 lightDirection;\n"
"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"
"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 < shadowCount; ++i)\n"
" {\n"
" highp vec3 satellitePosition = shadowData[i].xy
z;\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(sun
Position - 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 - a
bs(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 * s
in(2.0 * alpha));\n"
" mediump float Ar = r * r * (beta - 0.5 * si
n(2.0 * beta));\n"
" mediump float AS = R * R * 2.0 * 1.57079633
;\n"
" illumination = 1.0 - (AR + Ar) / AS;\n"
"#endif\n"
" }\n"
"\n"
" final_illumination = min(illumination, final_il
lumination);\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"
" highp float cosAngleLightNormal = dot(normal, lightDire
ction);\n"
" highp float cosAngleEyeNormal = dot(normal, eyeDirectio
n);\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"
" mediump float roughness = 1.;\n"
" mediump float roughnessSquared = roughness * roughness;
\n"
" mediump float A = 1.0 - 0.5 * (roughnessSquared / (roug
hnessSquared + 0.57));\n"
" mediump float B = 0.45 * (roughnessSquared / (roughness
Squared + 0.09));\n"
" mediump float C = sin(alpha) * tan(beta);\n"
" lum = max(0.0, cosAngleLightNormal) * (A + B * max(0.0,
gamma) * C) * 2.;\n"
"#endif\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
QOpenGLShader vshader(QOpenGLShader::Vertex);
vshader.compileSourceCode(vsrc);
if (!vshader.log().isEmpty()) { qWarning() << "Planet: Warnings whil
e compiling vshader: " << vshader.log(); }
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
QByteArray arr = "#define RINGS_SUPPORT\n\n";
arr+=fsrc;
QOpenGLShader ringFragmentShader(QOpenGLShader::Fragment);
ringFragmentShader.compileSourceCode(arr.constData());
if (!ringFragmentShader.log().isEmpty()) { qWarning() << "Planet: Wa
rnings while compiling ringFragmentShader: " << ringFragmentShader.log(); }
ringPlanetShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::c
urrentContext());
ringPlanetShaderProgram->addShader(&vshader);
ringPlanetShaderProgram->addShader(&ringFragmentShader);
GL(StelPainter::linkProg(ringPlanetShaderProgram, "ringPlanetShaderP
rogram"));
GL(ringPlanetShaderProgram->bind());
ringPlanetShaderVars.initLocations(ringPlanetShaderProgram);
GL(ringPlanetShaderVars.isRing = ringPlanetShaderProgram->uniformLoc
ation("isRing"));
GL(ringPlanetShaderVars.ring = ringPlanetShaderProgram->uniformLocat
ion("ring"));
GL(ringPlanetShaderVars.outerRadius = ringPlanetShaderProgram->unifo
rmLocation("outerRadius"));
GL(ringPlanetShaderVars.innerRadius = ringPlanetShaderProgram->unifo
rmLocation("innerRadius"));
GL(ringPlanetShaderVars.ringS = ringPlanetShaderProgram->uniformLoca
tion("ringS"));
GL(ringPlanetShaderProgram->release());
// Moon shader program
arr = "#define IS_MOON\n\n";
arr+=vsrc;
QOpenGLShader moonVertexShader(QOpenGLShader::Vertex);
moonVertexShader.compileSourceCode(arr.constData());
if (!moonVertexShader.log().isEmpty()) { qWarning() << "Planet: Warn
ings while compiling moonVertexShader: " << moonVertexShader.log(); }
arr = "#define IS_MOON\n\n";
arr+=fsrc;
QOpenGLShader moonFragmentShader(QOpenGLShader::Fragment);
moonFragmentShader.compileSourceCode(arr.constData());
if (!moonFragmentShader.log().isEmpty()) { qWarning() << "Planet: Wa
rnings while compiling moonFragmentShader: " << moonFragmentShader.log(); }
moonShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::current
Context());
moonShaderProgram->addShader(&moonVertexShader);
moonShaderProgram->addShader(&moonFragmentShader);
GL(StelPainter::linkProg(moonShaderProgram, "moonPlanetShaderProgram
"));
GL(moonShaderProgram->bind());
moonShaderVars.initLocations(moonShaderProgram);
GL(moonShaderVars.earthShadow = moonShaderProgram->uniformLocation("
earthShadow"));
GL(moonShaderVars.normalMap = moonShaderProgram->uniformLocation("no
rmalMap"));
GL(moonShaderProgram->release());
}
void Planet::deinitShader()
{
delete planetShaderProgram;
planetShaderProgram = NULL;
}
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);
if (screenSz > 1.0f) if (screenSz>1.)
{ {
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.)));
StelProjectorP projector = core->getProjection(transfo2); StelPainter* sPainter = new StelPainter(core->getProjection(
StelLight light; transfo2));
if (flagLighting) if (flagLighting)
{ {
// Set the main source of light to be the sun // Set the main source of light to be the sun
Vec3d sunPos(0); Vec3d sunPos(0);
core->getHeliocentricEclipticModelViewTransform()->f orward(sunPos); core->getHeliocentricEclipticModelViewTransform()->f orward(sunPos);
light.position=Vec4f(sunPos[0],sunPos[1],sunPos[2],1
.f);
// Set the light parameters taking sun as the light source // Set the light parameters taking sun as the light source
light.position = Vec3f(sunPos[0], sunPos[1], sunPos[ light.diffuse = Vec4f(1.f,1.f,1.f);
2]); light.ambient = Vec4f(0.02f,0.02f,0.02f);
light.ambient = Vec4f(0.02f, 0.02f, 0.02f, 0.02f);
light.diffuse = Vec4f(2.0f, 2.0f, 2.0f, 1.0f); if (this==ssm->getMoon())
if (StelApp::getInstance().getVisionModeNight())
{ {
light.diffuse[1] = 0.; light.diffuse[2] = 0. // Special case for the Moon (maybe better u
; se 1.5,1.5,1.5,1.0 ?)
light.ambient[1] = 0.; light.ambient[2] = 0. light.diffuse = Vec4f(1.6f,1.6f,1.6f,1.f);
;
} }
} }
else
{
sPainter->setColor(albedo,albedo,albedo);
}
if (rings) if (rings)
{ {
// The planet has rings, we need to use depth buffer
and adjust the clipping planes to avoid
// reaching the maximum resolution of the depth buff
er
const double dist = getEquinoxEquatorialPos(core).le ngth(); const double dist = getEquinoxEquatorialPos(core).le ngth();
double z_near = 0.9*(dist - rings->getSize()); double z_near = 0.9*(dist - rings->getSize());
double z_far = 1.1*(dist + rings->getSize()); double z_far = 1.1*(dist + rings->getSize());
if (z_near < 0.0) z_near = 0.0; if (z_near < 0.0) z_near = 0.0;
double n,f; double n,f;
core->getClippingPlanes(&n,&f); // Save clipping pla nes core->getClippingPlanes(&n,&f); // Save clipping pla nes
core->setClippingPlanes(z_near,z_far); core->setClippingPlanes(z_near,z_far);
renderer->clearDepthBuffer(); drawSphere(sPainter, screenSz, drawOnlyRing);
renderer->setDepthTest(DepthTest_ReadWrite);
drawSphere(renderer, projector, flagLighting ? &ligh
t : NULL,
planetGraphics, screenSz);
renderer->setDepthTest(DepthTest_ReadOnly);
rings->draw(projector, renderer, transfo, planetGrap
hics.planetShader, screenSz,
planetGraphics.planetShader
== planetGraphics.shadowPlanetShader ? &planetGraphics.info : NULL);
renderer->setDepthTest(DepthTest_Disabled);
core->setClippingPlanes(n,f); // Restore old clippi ng planes core->setClippingPlanes(n,f); // Restore old clippi ng planes
} }
else else
{ {
SolarSystem* ssm = GETSTELMODULE(SolarSystem); // Normal planet
if (this==ssm->getMoon() && core->getCurrentLocation drawSphere(sPainter, screenSz);
().planetName=="Earth" && ssm->nearLunarEclipse())
{
// Draw earth shadow over moon using stencil
buffer if appropriate
// This effect curently only looks right fro
m earth viewpoint
// TODO: moon magnitude label during eclipse
isn't accurate...
renderer->clearStencilBuffer();
renderer->setStencilTest(StencilTest_Write_1
);
drawSphere(renderer, projector, flagLighting
? &light : NULL,
planetGraphics, screenSz)
;
renderer->setStencilTest(StencilTest_Disable
d);
if(planetGraphics.planetShader == planetGrap
hics.simplePlanetShader)
drawEarthShadow(core, renderer, plan
etGraphics);
}
else
{
// Normal planet
drawSphere(renderer, projector, flagLighting
? &light : NULL,
planetGraphics, screenSz)
;
}
} }
delete sPainter;
sPainter=NULL;
} }
// Draw the halo // Draw the halo if it enabled in the ssystem.ini file (+ special ca
se for backward compatible for the Sun)
float surfArcMin2 = getSpheroidAngularSize(core)*60; if (hasHalo() || this==ssm->getSun())
surfArcMin2 = surfArcMin2*surfArcMin2*M_PI; // the total illuminated
area in arcmin^2
const Vec3d tmp = getJ2000EquatorialPos(core);
float mag = getVMagnitude(core, true);
SolarSystem* ssm = GETSTELMODULE(SolarSystem);
if(this != ssm->getSun() || mag < -15.0f)
core->getSkyDrawer()
->postDrawSky3dModel(core->getProjection(StelCore::F
rameJ2000),
tmp, surfAr
cMin2, mag, color);
if(this == ssm->getSun() && core->getCurrentLocation().planetName ==
"Earth")
{ {
float eclipseFactor = ssm->getEclipseFactor(core); // Prepare openGL lighting parameters according to luminance
if(eclipseFactor < 0.001) float surfArcMin2 = getSpheroidAngularSize(core)*60;
{ surfArcMin2 = surfArcMin2*surfArcMin2*M_PI; // the total ill
core->getSkyDrawer()->drawSunCorona(core->getProject uminated area in arcmin^2
ion(StelCore::FrameJ2000), tmp, screenSz, 1.0 - eclipseFactor * 1000);
}
}
}
void Planet::drawUnlitSphere(StelRenderer* renderer, StelProjectorP project StelPainter sPainter(core->getProjection(StelCore::FrameJ200
or) 0));
{ Vec3d tmp = getJ2000EquatorialPos(core);
if(NULL == unlitSphere) core->getSkyDrawer()->postDrawSky3dModel(&sPainter, Vec3f(tm
{ p[0], tmp[1], tmp[2]), surfArcMin2, getVMagnitudeWithExtinction(core), colo
const SphereParams params = SphereParams(radius * sphereScal r);
e).resolution(40, 40)
.oneMinusOblateness(oneMinusObla
teness);
unlitSphere = StelGeometryBuilder().buildSphereUnlit(params)
;
} }
unlitSphere->draw(renderer, projector);
} }
void Planet::drawSphere(StelRenderer* renderer, StelProjectorP projector, struct Planet3DModel
const StelLight* light, Shar
edPlanetGraphics& planetGraphics, float screenSz)
{ {
if(texMapName == "") {return;} QVector<float> vertexArr;
if(NULL == texture) QVector<float> texCoordArr;
{ QVector<unsigned short> indiceArr;
const TextureParams textureParams = };
TextureParams().generateMipmaps().wrap(TextureWrap_R
epeat);
texture = renderer->createTexture("textures/" + texMapName,
textureParams,
TextureLoadingMode_LazyAsy
nchronous);
}
texture->bind();
renderer->setBlendMode(BlendMode_None); void sSphere(Planet3DModel* model, const float radius, const float oneMinus
renderer->setCulledFaces(CullFace_Back); Oblateness, const int slices, const int stacks)
{
model->indiceArr.resize(0);
model->vertexArr.resize(0);
model->texCoordArr.resize(0);
// Now draw the sphere GLfloat x, y, z;
// Lighting is disabled, so just draw the plain sphere. GLfloat s=0.f, t=1.f;
if(NULL == light) GLint i, j;
{
const Vec4f color = StelApp::getInstance().getVisionModeNigh
t()
? Vec4f(1.f, 0.f, 0.f, 1.0f) : Vec4f(1.f,
1.f, 1.f, 1.0f);
renderer->setGlobalColor(color);
drawUnlitSphere(renderer, projector);
}
// Do the lighting on shader, avoiding the need to regenerate the sp
here.
// Shader is NULL if it failed to load, in that case we need to do l
ighting on the CPU.
else if(renderer->isGLSLSupported() && NULL != planetGraphics.planet
Shader)
{
StelGLSLShader* shader = planetGraphics.planetShader;
shader->bind(); const float* cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
// provides the unprojectedVertex attribute to the shader. const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
shader->useUnprojectedPositionAttribute();
Vec3d lightPos = Vec3d(light->position[0], light->position[1 const float* cos_sin_rho_p;
], light->position[2]); const float *cos_sin_theta_p;
projector->getModelViewTransform()
->getApproximateLinearTransfo()
.transpose()
.multiplyWithoutTranslation(Vec3d(lightPos[0], ligh
tPos[1], lightPos[2]));
projector->getModelViewTransform()->backward(lightPos);
lightPos.normalize();
shader->setUniformValue("lightPos" , Vec3f(lightPo // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y ax
s[0], lightPos[1] , lightPos[2])); is
shader->setUniformValue("diffuseLight" , light->diffus // t goes from -1.0/+1.0 at z = -radius/+radius (linear along longit
e); udes)
shader->setUniformValue("ambientLight" , light->ambien // cannot use triangle fan on texturing (s coord. at top/bottom tip
t); varies)
shader->setUniformValue("radius" , static_cast<f // If the texture is flipped, we iterate the coordinates backward.
loat>(radius * sphereScale)); const GLfloat ds = 1.f / slices;
shader->setUniformValue("oneMinusOblateness" , static_cast<f const GLfloat dt = 1.f / stacks; // from inside texture is reversed
loat>(oneMinusOblateness));
if(shader == planetGraphics.shadowPlanetShader) // draw intermediate as quad strips
for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks; ++i,cos_sin_rho_
p+=2)
{
s = 0.f;
for (j = 0,cos_sin_theta_p = cos_sin_theta; j<=slices;++j,co
s_sin_theta_p+=2)
{
x = -cos_sin_theta_p[1] * cos_sin_rho_p[1];
y = cos_sin_theta_p[0] * cos_sin_rho_p[1];
z = cos_sin_rho_p[0];
model->texCoordArr << s << t;
model->vertexArr << x * radius << y * radius << z *
oneMinusOblateness * radius;
x = -cos_sin_theta_p[1] * cos_sin_rho_p[3];
y = cos_sin_theta_p[0] * cos_sin_rho_p[3];
z = cos_sin_rho_p[2];
model->texCoordArr << s << t - dt;
model->vertexArr << x * radius << y * radius << z *
oneMinusOblateness * radius;
s += ds;
}
unsigned int offset = i*(slices+1)*2;
for (j = 2;j<slices*2+2;j+=2)
{ {
shader->setUniformValue("info", planetGraphics.info. model->indiceArr << offset+j-2 << offset+j-1 << offs
info); et+j;
shader->setUniformValue("infoCount", planetGraphics. model->indiceArr << offset+j << offset+j-1 << offset
info.infoCount); +j+1;
shader->setUniformValue("infoSize", planetGraphics.i }
nfo.infoSize); t -= dt;
shader->setUniformValue("current", planetGraphics.in }
fo.current); }
shader->setUniformValue("isRing", false); struct Ring3DModel
{
QVector<float> vertexArr;
QVector<float> texCoordArr;
QVector<unsigned short> indiceArr;
};
const bool ring = (rings != NULL) && rings->texture; void sRing(Ring3DModel* model, const float rMin, const float rMax, int slic
if(ring) es, const int stacks)
rings->texture->bind(2); {
shader->setUniformValue("ring", ring); float x,y;
shader->setUniformValue("outerRadius", ring ? static
_cast<float>(rings->radiusMax) : 0.0f);
shader->setUniformValue("innerRadius", ring ? static
_cast<float>(rings->radiusMin) : 0.0f);
shader->setUniformValue("ringS", ring ? 2 : 0)
;
const bool moon = this == GETSTELMODULE(SolarSystem) const float dr = (rMax-rMin) / stacks;
->getMoon(); const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
if(moon) const float* cos_sin_theta_p;
planetGraphics.texEarthShadow->bind(3);
shader->setUniformValue("isMoon", moon);
shader->setUniformValue("earthShadow", moon ? 3: 0);
}
drawUnlitSphere(renderer, projector); model->vertexArr.resize(0);
model->texCoordArr.resize(0);
model->indiceArr.resize(0);
shader->release(); float r = rMin;
} for (int i=0; i<=stacks; ++i)
// If shaders are not supported and we need lighting, we generate th
e sphere
// with lighting baked into vertex colors.
else
{ {
// Adapt the number of facets according with the size of the const float tex_r0 = (r-rMin)/(rMax-rMin);
sphere for optimization int j;
// 40 facets for 1024 pixels diameter on screen for (j=0,cos_sin_theta_p=cos_sin_theta; j<=slices; ++j,cos_s
const int resolution = std::min(40, std::max(7, static_cast< in_theta_p+=2)
int>(screenSz * 40.0 / 50.0))); {
x = r*cos_sin_theta_p[0];
// Lazily construct the lit sphere. y = r*cos_sin_theta_p[1];
if(NULL == litSphere) model->texCoordArr << tex_r0 << 0.5f;
{ model->vertexArr << x << y << 0.f;
const SphereParams params = SphereParams(radius * sp
hereScale)
.resolution(resolution,
resolution)
.oneMinusOblateness(oneM
inusOblateness);
litSphere = StelGeometryBuilder().buildSphereLit(par
ams, *light);
} }
else r+=dr;
}
for (int i=0; i<stacks; ++i)
{
for (int j=0; j<slices; ++j)
{ {
litSphere->setResolution(resolution, resolution); model->indiceArr << i*slices+j << (i+1)*slices+j <<
litSphere->setLight(*light); i*slices+j+1;
model->indiceArr << i*slices+j+1 << (i+1)*slices+j <
< (i+1)*slices+j+1;
} }
litSphere->draw(renderer, projector);
} }
renderer->setCulledFaces(CullFace_None);
} }
// draws earth shadow overlapping the moon using stencil buffer void Planet::computeModelMatrix(Mat4d &result) const
// umbra and penumbra are sized separately for accuracy
void Planet::drawEarthShadow(StelCore* core, StelRenderer* renderer,
SharedPlanetGraphics& planetGraphics)
{ {
SolarSystem* ssm = GETSTELMODULE(SolarSystem); result = Mat4d::translation(eclipticPos) * rotLocalToParent * Mat4d:
Vec3d e = ssm->getEarth()->getEclipticPos(); :zrotation(M_PI/180*(axisRotation + 90.));
Vec3d m = ssm->getMoon()->getEclipticPos(); // relative to earth PlanetP p = parent;
Vec3d mh = ssm->getMoon()->getHeliocentricEclipticPos(); // relativ while (p && p->parent)
e to sun {
float mscale = ssm->getMoon()->getSphereScale(); result = Mat4d::translation(p->eclipticPos) * result * p->ro
tLocalToParent;
// shadow location at earth + moon distance along earth vector from p = p->parent;
sun }
Vec3d en = e;
en.normalize();
Vec3d shadow = en * (e.length() + m.length());
// find shadow radii in AU
double r_penumbra = shadow.length()*702378.1/AU/e.length() - 696000.
/AU;
double r_umbra = 6378.1/AU - m.length()*(689621.9/AU/e.length());
// find vector orthogonal to sun-earth vector using cross product wi
th
// a non-parallel vector
Vec3d rpt = shadow^Vec3d(0,0,1);
rpt.normalize();
Vec3d upt = rpt*r_umbra*mscale*1.02; // point on umbra edge
rpt *= r_penumbra*mscale; // point on penumbra edge
// modify shadow location for scaled moon
Vec3d mdist = shadow - mh;
if (mdist.length() > r_penumbra + 2000./AU)
return; // not visible so don't bother drawing
shadow = mh + mdist*mscale;
StelProjectorP projector = core->getProjection(StelCore::FrameHelioc
entricEcliptic);
renderer->setBlendMode(BlendMode_Alpha);
renderer->setGlobalColor(1.0f, 1.0f, 1.0f);
// We draw only where the stencil buffer is at 1, i.e. where the moo
n was drawn
renderer->setStencilTest(StencilTest_DrawIf_1);
// shadow radial texture
planetGraphics.texEarthShadow->bind();
// Draw umbra first
StelVertexBuffer<VertexP3T2>* umbra =
renderer->createVertexBuffer<VertexP3T2>(PrimitiveType_Trian
gleFan);
// johannes: work-around for nasty ATI rendering bug: use y-texture
coordinate of 0.5 instead of 0.0
const Mat4d& rotMat = Mat4d::rotation(shadow, 2.*M_PI/100.);
Vec3f r(upt[0], upt[1], upt[2]);
const Vec3f shadowF(shadow[0], shadow[1], shadow[2]);
umbra->addVertex(VertexP3T2(shadowF, Vec2f(0.0f, 0.5f)));
for (int i=1; i<=101; ++i)
{
r.transfo4d(rotMat);
// position in texture of umbra edge
umbra->addVertex(VertexP3T2(shadowF + r, Vec2f(0.6f, 0.5f)))
;
}
umbra->lock();
renderer->drawVertexBuffer(umbra, NULL, projector);
delete umbra;
// now penumbra
StelVertexBuffer<VertexP3T2>* penumbra =
renderer->createVertexBuffer<VertexP3T2>(PrimitiveType_Trian
gleStrip);
Vec3f u = r;
r = Vec3f(rpt[0], rpt[1], rpt[2]);
for (int i=0; i<=200; i+=2)
{
r.transfo4d(rotMat);
u.transfo4d(rotMat);
// position in texture of umbra edge
penumbra->addVertex(VertexP3T2(shadowF + u, Vec2f(0.6f, 0.5f
)));
penumbra->addVertex(VertexP3T2(shadowF + r, Vec2f(1.0f, 0.5f
)));
}
penumbra->lock();
renderer->drawVertexBuffer(penumbra, NULL, projector);
delete penumbra;
renderer->setStencilTest(StencilTest_Disabled);
renderer->clearStencilBuffer();
} }
void Planet::drawHints(const StelCore* core, StelRenderer* renderer, void Planet::drawSphere(StelPainter* painter, float screenSz, bool drawOnly
const QFont& planetNameFont, SharedPlanetGraphics& p Ring)
lanetGraphics)
{ {
if (labelsFader.getInterstate()<=0.f) if (texMap)
return; {
// For lazy loading, return if texture not yet loaded
if (!texMap->bind(0))
{
return;
}
}
painter->enableTexture2d(true);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000) // Draw the spheroid itself
; // Adapt the number of facets according with the size of the sphere
renderer->setFont(planetNameFont); for optimization
// Draw nameI18 + scaling if it's not == 1. int nb_facet = (int)(screenSz * 40.f/50.f); // 40 facets for 102
float tmp = (hintFader.getInterstate()<=0 ? 7.f : 10.f) + getAngular 4 pixels diameter on screen
Size(core)*M_PI/180.f*prj->getPixelPerRadAtCenter()/1.44f; // Shift for nam if (nb_facet<10) nb_facet = 10;
eI18 printing if (nb_facet>100) nb_facet = 100;
Vec4f color(labelColor[0], labelColor[1], labelColor[2], labelsFader // Generates the vertice
.getInterstate()); Planet3DModel model;
renderer->setGlobalColor(color); sSphere(&model, radius*sphereScale, oneMinusOblateness, nb_facet, nb
renderer->drawText(TextParams(screenPos[0], screenPos[1], getSkyLabe _facet);
l(core))
.shift(tmp, tmp).useGravity());
// hint disapears smoothly on close view QVector<float> projectedVertexArr;
if (hintFader.getInterstate()<=0) projectedVertexArr.resize(model.vertexArr.size());
return; for (int i=0;i<model.vertexArr.size()/3;++i)
tmp -= 10.f; painter->getProjector()->project(*((Vec3f*)(model.vertexArr.
if (tmp<1) tmp=1; constData()+i*3)), *((Vec3f*)(projectedVertexArr.data()+i*3)));
color[3] *= hintFader.getInterstate() / tmp * 0.7f;
renderer->setGlobalColor(color);
// Draw the 2D small circle const SolarSystem* ssm = GETSTELMODULE(SolarSystem);
renderer->setBlendMode(BlendMode_Alpha);
planetGraphics.texHintCircle->bind();
renderer->drawTexturedRect(screenPos[0] - 11, screenPos[1] - 11, 22,
22);
}
Ring::Ring(double radiusMin,double radiusMax,const QString &texname) if (this==ssm->getSun())
: radiusMin(radiusMin) {
, radiusMax(radiusMax) texMap->bind();
, texName(texname) painter->setColor(2, 2, 2);
, texture(NULL) painter->setArrays((Vec3f*)projectedVertexArr.constData(), (
, ring(NULL) Vec2f*)model.texCoordArr.constData());
{ painter->drawFromArray(StelPainter::Triangles, model.indiceA
} rr.size(), 0, false, model.indiceArr.constData());
return;
}
Ring::~Ring(void) if (planetShaderProgram==NULL)
{ Planet::initShader();
if(NULL != ring) Q_ASSERT(planetShaderProgram!=NULL);
Q_ASSERT(ringPlanetShaderProgram!=NULL);
Q_ASSERT(moonShaderProgram!=NULL);
QOpenGLShaderProgram* shader = planetShaderProgram;
const PlanetShaderVars* shaderVars = &planetShaderVars;
if (rings)
{ {
delete ring; shader = ringPlanetShaderProgram;
ring = NULL; shaderVars = &ringPlanetShaderVars;
} }
if(NULL != texture) if (this==ssm->getMoon())
{ {
delete texture; shader = moonShaderProgram;
texture = NULL; shaderVars = &moonShaderVars;
} }
} GL(shader->bind());
void Ring::draw(StelProjectorP projector, StelRenderer* renderer, const Mat4f& m = painter->getProjector()->getProjectionMatrix();
StelProjector::ModelViewTranformP transfo, c const QMatrix4x4 qMat(m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[1
lass StelGLSLShader* shader, double screenSz, ShadowPlanetShaderInfo* info) 3], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]);
{
if(NULL == texture) 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)
{ {
texture = renderer->createTexture("textures/" + texName); qDebug() << "Too many satellite shadows, some won't be displ
ayed";
shadowCandidates.resize(4);
} }
screenSz -= 50; for (int i=0;i<shadowCandidates.size();++i)
screenSz /= 250.0; {
if (screenSz < 0.0) screenSz = 0.0; shadowCandidates.at(i)->computeModelMatrix(modelMatrix);
else if (screenSz > 1.0) screenSz = 1.0; const Vec4d position = mTarget * modelMatrix.getColumn(3);
const int slices = 128+(int)((256-128)*screenSz); shadowCandidatesData(0, i) = position[0];
const int stacks = 8+(int)((32-8)*screenSz); shadowCandidatesData(1, i) = position[1];
shadowCandidatesData(2, i) = position[2];
shadowCandidatesData(3, i) = shadowCandidates.at(i)->getRadi
us();
}
const StelProjectorP& projector = painter->getProjector();
renderer->setBlendMode(BlendMode_Alpha); Vec3f lightPos3(light.position[0], light.position[1], light.position
renderer->setCulledFaces(CullFace_Back); [2]);
const Vec4f color = StelApp::getInstance().getVisionModeNight() projector->getModelViewTransform()->backward(lightPos3);
? Vec4f(1.f, 0.f, 0.f, 1.0f) : Vec4f(1.f, 1.f, 1.f lightPos3.normalize();
, 1.0f);
renderer->setGlobalColor(color);
texture->bind(); Vec3d eyePos = StelApp::getInstance().getCore()->getObserverHeliocen
tricEclipticPos();
StelApp::getInstance().getCore()->getHeliocentricEclipticModelViewTr
ansform()->forward(eyePos);
projector->getModelViewTransform()->backward(eyePos);
eyePos.normalize();
Mat4d mat = transfo->getApproximateLinearTransfo(); GL(shader->setUniformValue(shaderVars->projectionMatrix, qMat));
// solve the ring wraparound by culling: GL(shader->setUniformValue(shaderVars->lightDirection, lightPos3[0],
// decide if we are above or below the ring plane lightPos3[1], lightPos3[2]));
const double h = mat.r[ 8] * mat.r[12] GL(shader->setUniformValue(shaderVars->eyeDirection, eyePos[0], eyeP
+ mat.r[ 9] * mat.r[13] os[1], eyePos[2]));
+ mat.r[10] * mat.r[14]; 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));
if(NULL == ring) if (rings!=NULL)
{ {
ring = StelGeometryBuilder() GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader
.buildRingTextured(RingParams(radiusMin, radiusMax). Vars.isRing, false));
resolution(slices, stacks)); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader
Vars.ring, true));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader
Vars.outerRadius, rings->radiusMax));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader
Vars.innerRadius, rings->radiusMin));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader
Vars.ringS, 2));
rings->tex->bind(2);
} }
else
if (this==ssm->getMoon())
{ {
ring->setResolution(slices, stacks); GL(normalMap->bind(2));
GL(moonShaderProgram->setUniformValue(moonShaderVars.normalM
ap, 2));
if (!shadowCandidates.isEmpty())
{
GL(texEarthShadow->bind(3));
GL(moonShaderProgram->setUniformValue(moonShaderVars
.earthShadow, 3));
}
} }
ring->setFlipFaces(h >= 0);
if(info && renderer->isGLSLSupported()) GL(shader->setAttributeArray(shaderVars->vertex, (const GLfloat*)pro
jectedVertexArr.constData(), 3));
GL(shader->enableAttributeArray(shaderVars->vertex));
GL(shader->setAttributeArray(shaderVars->unprojectedVertex, (const G
Lfloat*)model.vertexArr.constData(), 3));
GL(shader->enableAttributeArray(shaderVars->unprojectedVertex));
GL(shader->setAttributeArray(shaderVars->texCoord, (const GLfloat*)m
odel.texCoordArr.constData(), 2));
GL(shader->enableAttributeArray(shaderVars->texCoord));
if (rings)
{ {
shader->bind(); glDepthMask(GL_TRUE);
// provides the unprojectedVertex attribute to the shader. glClear(GL_DEPTH_BUFFER_BIT);
shader->useUnprojectedPositionAttribute(); glEnable(GL_DEPTH_TEST);
}
shader->setUniformValue("lightPos" , Vec3f(0, 0, 0 if (!drawOnlyRing)
)); GL(glDrawElements(GL_TRIANGLES, model.indiceArr.size(), GL_U
shader->setUniformValue("diffuseLight" , Vec4f(1, 1, 1 NSIGNED_SHORT, model.indiceArr.constData()));
, 1));
shader->setUniformValue("ambientLight" , Vec4f(0, 0, 0
, 1));
shader->setUniformValue("radius" , 1.0f);
shader->setUniformValue("oneMinusOblateness" , 1.0f);
shader->setUniformValue("info", info->info); if (rings)
shader->setUniformValue("infoCount", info->infoCount); {
shader->setUniformValue("infoSize", info->infoSize); // Draw the rings just after the planet
shader->setUniformValue("current", info->current); glDepthMask(GL_FALSE);
shader->setUniformValue("isRing", true); // Normal transparency mode
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
shader->setUniformValue("ring", true); Ring3DModel ringModel;
shader->setUniformValue("outerRadius", static_cast<float>(ra sRing(&ringModel, rings->radiusMin, rings->radiusMax, 128, 3
diusMax)); 2);
shader->setUniformValue("innerRadius", static_cast<float>(ra
diusMin));
shader->setUniformValue("ringS", 0);
}
ring->draw(renderer, projector); GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader
Vars.isRing, true));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader
Vars.texture, 2));
if(info && renderer->isGLSLSupported()) computeModelMatrix(modelMatrix);
{ const Vec4d position = mTarget * modelMatrix.getColumn(3);
shader->release(); shadowCandidatesData(0, 0) = position[0];
shadowCandidatesData(1, 0) = position[1];
shadowCandidatesData(2, 0) = position[2];
shadowCandidatesData(3, 0) = getRadius();
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader
Vars.shadowCount, 1));
GL(ringPlanetShaderProgram->setUniformValue(ringPlanetShader
Vars.shadowData, shadowCandidatesData));
projectedVertexArr.resize(ringModel.vertexArr.size());
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)));
GL(ringPlanetShaderProgram->setAttributeArray(ringPlanetShad
erVars.vertex, (const GLfloat*)projectedVertexArr.constData(), 3));
GL(ringPlanetShaderProgram->enableAttributeArray(ringPlanetS
haderVars.vertex));
GL(ringPlanetShaderProgram->setAttributeArray(ringPlanetShad
erVars.unprojectedVertex, (const GLfloat*)ringModel.vertexArr.constData(),
3));
GL(ringPlanetShaderProgram->enableAttributeArray(ringPlanetS
haderVars.unprojectedVertex));
GL(ringPlanetShaderProgram->setAttributeArray(ringPlanetShad
erVars.texCoord, (const GLfloat*)ringModel.texCoordArr.constData(), 2));
GL(ringPlanetShaderProgram->enableAttributeArray(ringPlanetS
haderVars.texCoord));
if (eyePos[2]<0)
glCullFace(GL_FRONT);
GL(glDrawElements(GL_TRIANGLES, ringModel.indiceArr.size(),
GL_UNSIGNED_SHORT, ringModel.indiceArr.constData()));
if (eyePos[2]<0)
glCullFace(GL_BACK);
glDisable(GL_DEPTH_TEST);
} }
renderer->setCulledFaces(CullFace_None); GL(shader->release());
glDisable(GL_CULL_FACE);
}
void Planet::drawHints(const StelCore* core, const QFont& planetNameFont)
{
if (labelsFader.getInterstate()<=0.f)
return;
const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000)
;
StelPainter sPainter(prj);
sPainter.setFont(planetNameFont);
// 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
sPainter.setColor(labelColor[0], labelColor[1], labelColor[2],labels
Fader.getInterstate());
sPainter.drawText(screenPos[0],screenPos[1], getSkyLabel(core), 0, t
mp, tmp, false);
// hint disappears smoothly on close view
if (hintFader.getInterstate()<=0)
return;
tmp -= 10.f;
if (tmp<1) tmp=1;
sPainter.setColor(labelColor[0], labelColor[1], labelColor[2],labels
Fader.getInterstate()*hintFader.getInterstate()/tmp*0.7f);
// Draw the 2D small circle
glEnable(GL_BLEND);
sPainter.enableTexture2d(true);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Planet::hintCircleTex->bind();
sPainter.drawSprite2dMode(screenPos[0], screenPos[1], 11);
}
Ring::Ring(float radiusMin, float radiusMax, const QString &texname)
:radiusMin(radiusMin),radiusMax(radiusMax)
{
tex = StelApp::getInstance().getTextureManager().createTexture(StelF
ileMgr::getInstallationDir()+"/textures/"+texname);
} }
// draw orbital path of Planet // draw orbital path of Planet
void Planet::drawOrbit(const StelCore* core, StelRenderer* renderer) void Planet::drawOrbit(const StelCore* core)
{ {
if (!orbitFader.getInterstate()) if (!orbitFader.getInterstate())
return; return;
if (!re.siderealPeriod) if (!re.siderealPeriod)
return; return;
const StelProjectorP prj = core->getProjection(StelCore::FrameHelioc entricEcliptic); const StelProjectorP prj = core->getProjection(StelCore::FrameHelioc entricEcliptic);
renderer->setBlendMode(BlendMode_Alpha); StelPainter sPainter(prj);
renderer->setGlobalColor(orbitColor[0], orbitColor[1],
orbitColor[2], orbitFader.getInterstate());
// Normal transparency mode
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
sPainter.setColor(orbitColor[0], orbitColor[1], orbitColor[2], orbit
Fader.getInterstate());
Vec3d onscreen; Vec3d onscreen;
// special case - use current Planet position as center vertex so th at draws // special case - use current Planet position as center vertex so th at draws
// on it's orbit all the time (since segmented rather than smooth cu rve) // on it's orbit all the time (since segmented rather than smooth cu rve)
Vec3d savePos = orbit[ORBIT_SEGMENTS/2]; Vec3d savePos = orbit[ORBIT_SEGMENTS/2];
orbit[ORBIT_SEGMENTS/2]=getHeliocentricEclipticPos(); orbit[ORBIT_SEGMENTS/2]=getHeliocentricEclipticPos();
orbit[ORBIT_SEGMENTS]=orbit[0]; orbit[ORBIT_SEGMENTS]=orbit[0];
int nbIter = closeOrbit ? ORBIT_SEGMENTS : ORBIT_SEGMENTS-1; int nbIter = closeOrbit ? ORBIT_SEGMENTS : ORBIT_SEGMENTS-1;
QVarLengthArray<float, 1024> vertexArray;
if(NULL == orbitVertices) sPainter.enableClientStates(true, false, false);
{
orbitVertices =
renderer->createVertexBuffer<Vertex2D>(PrimitiveType
_LineStrip);
}
for (int n=0; n<=nbIter; ++n) for (int n=0; n<=nbIter; ++n)
{ {
if (prj->project(orbit[n],onscreen) && (orbitVertices->lengt h()==0 || !prj->intersectViewportDiscontinuity(orbit[n-1], orbit[n]))) if (prj->project(orbit[n],onscreen) && (vertexArray.size()== 0 || !prj->intersectViewportDiscontinuity(orbit[n-1], orbit[n])))
{ {
orbitVertices->addVertex(Vertex2D(onscreen[0], onscr vertexArray.append(onscreen[0]);
een[1])); vertexArray.append(onscreen[1]);
} }
else if(orbitVertices->length() > 0) else if (!vertexArray.isEmpty())
{ {
orbitVertices->lock(); sPainter.setVertexPointer(2, GL_FLOAT, vertexArray.c
renderer->drawVertexBuffer(orbitVertices); onstData());
orbitVertices->unlock(); sPainter.drawFromArray(StelPainter::LineStrip, verte
orbitVertices->clear(); xArray.size()/2, 0, false);
vertexArray.clear();
} }
} }
orbit[ORBIT_SEGMENTS/2]=savePos; orbit[ORBIT_SEGMENTS/2]=savePos;
if (!vertexArray.isEmpty())
if(orbitVertices->length() > 0)
{ {
orbitVertices->lock(); sPainter.setVertexPointer(2, GL_FLOAT, vertexArray.constData
renderer->drawVertexBuffer(orbitVertices); ());
orbitVertices->unlock(); sPainter.drawFromArray(StelPainter::LineStrip, vertexArray.s
orbitVertices->clear(); ize()/2, 0, false);
} }
sPainter.enableClientStates(false);
} }
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::setSphereScale(float s)
{
sphereScale = s;
if(NULL != unlitSphere) {unlitSphere->setRadius(radius * s);}
if(NULL != litSphere) {litSphere->setRadius(radius * s);}
}
 End of changes. 163 change blocks. 
976 lines changed or deleted 967 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/