1 /*
2  * Stellarium
3  * Copyright (C) 2003 Fabien Chereau
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
18  */
19 
20 #ifndef LANDSCAPE_HPP
21 #define LANDSCAPE_HPP
22 
23 #include "VecMath.hpp"
24 #include "StelToneReproducer.hpp"
25 #include "StelProjector.hpp"
26 
27 #include "StelFader.hpp"
28 #include "StelUtils.hpp"
29 #include "StelTextureTypes.hpp"
30 #include "StelLocation.hpp"
31 #include "StelSphereGeometry.hpp"
32 
33 #include <QMap>
34 #include <QImage>
35 #include <QList>
36 #include <QFont>
37 
38 class QSettings;
39 class StelLocation;
40 class StelCore;
41 class StelPainter;
42 
43 //! @class Landscape
44 //! Store and manages the displaying of the Landscape.
45 //! Don't use this class directly, use the LandscapeMgr.
46 //! A landscape's most important element is a photo panorama, or at least a polygon that describes the true horizon visible from your observing location.
47 //! Optional components include:
48 //!  - A fog texture that is displayed with the Fog [F] command (displayed only if atmosphere is on!).
49 //!  - A location. It is possible to auto-move to the location when loading.
50 //!  - Atmospheric conditions: temperature/pressure/extinction coefficients. These influence refraction and extinction.
51 //!  - Light pollution information (Bortle index)
52 //!  - A night texture that gets blended over the dimmed daylight panorama. (All landscapes except Polygonal.)
53 //!  - A polygonal horizon line (required for PolygonalLandscape). If present, defines a measured horizon line, which can be plotted or queried for rise/set predictions.
54 //!  - You can set a minimum brightness level to prevent too dark landscape. There is
55 //!    a global activation setting (config.ini[landscape]flag_minimal_brightness),
56 //!    a global value (config.ini[landscape]minimal_brightness),
57 //!    and, if config.ini[landscape]flag_landscape_sets_minimal_brightness=true,
58 //!    optional individual values given in landscape.ini[landscape]minimal_brightness are used.
59 //!
60 //! We discern:
61 //!   @param LandscapeId: The directory name of the landscape.
62 //!   @param name: The landscape name as specified in the LandscapeIni (may contain spaces, translatable, UTF8, ...)
63 class Landscape
64 {
65 public:
66 	typedef struct
67 	{
68 		QString name;
69 		Vec3d featurePoint; // start of the line: mountain peak, building, ...
70 		Vec3d labelPoint;   // end of the line, where the centered label best fits.
71 	} LandscapeLabel;
72 
73 	Landscape(float _radius = 2.f);
74 	virtual ~Landscape();
75 	//! Load landscape.
76 	//! @param landscapeIni A reference to an existing QSettings object which describes the landscape
77 	//! @param landscapeId The name of the directory for the landscape files (e.g. "ocean")
78 	virtual void load(const QSettings& landscapeIni, const QString& landscapeId) = 0;
79 
80 	//! Return approximate memory footprint in bytes (required for cache cost estimate in LandscapeMgr)
81 	//! The returned value is only approximate, content of QStrings and other small containers like the horizon polygon are not put in in detail.
82 	//! However, texture image sizes must be computed and added in subclasses.
83 	//! The value returned is a sum of RAM and texture memory requirements.
getMemorySize() const84 	unsigned int getMemorySize() const {return memorySize;}
85 
86 	//! Draw the landscape. If onlyPolygon, only draw the landscape polygon, if one is defined. If no polygon is defined, the
87 	virtual void draw(StelCore* core, bool onlyPolygon) = 0;
update(double deltaTime)88 	void update(double deltaTime)
89 	{
90 		landFader.update(static_cast<int>(deltaTime*1000));
91 		fogFader.update(static_cast<int>(deltaTime*1000));
92 		illumFader.update(static_cast<int>(deltaTime*1000));
93 		labelFader.update(static_cast<int>(deltaTime*1000));
94 	}
95 
96 	//! Set the brightness of the landscape plus brightness of optional add-on night lightscape.
97 	//! This is called in each draw().
setBrightness(const double b,const double pollutionBrightness=0.0)98 	void setBrightness(const double b, const double pollutionBrightness=0.0) {landscapeBrightness = static_cast<float>(b); lightScapeBrightness=static_cast<float>(pollutionBrightness); }
99 
100 	//! Returns the current brightness level
getBrightness() const101 	double getBrightness() const { return static_cast<double>(landscapeBrightness); }
102 	//! Returns the lightscape brightness
getLightscapeBrightness() const103 	double getLightscapeBrightness() const { return static_cast<double>(lightScapeBrightness); }
104 	//! Returns the lightscape brighness modulated with the fader's target state (i.e. binary on/off)
getTargetLightscapeBrightness() const105 	double getTargetLightscapeBrightness() const { return static_cast<double>(lightScapeBrightness * illumFader); }
106 	//! Gets the currently effective lightscape brightness (modulated by the fader)
getEffectiveLightscapeBrightness() const107 	double getEffectiveLightscapeBrightness() const { return static_cast<double>(lightScapeBrightness * illumFader.getInterstate()); }
108 
109 	//! Set whether landscape is displayed (does not concern fog)
setFlagShow(const bool b)110 	void setFlagShow(const bool b) {landFader=b;}
111 	//! Get whether landscape is displayed (does not concern fog)
getFlagShow() const112 	bool getFlagShow() const {return static_cast<bool>(landFader);}
113 	//! Returns the currently effective land fade value
getEffectiveLandFadeValue() const114 	float getEffectiveLandFadeValue() const { return landFader.getInterstate(); }
115 	//! Set whether fog is displayed
setFlagShowFog(const bool b)116 	void setFlagShowFog(const bool b) {fogFader=b;}
117 	//! Get whether fog is displayed
getFlagShowFog() const118 	bool getFlagShowFog() const {return static_cast<bool>(fogFader);}
119 	//! Set whether illumination is displayed
setFlagShowIllumination(const bool b)120 	void setFlagShowIllumination(const bool b) {illumFader=b;}
121 	//! Get whether illumination is displayed
getFlagShowIllumination() const122 	bool getFlagShowIllumination() const {return static_cast<bool>(illumFader);}
123 	//! Set whether labels are displayed
setFlagShowLabels(const bool b)124 	void setFlagShowLabels(const bool b) {labelFader=b;}
125 	//! Get whether labels are displayed
getFlagShowLabels() const126 	bool getFlagShowLabels() const {return static_cast<bool>(labelFader);}
127 	//! change font and fontsize for landscape labels
setLabelFontSize(const int size)128 	void setLabelFontSize(const int size){fontSize=size;}
129 
130 	//! Get landscape name
getName() const131 	QString getName() const {return name;}
132 	//! Get landscape author name
getAuthorName() const133 	QString getAuthorName() const {return author;}
134 	//! Get landscape description
getDescription() const135 	QString getDescription() const {return description;}
136 	//! Get landscape id. This is the landscape directory name, used for cache handling.
getId() const137 	QString getId() const {return id;}
138 
139 	//! Return the associated location (may be empty!)
getLocation() const140 	const StelLocation& getLocation() const {return location;}
141 	//! Return if the location is valid (a valid location has a valid planetName!)
hasLocation() const142 	bool hasLocation() const {return (!(location.planetName.isEmpty()));}
143   	//! Return default Bortle index (light pollution value) or -1 (unknown/no change)
getDefaultBortleIndex() const144 	int getDefaultBortleIndex() const {return defaultBortleIndex;}
145 	//! Return default fog setting (0/1) or -1 (no change)
getDefaultFogSetting() const146 	int getDefaultFogSetting() const {return defaultFogSetting;}
147 	//! Return default atmosperic extinction [mag/airmass], or -1 (no change)
getDefaultAtmosphericExtinction() const148 	double getDefaultAtmosphericExtinction() const {return defaultExtinctionCoefficient;}
149 	//! Return configured atmospheric temperature [degrees Celsius], for refraction computation, or -1000 for "unknown/no change".
getDefaultAtmosphericTemperature() const150 	double getDefaultAtmosphericTemperature() const {return defaultTemperature;}
151 	//! Return configured atmospheric pressure [mbar], for refraction computation.
152 	//! returns -1 to signal "standard conditions" [compute from altitude], or -2 for "unknown/invalid/no change"
getDefaultAtmosphericPressure() const153 	double getDefaultAtmosphericPressure() const {return defaultPressure;}
154 	//! Return minimal brightness for landscape
155 	//! returns -1 to signal "standard conditions" (use default value from config.ini)
getLandscapeMinimalBrightness() const156 	double getLandscapeMinimalBrightness() const {return static_cast<double>(minBrightness);}
157 
158 	//! Set an additional z-axis (azimuth) rotation after landscape has been loaded.
159 	//! This is intended for special uses such as when the landscape consists of
160 	//! a vehicle which might change orientation over time (e.g. a ship). It is called
161 	//! e.g. by the LandscapeMgr. Contrary to that, the purpose of the azimuth rotation
162 	//! (landscape/[decor_]angle_rotatez) in landscape.ini is to orient the pano.
163 	//! @param d the rotation angle in degrees.
setZRotation(float d)164 	void setZRotation(float d) {angleRotateZOffset = d * static_cast<float>(M_PI)/180.0f;}
165 
166 	//! Get whether the landscape is currently fully visible (i.e. opaque).
getIsFullyVisible() const167 	bool getIsFullyVisible() const {return landFader.getInterstate() >= 0.999f;}
168 	//! Get the sine of the limiting altitude (can be used to short-cut drawing below horizon, like star fields). There is no set here, value is only from landscape.ini
getSinMinAltitudeLimit() const169 	double getSinMinAltitudeLimit() const {return sinMinAltitudeLimit;}
170 
171 	//! Find opacity in a certain direction. (New in V0.13 series)
172 	//! can be used to find sunrise or visibility questions on the real-world landscape horizon.
173 	//! Default implementation indicates the horizon equals math horizon.
174 	// TBD: Maybe change this to azalt[2]<sinMinAltitudeLimit ? (But never called in practice, reimplemented by the subclasses...)
getOpacity(Vec3d azalt) const175 	virtual float getOpacity(Vec3d azalt) const { Q_ASSERT(0); return (azalt[2]<0 ? 1.0f : 0.0f); }
176 	//! The list of azimuths (counted from True North towards East) and altitudes can come in various formats. We read the first two elements, which can be of formats:
177 	enum horizonListMode {
178 		invalid        =-1,
179 		azDeg_altDeg   = 0, //! azimuth[degrees] altitude[degrees]
180 		azDeg_zdDeg    = 1, //! azimuth[degrees] zenithDistance[degrees]
181 		azRad_altRad   = 2, //! azimuth[radians] altitude[radians]
182 		azRad_zdRad    = 3, //! azimuth[radians] zenithDistance[radians]
183 		azGrad_altGrad = 4, //! azimuth[new_degrees] altitude[new_degrees] (may be found on theodolites)
184 		azGrad_zdGrad  = 5  //! azimuth[new_degrees] zenithDistance[new_degrees] (may be found on theodolites)
185 	};
186 
187 	//! Load descriptive labels from optional file gazetteer.LANG.utf8.
188 	void loadLabels(const QString& landscapeId);
hasLandscapePolygon() const189 	bool hasLandscapePolygon() const {return !horizonPolygon.isNull();}
190 
191 protected:
192 	//! Load attributes common to all landscapes
193 	//! @param landscapeIni A reference to an existing QSettings object which describes the landscape
194 	//! @param landscapeId The name of the directory for the landscape files (e.g. "ocean")
195 	void loadCommon(const QSettings& landscapeIni, const QString& landscapeId);
196 
197 	//! Draw optional labels on the landscape
198 	void drawLabels(StelCore *core, StelPainter *painter);
199 
200 
201 	//! Create a StelSphericalPolygon that describes a measured horizon line. If present, this can be used to draw a horizon line
202 	//! or simplify the functionality to discern if an object is below the horizon.
203 	//! @param lineFileName A text file with lines that are either empty or comment lines starting with # or azimuth altitude [degrees]
204 	//! @param polyAngleRotateZ possibility to set some final calibration offset like meridian convergence correction.
205 	//! @param listMode keys which indicate angular units for the angles
206 	void createPolygonalHorizon(const QString& lineFileName, const float polyAngleRotateZ=0.0f, const QString &listMode="azDeg_altDeg");
207 
208 	//! search for a texture in landscape directory, else global textures directory
209 	//! @param basename The name of a texture file, e.g. "fog.png"
210 	//! @param landscapeId The landscape ID (directory name) to which the texture belongs
211 	//! @note returns an empty string if file not found.
212 	static const QString getTexturePath(const QString& basename, const QString& landscapeId);
213 	double radius;
214 	QString name;          //! Read from landscape.ini:[landscape]name
215 	QString author;        //! Read from landscape.ini:[landscape]author
216 	QString description;   //! Read from landscape.ini:[landscape]description
217 	QString id;            //! Set during load. Required for consistent caching.
218 
219 	float minBrightness;   //! Read from landscape.ini:[landscape]minimal_brightness. Allows minimum visibility that cannot be underpowered.
220 	float landscapeBrightness;  //! brightness [0..1] to draw the landscape. Computed by the LandscapeMgr.
221 	float lightScapeBrightness; //! can be used to draw nightscape texture (e.g. city light pollution), if available. Computed by the LandscapeMgr.
222 	bool validLandscape;   //! was a landscape loaded properly?
223 	LinearFader landFader; //! Used to slowly fade in/out landscape painting.
224 	LinearFader fogFader;  //! Used to slowly fade in/out fog painting.
225 	LinearFader illumFader;//! Used to slowly fade in/out illumination painting.
226 	LinearFader labelFader;//! Used to slowly fade in/out landscape feature labels.
227 	unsigned int rows;     //! horizontal rows.  May be given in landscape.ini:[landscape]tesselate_rows. More indicates higher accuracy, but is slower.
228 	unsigned int cols;     //! vertical columns. May be given in landscape.ini:[landscape]tesselate_cols. More indicates higher accuracy, but is slower.
229 	float angleRotateZ;    //! [radians] if pano does not have its left border in the east, rotate in azimuth. Configured in landscape.ini[landscape]angle_rotatez (or decor_angle_rotatez for old_style landscapes)
230 	float angleRotateZOffset; //! [radians] This is a rotation changeable at runtime via setZRotation (called by LandscapeMgr::setZRotation).
231 				  //! Not in landscape.ini: Used in special cases where the horizon may rotate, e.g. on a ship.
232 
233 	double sinMinAltitudeLimit; //! Minimal altitude of landscape cover. Can be used to construct bounding caps, so that e.g. no stars are drawn below this altitude. Default -0.035, i.e. sin(-2 degrees).
234 
235 	StelLocation location; //! OPTIONAL. If present, can be used to set location.
236 	int defaultBortleIndex; //! May be given in landscape.ini:[location]light_pollution. Default: -1 (no change).
237 	int defaultFogSetting;  //! May be given in landscape.ini:[location]display_fog: -1(no change), 0(off), 1(on). Default: -1.
238 	double defaultExtinctionCoefficient; //! May be given in landscape.ini:[location]atmospheric_extinction_coefficient. Default -1 (no change).
239 	double defaultTemperature; //! [Celsius] May be given in landscape.ini:[location]atmospheric_temperature. default: -1000.0 (no change)
240 	double defaultPressure;    //! [mbar]    May be given in landscape.ini:[location]atmospheric_pressure. Default -1.0 (compute from [location]/altitude), use -2 to indicate "no change".
241 
242 	// Optional elements which, if present, describe a horizon polygon. They can be used to render a line or a filled region, esp. in LandscapePolygonal
243 	SphericalRegionP horizonPolygon;   //! Optional element describing the horizon line.
244 					   //! Data shall be read from the file given as landscape.ini[landscape]polygonal_horizon_list
245 					   //! For LandscapePolygonal, this is the only horizon data item.
246 	Vec3f horizonPolygonLineColor;     //! for all horizon types, the horizonPolygon line, if specified, will be drawn in this color
247 					   //! specified in landscape.ini[landscape]horizon_line_color. Negative red (default) indicated "don't draw".
248 	// Optional element: labels for landscape features.
249 	QList<LandscapeLabel> landscapeLabels;
250 	int fontSize;     //! Used for landscape labels (optionally indicating landscape features)
251 	Vec3f labelColor; //! Color for the landscape labels.
252 	unsigned int memorySize;   //!< holds an approximate value of memory consumption (for cache cost estimate)
253 };
254 
255 //! @class LandscapeOldStyle
256 //! This was the original landscape, introduced for decorative purposes. It segments the horizon in several tiles
257 //! (usually 4 or 8), therefore allowing very high resolution horizons also on limited hardware,
258 //! and closes the ground with a separate bottom piece. (You may want to configure a map with pointers to surrounding mountains or a compass rose instead!)
259 //! You can use panoramas created in equirectangular or cylindrical coordinates, for the latter case set
260 //! [landscape]tan_mode=true.
261 //! Until V0.10.5 there was an undetected bug involving vertical positioning. For historical reasons (many landscapes
262 //! were already configured and published), it was decided to keep this bug as feature, but a fix for new landscapes is
263 //! available: [landscape]calibrated=true.
264 //! As of 0.10.6, the fix is only valid for equirectangular panoramas.
265 //! As of V0.13, [landscape]calibrated=true and [landscape]tan_mode=true go together for cylindrical panoramas.
266 //! It is more involved to configure, but may still be preferred if you require the resolution, e.g. for alignment studies
267 //! for archaeoastronomy. In this case, don't forget to set calibrated=true in landscape.ini.
268 //! Since V0.13.1, also this landscape has a self-luminous (light pollution) option: Configure light<n> entries with textures overlaid the tex<n> textures. Only textures with light are necessary!
269 //! Can be easily made using layers with e.g. Photoshop or Gimp.
270 class LandscapeOldStyle : public Landscape
271 {
272 public:
273 	LandscapeOldStyle(float radius = 2.0f);
274 	virtual ~LandscapeOldStyle() Q_DECL_OVERRIDE;
275 	virtual void load(const QSettings& landscapeIni, const QString& landscapeId) Q_DECL_OVERRIDE;
276 	virtual void draw(StelCore* core, bool onlyPolygon) Q_DECL_OVERRIDE;
277 	//void create(bool _fullpath, QMap<QString, QString> param); // still not implemented
278 	virtual float getOpacity(Vec3d azalt) const Q_DECL_OVERRIDE;
279 protected:
280 	typedef struct
281 	{
282 		StelTextureSP tex;
283 		StelTextureSP tex_illum; // optional light texture.
284 		float texCoords[4];
285 	} landscapeTexCoord;
286 
287 private:
288 	void drawFog(StelCore* core, StelPainter&) const;
289 	// drawLight==true for illumination layer, it then selects only the self-illuminating panels.
290 	void drawDecor(StelCore* core, StelPainter&, const bool drawLight=false) const;
291 	void drawGround(StelCore* core, StelPainter&) const;
292 	QVector<Vec3d> groundVertexArr;
293 	QVector<Vec2f> groundTexCoordArr;
294 	StelTextureSP* sideTexs;
295 	unsigned short int nbSideTexs;
296 	unsigned short int nbSide;
297 	landscapeTexCoord* sides;
298 	StelTextureSP fogTex;
299 	StelTextureSP groundTex;
300 	QVector<QImage*> sidesImages; // Required for opacity lookup
301 	unsigned short int nbDecorRepeat;
302 	float fogAltAngle;
303 	float fogAngleShift;
304 	float decorAltAngle; // vertical extent of the side panels
305 	float decorAngleShift;
306 	float groundAngleShift; //! [radians]: altitude of the bottom plane. Usually negative and equal to decorAngleShift
307 	double groundAngleRotateZ; //! [radians]: rotation to bring top of texture away from due east.
308 	bool drawGroundFirst;
309 	bool tanMode;		// Whether the angles should be converted using tan instead of sin, i.e., for a cylindrical pano
310 	bool calibrated;	// if true, the documented altitudes are indeed correct (the original code is buggy!)
311 	struct LOSSide
312 	{
313 		StelVertexArray arr;
314 		StelTextureSP tex;
315 		bool light; // true if texture is self-lighting.
316 	};
317 
318 	QList<LOSSide> precomputedSides;
319 };
320 
321 /////////////////////////////////////////////////////////
322 ///
323 //! @class LandscapePolygonal
324 //! This uses the list of (usually measured) horizon altitudes to define the horizon.
325 //! Define it with the following names in landscape.ini:
326 //! @param landscape/ground_color use this color below horizon
327 //! @param landscape/polygonal_horizon_list filename containing azimuths/altitudes, compatible with Carte du Ciel.
328 //! @param landscape/polygonal_angle_rotatez offset for the polygonal measurement
329 //!        (different from landscape/angle_rotatez in photo panos, often photo and line are not aligned.)
330 class LandscapePolygonal : public Landscape
331 {
332 public:
333 	LandscapePolygonal(float radius = 1.f);
334 	virtual ~LandscapePolygonal() Q_DECL_OVERRIDE;
335 	virtual void load(const QSettings& landscapeIni, const QString& landscapeId) Q_DECL_OVERRIDE;
336 	virtual void draw(StelCore* core, bool onlyPolygon) Q_DECL_OVERRIDE;
337 	virtual float getOpacity(Vec3d azalt) const Q_DECL_OVERRIDE;
338 private:
339 	// we have inherited: horizonFileName, horizonPolygon, horizonPolygonLineColor
340 	Vec3f groundColor; //! specified in landscape.ini[landscape]ground_color.
341 };
342 
343 ///////////////////////////////////////////////////////////////
344 ///
345 //! @class LandscapeFisheye
346 //! This uses a single image in fisheye projection. The image is typically square, ...
347 //! @param texFov:  field of view (opening angle) of the square texture, radians.
348 //! If @param angleRotateZ==0, the top image border is due south.
349 class LandscapeFisheye : public Landscape
350 {
351 public:
352 	LandscapeFisheye(float radius = 1.f);
353 	virtual ~LandscapeFisheye() Q_DECL_OVERRIDE;
354 	virtual void load(const QSettings& landscapeIni, const QString& landscapeId) Q_DECL_OVERRIDE;
355 	virtual void draw(StelCore* core, bool onlyPolygon) Q_DECL_OVERRIDE;
356 	//! Sample landscape texture for transparency/opacity. May be used for visibility, sunrise etc.
357 	//! @param azalt normalized direction in alt-az frame
358 	virtual float getOpacity(Vec3d azalt) const Q_DECL_OVERRIDE;
359 	//! create a fisheye landscape from basic parameters (no ini file needed).
360 	//! @param name Landscape name
361 	//! @param maptex the fisheye texture
362 	//! @param maptexIllum the fisheye texture that is overlaid in the night (streetlights, skyglow, ...)
363 	//! @param texturefov field of view for the photo, degrees
364 	//! @param angleRotateZ azimuth rotation angle, degrees
365 	void create(const QString name, const QString& maptex, float texturefov, float angleRotateZ);
366 	void create(const QString name, float texturefov, const QString& maptex, const QString &_maptexFog="", const QString& _maptexIllum="", const float angleRotateZ=0.0f);
367 
368 private:
369 	StelTextureSP mapTex;      //!< The fisheye image, centered on the zenith.
370 	StelTextureSP mapTexFog;   //!< Optional panorama of identical size (create as layer over the mapTex image in your favorite image processor).
371 				   //!< can also be smaller, just the texture is again mapped onto the same geometry.
372 	StelTextureSP mapTexIllum; //!< Optional fisheye image of identical size (create as layer in your favorite image processor) or at least, proportions.
373 				   //!< To simulate light pollution (skyglow), street lights, light in windows, ... at night
374 	QImage *mapImage;          //!< The same image as mapTex, but stored in-mem for sampling.
375 
376 	float texFov;
377 };
378 
379 //////////////////////////////////////////////////////////////////////////
380 //! @class LandscapeSpherical
381 //! This uses a single panorama image in spherical (equirectangular) projection. A complete image is rectangular with the horizon forming a
382 //! horizontal line centered vertically, and vertical altitude angles linearly mapped in image height.
383 //! Since 0.13 and Qt5, large images of 8192x4096 pixels are available, but they still may not work on every hardware.
384 //! If @param angleRotateZ==0, the left/right image border is due east.
385 //! It is possible to remove empty top or bottom parts of the textures (main texture: only top part should meaningfully be cut away!)
386 //! The textures should still be power-of-two, so maybe 8192x1024 for the fog, or 8192x2048 for the light pollution.
387 //! (It's OK to stretch the textures. They just have to fit, geometrically!)
388 //! TODO: Allow a horizontal split for 2 or even 4 parts, i.e. super-large, super-accurate panos.
389 class LandscapeSpherical : public Landscape
390 {
391 public:
392 	LandscapeSpherical(float radius = 1.f);
393 	virtual ~LandscapeSpherical() Q_DECL_OVERRIDE;
394 	virtual void load(const QSettings& landscapeIni, const QString& landscapeId) Q_DECL_OVERRIDE;
395 	virtual void draw(StelCore* core, bool onlyPolygon) Q_DECL_OVERRIDE;
396 	//! Sample landscape texture for transparency/opacity. May be used for visibility, sunrise etc.
397 	//! @param azalt normalized direction in alt-az frame
398 	//! @retval alpha (0=fully transparent, 1=fully opaque. Trees, leaves, glass etc may have intermediate values.)
399 	virtual float getOpacity(Vec3d azalt) const Q_DECL_OVERRIDE;
400 	//! create a spherical landscape from basic parameters (no ini file needed).
401 	//! @param name Landscape name
402 	//! @param maptex the equirectangular texture
403 	//! @param maptexIllum the equirectangular texture that is overlaid in the night (streetlights, skyglow, ...)
404 	//! @param angleRotateZ azimuth rotation angle, degrees [0]
405 	//! @param _mapTexTop altitude angle of top edge of texture, degrees [90]
406 	//! @param _mapTexBottom altitude angle of bottom edge of texture, degrees [-90]
407 	//! @param _fogTexTop altitude angle of top edge of fog texture, degrees [90]
408 	//! @param _fogTexBottom altitude angle of bottom edge of fog texture, degrees [-90]
409 	//! @param _illumTexTop altitude angle of top edge of light pollution texture, degrees [90]
410 	//! @param _illumTexBottom altitude angle of bottom edge of light pollution texture, degrees [-90]
411 	//! @param _bottomCapColor RGB triplet for closing the hole around the nadir, if any. A color value of (-1/0/0) signals "no cap"
412 	void create(const QString name, const QString& maptex, const QString &_maptexFog="", const QString& _maptexIllum="", const float _angleRotateZ=0.0f,
413 				const float _mapTexTop=90.0f, const float _mapTexBottom=-90.0f,
414 				const float _fogTexTop=90.0f, const float _fogTexBottom=-90.0f,
415 				const float _illumTexTop=90.0f, const float _illumTexBottom=-90.0f, const Vec3f _bottomCapColor=Vec3f(-1.0f, 0.0f, 0.0f));
416 
417 private:
418 	StelTextureSP mapTex;      //!< The equirectangular panorama texture
419 	StelTextureSP mapTexFog;   //!< Optional panorama of identical size (create as layer over the mapTex image in your favorite image processor).
420 				   //!< can also be smaller, just the texture is again mapped onto the same geometry.
421 	StelTextureSP mapTexIllum; //!< Optional panorama of identical size (create as layer over the mapTex image in your favorite image processor).
422 				   //!< To simulate light pollution (skyglow), street lights, light in windows, ... at night
423 	SphericalCap bottomCap;	   //!< Geometry to close the bottom with a monochrome color when mapTexBottom is given. (Avoid hole in Nadir!)
424 	// These vars are here to conserve texture memory. They must be allowed to be different: a landscape may have its highest elevations at 15°, fog may reach from -25 to +15°,
425 	// light pollution may cover -5° (street lamps slightly below) plus parts of or even the whole sky. All have default values to simplify life.
426 	float mapTexTop;           //!< zenithal top angle of the landscape texture, radians
427 	float mapTexBottom;	   //!< zenithal bottom angle of the landscape texture, radians
428 	float fogTexTop;	   //!< zenithal top angle of the fog texture, radians
429 	float fogTexBottom;	   //!< zenithal bottom angle of the fog texture, radians
430 	float illumTexTop;	   //!< zenithal top angle of the illumination texture, radians
431 	float illumTexBottom;	   //!< zenithal bottom angle of the illumination texture, radians
432 	QImage *mapImage;          //!< The same image as mapTex, but stored in-mem for opacity sampling.
433 	Vec3f bottomCapColor;      //!< The bottomCap, if specified, will be drawn in this color
434 };
435 
436 #endif // LANDSCAPE_HPP
437