1 /*
2  * Stellarium
3  * Copyright (C) 2002 Fabien Chereau
4  * Copyright (C) 2014 Georg Zotti (extinction parts)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
19  */
20 
21 #include "MilkyWay.hpp"
22 #include "StelFader.hpp"
23 #include "StelTexture.hpp"
24 #include "StelUtils.hpp"
25 #include "StelFileMgr.hpp"
26 
27 #include "StelProjector.hpp"
28 #include "StelToneReproducer.hpp"
29 #include "StelApp.hpp"
30 #include "StelTextureMgr.hpp"
31 #include "StelCore.hpp"
32 #include "StelSkyDrawer.hpp"
33 #include "StelPainter.hpp"
34 #include "StelTranslator.hpp"
35 #include "StelModuleMgr.hpp"
36 #include "LandscapeMgr.hpp"
37 #include "StelMovementMgr.hpp"
38 #include "Planet.hpp"
39 
40 #include <QDebug>
41 #include <QSettings>
42 
43 // Class which manages the displaying of the Milky Way
MilkyWay()44 MilkyWay::MilkyWay()
45 	: color(1.f, 1.f, 1.f)
46 	, intensity(1.)
47 	, intensityFovScale(1.0)
48 	, intensityMinFov(0.25) // when zooming in further, MilkyWay is no longer visible.
49 	, intensityMaxFov(2.5) // when zooming out further, MilkyWay is fully visible (when enabled).
50 	, vertexArray()
51 	, vertexArrayNoAberration()
52 {
53 	setObjectName("MilkyWay");
54 	fader = new LinearFader();
55 }
56 
~MilkyWay()57 MilkyWay::~MilkyWay()
58 {
59 	delete fader;
60 	fader = Q_NULLPTR;
61 
62 	delete vertexArray;
63 	vertexArray = Q_NULLPTR;
64 	delete vertexArrayNoAberration;
65 	vertexArrayNoAberration = Q_NULLPTR;
66 }
67 
init()68 void MilkyWay::init()
69 {
70 	QSettings* conf = StelApp::getInstance().getSettings();
71 	Q_ASSERT(conf);
72 
73 	tex = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/milkyway.png");
74 	setFlagShow(conf->value("astro/flag_milky_way").toBool());
75 	setIntensity(conf->value("astro/milky_way_intensity",1.).toDouble());
76 	setSaturation(conf->value("astro/milky_way_saturation", 1.).toDouble());
77 
78 	// A new texture was provided by Fabien. Better resolution, but in equatorial coordinates. I had to enhance it a bit, and shift it by 90 degrees.
79 	// We must create a constant array to take and derive possibly aberrated positions into the vertexArray
80 	vertexArrayNoAberration = new StelVertexArray(StelPainter::computeSphereNoLight(1.,1.,45,15,1, true)); // GZ orig: slices=stacks=20.
81 	vertexArray =             new StelVertexArray(StelPainter::computeSphereNoLight(1.,1.,45,15,1, true)); // GZ orig: slices=stacks=20.
82 	vertexArray->colors.resize(vertexArray->vertex.length());
83 	vertexArray->colors.fill(color);
84 
85 	QString displayGroup = N_("Display Options");
86 	addAction("actionShow_MilkyWay", displayGroup, N_("Milky Way"), "flagMilkyWayDisplayed", "M");
87 }
88 
89 
update(double deltaTime)90 void MilkyWay::update(double deltaTime)
91 {
92 	fader->update(static_cast<int>(deltaTime*1000));
93 	//calculate FOV fade value, linear fade between intensityMaxFov and intensityMinFov
94 	double fov = StelApp::getInstance().getCore()->getMovementMgr()->getCurrentFov();
95 	intensityFovScale = qBound(0.0,(fov - intensityMinFov) / (intensityMaxFov - intensityMinFov),1.0);
96 }
97 
98 /*************************************************************************
99  Reimplementation of the getCallOrder method
100 *************************************************************************/
getCallOrder(StelModuleActionName actionName) const101 double MilkyWay::getCallOrder(StelModuleActionName actionName) const
102 {
103 	if (actionName==StelModule::ActionDraw)
104 		return 1;
105 	return 0;
106 }
107 
setFlagShow(bool b)108 void MilkyWay::setFlagShow(bool b)
109 {
110 	if (*fader != b)
111 	{
112 		*fader = b;
113 		emit milkyWayDisplayedChanged(b);
114 	}
115 }
116 
getFlagShow() const117 bool MilkyWay::getFlagShow() const {return *fader;}
118 
draw(StelCore * core)119 void MilkyWay::draw(StelCore* core)
120 {
121 	if (!fader->getInterstate())
122 		return;
123 
124 	// Apply annual aberration. We take original vertices, and put the aberrated positions into the vertexArray which we draw.
125 	// prepare for aberration: Explan. Suppl. 2013, (7.38)
126 	if (core->getUseAberration())
127 	{
128 		Vec3d vel=core->getCurrentPlanet()->getHeliocentricEclipticVelocity();
129 		vel=StelCore::matVsop87ToJ2000*vel;
130 		vel*=core->getAberrationFactor() * (AU/(86400.0*SPEED_OF_LIGHT));
131 		for (int i=0; i<vertexArrayNoAberration->vertex.size(); ++i)
132 		{
133 			Vec3d vert=vertexArrayNoAberration->vertex.at(i);
134 			Q_ASSERT_X(fabs(vert.lengthSquared()-1.0)<0.0001, "Milky Way aberration", "vertex length not unity");
135 			vert+=vel;
136 			vert.normalize();
137 
138 			vertexArray->vertex[i]=vert;
139 		}
140 	}
141 	else
142 	{
143 	//	for (int i=0; i<vertexArrayNoAberration->vertex.size(); ++i)
144 	//		vertexArray->vertex[i]=vertexArrayNoAberration->vertex.at(i);
145 		vertexArray->vertex=vertexArrayNoAberration->vertex;
146 	}
147 
148 	StelProjector::ModelViewTranformP transfo = core->getJ2000ModelViewTransform();
149 
150 	const StelProjectorP prj = core->getProjection(transfo); // GZ: Maybe this can now be simplified?
151 	StelToneReproducer* eye = core->getToneReproducer();
152 	StelSkyDrawer *drawer=core->getSkyDrawer();
153 
154 	Q_ASSERT(tex);	// A texture must be loaded before calling this
155 
156 	// This RGB color corresponds to the night blue scotopic color = 0.25, 0.25 in xyY mode.
157 	// since milky way is always seen white RGB value in the texture (1.0,1.0,1.0)
158 	// Vec3f c = Vec3f(0.34165f, 0.429666f, 0.63586f);
159 	// This is the same color, just brighter to have Blue=1.
160 	//Vec3f c = Vec3f(0.53730381f, .675724216f, 1.0f);
161 	// The new texture (V0.13.1) is quite blue to start with. It is better to apply white color for it.
162 	//Vec3f c = Vec3f(1.0f, 1.0f, 1.0f);
163 	// Still better: Re-activate the configurable color!
164 	Vec3f c = color;
165 
166 	// We must also adjust milky way to light pollution.
167 	// Is there any way to calibrate this?
168 	// We compute a float 1..9 from Bortle index and atmosphere display value (allows smooth fade when switching)
169 	float atmFadeIntensity = GETSTELMODULE(LandscapeMgr)->getAtmosphereFadeIntensity();
170 	int bortle=drawer->getBortleScaleIndex();
171 	float bortleIntensity = 1.f+ (bortle-1)*atmFadeIntensity; // Bortle index moderated by atmosphere fader.
172 	//aLum*=(11.0f-bortle)*0.1f;
173 
174 	float lum = drawer->surfaceBrightnessToLuminance(12.f+0.15f*bortleIntensity); // was 11.5; Source? How to calibrate the new texture?
175 
176 	// Get the luminance scaled between 0 and 1
177 	float aLum =eye->adaptLuminanceScaled(lum*fader->getInterstate());
178 
179 	// Bound a maximum luminance. GZ: Is there any reference/reason, or just trial and error?
180 	aLum = qMin(0.38f, aLum*2.f);
181 
182 
183 	// intensity of 1.0 is "proper", but allow boost for dim screens
184 	c*=aLum*static_cast<float>(intensity*intensityFovScale);
185 
186 
187 	// TODO: Find an even better balance with sky brightness, MW should be hard to see during Full Moon and at least somewhat reduced in smaller phases.
188 	// adapt brightness by atmospheric brightness. This block developed for ZodiacalLight, hopefully similarly applicable...
189 	const float atmLum = GETSTELMODULE(LandscapeMgr)->getAtmosphereAverageLuminance();
190 	// 10cd/m^2 at sunset, 3.3 at civil twilight (sun at -6deg). 0.0145 sun at -12, 0.0004 sun at -18,  0.01 at Full Moon!?
191 	//qDebug() << "AtmLum: " << atmLum;
192 	float atmFactor=qMax(0.35f, 50.0f*(0.02f-atmLum)); // keep visible in twilight, but this is enough for some effect with the moon.
193 	c*=atmFactor*atmFactor;
194 
195 	if (c[0]<0) c[0]=0;
196 	if (c[1]<0) c[1]=0;
197 	if (c[2]<0) c[2]=0;
198 
199 	const bool withExtinction=(drawer->getFlagHasAtmosphere() && drawer->getExtinction().getExtinctionCoefficient()>=0.01f);
200 	if (withExtinction)
201 	{
202 		// We must process the vertices to find geometric altitudes in order to compute vertex colors.
203 		// Note that there is a visible boost of extinction for higher Bortle indices. I must reflect that as well.
204 		const Extinction& extinction=drawer->getExtinction();
205 		vertexArray->colors.clear();
206 
207 		for (int i=0; i<vertexArray->vertex.size(); ++i)
208 		{
209 			Vec3d vertAltAz=core->j2000ToAltAz(vertexArray->vertex.at(i), StelCore::RefractionOn);
210 			Q_ASSERT(fabs(vertAltAz.lengthSquared()-1.0) < 0.001);
211 
212 			float mag=0.0f;
213 			extinction.forward(vertAltAz, &mag);
214 			float extinctionFactor=std::pow(0.3f, mag) * (1.1f-bortleIntensity*0.1f); // drop of one magnitude: should be factor 2.5 or 40%. We take 30%, it looks more realistic.
215 			vertexArray->colors.append(c*extinctionFactor);
216 		}
217 	}
218 	else
219 		vertexArray->colors.fill(c);
220 
221 	StelPainter sPainter(prj);
222 	sPainter.setCullFace(true);
223 	sPainter.setBlending(true, GL_ONE, GL_ONE); // allow colored sky background
224 	tex->bind();
225 	sPainter.setSaturation(static_cast<float>(saturation));
226 	sPainter.drawStelVertexArray(*vertexArray);
227 	sPainter.setCullFace(false);
228 }
229