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