Merge lp:~xalioth/stellarium/planet-shadows into lp:stellarium

Proposed by Fabien Chéreau
Status: Merged
Merged at revision: 6810
Proposed branch: lp:~xalioth/stellarium/planet-shadows
Merge into: lp:stellarium
Diff against target: 1688 lines (+752/-533)
11 files modified
src/core/StelPainter.cpp (+21/-274)
src/core/StelPainter.hpp (+0/-41)
src/core/StelTexture.cpp (+2/-2)
src/core/StelTexture.hpp (+1/-1)
src/core/StelUtils.cpp (+100/-0)
src/core/StelUtils.hpp (+22/-0)
src/core/modules/Comet.cpp (+0/-5)
src/core/modules/Planet.cpp (+560/-191)
src/core/modules/Planet.hpp (+38/-18)
src/core/modules/SolarSystem.cpp (+6/-1)
src/core/modules/SolarSystem.hpp (+2/-0)
To merge this branch: bzr merge lp:~xalioth/stellarium/planet-shadows
Reviewer Review Type Date Requested Status
Alexander Wolf Needs Fixing
Review via email: mp+221967@code.launchpad.net

Description of the change

Re-integrated Jörg's work on planet shadow rendering

To post a comment you must log in.
Revision history for this message
Alexander Wolf (alexwolf) wrote :

This code give strange effect on the Sun in the moment of solar eclipse.

review: Needs Fixing
6814. By Fabien Chéreau

Don't draw planet when standing on it, even for planet with rings.

6815. By Fabien Chéreau

Fixed sun rendering.

6816. By Fabien Chéreau

Use new moon eclipse rendering. Got rid of old stencil based code.

Revision history for this message
Fabien Chéreau (xalioth) wrote :

Thanks. I fixed this issue. I also improved moon eclipse rendering.

On Wed, Jun 4, 2014 at 7:20 PM, Alexander Wolf <email address hidden>
wrote:

> Review: Needs Fixing
>
> This code give strange effect on the Sun in the moment of solar eclipse.
> --
> https://code.launchpad.net/~xalioth/stellarium/planet-shadows/+merge/221967
> You are the owner of lp:~xalioth/stellarium/planet-shadows.
>

6817. By Fabien Chéreau

First shader cleanup.

More can probably be done by replacing some trigo with simpler
vector operations.

6818. By Fabien Chéreau

Simplified further shader.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/core/StelPainter.cpp'
2--- src/core/StelPainter.cpp 2014-05-23 22:05:02 +0000
3+++ src/core/StelPainter.cpp 2014-06-04 22:13:44 +0000
4@@ -226,94 +226,7 @@
5 enableClientStates(false);
6 }
7
8-// Arrays to keep cos/sin of angles and multiples of angles. rho and theta are delta angles, and these arrays
9-#define MAX_STACKS 4096
10-static float cos_sin_rho[2*(MAX_STACKS+1)];
11-#define MAX_SLICES 4096
12-static float cos_sin_theta[2*(MAX_SLICES+1)];
13-
14-//! Compute cosines and sines around a circle which is split in "segments" parts.
15-//! Values are stored in the global static array cos_sin_theta.
16-//! Used for the sin/cos values along a latitude circle, equator, etc. for a spherical mesh.
17-//! @param dTheta a difference angle between the stops. Always use 2*M_PI/segments!
18-//! @param segments number of partitions (elsewhere called "slices") for the circle
19-static void ComputeCosSinTheta(const float dTheta, const int segments)
20-{
21- float *cos_sin = cos_sin_theta;
22- float *cos_sin_rev = cos_sin + 2*(segments+1);
23- const float c = std::cos(dTheta);
24- const float s = std::sin(dTheta);
25- *cos_sin++ = 1.f;
26- *cos_sin++ = 0.f;
27- *--cos_sin_rev = -cos_sin[-1];
28- *--cos_sin_rev = cos_sin[-2];
29- *cos_sin++ = c;
30- *cos_sin++ = s;
31- *--cos_sin_rev = -cos_sin[-1];
32- *--cos_sin_rev = cos_sin[-2];
33- while (cos_sin < cos_sin_rev) // compares array address indices only!
34- {
35- // avoid expensive trig functions by use of the addition theorem.
36- cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
37- cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
38- cos_sin += 2;
39- *--cos_sin_rev = -cos_sin[-1];
40- *--cos_sin_rev = cos_sin[-2];
41- }
42-}
43-
44-//! Compute cosines and sines around a half-circle which is split in "segments" parts.
45-//! Values are stored in the global static array cos_sin_rho.
46-//! Used for the sin/cos values along a meridian for a spherical mesh.
47-//! @param dRho a difference angle between the stops. Always use M_PI/segments!
48-//! @param segments number of partitions (elsewhere called "stacks") for the half-circle
49-static void ComputeCosSinRho(const float dRho, const int segments)
50-{
51- float *cos_sin = cos_sin_rho;
52- float *cos_sin_rev = cos_sin + 2*(segments+1);
53- const float c = std::cos(dRho);
54- const float s = std::sin(dRho);
55- *cos_sin++ = 1.f;
56- *cos_sin++ = 0.f;
57- *--cos_sin_rev = cos_sin[-1];
58- *--cos_sin_rev = -cos_sin[-2];
59- *cos_sin++ = c;
60- *cos_sin++ = s;
61- *--cos_sin_rev = cos_sin[-1];
62- *--cos_sin_rev = -cos_sin[-2];
63- while (cos_sin < cos_sin_rev) // compares array address indices only!
64- {
65- // avoid expensive trig functions by use of the addition theorem.
66- cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
67- cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
68- cos_sin += 2;
69- *--cos_sin_rev = cos_sin[-1];
70- *--cos_sin_rev = -cos_sin[-2];
71- // segments--; // GZ: WHAT'S THAT GOOD FOR?
72- }
73-}
74-
75-//! Compute cosines and sines around part of a circle (from top to bottom) which is split in "segments" parts.
76-//! Values are stored in the global static array cos_sin_rho.
77-//! Used for the sin/cos values along a meridian.
78-//! GZ: allow leaving away pole caps. The array now contains values for the region minAngle+segments*phi
79-//! @param dRho a difference angle between the stops
80-//! @param segments number of segments
81-//! @param minAngle start angle inside the half-circle. maxAngle=minAngle+segments*phi
82-static void ComputeCosSinRhoZone(const float dRho, const int segments, const float minAngle)
83-{
84- float *cos_sin = cos_sin_rho;
85- const float c = cos(dRho);
86- const float s = sin(dRho);
87- *cos_sin++ = cos(minAngle);
88- *cos_sin++ = sin(minAngle);
89- for (int i=0; i<segments; ++i) // we cannot mirror this, it may be unequal.
90- { // efficient computation, avoid expensive trig functions by use of the addition theorem.
91- cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
92- cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
93- cos_sin += 2;
94- }
95-}
96+
97
98 void StelPainter::computeFanDisk(float radius, int innerFanSlices, int level, QVector<double>& vertexArr, QVector<float>& texCoordArr)
99 {
100@@ -326,9 +239,8 @@
101 rad[i] = rad[i+1]*(1.f-M_PI/(innerFanSlices<<(i+1)))*2.f/3.f;
102 }
103 int slices = innerFanSlices<<level;
104- const float dtheta = 2.f * M_PI / slices;
105- Q_ASSERT(slices<=MAX_SLICES);
106- ComputeCosSinTheta(dtheta,slices);
107+
108+ float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
109 float* cos_sin_theta_p;
110 int slices_step = 2;
111 float x,y,xa,ya;
112@@ -419,83 +331,6 @@
113
114 }
115
116-void StelPainter::sRing(const float rMin, const float rMax, int slices, const int stacks, const int orientInside)
117-{
118- float x,y;
119- int j;
120-
121- static Vec3f lightPos3;
122- static Vec4f ambientLight;
123- static Vec4f diffuseLight;
124- float c;
125- const bool isLightOn = light.isEnabled();
126- if (isLightOn)
127- {
128- lightPos3.set(light.getPosition()[0], light.getPosition()[1], light.getPosition()[2]);
129- Vec3f tmpv(0.f);
130- prj->getModelViewTransform()->forward(tmpv); // -posCenterEye
131- //lightPos3 -= tmpv;
132- //lightPos3 = prj->modelViewMatrixf.transpose().multiplyWithoutTranslation(lightPos3);
133- prj->getModelViewTransform()->getApproximateLinearTransfo().transpose().multiplyWithoutTranslation(Vec3d(lightPos3[0], lightPos3[1], lightPos3[2]));
134- prj->getModelViewTransform()->backward(lightPos3);
135- lightPos3.normalize();
136- ambientLight = light.getAmbient();
137- diffuseLight = light.getDiffuse();
138- }
139-
140- const float nsign = orientInside?-1.f:1.f;
141-
142- const float dr = (rMax-rMin) / stacks;
143- const float dtheta = 2.f * M_PI / slices;
144- if (slices < 0) slices = -slices;
145- Q_ASSERT(slices<=MAX_SLICES);
146- ComputeCosSinTheta(dtheta,slices);
147- float *cos_sin_theta_p;
148-
149- static QVector<double> vertexArr;
150- static QVector<float> texCoordArr;
151- static QVector<float> colorArr;
152-
153- // draw intermediate stacks as quad strips
154- for (float r = rMin; r < rMax; r+=dr)
155- {
156- const float tex_r0 = (r-rMin)/(rMax-rMin);
157- const float tex_r1 = (r+dr-rMin)/(rMax-rMin);
158- vertexArr.resize(0);
159- texCoordArr.resize(0);
160- colorArr.resize(0);
161- for (j=0,cos_sin_theta_p=cos_sin_theta; j<=slices; ++j,cos_sin_theta_p+=2)
162- {
163- x = r*cos_sin_theta_p[0];
164- y = r*cos_sin_theta_p[1];
165- if (isLightOn)
166- {
167- c = nsign * (lightPos3[0]*x + lightPos3[1]*y);
168- if (c<0) {c=0;}
169- colorArr << c*diffuseLight[0] + ambientLight[0] << c*diffuseLight[1] + ambientLight[1] << c*diffuseLight[2] + ambientLight[2];
170- }
171- texCoordArr << tex_r0 << 0.5f;
172- vertexArr << x << y << 0.f;
173- x = (r+dr)*cos_sin_theta_p[0];
174- y = (r+dr)*cos_sin_theta_p[1];
175- if (isLightOn)
176- {
177- c = nsign * (lightPos3[0]*x + lightPos3[1]*y);
178- if (c<0) {c=0;}
179- colorArr << c*diffuseLight[0] + ambientLight[0] << c*diffuseLight[1] + ambientLight[1] << c*diffuseLight[2] + ambientLight[2];
180- }
181- texCoordArr << tex_r1 << 0.5f;
182- vertexArr << x << y << 0.f;
183- }
184-
185- if (isLightOn)
186- setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData(), (Vec3f*)colorArr.constData());
187- else
188- setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData());
189- drawFromArray(TriangleStrip, vertexArr.size()/3);
190- }
191-}
192-
193 static void sSphereMapTexCoordFast(float rho_div_fov, const float costheta, const float sintheta, QVector<float>& out)
194 {
195 if (rho_div_fov>0.5f)
196@@ -507,17 +342,13 @@
197 {
198 float rho,x,y,z;
199 int i, j;
200+ const float* cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
201+ const float* cos_sin_rho_p;
202+
203+ const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
204+ const float* cos_sin_theta_p;
205+
206 float drho = M_PI / stacks;
207- Q_ASSERT(stacks<=MAX_STACKS);
208- ComputeCosSinRho(drho,stacks);
209- float* cos_sin_rho_p;
210-
211- const float dtheta = 2.f * M_PI / slices;
212- Q_ASSERT(slices<=MAX_SLICES);
213-
214- ComputeCosSinTheta(dtheta,slices);
215- float* cos_sin_theta_p;
216-
217 drho/=textureFov;
218
219 // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis
220@@ -1546,28 +1377,6 @@
221 // GZ This used to draw a full sphere. Now it's possible to have a spherical zone only.
222 void StelPainter::sSphere(const float radius, const float oneMinusOblateness, const int slices, const int stacks, const int orientInside, const bool flipTexture, const float topAngle, const float bottomAngle)
223 {
224- // It is really good for performance to have Vec4f,Vec3f objects
225- // static rather than on the stack. But why?
226- // Is the constructor/destructor so expensive?
227- static Vec3f lightPos3;
228- static Vec4f ambientLight;
229- static Vec4f diffuseLight;
230- float c;
231- const bool isLightOn = light.isEnabled();
232- if (isLightOn)
233- {
234- lightPos3.set(light.getPosition()[0], light.getPosition()[1], light.getPosition()[2]);
235- Vec3f tmpv(0.f);
236- prj->getModelViewTransform()->forward(tmpv); // -posCenterEye
237- //lightPos3 -= tmpv;
238- //lightPos3 = prj->modelViewMatrixf.transpose().multiplyWithoutTranslation(lightPos3);
239- prj->getModelViewTransform()->getApproximateLinearTransfo().transpose().multiplyWithoutTranslation(Vec3d(lightPos3[0], lightPos3[1], lightPos3[2]));
240- prj->getModelViewTransform()->backward(lightPos3);
241- lightPos3.normalize();
242- ambientLight = light.getAmbient();
243- diffuseLight = light.getDiffuse();
244- }
245-
246 GLfloat x, y, z;
247 GLfloat s=0.f, t=0.f;
248 GLint i, j;
249@@ -1584,20 +1393,19 @@
250 t=1.f;
251 }
252
253+ const float* cos_sin_rho = NULL;
254 Q_ASSERT(topAngle<bottomAngle); // don't forget: These are opening angles counted from top.
255- const float drho = (bottomAngle-topAngle) / stacks; // deltaRho: originally just 180degrees/stacks, now the range clamped.
256- Q_ASSERT(stacks<=MAX_STACKS);
257- //if ((bottomAngle==M_PI) && (topAngle==0))
258 if ((bottomAngle>3.1415) && (topAngle<0.0001)) // safety margin.
259- ComputeCosSinRho(drho, stacks);
260+ cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
261 else
262- ComputeCosSinRhoZone(drho, stacks, M_PI-bottomAngle);
263+ {
264+ const float drho = (bottomAngle-topAngle) / stacks; // deltaRho: originally just 180degrees/stacks, now the range clamped.
265+ cos_sin_rho = StelUtils::ComputeCosSinRhoZone(drho, stacks, M_PI-bottomAngle);
266+ }
267 // GZ: Allow parameters so that pole regions may remain free.
268- float* cos_sin_rho_p;
269+ const float* cos_sin_rho_p;
270
271- const float dtheta = 2.f * M_PI / slices;
272- Q_ASSERT(slices<=MAX_SLICES);
273- ComputeCosSinTheta(dtheta,slices);
274+ const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
275 const float *cos_sin_theta_p;
276
277 // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis
278@@ -1627,23 +1435,11 @@
279 y = cos_sin_theta_p[0] * cos_sin_rho_p[1];
280 z = nsign * cos_sin_rho_p[0];
281 texCoordArr << s << t;
282- if (isLightOn)
283- {
284- c = nsign * (lightPos3[0]*x*oneMinusOblateness + lightPos3[1]*y*oneMinusOblateness + lightPos3[2]*z);
285- if (c<0) {c=0;}
286- colorArr << c*diffuseLight[0] + ambientLight[0] << c*diffuseLight[1] + ambientLight[1] << c*diffuseLight[2] + ambientLight[2];
287- }
288 vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius;
289 x = -cos_sin_theta_p[1] * cos_sin_rho_p[3];
290 y = cos_sin_theta_p[0] * cos_sin_rho_p[3];
291 z = nsign * cos_sin_rho_p[2];
292 texCoordArr << s << t - dt;
293- if (isLightOn)
294- {
295- c = nsign * (lightPos3[0]*x*oneMinusOblateness + lightPos3[1]*y*oneMinusOblateness + lightPos3[2]*z);
296- if (c<0) {c=0;}
297- colorArr << c*diffuseLight[0] + ambientLight[0] << c*diffuseLight[1] + ambientLight[1] << c*diffuseLight[2] + ambientLight[2];
298- }
299 vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius;
300 s += ds;
301 }
302@@ -1657,10 +1453,7 @@
303 }
304
305 // Draw the array now
306- if (isLightOn)
307- setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData(), (Vec3f*)colorArr.constData());
308- else
309- setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData());
310+ setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData());
311 drawFromArray(Triangles, indiceArr.size(), 0, true, indiceArr.constData());
312 }
313
314@@ -1682,14 +1475,10 @@
315 t=1.f;
316 }
317
318- const float drho = M_PI / stacks;
319- Q_ASSERT(stacks<=MAX_STACKS);
320- ComputeCosSinRho(drho,stacks);
321- float* cos_sin_rho_p;
322+ const float* cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
323+ const float* cos_sin_rho_p;
324
325- const float dtheta = 2.f * M_PI / slices;
326- Q_ASSERT(slices<=MAX_SLICES);
327- ComputeCosSinTheta(dtheta,slices);
328+ const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
329 const float *cos_sin_theta_p;
330
331 // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis
332@@ -1726,8 +1515,6 @@
333 t -= dt;
334 }
335 return result;
336- //setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData());
337- //drawFromArray(Triangles, indiceArr.size(), 0, true, indiceArr.constData());
338 }
339
340 // Reimplementation of gluCylinder : glu is overrided for non standard projection
341@@ -2018,7 +1805,6 @@
342 else
343 {
344 qDebug() << "Unhandled parameters." << texCoordArray.enabled << colorArray.enabled << normalArray.enabled;
345- qDebug() << "Light: " << light.isEnabled();
346 Q_ASSERT(0);
347 return;
348 }
349@@ -2092,42 +1878,3 @@
350 return ret;
351 }
352
353-// Light methods
354-
355-void StelPainterLight::setPosition(const Vec4f& v)
356-{
357- position = v;
358-}
359-
360-void StelPainterLight::setDiffuse(const Vec4f& v)
361-{
362- diffuse = v;
363-}
364-
365-void StelPainterLight::setSpecular(const Vec4f& v)
366-{
367- specular = v;
368-}
369-
370-void StelPainterLight::setAmbient(const Vec4f& v)
371-{
372- ambient = v;
373-}
374-
375-void StelPainterLight::setEnable(bool v)
376-{
377- if (v)
378- enable();
379- else
380- disable();
381-}
382-
383-void StelPainterLight::enable()
384-{
385- enabled = true;
386-}
387-
388-void StelPainterLight::disable()
389-{
390- enabled = false;
391-}
392
393=== modified file 'src/core/StelPainter.hpp'
394--- src/core/StelPainter.hpp 2014-05-23 22:05:02 +0000
395+++ src/core/StelPainter.hpp 2014-06-04 22:13:44 +0000
396@@ -30,38 +30,6 @@
397
398 class QOpenGLShaderProgram;
399
400-class StelPainterLight
401-{
402-public:
403- StelPainterLight(int alight=0) : light(alight), enabled(false) {}
404-
405- void setPosition(const Vec4f& v);
406- Vec4f& getPosition() {return position;}
407-
408- void setDiffuse(const Vec4f& v);
409- Vec4f& getDiffuse() {return diffuse;}
410-
411- void setSpecular(const Vec4f& v);
412- Vec4f& getSpecular() {return specular;}
413-
414- void setAmbient(const Vec4f& v);
415- Vec4f& getAmbient() {return ambient;}
416-
417- void setEnable(bool v);
418- void enable();
419- void disable();
420- bool isEnabled() const {return enabled;}
421-
422-private:
423- int light;
424- Vec4f position;
425- Vec4f diffuse;
426- Vec4f specular;
427- Vec4f ambient;
428- bool enabled;
429-};
430-
431-
432 //! @class StelPainter
433 //! Provides functions for performing openGL drawing operations.
434 //! All coordinates are converted using the StelProjector instance passed at construction.
435@@ -225,9 +193,6 @@
436 //! @param texCoordArr the vertex array in which the resulting texture coordinates are returned.
437 static void computeFanDisk(float radius, int innerFanSlices, int level, QVector<double>& vertexArr, QVector<float>& texCoordArr);
438
439- //! Draw a ring with a radial texturing.
440- void sRing(const float rMin, const float rMax, int slices, const int stacks, const int orientInside);
441-
442 //! Draw a fisheye texture in a sphere.
443 void sSphereMap(const float radius, const int slices, const int stacks, const float textureFov = 2.f*M_PI, const int orientInside = 0);
444
445@@ -240,9 +205,6 @@
446 //! Get the color currently used for drawing.
447 Vec4f getColor() const;
448
449- //! Get the light
450- StelPainterLight& getLight() {return light;}
451-
452 //! Get the font metrics for the current font.
453 QFontMetrics getFontMetrics() const;
454
455@@ -404,9 +366,6 @@
456 ArrayDesc normalArray;
457 //! The descriptor for the current opengl color array
458 ArrayDesc colorArray;
459-
460- //! the single light used by the painter
461- StelPainterLight light;
462 };
463
464 #endif // _STELPAINTER_HPP_
465
466=== modified file 'src/core/StelTexture.cpp'
467--- src/core/StelTexture.cpp 2014-05-23 22:05:02 +0000
468+++ src/core/StelTexture.cpp 2014-06-04 22:13:44 +0000
469@@ -108,12 +108,12 @@
470 Bind the texture so that it can be used for openGL drawing (calls glBindTexture)
471 *************************************************************************/
472
473-bool StelTexture::bind()
474+bool StelTexture::bind(int slot)
475 {
476 if (id != 0)
477 {
478 // The texture is already fully loaded, just bind and return true;
479- glActiveTexture(GL_TEXTURE0);
480+ glActiveTexture(GL_TEXTURE0 + slot);
481 glBindTexture(GL_TEXTURE_2D, id);
482 return true;
483 }
484
485=== modified file 'src/core/StelTexture.hpp'
486--- src/core/StelTexture.hpp 2014-05-23 22:05:02 +0000
487+++ src/core/StelTexture.hpp 2014-06-04 22:13:44 +0000
488@@ -65,7 +65,7 @@
489 //! If the texture is lazyly loaded, this starts the loading and return false immediately.
490 //! @return true if the binding successfully occured, false if the texture is not yet loaded.
491
492- bool bind();
493+ bool bind(int slot=0);
494
495 //! Return whether the texture can be binded, i.e. it is fully loaded
496 bool canBind() const {return id!=0;}
497
498=== modified file 'src/core/StelUtils.cpp'
499--- src/core/StelUtils.cpp 2014-05-23 22:05:02 +0000
500+++ src/core/StelUtils.cpp 2014-06-04 22:13:44 +0000
501@@ -1780,5 +1780,105 @@
502 return sigma;
503 }
504
505+
506+// Arrays to keep cos/sin of angles and multiples of angles. rho and theta are delta angles, and these arrays
507+#define MAX_STACKS 4096
508+static float cos_sin_rho[2*(MAX_STACKS+1)];
509+#define MAX_SLICES 4096
510+static float cos_sin_theta[2*(MAX_SLICES+1)];
511+
512+//! Compute cosines and sines around a circle which is split in "segments" parts.
513+//! Values are stored in the global static array cos_sin_theta.
514+//! Used for the sin/cos values along a latitude circle, equator, etc. for a spherical mesh.
515+//! @param slices number of partitions (elsewhere called "segments") for the circle
516+float* ComputeCosSinTheta(const int slices)
517+{
518+ Q_ASSERT(slices<=MAX_SLICES);
519+
520+ // Difference angle between the stops. Always use 2*M_PI/slices!
521+ const float dTheta = 2.f * M_PI / slices;
522+ float *cos_sin = cos_sin_theta;
523+ float *cos_sin_rev = cos_sin + 2*(slices+1);
524+ const float c = std::cos(dTheta);
525+ const float s = std::sin(dTheta);
526+ *cos_sin++ = 1.f;
527+ *cos_sin++ = 0.f;
528+ *--cos_sin_rev = -cos_sin[-1];
529+ *--cos_sin_rev = cos_sin[-2];
530+ *cos_sin++ = c;
531+ *cos_sin++ = s;
532+ *--cos_sin_rev = -cos_sin[-1];
533+ *--cos_sin_rev = cos_sin[-2];
534+ while (cos_sin < cos_sin_rev) // compares array address indices only!
535+ {
536+ // avoid expensive trig functions by use of the addition theorem.
537+ cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
538+ cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
539+ cos_sin += 2;
540+ *--cos_sin_rev = -cos_sin[-1];
541+ *--cos_sin_rev = cos_sin[-2];
542+ }
543+ return cos_sin_theta;
544+}
545+
546+//! Compute cosines and sines around a half-circle which is split in "segments" parts.
547+//! Values are stored in the global static array cos_sin_rho.
548+//! Used for the sin/cos values along a meridian for a spherical mesh.
549+//! @param segments number of partitions (elsewhere called "stacks") for the half-circle
550+float* ComputeCosSinRho(const int segments)
551+{
552+ Q_ASSERT(segments<=MAX_STACKS);
553+
554+ // Difference angle between the stops. Always use M_PI/segments!
555+ const float dRho = M_PI / segments;
556+ float *cos_sin = cos_sin_rho;
557+ float *cos_sin_rev = cos_sin + 2*(segments+1);
558+ const float c = std::cos(dRho);
559+ const float s = std::sin(dRho);
560+ *cos_sin++ = 1.f;
561+ *cos_sin++ = 0.f;
562+ *--cos_sin_rev = cos_sin[-1];
563+ *--cos_sin_rev = -cos_sin[-2];
564+ *cos_sin++ = c;
565+ *cos_sin++ = s;
566+ *--cos_sin_rev = cos_sin[-1];
567+ *--cos_sin_rev = -cos_sin[-2];
568+ while (cos_sin < cos_sin_rev) // compares array address indices only!
569+ {
570+ // avoid expensive trig functions by use of the addition theorem.
571+ cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
572+ cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
573+ cos_sin += 2;
574+ *--cos_sin_rev = cos_sin[-1];
575+ *--cos_sin_rev = -cos_sin[-2];
576+ }
577+
578+ return cos_sin_rho;
579+}
580+
581+//! Compute cosines and sines around part of a circle (from top to bottom) which is split in "segments" parts.
582+//! Values are stored in the global static array cos_sin_rho.
583+//! Used for the sin/cos values along a meridian.
584+//! GZ: allow leaving away pole caps. The array now contains values for the region minAngle+segments*phi
585+//! @param dRho a difference angle between the stops
586+//! @param segments number of segments
587+//! @param minAngle start angle inside the half-circle. maxAngle=minAngle+segments*phi
588+float *ComputeCosSinRhoZone(const float dRho, const int segments, const float minAngle)
589+{
590+ float *cos_sin = cos_sin_rho;
591+ const float c = cos(dRho);
592+ const float s = sin(dRho);
593+ *cos_sin++ = cos(minAngle);
594+ *cos_sin++ = sin(minAngle);
595+ for (int i=0; i<segments; ++i) // we cannot mirror this, it may be unequal.
596+ { // efficient computation, avoid expensive trig functions by use of the addition theorem.
597+ cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
598+ cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
599+ cos_sin += 2;
600+ }
601+ return cos_sin_rho;
602+}
603+
604+
605 } // end of the StelUtils namespace
606
607
608=== modified file 'src/core/StelUtils.hpp'
609--- src/core/StelUtils.hpp 2014-05-23 22:05:02 +0000
610+++ src/core/StelUtils.hpp 2014-06-04 22:13:44 +0000
611@@ -36,6 +36,7 @@
612 // speed of light (km/sec)
613 #define SPEED_OF_LIGHT 299792.458
614
615+
616 //! @namespace StelUtils contains general purpose utility functions.
617 namespace StelUtils
618 {
619@@ -570,6 +571,27 @@
620 template <typename T> int sign(T val) {
621 return (T(0) < val) - (val < T(0));
622 }
623+
624+ //! Compute cosines and sines around a circle which is split in "segments" parts.
625+ //! Values are stored in the global static array cos_sin_theta.
626+ //! Used for the sin/cos values along a latitude circle, equator, etc. for a spherical mesh.
627+ //! @param slices number of partitions (elsewhere called "segments") for the circle
628+ float *ComputeCosSinTheta(const int slices);
629+
630+ //! Compute cosines and sines around a half-circle which is split in "segments" parts.
631+ //! Values are stored in the global static array cos_sin_rho.
632+ //! Used for the sin/cos values along a meridian for a spherical mesh.
633+ //! @param segments number of partitions (elsewhere called "stacks") for the half-circle
634+ float *ComputeCosSinRho(const int segments);
635+
636+ //! Compute cosines and sines around part of a circle (from top to bottom) which is split in "segments" parts.
637+ //! Values are stored in the global static array cos_sin_rho.
638+ //! Used for the sin/cos values along a meridian.
639+ //! GZ: allow leaving away pole caps. The array now contains values for the region minAngle+segments*phi
640+ //! @param dRho a difference angle between the stops
641+ //! @param segments number of segments
642+ //! @param minAngle start angle inside the half-circle. maxAngle=minAngle+segments*phi
643+ float* ComputeCosSinRhoZone(const float dRho, const int segments, const float minAngle);
644 }
645
646 #endif // _STELUTILS_HPP_
647
648=== modified file 'src/core/modules/Comet.cpp'
649--- src/core/modules/Comet.cpp 2014-04-14 15:40:40 +0000
650+++ src/core/modules/Comet.cpp 2014-06-04 22:13:44 +0000
651@@ -368,7 +368,6 @@
652
653 void Comet::drawTail(StelCore* core, StelProjector::ModelViewTranformP transfo, bool gas)
654 {
655-
656 // Find rotation matrix from 0/0/1 to eclipticPosition: crossproduct for axis (normal vector), dotproduct for angle.
657 Vec3d eclposNrm=eclipticPos; eclposNrm.normalize();
658 Mat4d tailrot=Mat4d::rotation(Vec3d(0.0, 0.0, 1.0)^(eclposNrm), std::acos(Vec3d(0.0, 0.0, 1.0).dot(eclposNrm)) );
659@@ -388,7 +387,6 @@
660 transfo2->combine(dustTailYrot);
661 }
662 StelPainter* sPainter = new StelPainter(core->getProjection(transfo2));
663- sPainter->getLight().disable();
664 glEnable(GL_BLEND);
665 glBlendFunc(GL_ONE, GL_ONE);
666 glDisable(GL_CULL_FACE);
667@@ -439,14 +437,12 @@
668
669 void Comet::drawComa(StelCore* core, StelProjector::ModelViewTranformP transfo)
670 {
671-
672 // Find rotation matrix from 0/0/1 to viewdirection! crossproduct for axis (normal vector), dotproduct for angle.
673 Vec3d eclposNrm=eclipticPos - core->getObserverHeliocentricEclipticPos() ; eclposNrm.normalize();
674 Mat4d comarot=Mat4d::rotation(Vec3d(0.0, 0.0, 1.0)^(eclposNrm), std::acos(Vec3d(0.0, 0.0, 1.0).dot(eclposNrm)) );
675 StelProjector::ModelViewTranformP transfo2 = transfo->clone();
676 transfo2->combine(comarot);
677 StelPainter* sPainter = new StelPainter(core->getProjection(transfo2));
678- sPainter->getLight().disable();
679
680 glEnable(GL_BLEND);
681 glBlendFunc(GL_ONE, GL_ONE);
682@@ -460,7 +456,6 @@
683 float magFactor=std::pow(0.6f , magDrop);
684 magFactor=qMin(magFactor, 2.0f); // Limit excessively bright display.
685
686-
687 comaTexture->bind();
688 sPainter->setColor(magFactor,magFactor,0.6f*magFactor);
689 sPainter->setArrays((Vec3d*)comaVertexArr.constData(), (Vec2f*)comaTexCoordArr.constData());
690
691=== modified file 'src/core/modules/Planet.cpp'
692--- src/core/modules/Planet.cpp 2014-05-23 22:05:02 +0000
693+++ src/core/modules/Planet.cpp 2014-06-04 22:13:44 +0000
694@@ -40,11 +40,58 @@
695 #include <QString>
696 #include <QDebug>
697 #include <QVarLengthArray>
698+#include <QOpenGLShader>
699+
700+#ifndef NDEBUG
701+static const char* get_gl_error_text(int code) {
702+ switch (code) {
703+ case GL_INVALID_ENUM:
704+ return "GL_INVALID_ENUM";
705+ case GL_INVALID_FRAMEBUFFER_OPERATION:
706+ return "GL_INVALID_FRAMEBUFFER_OPERATION";
707+ case GL_INVALID_VALUE:
708+ return "GL_INVALID_VALUE";
709+ case GL_INVALID_OPERATION:
710+ return "GL_INVALID_OPERATION";
711+ case GL_OUT_OF_MEMORY:
712+ return "GL_OUT_OF_MEMORY";
713+ default:
714+ return "undefined error";
715+ }
716+}
717+
718+int check_gl_errors(const char *file, int line)
719+{
720+ int errors = 0;
721+ while (true)
722+ {
723+ GLenum x = glGetError();
724+ if (x == GL_NO_ERROR)
725+ return errors;
726+ printf("%s:%d: OpenGL error: %d (%s)\n",
727+ file, line, x, get_gl_error_text(x));
728+ errors++;
729+ }
730+}
731+#endif
732+
733+#ifndef NDEBUG
734+# define GL(line) do { \
735+ line; \
736+ if (check_gl_errors(__FILE__, __LINE__)) \
737+ exit(-1); \
738+ } while(0)
739+#else
740+# define GL(line) line
741+#endif
742
743 Vec3f Planet::labelColor = Vec3f(0.4,0.4,0.8);
744 Vec3f Planet::orbitColor = Vec3f(1,0.6,1);
745 StelTextureSP Planet::hintCircleTex;
746 StelTextureSP Planet::texEarthShadow;
747+QOpenGLShaderProgram* Planet::shaderProgram=NULL;
748+Planet::ShaderVars Planet::shaderVars;
749+
750 Planet::Planet(const QString& englishName,
751 int flagLighting,
752 double radius,
753@@ -316,6 +363,50 @@
754 return re.obliquity;
755 }
756
757+
758+bool willCastShadow(const Planet* thisPlanet, const Planet* p)
759+{
760+ Vec3d thisPos = thisPlanet->getHeliocentricEclipticPos();
761+ Vec3d planetPos = p->getHeliocentricEclipticPos();
762+
763+ // If the planet p is farther from the sun than this planet, it can't cast shadow on it.
764+ if (planetPos.lengthSquared()>thisPos.lengthSquared())
765+ return false;
766+
767+ Vec3d ppVector = planetPos;
768+ ppVector.normalize();
769+
770+ double shadowDistance = ppVector * thisPos;
771+ static const double sunRadius = 696000./AU;
772+ double d = planetPos.length() / (p->getRadius()/sunRadius+1);
773+ double penumbraRadius = (shadowDistance-d)/d*sunRadius;
774+
775+ double penumbraCenterToThisPlanetCenterDistance = (ppVector*shadowDistance-thisPos).length();
776+
777+ if (penumbraCenterToThisPlanetCenterDistance<penumbraRadius+thisPlanet->getRadius())
778+ return true;
779+ return false;
780+}
781+
782+QVector<const Planet*> Planet::getCandidatesForShadow() const
783+{
784+ QVector<const Planet*> res;
785+ const SolarSystem *ssystem=GETSTELMODULE(SolarSystem);
786+ const Planet* sun = ssystem->getSun().data();
787+ if (this==sun || (parent.data()==sun && satellites.empty()))
788+ return res;
789+
790+ foreach (const PlanetP& planet, satellites)
791+ {
792+ if (willCastShadow(this, planet.data()))
793+ res.append(planet.data());
794+ }
795+ if (willCastShadow(this, parent.data()))
796+ res.append(parent.data());
797+
798+ return res;
799+}
800+
801 void Planet::computePosition(const double date)
802 {
803
804@@ -822,8 +913,7 @@
805 // Draw the rings if we are located on a planet with rings, but not the planet itself.
806 if (rings)
807 {
808- StelPainter sPainter(core->getProjection(transfo));
809- rings->draw(&sPainter,transfo,1000.0);
810+ draw3dModel(core, transfo, 1024, true);
811 }
812 return;
813 }
814@@ -861,7 +951,191 @@
815 return;
816 }
817
818-void Planet::draw3dModel(StelCore* core, StelProjector::ModelViewTranformP transfo, float screenSz)
819+class StelPainterLight
820+{
821+public:
822+ Vec3f position;
823+ Vec3f diffuse;
824+ Vec3f ambient;
825+};
826+static StelPainterLight light;
827+
828+void Planet::initShader()
829+{
830+ // Default planet texture shader program
831+ QOpenGLShader vshader(QOpenGLShader::Vertex);
832+ const char *vsrc =
833+ "attribute highp vec3 vertex;\n"
834+ "attribute highp vec3 unprojectedVertex;\n"
835+ "attribute mediump vec2 texCoord;\n"
836+ "uniform highp mat4 projectionMatrix;\n"
837+ "uniform highp vec3 lightPos;\n"
838+ "varying mediump vec2 texc;\n"
839+ "varying mediump float lambert;\n"
840+ "varying highp vec3 P;\n"
841+ "\n"
842+ "void main()\n"
843+ "{\n"
844+ " gl_Position = projectionMatrix * vec4(vertex, 1.);\n"
845+ " texc = texCoord;\n"
846+ " vec3 normal = normalize(unprojectedVertex);\n"
847+ " float c = lightPos.x * normal.x +\n"
848+ " lightPos.y * normal.y +\n"
849+ " lightPos.z * normal.z;\n"
850+ " lambert = clamp(c, 0.0, 1.0);\n"
851+ "\n"
852+ " P = unprojectedVertex;\n"
853+ "}\n"
854+ "\n";
855+ vshader.compileSourceCode(vsrc);
856+ if (!vshader.log().isEmpty()) { qWarning() << "Planet: Warnings while compiling vshader: " << vshader.log(); }
857+
858+ QOpenGLShader fshader(QOpenGLShader::Fragment);
859+
860+ const char *fsrc =
861+ "varying mediump vec2 texc;\n"
862+ "varying mediump float lambert;\n"
863+ "uniform sampler2D tex;\n"
864+ "uniform mediump vec3 ambientLight;\n"
865+ "uniform mediump vec3 diffuseLight;\n"
866+ "uniform highp vec4 sunInfo;\n"
867+ "\n"
868+ "varying highp vec3 P;\n"
869+ "\n"
870+ "uniform int shadowCount;\n"
871+ "uniform highp mat4 shadowData;\n"
872+ "\n"
873+ "uniform bool ring;\n"
874+ "uniform highp float outerRadius;\n"
875+ "uniform highp float innerRadius;\n"
876+ "uniform sampler2D ringS;\n"
877+ "uniform bool isRing;\n"
878+ "\n"
879+ "uniform bool isMoon;\n"
880+ "uniform sampler2D earthShadow;\n"
881+ "\n"
882+ "void main()\n"
883+ "{\n"
884+ " float final_illumination = 1.0;\n"
885+ " if(lambert > 0.0 || isRing)\n"
886+ " {\n"
887+ " vec3 sunPosition = sunInfo.xyz;\n"
888+ " if(ring && !isRing)\n"
889+ " {\n"
890+ " vec3 ray = normalize(sunPosition);\n"
891+ " float u = - P.z / ray.z;\n"
892+ " if(u > 0.0 && u < 1e10)\n"
893+ " {\n"
894+ " float ring_radius = length(P + u * ray);\n"
895+ " if(ring_radius > innerRadius && ring_radius < outerRadius)\n"
896+ " {\n"
897+ " ring_radius = (ring_radius - innerRadius) / (outerRadius - innerRadius);\n"
898+ " float ringAlpha = texture2D(ringS, vec2(ring_radius, 0.5)).w;\n"
899+ " final_illumination = 1.0 - ringAlpha;\n"
900+ " }\n"
901+ " }\n"
902+ " }\n"
903+ "\n"
904+ " float sunRadius = sunInfo.w;\n"
905+ " float L = length(sunPosition - P);\n"
906+ " float R = asin(sunRadius / L);\n"
907+ " for (int i = 0; i < shadowCount; ++i)\n"
908+ " {\n"
909+ " vec3 satellitePosition = shadowData[i].xyz;\n"
910+ " float satelliteRadius = shadowData[i].w;\n"
911+ " float l = length(satellitePosition - P);\n"
912+ " float r = asin(satelliteRadius / l);\n"
913+ " float d = acos(min(1.0, dot(normalize(sunPosition - P), normalize(satellitePosition - P))));\n"
914+ "\n"
915+ " float illumination = 1.0;\n"
916+ "\n"
917+ " // distance too far\n"
918+ " if(d >= R + r)\n"
919+ " {\n"
920+ " illumination = 1.0;\n"
921+ " }\n"
922+ " // umbra\n"
923+ " else if(r >= R + d)\n"
924+ " {\n"
925+ " if(isMoon)\n"
926+ " illumination = d / (r - R) * 0.6;\n"
927+ " else"
928+ " illumination = 0.0;\n"
929+ " }\n"
930+ " // penumbra completely inside\n"
931+ " else if(d + r <= R)\n"
932+ " {\n"
933+ " illumination = 1.0 - r * r / (R * R);\n"
934+ " }\n"
935+ " // penumbra partially inside\n"
936+ " else\n"
937+ " {\n"
938+ " if(isMoon)\n"
939+ " illumination = ((d - abs(R-r)) / (R + r - abs(R-r))) * 0.4 + 0.6;\n"
940+ " else\n"
941+ " {\n"
942+ " float x = (R * R + d * d - r * r) / (2.0 * d);\n"
943+ " float alpha = acos(x / R);\n"
944+ " float beta = acos((d - x) / r);\n"
945+ " float AR = R * R * (alpha - 0.5 * sin(2.0 * alpha));\n"
946+ " float Ar = r * r * (beta - 0.5 * sin(2.0 * beta));\n"
947+ " float AS = R * R * 2.0 * 1.57079633;\n"
948+ " illumination = 1.0 - (AR + Ar) / AS;\n"
949+ " }\n"
950+ " }\n"
951+ "\n"
952+ " if(illumination < final_illumination)\n"
953+ " final_illumination = illumination;\n"
954+ " }\n"
955+ " }\n"
956+ "\n"
957+ " vec4 litColor = vec4((isRing ? 1.0 : lambert) * final_illumination * diffuseLight + ambientLight, 1.0);\n"
958+ " if(isMoon && final_illumination < 1.0)\n"
959+ " {\n"
960+ " vec4 shadowColor = texture2D(earthShadow, vec2(final_illumination, 0.5));\n"
961+ " gl_FragColor = mix(texture2D(tex, texc) * litColor, shadowColor, shadowColor.a);\n"
962+ " }\n"
963+ " else\n"
964+ " gl_FragColor = texture2D(tex, texc) * litColor;\n"
965+ "}\n"
966+ "\n";
967+ fshader.compileSourceCode(fsrc);
968+ if (!fshader.log().isEmpty()) { qWarning() << "Planet: Warnings while compiling fshader: " << fshader.log(); }
969+
970+ shaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
971+ shaderProgram->addShader(&vshader);
972+ shaderProgram->addShader(&fshader);
973+ GL(StelPainter::linkProg(shaderProgram, "planetShaderProgram"));
974+ GL(shaderProgram->bind());
975+ GL(shaderVars.projectionMatrix = shaderProgram->uniformLocation("projectionMatrix"));
976+ GL(shaderVars.texCoord = shaderProgram->attributeLocation("texCoord"));
977+ GL(shaderVars.unprojectedVertex = shaderProgram->attributeLocation("unprojectedVertex"));
978+ GL(shaderVars.vertex = shaderProgram->attributeLocation("vertex"));
979+ GL(shaderVars.texture = shaderProgram->uniformLocation("tex"));
980+
981+ GL(shaderVars.lightPos = shaderProgram->uniformLocation("lightPos"));
982+ GL(shaderVars.diffuseLight = shaderProgram->uniformLocation("diffuseLight"));
983+ GL(shaderVars.ambientLight = shaderProgram->uniformLocation("ambientLight"));
984+ GL(shaderVars.shadowCount = shaderProgram->uniformLocation("shadowCount"));
985+ GL(shaderVars.shadowData = shaderProgram->uniformLocation("shadowData"));
986+ GL(shaderVars.sunInfo = shaderProgram->uniformLocation("sunInfo"));
987+ GL(shaderVars.isRing = shaderProgram->uniformLocation("isRing"));
988+ GL(shaderVars.ring = shaderProgram->uniformLocation("ring"));
989+ GL(shaderVars.outerRadius = shaderProgram->uniformLocation("outerRadius"));
990+ GL(shaderVars.innerRadius = shaderProgram->uniformLocation("innerRadius"));
991+ GL(shaderVars.ringS = shaderProgram->uniformLocation("ringS"));
992+ GL(shaderVars.isMoon = shaderProgram->uniformLocation("isMoon"));
993+ GL(shaderVars.earthShadow = shaderProgram->uniformLocation("earthShadow"));
994+ GL(shaderProgram->release());
995+}
996+
997+void Planet::deinitShader()
998+{
999+ delete shaderProgram;
1000+ shaderProgram = NULL;
1001+}
1002+
1003+void Planet::draw3dModel(StelCore* core, StelProjector::ModelViewTranformP transfo, float screenSz, bool drawOnlyRing)
1004 {
1005 // This is the main method drawing a planet 3d model
1006 // Some work has to be done on this method to make the rendering nicer
1007@@ -872,39 +1146,33 @@
1008 StelProjector::ModelViewTranformP transfo2 = transfo->clone();
1009 transfo2->combine(Mat4d::zrotation(M_PI/180*(axisRotation + 90.)));
1010 StelPainter* sPainter = new StelPainter(core->getProjection(transfo2));
1011-
1012+
1013 if (flagLighting)
1014 {
1015- sPainter->getLight().enable();
1016-
1017 // Set the main source of light to be the sun
1018 Vec3d sunPos(0);
1019 core->getHeliocentricEclipticModelViewTransform()->forward(sunPos);
1020- sPainter->getLight().setPosition(Vec4f(sunPos[0],sunPos[1],sunPos[2],1.f));
1021+ light.position=Vec4f(sunPos[0],sunPos[1],sunPos[2],1.f);
1022
1023 // Set the light parameters taking sun as the light source
1024- static Vec4f diffuse = Vec4f(1.f,1.f,1.f,1.f);
1025- static Vec4f zero = Vec4f(0.f,0.f,0.f,0.f);
1026- static Vec4f ambient = Vec4f(0.02f,0.02f,0.02f,0.02f);
1027+ light.diffuse = Vec4f(1.f,1.f,1.f);
1028+ light.ambient = Vec4f(0.02f,0.02f,0.02f);
1029
1030 if (this==ssm->getMoon())
1031 {
1032 // Special case for the Moon (maybe better use 1.5,1.5,1.5,1.0 ?)
1033- diffuse = Vec4f(1.6f,1.6f,1.6f,1.f);
1034+ light.diffuse = Vec4f(1.6f,1.6f,1.6f,1.f);
1035 }
1036-
1037- sPainter->getLight().setAmbient(ambient);
1038- sPainter->getLight().setDiffuse(diffuse);
1039- sPainter->getLight().setSpecular(zero);
1040 }
1041 else
1042 {
1043- sPainter->getLight().disable();
1044 sPainter->setColor(albedo,albedo,albedo);
1045 }
1046
1047 if (rings)
1048 {
1049+ // The planet has rings, we need to use depth buffer and adjust the clipping planes to avoid
1050+ // reaching the maximum resolution of the depth buffer
1051 const double dist = getEquinoxEquatorialPos(core).length();
1052 double z_near = 0.9*(dist - rings->getSize());
1053 double z_far = 1.1*(dist + rings->getSize());
1054@@ -912,48 +1180,22 @@
1055 double n,f;
1056 core->getClippingPlanes(&n,&f); // Save clipping planes
1057 core->setClippingPlanes(z_near,z_far);
1058- glDepthMask(GL_TRUE);
1059- glClear(GL_DEPTH_BUFFER_BIT);
1060- glEnable(GL_DEPTH_TEST);
1061+
1062+ drawSphere(sPainter, screenSz, drawOnlyRing);
1063+
1064+ core->setClippingPlanes(n,f); // Restore old clipping planes
1065+ }
1066+ else
1067+ {
1068+ // Normal planet
1069 drawSphere(sPainter, screenSz);
1070- glDepthMask(GL_FALSE);
1071- sPainter->getLight().disable();
1072- rings->draw(sPainter,transfo,screenSz);
1073- sPainter->getLight().enable();
1074- glDisable(GL_DEPTH_TEST);
1075- core->setClippingPlanes(n,f); // Restore old clipping planes
1076- }
1077- else
1078- {
1079- if (this==ssm->getMoon() && core->getCurrentLocation().planetName=="Earth" && ssm->nearLunarEclipse())
1080- {
1081- // Draw earth shadow over moon using stencil buffer if appropriate
1082- // This effect curently only looks right from earth viewpoint
1083- // TODO: moon magnitude label during eclipse isn't accurate...
1084- glClearStencil(0x0);
1085- glClear(GL_STENCIL_BUFFER_BIT);
1086- glStencilFunc(GL_ALWAYS, 0x1, 0x1);
1087- glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE);
1088- glEnable(GL_STENCIL_TEST);
1089- drawSphere(sPainter, screenSz);
1090- glDisable(GL_STENCIL_TEST);
1091-
1092- sPainter->getLight().disable();
1093- drawEarthShadow(core, sPainter);
1094- }
1095- else
1096- {
1097- // Normal planet
1098- drawSphere(sPainter, screenSz);
1099- }
1100- }
1101- if (sPainter)
1102- delete sPainter;
1103+ }
1104+ delete sPainter;
1105 sPainter=NULL;
1106 }
1107
1108 // Draw the halo if it enabled in the ssystem.ini file (+ special case for backward compatible for the Sun)
1109- if (hasHalo() || getEnglishName().contains("Sun"))
1110+ if (hasHalo() || this==ssm->getSun())
1111 {
1112 // Prepare openGL lighting parameters according to luminance
1113 float surfArcMin2 = getSpheroidAngularSize(core)*60;
1114@@ -965,8 +1207,120 @@
1115 }
1116 }
1117
1118-
1119-void Planet::drawSphere(StelPainter* painter, float screenSz)
1120+struct Planet3DModel
1121+{
1122+ QVector<float> vertexArr;
1123+ QVector<float> texCoordArr;
1124+ QVector<unsigned short> indiceArr;
1125+};
1126+
1127+void sSphere(Planet3DModel* model, const float radius, const float oneMinusOblateness, const int slices, const int stacks)
1128+{
1129+ model->indiceArr.resize(0);
1130+ model->vertexArr.resize(0);
1131+ model->texCoordArr.resize(0);
1132+
1133+ GLfloat x, y, z;
1134+ GLfloat s=0.f, t=1.f;
1135+ GLint i, j;
1136+
1137+ const float* cos_sin_rho = StelUtils::ComputeCosSinRho(stacks);
1138+ const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
1139+
1140+ const float* cos_sin_rho_p;
1141+ const float *cos_sin_theta_p;
1142+
1143+ // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis
1144+ // t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes)
1145+ // cannot use triangle fan on texturing (s coord. at top/bottom tip varies)
1146+ // If the texture is flipped, we iterate the coordinates backward.
1147+ const GLfloat ds = 1.f / slices;
1148+ const GLfloat dt = 1.f / stacks; // from inside texture is reversed
1149+
1150+ // draw intermediate as quad strips
1151+ for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks; ++i,cos_sin_rho_p+=2)
1152+ {
1153+ s = 0.f;
1154+ for (j = 0,cos_sin_theta_p = cos_sin_theta; j<=slices;++j,cos_sin_theta_p+=2)
1155+ {
1156+ x = -cos_sin_theta_p[1] * cos_sin_rho_p[1];
1157+ y = cos_sin_theta_p[0] * cos_sin_rho_p[1];
1158+ z = cos_sin_rho_p[0];
1159+ model->texCoordArr << s << t;
1160+ model->vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius;
1161+ x = -cos_sin_theta_p[1] * cos_sin_rho_p[3];
1162+ y = cos_sin_theta_p[0] * cos_sin_rho_p[3];
1163+ z = cos_sin_rho_p[2];
1164+ model->texCoordArr << s << t - dt;
1165+ model->vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius;
1166+ s += ds;
1167+ }
1168+ unsigned int offset = i*(slices+1)*2;
1169+ for (j = 2;j<slices*2+2;j+=2)
1170+ {
1171+ model->indiceArr << offset+j-2 << offset+j-1 << offset+j;
1172+ model->indiceArr << offset+j << offset+j-1 << offset+j+1;
1173+ }
1174+ t -= dt;
1175+ }
1176+}
1177+
1178+struct Ring3DModel
1179+{
1180+ QVector<float> vertexArr;
1181+ QVector<float> texCoordArr;
1182+ QVector<unsigned short> indiceArr;
1183+};
1184+
1185+
1186+void sRing(Ring3DModel* model, const float rMin, const float rMax, int slices, const int stacks)
1187+{
1188+ float x,y;
1189+
1190+ const float dr = (rMax-rMin) / stacks;
1191+ const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices);
1192+ const float* cos_sin_theta_p;
1193+
1194+ model->vertexArr.resize(0);
1195+ model->texCoordArr.resize(0);
1196+ model->indiceArr.resize(0);
1197+
1198+ float r = rMin;
1199+ for (int i=0; i<=stacks; ++i)
1200+ {
1201+ const float tex_r0 = (r-rMin)/(rMax-rMin);
1202+ int j;
1203+ for (j=0,cos_sin_theta_p=cos_sin_theta; j<=slices; ++j,cos_sin_theta_p+=2)
1204+ {
1205+ x = r*cos_sin_theta_p[0];
1206+ y = r*cos_sin_theta_p[1];
1207+ model->texCoordArr << tex_r0 << 0.5f;
1208+ model->vertexArr << x << y << 0.f;
1209+ }
1210+ r+=dr;
1211+ }
1212+ for (int i=0; i<stacks; ++i)
1213+ {
1214+ for (int j=0; j<slices; ++j)
1215+ {
1216+ model->indiceArr << i*slices+j << (i+1)*slices+j << i*slices+j+1;
1217+ model->indiceArr << i*slices+j+1 << (i+1)*slices+j << (i+1)*slices+j+1;
1218+ }
1219+ }
1220+}
1221+
1222+void Planet::computeModelMatrix(Mat4d &result) const
1223+{
1224+ result = Mat4d::translation(eclipticPos) * rotLocalToParent * Mat4d::zrotation(M_PI/180*(axisRotation + 90.));
1225+ PlanetP p = parent;
1226+ while (p && p->parent)
1227+ {
1228+ result = Mat4d::translation(p->eclipticPos) * result * p->rotLocalToParent;
1229+ p = p->parent;
1230+ }
1231+}
1232+
1233+void Planet::drawSphere(StelPainter* painter, float screenSz, bool drawOnlyRing)
1234 {
1235 if (texMap)
1236 {
1237@@ -976,119 +1330,166 @@
1238 return;
1239 }
1240 }
1241- //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GZ deactivated. 2013-12-27. If disabling blend, who cares which one?
1242- painter->setColor(1.f, 1.f, 1.f);
1243-
1244 painter->enableTexture2d(true);
1245 glDisable(GL_BLEND);
1246 glEnable(GL_CULL_FACE);
1247
1248 // Draw the spheroid itself
1249 // Adapt the number of facets according with the size of the sphere for optimization
1250- int nb_facet = (int)(screenSz * 40/50); // 40 facets for 1024 pixels diameter on screen
1251+ int nb_facet = (int)(screenSz * 40.f/50.f); // 40 facets for 1024 pixels diameter on screen
1252 if (nb_facet<10) nb_facet = 10;
1253- if (nb_facet>40) nb_facet = 40;
1254- // Rotate and add an extra quarter rotation so that the planet texture map
1255- // fits to the observers position. No idea why this is necessary,
1256- // perhaps some openGl strangeness, or confusing sin/cos.
1257-
1258- painter->sSphere(radius*sphereScale, oneMinusOblateness, nb_facet, nb_facet);
1259+ if (nb_facet>100) nb_facet = 100;
1260+
1261+ // Generates the vertice
1262+ Planet3DModel model;
1263+ sSphere(&model, radius*sphereScale, oneMinusOblateness, nb_facet, nb_facet);
1264+
1265+ QVector<float> projectedVertexArr;
1266+ projectedVertexArr.resize(model.vertexArr.size());
1267+ for (int i=0;i<model.vertexArr.size()/3;++i)
1268+ painter->getProjector()->project(*((Vec3f*)(model.vertexArr.constData()+i*3)), *((Vec3f*)(projectedVertexArr.data()+i*3)));
1269+
1270+ if (englishName=="Sun")
1271+ {
1272+ texMap->bind();
1273+ painter->setColor(2, 2, 2);
1274+ painter->setArrays((Vec3f*)projectedVertexArr.constData(), (Vec2f*)model.texCoordArr.constData());
1275+ painter->drawFromArray(StelPainter::Triangles, model.indiceArr.size(), 0, false, model.indiceArr.constData());
1276+ return;
1277+ }
1278+
1279+ if (shaderProgram==NULL)
1280+ Planet::initShader();
1281+ Q_ASSERT(shaderProgram!=NULL);
1282+ GL(shaderProgram->bind());
1283+
1284+ const Mat4f& m = painter->getProjector()->getProjectionMatrix();
1285+ const QMatrix4x4 qMat(m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]);
1286+ shaderProgram->setUniformValue(shaderVars.projectionMatrix, qMat);
1287+
1288+ Mat4d modelMatrix;
1289+ computeModelMatrix(modelMatrix);
1290+ // TODO explain this
1291+ const Mat4d mTarget = modelMatrix.inverse();
1292+
1293+ QMatrix4x4 shadowCandidatesData;
1294+ QVector<const Planet*> shadowCandidates = getCandidatesForShadow();
1295+ // Our shader doesn't support more than 4 planets creating shadow
1296+ if (shadowCandidates.size()>4)
1297+ shadowCandidates.resize(4);
1298+ for (int i=0;i<shadowCandidates.size();++i)
1299+ {
1300+ shadowCandidates.at(i)->computeModelMatrix(modelMatrix);
1301+ const Vec4d position = mTarget * modelMatrix.getColumn(3);
1302+ shadowCandidatesData(0, i) = position[0];
1303+ shadowCandidatesData(1, i) = position[1];
1304+ shadowCandidatesData(2, i) = position[2];
1305+ shadowCandidatesData(3, i) = shadowCandidates.at(i)->getRadius();
1306+ }
1307+
1308+ const StelProjectorP& projector = painter->getProjector();
1309+
1310+ Vec3f lightPos3;
1311+ lightPos3.set(light.position[0], light.position[1], light.position[2]);
1312+ Vec3f tmpv(0.f);
1313+ projector->getModelViewTransform()->forward(tmpv);
1314+ projector->getModelViewTransform()->getApproximateLinearTransfo().transpose().multiplyWithoutTranslation(Vec3d(lightPos3[0], lightPos3[1], lightPos3[2]));
1315+ projector->getModelViewTransform()->backward(lightPos3);
1316+ lightPos3.normalize();
1317+
1318+ GL(shaderProgram->setUniformValue(shaderVars.lightPos, lightPos3[0], lightPos3[1], lightPos3[2]));
1319+ GL(shaderProgram->setUniformValue(shaderVars.diffuseLight, light.diffuse[0], light.diffuse[1], light.diffuse[2]));
1320+ GL(shaderProgram->setUniformValue(shaderVars.ambientLight, light.ambient[0], light.ambient[1], light.ambient[2]));
1321+ GL(shaderProgram->setUniformValue(shaderVars.texture, 0));
1322+ GL(shaderProgram->setUniformValue(shaderVars.shadowCount, shadowCandidates.size()));
1323+ GL(shaderProgram->setUniformValue(shaderVars.shadowData, shadowCandidatesData));
1324+
1325+ const SolarSystem* ssm = GETSTELMODULE(SolarSystem);
1326+ GL(shaderProgram->setUniformValue(shaderVars.sunInfo, mTarget[12], mTarget[13], mTarget[14], ssm->getSun()->getRadius()));
1327+ GL(shaderProgram->setUniformValue(shaderVars.isRing, false));
1328+
1329+ GL(shaderProgram->setUniformValue(shaderVars.ring, rings!=NULL));
1330+ if (rings!=NULL)
1331+ {
1332+ rings->tex->bind(2);
1333+ GL(shaderProgram->setUniformValue(shaderVars.outerRadius, rings->radiusMax));
1334+ GL(shaderProgram->setUniformValue(shaderVars.innerRadius, rings->radiusMin));
1335+ GL(shaderProgram->setUniformValue(shaderVars.ringS, rings ? 2 : 0));
1336+ }
1337+
1338+ const bool isMoon = (this==ssm->getMoon());
1339+ if (isMoon)
1340+ texEarthShadow->bind(3);
1341+ GL(shaderProgram->setUniformValue(shaderVars.isMoon, isMoon));
1342+ GL(shaderProgram->setUniformValue(shaderVars.earthShadow, isMoon ? 3: 0));
1343+
1344+ GL(texMap->bind(1));
1345+
1346+ GL(shaderProgram->setAttributeArray(shaderVars.vertex, (const GLfloat*)projectedVertexArr.constData(), 3));
1347+ GL(shaderProgram->enableAttributeArray(shaderVars.vertex));
1348+ GL(shaderProgram->setAttributeArray(shaderVars.unprojectedVertex, (const GLfloat*)model.vertexArr.constData(), 3));
1349+ GL(shaderProgram->enableAttributeArray(shaderVars.unprojectedVertex));
1350+ GL(shaderProgram->setAttributeArray(shaderVars.texCoord, (const GLfloat*)model.texCoordArr.constData(), 2));
1351+ GL(shaderProgram->enableAttributeArray(shaderVars.texCoord));
1352+
1353+ if (rings)
1354+ {
1355+ glDepthMask(GL_TRUE);
1356+ glClear(GL_DEPTH_BUFFER_BIT);
1357+ glEnable(GL_DEPTH_TEST);
1358+ }
1359+
1360+ if (!drawOnlyRing)
1361+ GL(glDrawElements(GL_TRIANGLES, model.indiceArr.size(), GL_UNSIGNED_SHORT, model.indiceArr.constData()));
1362+
1363+ if (rings)
1364+ {
1365+ // Draw the rings just after the planet
1366+
1367+ glDepthMask(GL_FALSE);
1368+
1369+ // Normal transparency mode
1370+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1371+ glEnable(GL_BLEND);
1372+
1373+ Ring3DModel ringModel;
1374+ sRing(&ringModel, rings->radiusMin, rings->radiusMax, 128, 32);
1375+
1376+ GL(shaderProgram->setUniformValue(shaderVars.isRing, true));
1377+ GL(shaderProgram->setUniformValue(shaderVars.texture, 2));
1378+
1379+ computeModelMatrix(modelMatrix);
1380+ const Vec4d position = mTarget * modelMatrix.getColumn(3);
1381+ shadowCandidatesData(0, 0) = position[0];
1382+ shadowCandidatesData(1, 0) = position[1];
1383+ shadowCandidatesData(2, 0) = position[2];
1384+ shadowCandidatesData(3, 0) = getRadius();
1385+ GL(shaderProgram->setUniformValue(shaderVars.shadowCount, 1));
1386+ GL(shaderProgram->setUniformValue(shaderVars.shadowData, shadowCandidatesData));
1387+
1388+ projectedVertexArr.resize(ringModel.vertexArr.size());
1389+ for (int i=0;i<ringModel.vertexArr.size()/3;++i)
1390+ painter->getProjector()->project(*((Vec3f*)(ringModel.vertexArr.constData()+i*3)), *((Vec3f*)(projectedVertexArr.data()+i*3)));
1391+
1392+ GL(shaderProgram->setAttributeArray(shaderVars.vertex, (const GLfloat*)projectedVertexArr.constData(), 3));
1393+ GL(shaderProgram->enableAttributeArray(shaderVars.vertex));
1394+ GL(shaderProgram->setAttributeArray(shaderVars.unprojectedVertex, (const GLfloat*)ringModel.vertexArr.constData(), 3));
1395+ GL(shaderProgram->enableAttributeArray(shaderVars.unprojectedVertex));
1396+ GL(shaderProgram->setAttributeArray(shaderVars.texCoord, (const GLfloat*)ringModel.texCoordArr.constData(), 2));
1397+ GL(shaderProgram->enableAttributeArray(shaderVars.texCoord));
1398+
1399+ glDisable(GL_CULL_FACE);
1400+
1401+ GL(glDrawElements(GL_TRIANGLES, ringModel.indiceArr.size(), GL_UNSIGNED_SHORT, ringModel.indiceArr.constData()));
1402+
1403+ glDisable(GL_DEPTH_TEST);
1404+ }
1405+
1406+ GL(shaderProgram->release());
1407+
1408 glDisable(GL_CULL_FACE);
1409 }
1410
1411-// draws earth shadow overlapping the moon using stencil buffer
1412-// umbra and penumbra are sized separately for accuracy
1413-void Planet::drawEarthShadow(StelCore* core, StelPainter* sPainter)
1414-{
1415- SolarSystem* ssm = GETSTELMODULE(SolarSystem);
1416- Vec3d e = ssm->getEarth()->getEclipticPos();
1417- Vec3d m = ssm->getMoon()->getEclipticPos(); // relative to earth
1418- Vec3d mh = ssm->getMoon()->getHeliocentricEclipticPos(); // relative to sun
1419- float mscale = ssm->getMoon()->getSphereScale();
1420-
1421- // shadow location at earth + moon distance along earth vector from sun
1422- Vec3d en = e;
1423- en.normalize();
1424- Vec3d shadow = en * (e.length() + m.length());
1425-
1426- // find shadow radii in AU
1427- double r_penumbra = shadow.length()*702378.1/AU/e.length() - 696000./AU;
1428- double r_umbra = 6378.1/AU - m.length()*(689621.9/AU/e.length());
1429-
1430- // find vector orthogonal to sun-earth vector using cross product with
1431- // a non-parallel vector
1432- Vec3d rpt = shadow^Vec3d(0,0,1);
1433- rpt.normalize();
1434- Vec3d upt = rpt*r_umbra*mscale*1.02; // point on umbra edge
1435- rpt *= r_penumbra*mscale; // point on penumbra edge
1436-
1437- // modify shadow location for scaled moon
1438- Vec3d mdist = shadow - mh;
1439- if (mdist.length() > r_penumbra + 2000./AU)
1440- return; // not visible so don't bother drawing
1441-
1442- shadow = mh + mdist*mscale;
1443-
1444- StelProjectorP saveProj = sPainter->getProjector();
1445- sPainter->setProjector(core->getProjection(StelCore::FrameHeliocentricEcliptic));
1446-
1447- sPainter->enableTexture2d(true);
1448- glEnable(GL_BLEND);
1449- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1450- sPainter->setColor(1,1,1);
1451-
1452- glEnable(GL_STENCIL_TEST);
1453- // We draw only where the stencil buffer is at 1, i.e. where the moon was drawn
1454- glStencilFunc(GL_EQUAL, 0x1, 0x1);
1455- // Don't change stencil buffer value
1456- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1457-
1458- // shadow radial texture
1459- texEarthShadow->bind();
1460-
1461- Vec3d r;
1462-
1463- // Draw umbra first
1464- QVector<Vec2f> texCoordArray;
1465- QVector<Vec3d> vertexArray;
1466- texCoordArray.reserve(210);
1467- vertexArray.reserve(210);
1468- texCoordArray << Vec2f(0.f, 0.5f);
1469- // johannes: work-around for nasty ATI rendering bug: use y-texture coordinate of 0.5 instead of 0.0
1470- vertexArray << shadow;
1471-
1472- const Mat4d& rotMat = Mat4d::rotation(shadow, 2.*M_PI/100.);
1473- r = upt;
1474- for (int i=1; i<=101; ++i)
1475- {
1476- // position in texture of umbra edge
1477- texCoordArray << Vec2f(0.6f, 0.5f);
1478- r.transfo4d(rotMat);
1479- vertexArray << shadow + r;
1480- }
1481- sPainter->setArrays(vertexArray.constData(), texCoordArray.constData());
1482- sPainter->drawFromArray(StelPainter::TriangleFan, 102);
1483-
1484- // now penumbra
1485- vertexArray.resize(0);
1486- texCoordArray.resize(0);
1487- Vec3d u;
1488- r = rpt;
1489- u = upt;
1490- for (int i=0; i<=200; i+=2)
1491- {
1492- r.transfo4d(rotMat);
1493- u.transfo4d(rotMat);
1494- texCoordArray << Vec2f(0.6f, 0.5f) << Vec2f(1.f, 0.5f); // position in texture of umbra edge
1495- vertexArray << shadow + u << shadow + r;
1496- }
1497- sPainter->setArrays(vertexArray.constData(), texCoordArray.constData());
1498- sPainter->drawFromArray(StelPainter::TriangleStrip, 202);
1499- glDisable(GL_STENCIL_TEST);
1500- glClearStencil(0x0);
1501- glClear(GL_STENCIL_BUFFER_BIT); // Clean again to let a clean buffer for later Qt display
1502- sPainter->setProjector(saveProj);
1503-}
1504
1505 void Planet::drawHints(const StelCore* core, const QFont& planetNameFont)
1506 {
1507@@ -1118,44 +1519,12 @@
1508 sPainter.drawSprite2dMode(screenPos[0], screenPos[1], 11);
1509 }
1510
1511-Ring::Ring(double radiusMin,double radiusMax,const QString &texname)
1512+Ring::Ring(float radiusMin, float radiusMax, const QString &texname)
1513 :radiusMin(radiusMin),radiusMax(radiusMax)
1514 {
1515 tex = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/"+texname);
1516 }
1517
1518-Ring::~Ring(void)
1519-{
1520-}
1521-
1522-void Ring::draw(StelPainter* sPainter,StelProjector::ModelViewTranformP transfo,double screenSz)
1523-{
1524- screenSz -= 50;
1525- screenSz /= 250.0;
1526- if (screenSz < 0.0) screenSz = 0.0;
1527- else if (screenSz > 1.0) screenSz = 1.0;
1528- const int slices = 128+(int)((256-128)*screenSz);
1529- const int stacks = 8+(int)((32-8)*screenSz);
1530-
1531- // Normal transparency mode
1532- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1533- sPainter->setColor(1.f, 1.f, 1.f);
1534- sPainter->enableTexture2d(true);
1535- glEnable(GL_CULL_FACE);
1536- glEnable(GL_BLEND);
1537-
1538- if (tex) tex->bind();
1539-
1540- Mat4d mat = transfo->getApproximateLinearTransfo();
1541- // solve the ring wraparound by culling:
1542- // decide if we are above or below the ring plane
1543- const double h = mat.r[ 8]*mat.r[12]
1544- + mat.r[ 9]*mat.r[13]
1545- + mat.r[10]*mat.r[14];
1546- sPainter->sRing(radiusMin,radiusMax,(h<0.0)?slices:-slices,stacks, 0);
1547- glDisable(GL_CULL_FACE);
1548-}
1549-
1550
1551 // draw orbital path of Planet
1552 void Planet::drawOrbit(const StelCore* core)
1553
1554=== modified file 'src/core/modules/Planet.hpp'
1555--- src/core/modules/Planet.hpp 2014-05-23 22:05:02 +0000
1556+++ src/core/modules/Planet.hpp 2014-06-04 22:13:44 +0000
1557@@ -43,13 +43,6 @@
1558 class StelPainter;
1559 class StelTranslator;
1560
1561-struct TrailPoint
1562-{
1563- Vec3d point;
1564- double date;
1565-};
1566-
1567-
1568 // Class used to store orbital elements
1569 class RotationElements
1570 {
1571@@ -68,13 +61,10 @@
1572 class Ring
1573 {
1574 public:
1575- Ring(double radiusMin,double radiusMax,const QString &texname);
1576- ~Ring(void);
1577- void draw(StelPainter* painter, StelProjector::ModelViewTranformP transfo, double screenSz);
1578+ Ring(float radiusMin, float radiusMax,const QString &texname);
1579 double getSize(void) const {return radiusMax;}
1580-private:
1581- const double radiusMin;
1582- const double radiusMax;
1583+ const float radiusMin;
1584+ const float radiusMax;
1585 StelTextureSP tex;
1586 };
1587
1588@@ -241,20 +231,22 @@
1589 static void setOrbitColor(const Vec3f& oc) {orbitColor = oc;}
1590 static const Vec3f& getOrbitColor() {return orbitColor;}
1591
1592+ //! Return the list of planets which project some shadow on this planet
1593+ QVector<const Planet*> getCandidatesForShadow() const;
1594+
1595 protected:
1596 static StelTextureSP texEarthShadow; // for lunar eclipses
1597
1598- // draw earth shadow on moon for lunar eclipses
1599- void drawEarthShadow(StelCore* core, StelPainter* sPainter);
1600-
1601+ void computeModelMatrix(Mat4d &result) const;
1602+
1603 // Return the information string "ready to print" :)
1604 QString getSkyLabel(const StelCore* core) const;
1605
1606 // Draw the 3d model. Call the proper functions if there are rings etc..
1607- void draw3dModel(StelCore* core, StelProjector::ModelViewTranformP transfo, float screenSz);
1608+ void draw3dModel(StelCore* core, StelProjector::ModelViewTranformP transfo, float screenSz, bool drawOnlyRing=false);
1609
1610 // Draw the 3D sphere
1611- void drawSphere(StelPainter* painter, float screenSz);
1612+ void drawSphere(StelPainter* painter, float screenSz, bool drawOnlyRing=false);
1613
1614 // Draw the circle and name of the Planet
1615 void drawHints(const StelCore* core, const QFont& planetNameFont);
1616@@ -299,6 +291,34 @@
1617
1618 static Vec3f labelColor;
1619 static StelTextureSP hintCircleTex;
1620+
1621+ // Shader-related variables
1622+ struct ShaderVars {
1623+ int projectionMatrix;
1624+ int texCoord;
1625+ int unprojectedVertex;
1626+ int vertex;
1627+ int texture;
1628+
1629+ int lightPos;
1630+ int diffuseLight;
1631+ int ambientLight;
1632+ int shadowCount;
1633+ int shadowData;
1634+ int sunInfo;
1635+ int isRing;
1636+ int ring;
1637+ int outerRadius;
1638+ int innerRadius;
1639+ int ringS;
1640+ int isMoon;
1641+ int earthShadow;
1642+ };
1643+ static ShaderVars shaderVars;
1644+
1645+ static void initShader();
1646+ static void deinitShader();
1647+ static class QOpenGLShaderProgram* shaderProgram;
1648 };
1649
1650 #endif // _PLANET_HPP_
1651
1652=== modified file 'src/core/modules/SolarSystem.cpp'
1653--- src/core/modules/SolarSystem.cpp 2014-05-23 22:05:02 +0000
1654+++ src/core/modules/SolarSystem.cpp 2014-06-04 22:13:44 +0000
1655@@ -147,7 +147,7 @@
1656
1657 texPointer = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/pointeur4.png");
1658 Planet::hintCircleTex = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/planet-indicator.png");
1659-
1660+
1661 StelApp *app = &StelApp::getInstance();
1662 connect(app, SIGNAL(languageChanged()), this, SLOT(updateI18n()));
1663 connect(app, SIGNAL(colorSchemeChanged(const QString&)), this, SLOT(setStelStyle(const QString&)));
1664@@ -158,6 +158,11 @@
1665 addAction("actionShow_Planets_Trails", displayGroup, N_("Planet trails"), "trailsDisplayed", "Shift+T");
1666 }
1667
1668+void SolarSystem::deinit()
1669+{
1670+ Planet::deinitShader();
1671+}
1672+
1673 void SolarSystem::recreateTrails()
1674 {
1675 // Create a trail group containing all the planets orbiting the sun (not including satellites)
1676
1677=== modified file 'src/core/modules/SolarSystem.hpp'
1678--- src/core/modules/SolarSystem.hpp 2014-05-23 22:05:02 +0000
1679+++ src/core/modules/SolarSystem.hpp 2014-06-04 22:13:44 +0000
1680@@ -69,6 +69,8 @@
1681 //! - set display options from application settings
1682 virtual void init();
1683
1684+ virtual void deinit();
1685+
1686 //! Draw SolarSystem objects (planets).
1687 //! @param core The StelCore object.
1688 //! @return The maximum squared distance in pixels that any SolarSystem object