]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/dome.cxx
Modified Files:
[simgear.git] / simgear / scene / sky / dome.cxx
1 // dome.cxx -- model sky with an upside down "bowl"
2 //
3 // Written by Curtis Olson, started December 1997.
4 // SSG-ified by Curtis Olson, February 2000.
5 //
6 // Copyright (C) 1997-2000  Curtis L. Olson  - http://www.flightgear.org/~curt
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 //
22 // $Id$
23
24
25 #ifdef HAVE_CONFIG_H
26 #  include <simgear_config.h>
27 #endif
28
29 #ifdef HAVE_WINDOWS_H
30 #  include <windows.h>
31 #endif
32
33 #include <math.h>
34
35 #include <simgear/compiler.h>
36
37 #include <osg/Array>
38 #include <osg/Geode>
39 #include <osg/Geometry>
40 #include <osg/Node>
41 #include <osg/MatrixTransform>
42 #include <osg/Material>
43 #include <osg/ShadeModel>
44
45 #include <simgear/scene/util/SGDebugDrawCallback.hxx>
46 #include <simgear/debug/logstream.hxx>
47
48 #include "dome.hxx"
49
50
51 #ifdef __MWERKS__
52 #  pragma global_optimizer off
53 #endif
54
55
56 // proportions of max dimensions fed to the build() routine
57 static const float center_elev = 1.0;
58
59 static const float upper_radius = 0.6;
60 static const float upper_elev = 0.15;
61
62 static const float middle_radius = 0.9;
63 static const float middle_elev = 0.08;
64
65 static const float lower_radius = 1.0;
66 static const float lower_elev = 0.0;
67
68 static const float bottom_radius = 0.8;
69 static const float bottom_elev = -0.1;
70
71
72 // Constructor
73 SGSkyDome::SGSkyDome( void ) {
74     asl = 0;
75 }
76
77
78 // Destructor
79 SGSkyDome::~SGSkyDome( void ) {
80 }
81
82
83 // initialize the sky object and connect it into our scene graph
84 osg::Node*
85 SGSkyDome::build( double hscale, double vscale ) {
86
87     osg::Geode* geode = new osg::Geode;
88
89     // set up the state
90     osg::StateSet* stateSet = geode->getOrCreateStateSet();
91     stateSet->setRenderBinDetails(-10, "RenderBin");
92
93     osg::ShadeModel* shadeModel = new osg::ShadeModel;
94     shadeModel->setMode(osg::ShadeModel::SMOOTH);
95     stateSet->setAttributeAndModes(shadeModel);
96     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
97     stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
98     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
99     stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
100     stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
101     stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
102     osg::Material* material = new osg::Material;
103 //     material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
104 //     material->setEmission(osg::Material::FRONT_AND_BACK,
105 //                           osg::Vec4(0, 0, 0, 1));
106 //     material->setSpecular(osg::Material::FRONT_AND_BACK,
107 //                           osg::Vec4(0, 0, 0, 1));
108 //     material->setShininess(osg::Material::FRONT_AND_BACK, 0);
109     stateSet->setAttribute(material);
110 //     stateSet->setMode(GL_COLOR_MATERIAL, osg::StateAttribute::OFF);
111
112     // initialize arrays
113     // initially seed to all blue
114     center_disk_vl = new osg::Vec3Array;
115     center_disk_cl = new osg::Vec3Array;
116     center_disk_cl->assign(14, osg::Vec3(0, 0, 1));
117                                        
118     upper_ring_vl = new osg::Vec3Array;
119     upper_ring_cl = new osg::Vec3Array;
120     upper_ring_cl->assign(26, osg::Vec3(0, 0, 1));
121
122     middle_ring_vl = new osg::Vec3Array;
123     middle_ring_cl = new osg::Vec3Array;
124     middle_ring_cl->assign(26, osg::Vec3(0, 0, 1));
125
126     lower_ring_vl = new osg::Vec3Array;
127     lower_ring_cl = new osg::Vec3Array;
128     lower_ring_cl->assign(26, osg::Vec3(0, 0, 1));
129
130
131     // generate the raw vertex data
132     osg::Vec3 center_vertex(0.0, 0.0, center_elev*vscale);
133     osg::Vec3 upper_vertex[12];
134     osg::Vec3 middle_vertex[12];
135     osg::Vec3 lower_vertex[12];
136     osg::Vec3 bottom_vertex[12];
137
138     for ( int i = 0; i < 12; ++i ) {
139         double theta = (i * 30) * SGD_DEGREES_TO_RADIANS;
140         double sTheta = hscale*sin(theta);
141         double cTheta = hscale*cos(theta);
142
143         upper_vertex[i] = osg::Vec3(cTheta * upper_radius,
144                                     sTheta * upper_radius,
145                                     upper_elev * vscale);
146
147         middle_vertex[i] = osg::Vec3(cTheta * middle_radius,
148                                      sTheta * middle_radius,
149                                      middle_elev * vscale);
150
151         lower_vertex[i] = osg::Vec3(cTheta * lower_radius,
152                                     sTheta * lower_radius,
153                                     lower_elev * vscale);
154
155         bottom_vertex[i] = osg::Vec3(cTheta * bottom_radius,
156                                      sTheta * bottom_radius,
157                                      bottom_elev * vscale);
158     }
159
160     // generate the center disk vertex/color arrays
161     center_disk_vl->push_back(center_vertex);
162     for ( int i = 11; i >= 0; --i )
163         center_disk_vl->push_back(upper_vertex[i]);
164     center_disk_vl->push_back(upper_vertex[11]);
165
166     // generate the upper ring
167     for ( int i = 0; i < 12; ++i ) {
168         upper_ring_vl->push_back( middle_vertex[i] );
169         upper_ring_vl->push_back( upper_vertex[i] );
170     }
171     upper_ring_vl->push_back( middle_vertex[0] );
172     upper_ring_vl->push_back( upper_vertex[0] );
173
174     // generate middle ring
175     for ( int i = 0; i < 12; i++ ) {
176         middle_ring_vl->push_back( lower_vertex[i] );
177         middle_ring_vl->push_back( middle_vertex[i] );
178     }
179     middle_ring_vl->push_back( lower_vertex[0] );
180     middle_ring_vl->push_back( middle_vertex[0] );
181
182     // generate lower ring
183     for ( int i = 0; i < 12; i++ ) {
184         lower_ring_vl->push_back( bottom_vertex[i] );
185         lower_ring_vl->push_back( lower_vertex[i] );
186     }
187     lower_ring_vl->push_back( bottom_vertex[0] );
188     lower_ring_vl->push_back( lower_vertex[0] );
189
190     // force a repaint of the sky colors with ugly defaults
191     repaint(SGVec3f(1, 1, 1), SGVec3f(1, 1, 1), 0.0, 5000.0 );
192
193     // build the ssg scene graph sub tree for the sky and connected
194     // into the provide scene graph branch
195     osg::Geometry* geometry = new osg::Geometry;
196     geometry->setName("Dome Center");
197 //     geometry->setDrawCallback(new SGDebugDrawCallback);
198     geometry->setUseDisplayList(false);
199     geometry->setVertexArray(center_disk_vl.get());
200     geometry->setColorArray(center_disk_cl.get());
201     geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
202     geometry->setNormalBinding(osg::Geometry::BIND_OFF);
203     geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_FAN, 0, 14));
204     geode->addDrawable(geometry);
205
206     geometry = new osg::Geometry;
207     geometry->setName("Dome Upper Ring");
208 //     geometry->setDrawCallback(new SGDebugDrawCallback);
209     geometry->setUseDisplayList(false);
210     geometry->setVertexArray(upper_ring_vl.get());
211     geometry->setColorArray(upper_ring_cl.get());
212     geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
213     geometry->setNormalBinding(osg::Geometry::BIND_OFF);
214     geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 26));
215     geode->addDrawable(geometry);
216
217     geometry = new osg::Geometry;
218     geometry->setName("Dome Middle Ring");
219 //     geometry->setDrawCallback(new SGDebugDrawCallback);
220     geometry->setUseDisplayList(false);
221     geometry->setVertexArray(middle_ring_vl.get());
222     geometry->setColorArray(middle_ring_cl.get());
223     geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
224     geometry->setNormalBinding(osg::Geometry::BIND_OFF);
225     geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 26));
226     geode->addDrawable(geometry);
227
228     geometry = new osg::Geometry;
229     geometry->setName("Dome Lower Ring");
230 //     geometry->setDrawCallback(new SGDebugDrawCallback);
231     geometry->setUseDisplayList(false);
232     geometry->setVertexArray(lower_ring_vl.get());
233     geometry->setColorArray(lower_ring_cl.get());
234     geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
235     geometry->setNormalBinding(osg::Geometry::BIND_OFF);
236     geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 26));
237     geode->addDrawable(geometry);
238
239     dome_transform = new osg::MatrixTransform;
240     dome_transform->addChild(geode);
241
242     return dome_transform.get();
243 }
244
245 static void fade_to_black(osg::Vec3 sky_color[], float asl, int count) {
246     const float ref_asl = 10000.0f;
247     float d = exp( - asl / ref_asl );
248     for(int i = 0; i < count ; i++) {
249         float f = 1 - d;
250         sky_color[i][0] = sky_color[i][0] - f * sky_color[i][0] ;
251         sky_color[i][1] = sky_color[i][1] - f * sky_color[i][1] ;
252         sky_color[i][2] = sky_color[i][2] - f * sky_color[i][2] ;
253     }
254 }
255
256 // repaint the sky colors based on current value of sun_angle, sky,
257 // and fog colors.  This updates the color arrays for ssgVtxTable.
258 // sun angle in degrees relative to verticle
259 // 0 degrees = high noon
260 // 90 degrees = sun rise/set
261 // 180 degrees = darkest midnight
262 bool
263 SGSkyDome::repaint( const SGVec3f& sky_color, const SGVec3f& fog_color,
264                     double sun_angle, double vis )
265 {
266     SGVec3f outer_param, outer_diff;
267     SGVec3f middle_param, middle_diff;
268
269     // Check for sunrise/sunset condition
270     if (sun_angle > 80)
271     {
272         // 0.0 - 0.4
273         outer_param[0] = (10.0 - fabs(90.0 - sun_angle)) / 20.0;
274         outer_param[1] = (10.0 - fabs(90.0 - sun_angle)) / 40.0;
275         outer_param[2] = -(10.0 - fabs(90.0 - sun_angle)) / 30.0;
276
277         middle_param[0] = (10.0 - fabs(90.0 - sun_angle)) / 40.0;
278         middle_param[1] = (10.0 - fabs(90.0 - sun_angle)) / 80.0;
279         middle_param[2] = 0.0;
280
281         outer_diff = (1.0 / 6.0) * outer_param;
282         middle_diff = (1.0 / 6.0) * middle_param;
283     } else {
284         outer_param = SGVec3f(0, 0, 0);
285         middle_param = SGVec3f(0, 0, 0);
286
287         outer_diff = SGVec3f(0, 0, 0);
288         middle_diff = SGVec3f(0, 0, 0);
289     }
290     // printf("  outer_red_param = %.2f  outer_red_diff = %.2f\n", 
291     //        outer_red_param, outer_red_diff);
292
293     // calculate transition colors between sky and fog
294     SGVec3f outer_amt = outer_param;
295     SGVec3f middle_amt = middle_param;
296
297     //
298     // First, recalulate the basic colors
299     //
300
301     osg::Vec3 center_color;
302     osg::Vec3 upper_color[12];
303     osg::Vec3 middle_color[12];
304     osg::Vec3 lower_color[12];
305     osg::Vec3 bottom_color[12];
306
307     double vis_factor, cvf = vis;
308
309     if (cvf > 45000)
310         cvf = 45000;
311
312     vis_factor = (vis - 1000.0) / 2000.0;
313     if ( vis_factor < 0.0 ) {
314         vis_factor = 0.0;
315     } else if ( vis_factor > 1.0) {
316         vis_factor = 1.0;
317     }
318
319     center_color = sky_color.osg();
320
321     for ( int i = 0; i < 6; i++ ) {
322         for ( int j = 0; j < 3; j++ ) {
323             double saif = sun_angle/SG_PI;
324             double diff = (sky_color[j] - fog_color[j])
325               * (0.8 + j * 0.2) * (0.8 + saif - ((6-i)/10));
326
327             // printf("sky = %.2f  fog = %.2f  diff = %.2f\n", 
328             //        l->sky_color[j], l->fog_color[j], diff);
329
330             upper_color[i][j] = sky_color[j] - diff *
331               ( 1.0 - vis_factor * (0.7 + 0.3 * cvf/45000) );
332             middle_color[i][j] = sky_color[j] - diff *
333               ( 1.0 - vis_factor * (0.1 + 0.85 * cvf/45000) ) + middle_amt[j];
334             lower_color[i][j] = fog_color[j] + outer_amt[j];
335
336             if ( upper_color[i][j] > 1.0 ) { upper_color[i][j] = 1.0; }
337             if ( upper_color[i][j] < 0.0 ) { upper_color[i][j] = 0.0; }
338             if ( middle_color[i][j] > 1.0 ) { middle_color[i][j] = 1.0; }
339             if ( middle_color[i][j] < 0.0 ) { middle_color[i][j] = 0.0; }
340             if ( lower_color[i][j] > 1.0 ) { lower_color[i][j] = 1.0; }
341             if ( lower_color[i][j] < 0.0 ) { lower_color[i][j] = 0.0; }
342         }
343
344         outer_amt -= outer_diff;
345         middle_amt -= middle_diff;
346
347         /*
348         printf("upper_color[%d] = %.2f %.2f %.2f %.2f\n", i, upper_color[i][0],
349                upper_color[i][1], upper_color[i][2], upper_color[i][3]);
350         printf("middle_color[%d] = %.2f %.2f %.2f %.2f\n", i, 
351                middle_color[i][0], middle_color[i][1], middle_color[i][2], 
352                middle_color[i][3]);
353         printf("lower_color[%d] = %.2f %.2f %.2f %.2f\n", i, 
354                lower_color[i][0], lower_color[i][1], lower_color[i][2], 
355                lower_color[i][3]);
356         */
357     }
358
359     outer_amt = SGVec3f(0, 0, 0);
360     middle_amt = SGVec3f(0, 0, 0);
361
362     for ( int i = 6; i < 12; i++ ) {
363         for ( int j = 0; j < 3; j++ ) {
364             double saif = sun_angle/SGD_PI;
365             double diff = (sky_color[j] - fog_color[j])
366               * (0.8 + j * 0.2) * (0.8 + saif - ((-i+12)/10));
367
368             // printf("sky = %.2f  fog = %.2f  diff = %.2f\n", 
369             //        sky_color[j], fog_color[j], diff);
370
371             upper_color[i][j] = sky_color[j] - diff *
372               ( 1.0 - vis_factor * (0.7 + 0.3 * cvf/45000) );
373             middle_color[i][j] = sky_color[j] - diff *
374               ( 1.0 - vis_factor * (0.1 + 0.85 * cvf/45000) ) + middle_amt[j];
375             lower_color[i][j] = fog_color[j] + outer_amt[j];
376
377             if ( upper_color[i][j] > 1.0 ) { upper_color[i][j] = 1.0; }
378             if ( upper_color[i][j] < 0.0 ) { upper_color[i][j] = 0.0; }
379             if ( middle_color[i][j] > 1.0 ) { middle_color[i][j] = 1.0; }
380             if ( middle_color[i][j] < 0.0 ) { middle_color[i][j] = 0.0; }
381             if ( lower_color[i][j] > 1.0 ) { lower_color[i][j] = 1.0; }
382             if ( lower_color[i][j] < 0.0 ) { lower_color[i][j] = 0.0; }
383         }
384
385         outer_amt += outer_diff;
386         middle_amt += middle_diff;
387
388         /*
389         printf("upper_color[%d] = %.2f %.2f %.2f %.2f\n", i, upper_color[i][0],
390                upper_color[i][1], upper_color[i][2], upper_color[i][3]);
391         printf("middle_color[%d] = %.2f %.2f %.2f %.2f\n", i, 
392                middle_color[i][0], middle_color[i][1], middle_color[i][2], 
393                middle_color[i][3]);
394         printf("lower_color[%d] = %.2f %.2f %.2f %.2f\n", i, 
395                lower_color[i][0], lower_color[i][1], lower_color[i][2], 
396                lower_color[i][3]);
397         */
398    }
399
400     fade_to_black( &center_color, asl * center_elev, 1);
401     fade_to_black( upper_color, (asl+0.05f) * upper_elev, 12);
402     fade_to_black( middle_color, (asl+0.05f) * middle_elev, 12);
403     fade_to_black( lower_color, (asl+0.05f) * lower_elev, 12);
404
405     for ( int i = 0; i < 12; i++ )
406         bottom_color[i] = fog_color.osg();
407
408     //
409     // Second, assign the basic colors to the object color arrays
410     //
411
412     // update the center disk color arrays
413     int counter = 0;
414     (*center_disk_cl)[counter++] = center_color;
415     for ( int i = 11; i >= 0; i-- ) {
416         (*center_disk_cl)[counter++] = upper_color[i];
417     }
418     (*center_disk_cl)[counter++] = upper_color[11];
419     center_disk_cl->dirty();
420
421     // generate the upper ring
422     counter = 0;
423     for ( int i = 0; i < 12; i++ ) {
424         (*upper_ring_cl)[counter++] = middle_color[i];
425         (*upper_ring_cl)[counter++] = upper_color[i];
426     }
427     (*upper_ring_cl)[counter++] = middle_color[0];
428     (*upper_ring_cl)[counter++] = upper_color[0];
429     upper_ring_cl->dirty();
430
431     // generate middle ring
432     counter = 0;
433     for ( int i = 0; i < 12; i++ ) {
434         (*middle_ring_cl)[counter++] = lower_color[i];
435         (*middle_ring_cl)[counter++] = middle_color[i];
436     }
437     (*middle_ring_cl)[counter++] = lower_color[0];
438     (*middle_ring_cl)[counter++] = middle_color[0];
439     middle_ring_cl->dirty();
440
441     // generate lower ring
442     counter = 0;
443     for ( int i = 0; i < 12; i++ ) {
444         (*lower_ring_cl)[counter++] = bottom_color[i];
445         (*lower_ring_cl)[counter++] = lower_color[i];
446     }
447     (*lower_ring_cl)[counter++] = bottom_color[0];
448     (*lower_ring_cl)[counter++] = lower_color[0];
449     lower_ring_cl->dirty();
450
451     return true;
452 }
453
454
455 // reposition the sky at the specified origin and orientation
456 // lon specifies a rotation about the Z axis
457 // lat specifies a rotation about the new Y axis
458 // spin specifies a rotation about the new Z axis (and orients the
459 // sunrise/set effects
460 bool
461 SGSkyDome::reposition( const SGVec3f& p, double _asl,
462                        double lon, double lat, double spin ) {
463     asl = _asl;
464
465     osg::Matrix T, LON, LAT, SPIN;
466
467     // Translate to view position
468     // Point3D zero_elev = current_view.get_cur_zero_elev();
469     // xglTranslatef( zero_elev.x(), zero_elev.y(), zero_elev.z() );
470     T.makeTranslate( p.osg() );
471
472     // printf("  Translated to %.2f %.2f %.2f\n", 
473     //        zero_elev.x, zero_elev.y, zero_elev.z );
474
475     // Rotate to proper orientation
476     // printf("  lon = %.2f  lat = %.2f\n",
477     //        lon * SGD_RADIANS_TO_DEGREES,
478     //        lat * SGD_RADIANS_TO_DEGREES);
479     // xglRotatef( lon * SGD_RADIANS_TO_DEGREES, 0.0, 0.0, 1.0 );
480     LON.makeRotate(lon, osg::Vec3(0, 0, 1));
481
482     // xglRotatef( 90.0 - f->get_Latitude() * SGD_RADIANS_TO_DEGREES,
483     //             0.0, 1.0, 0.0 );
484     LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
485
486     // xglRotatef( l->sun_rotation * SGD_RADIANS_TO_DEGREES, 0.0, 0.0, 1.0 );
487     SPIN.makeRotate(spin, osg::Vec3(0, 0, 1));
488
489     dome_transform->setMatrix( SPIN*LAT*LON*T );
490     return true;
491 }