]> git.mxchange.org Git - flightgear.git/blob - src/Main/renderer.cxx
1e0569701e4733d0935e6446cb6bd9c3dbfc499a
[flightgear.git] / src / Main / renderer.cxx
1 // renderer.cxx -- top level sim routines
2 //
3 // Written by Curtis Olson, started May 1997.
4 // This file contains parts of main.cxx prior to october 2004
5 //
6 // Copyright (C) 1997 - 2002  Curtis L. Olson  - http://www.flightgear.org/~curt
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // 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 <config.h>
27 #endif
28
29 #include <simgear/compiler.h>
30
31 #ifdef HAVE_WINDOWS_H
32 #  include <windows.h>
33 #endif
34
35 #include <osg/ref_ptr>
36 #include <osg/AlphaFunc>
37 #include <osg/BlendFunc>
38 #include <osg/CameraNode>
39 #include <osg/CameraView>
40 #include <osg/CullFace>
41 #include <osg/Depth>
42 #include <osg/Fog>
43 #include <osg/Group>
44 #include <osg/LightModel>
45 #include <osg/NodeCallback>
46 #include <osg/Notify>
47 #include <osg/MatrixTransform>
48 #include <osg/Multisample>
49 #include <osg/Point>
50 #include <osg/PolygonMode>
51 #include <osg/ShadeModel>
52 #include <osg/TexEnv>
53 #include <osg/TexGen>
54 #include <osg/TexMat>
55 #include <osg/ColorMatrix>
56
57 #include <osgUtil/SceneView>
58 #include <osgUtil/UpdateVisitor>
59
60 #include <osg/io_utils>
61 #include <osgDB/WriteFile>
62 #include <osgDB/ReadFile>
63 #include <sstream>
64
65 #include <simgear/math/SGMath.hxx>
66 #include <simgear/screen/extensions.hxx>
67 #include <simgear/scene/material/matlib.hxx>
68 #include <simgear/scene/model/animation.hxx>
69 #include <simgear/scene/model/model.hxx>
70 #include <simgear/scene/model/modellib.hxx>
71 #include <simgear/scene/model/placement.hxx>
72 #include <simgear/scene/util/SGUpdateVisitor.hxx>
73 #include <simgear/scene/tgdb/pt_lights.hxx>
74 #include <simgear/props/props.hxx>
75 #include <simgear/timing/sg_time.hxx>
76 #include <simgear/ephemeris/ephemeris.hxx>
77 #include <simgear/math/sg_random.h>
78 #ifdef FG_JPEG_SERVER
79 #include <simgear/screen/jpgfactory.hxx>
80 #endif
81
82 #include <simgear/environment/visual_enviro.hxx>
83
84 #include <Scenery/tileentry.hxx>
85 #include <Time/light.hxx>
86 #include <Time/light.hxx>
87 #include <Aircraft/aircraft.hxx>
88 #include <Cockpit/panel.hxx>
89 #include <Cockpit/cockpit.hxx>
90 #include <Cockpit/hud.hxx>
91 #include <Model/panelnode.hxx>
92 #include <Model/modelmgr.hxx>
93 #include <Model/acmodel.hxx>
94 #include <Scenery/scenery.hxx>
95 #include <Scenery/tilemgr.hxx>
96 #include <ATC/ATCdisplay.hxx>
97 #include <GUI/new_gui.hxx>
98 #include <Instrumentation/instrument_mgr.hxx>
99 #include <Instrumentation/HUD/HUD.hxx>
100
101 #include "splash.hxx"
102 #include "renderer.hxx"
103 #include "main.hxx"
104
105
106 class FGSunLightUpdateCallback : public osg::StateAttribute::Callback {
107 public:
108   virtual void operator()(osg::StateAttribute* stateAttribute,
109                           osg::NodeVisitor*)
110   {
111     assert(dynamic_cast<osg::Light*>(stateAttribute));
112     osg::Light* light = static_cast<osg::Light*>(stateAttribute);
113
114     FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
115     light->setAmbient(l->scene_ambient().osg());
116     light->setDiffuse(l->scene_diffuse().osg());
117     light->setSpecular(l->scene_specular().osg());
118     SGVec4f position(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2], 0);
119     light->setPosition(position.osg());
120     SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]);
121     light->setDirection(direction.osg());
122     light->setSpotExponent(0);
123     light->setSpotCutoff(180);
124     light->setConstantAttenuation(1);
125     light->setLinearAttenuation(0);
126     light->setQuadraticAttenuation(0);
127   }
128 };
129
130 class FGWireFrameModeUpdateCallback : public osg::StateAttribute::Callback {
131 public:
132   FGWireFrameModeUpdateCallback() :
133     mWireframe(fgGetNode("/sim/rendering/wireframe"))
134   { }
135   virtual void operator()(osg::StateAttribute* stateAttribute,
136                           osg::NodeVisitor*)
137   {
138     assert(dynamic_cast<osg::PolygonMode*>(stateAttribute));
139     osg::PolygonMode* polygonMode;
140     polygonMode = static_cast<osg::PolygonMode*>(stateAttribute);
141
142     if (mWireframe->getBoolValue())
143       polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
144                            osg::PolygonMode::LINE);
145     else
146       polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
147                            osg::PolygonMode::FILL);
148   }
149 private:
150   SGSharedPtr<SGPropertyNode> mWireframe;
151 };
152
153 class FGLightModelUpdateCallback : public osg::StateAttribute::Callback {
154 public:
155   FGLightModelUpdateCallback() :
156     mHighlights(fgGetNode("/sim/rendering/specular-highlight"))
157   { }
158   virtual void operator()(osg::StateAttribute* stateAttribute,
159                           osg::NodeVisitor*)
160   {
161     assert(dynamic_cast<osg::LightModel*>(stateAttribute));
162     osg::LightModel* lightModel;
163     lightModel = static_cast<osg::LightModel*>(stateAttribute);
164
165 #if 0
166     FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
167     SGVec4f ambient(l->scene_ambient());
168     lightModel->setAmbientIntensity(ambient.osg());
169 #else
170     lightModel->setAmbientIntensity(osg::Vec4(0, 0, 0, 1));
171 #endif
172     lightModel->setTwoSided(true);
173
174     if (mHighlights->getBoolValue()) {
175       lightModel->setColorControl(osg::LightModel::SEPARATE_SPECULAR_COLOR);
176       lightModel->setLocalViewer(true);
177     } else {
178       lightModel->setColorControl(osg::LightModel::SINGLE_COLOR);
179       lightModel->setLocalViewer(false);
180     }
181   }
182 private:
183   SGSharedPtr<SGPropertyNode> mHighlights;
184 };
185
186 class FGFogEnableUpdateCallback : public osg::StateSet::Callback {
187 public:
188   FGFogEnableUpdateCallback() :
189     mFogEnabled(fgGetNode("/sim/rendering/fog"))
190   { }
191   virtual void operator()(osg::StateSet* stateSet, osg::NodeVisitor*)
192   {
193     if (strcmp(mFogEnabled->getStringValue(), "disabled") == 0) {
194       stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
195     } else {
196       stateSet->setMode(GL_FOG, osg::StateAttribute::ON);
197     }
198   }
199 private:
200   SGSharedPtr<SGPropertyNode> mFogEnabled;
201 };
202
203 // fog constants.  I'm a little nervous about putting actual code out
204 // here but it seems to work (?)
205 static const double m_log01 = -log( 0.01 );
206 static const double sqrt_m_log01 = sqrt( m_log01 );
207 static GLfloat fog_exp_density;
208 static GLfloat fog_exp2_density;
209 static GLfloat rwy_exp2_punch_through;
210 static GLfloat taxi_exp2_punch_through;
211 static GLfloat ground_exp2_punch_through;
212
213 // Sky structures
214 SGSky *thesky;
215
216 static osg::ref_ptr<osgUtil::SceneView> sceneView = new osgUtil::SceneView;
217 static osg::ref_ptr<osg::FrameStamp> mFrameStamp = new osg::FrameStamp;
218
219 static osg::ref_ptr<osg::Group> mRoot = new osg::Group;
220
221 static osg::ref_ptr<osg::CameraView> mCameraView = new osg::CameraView;
222 static osg::ref_ptr<osg::CameraNode> mBackGroundCamera = new osg::CameraNode;
223 static osg::ref_ptr<osg::CameraNode> mSceneCamera = new osg::CameraNode;
224
225 static osg::ref_ptr<osg::Fog> mFog = new osg::Fog;
226 static osg::ref_ptr<osg::Fog> mRunwayLightingFog = new osg::Fog;
227 static osg::ref_ptr<osg::Fog> mTaxiLightingFog = new osg::Fog;
228 static osg::ref_ptr<osg::Fog> mGroundLightingFog = new osg::Fog;
229
230 FGRenderer::FGRenderer()
231 {
232 #ifdef FG_JPEG_SERVER
233    jpgRenderFrame = FGRenderer::update;
234 #endif
235 }
236
237 FGRenderer::~FGRenderer()
238 {
239 #ifdef FG_JPEG_SERVER
240    jpgRenderFrame = NULL;
241 #endif
242 }
243
244 // Initialize various GL/view parameters
245 void
246 FGRenderer::init( void ) {
247
248     osg::initNotifyLevel();
249
250     // Go full screen if requested ...
251     if ( fgGetBool("/sim/startup/fullscreen") )
252         fgOSFullScreen();
253
254     if ( (!strcmp(fgGetString("/sim/rendering/fog"), "disabled")) || 
255          (!fgGetBool("/sim/rendering/shading"))) {
256         // if fastest fog requested, or if flat shading force fastest
257         glHint ( GL_FOG_HINT, GL_FASTEST );
258     } else if ( !strcmp(fgGetString("/sim/rendering/fog"), "nicest") ) {
259         glHint ( GL_FOG_HINT, GL_DONT_CARE );
260     }
261
262     glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
263     glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
264     glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
265
266     sceneView->setDefaults(osgUtil::SceneView::COMPILE_GLOBJECTS_AT_INIT);
267
268     mFog->setMode(osg::Fog::EXP2);
269     mRunwayLightingFog->setMode(osg::Fog::EXP2);
270     mTaxiLightingFog->setMode(osg::Fog::EXP2);
271     mGroundLightingFog->setMode(osg::Fog::EXP2);
272
273     sceneView->setFrameStamp(mFrameStamp.get());
274
275     sceneView->setUpdateVisitor(new SGUpdateVisitor);
276
277     sceneView->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
278
279     sceneView->getCamera()->setViewMatrix(osg::Matrix(0, 0,-1, 0,
280                                                       1, 0, 0, 0,
281                                                       0,-1, 0, 0,
282                                                       0, 0, 0, 1));
283
284     sceneView->getCamera()->setClearMask(0);
285
286     osg::StateSet* stateSet = mRoot->getOrCreateStateSet();
287
288     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
289     
290     stateSet->setAttribute(new osg::Depth(osg::Depth::LEQUAL));
291     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
292
293     stateSet->setAttribute(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01));
294     stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
295     stateSet->setAttribute(new osg::BlendFunc);
296     stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
297
298     stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
299     
300     // this will be set below
301     stateSet->setMode(GL_NORMALIZE, osg::StateAttribute::OFF);
302
303 //     osg::Material* material = new osg::Material;
304 //     stateSet->setAttribute(material);
305     
306 //     stateSet->setAttribute(new osg::CullFace(osg::CullFace::BACK));
307 //     stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
308
309
310     // need to update the light on every frame
311     osg::Light* sunLight = new osg::Light;
312     sunLight->setLightNum(0);
313     sunLight->setUpdateCallback(new FGSunLightUpdateCallback);
314     stateSet->setAttributeAndModes(sunLight, osg::StateAttribute::ON);
315     osg::LightModel* lightModel = new osg::LightModel;
316     lightModel->setUpdateCallback(new FGLightModelUpdateCallback);
317     stateSet->setAttributeAndModes(lightModel, osg::StateAttribute::ON);
318
319     // this is the topmost scenegraph node for osg
320     mBackGroundCamera->addChild(thesky->getPreRoot());
321     mBackGroundCamera->setClearMask(GL_COLOR_BUFFER_BIT);
322
323     GLbitfield inheritanceMask = osg::CullSettings::ALL_VARIABLES;
324     inheritanceMask &= ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE;
325     inheritanceMask &= ~osg::CullSettings::NEAR_FAR_RATIO;
326     inheritanceMask &= ~osg::CullSettings::CULLING_MODE;
327     mBackGroundCamera->setInheritanceMask(inheritanceMask);
328     mBackGroundCamera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
329     mBackGroundCamera->setCullingMode(osg::CullSettings::NO_CULLING);
330
331     mBackGroundCamera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
332
333     mRoot->addChild(mBackGroundCamera.get());
334
335
336     sceneView->getCamera()->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
337
338     mSceneCamera->setClearMask(GL_DEPTH_BUFFER_BIT);
339     inheritanceMask = osg::CullSettings::ALL_VARIABLES;
340     inheritanceMask &= ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE;
341     inheritanceMask &= ~osg::CullSettings::CULLING_MODE;
342     mSceneCamera->setInheritanceMask(inheritanceMask);
343     mSceneCamera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
344     mSceneCamera->setCullingMode(osg::CullSettings::DEFAULT_CULLING);
345
346
347     stateSet = globals->get_scenery()->get_scene_graph()->getOrCreateStateSet();
348     stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
349     stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
350     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
351     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
352
353     // switch to enable wireframe
354     osg::PolygonMode* polygonMode = new osg::PolygonMode;
355     polygonMode->setUpdateCallback(new FGWireFrameModeUpdateCallback);
356     stateSet->setAttributeAndModes(polygonMode);
357
358     // scene fog handling
359     stateSet->setAttributeAndModes(mFog.get());
360     stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
361
362     mRoot->addChild(mSceneCamera.get());
363
364     mSceneCamera->addChild(globals->get_scenery()->get_scene_graph());
365
366     stateSet = mSceneCamera->getOrCreateStateSet();
367     stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
368     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
369
370     // this one contains all lights, here we set the light states we did
371     // in the plib case with plain OpenGL
372     osg::Group* lightGroup = new osg::Group;
373     mSceneCamera->addChild(lightGroup);
374     lightGroup->addChild(globals->get_scenery()->get_gnd_lights_root());
375     lightGroup->addChild(globals->get_scenery()->get_vasi_lights_root());
376     lightGroup->addChild(globals->get_scenery()->get_rwy_lights_root());
377     lightGroup->addChild(globals->get_scenery()->get_taxi_lights_root());
378
379     stateSet = globals->get_scenery()->get_gnd_lights_root()->getOrCreateStateSet();
380     stateSet->setAttributeAndModes(mFog.get());
381     stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
382     stateSet = globals->get_scenery()->get_vasi_lights_root()->getOrCreateStateSet();
383     stateSet->setAttributeAndModes(mRunwayLightingFog.get());
384     stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
385     stateSet = globals->get_scenery()->get_rwy_lights_root()->getOrCreateStateSet();
386     stateSet->setAttributeAndModes(mRunwayLightingFog.get());
387     stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
388     stateSet = globals->get_scenery()->get_taxi_lights_root()->getOrCreateStateSet();
389     stateSet->setAttributeAndModes(mTaxiLightingFog.get());
390     stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
391
392     mCameraView->addChild(mRoot.get());
393     sceneView->setSceneData(mCameraView.get());
394
395     mSceneCamera->addChild(thesky->getCloudRoot());
396
397 //  sceneView->getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE);
398 }
399
400
401 // Update all Visuals (redraws anything graphics related)
402 void
403 FGRenderer::update( bool refresh_camera_settings ) {
404     bool scenery_loaded = fgGetBool("sim/sceneryloaded")
405                           || fgGetBool("sim/sceneryloaded-override");
406
407     if ( idle_state < 1000 || !scenery_loaded ) {
408         // still initializing, draw the splash screen
409         fgSplashUpdate(1.0);
410
411         // Keep resetting sim time while the sim is initializing
412         globals->set_sim_time_sec( 0.0 );
413         return;
414     }
415
416     bool skyblend = fgGetBool("/sim/rendering/skyblend");
417     bool use_point_sprites = fgGetBool("/sim/rendering/point-sprites");
418     bool enhanced_lighting = fgGetBool("/sim/rendering/enhanced-lighting");
419     bool distance_attenuation
420         = fgGetBool("/sim/rendering/distance-attenuation");
421     // OSGFIXME
422     SGConfigureDirectionalLights( use_point_sprites, enhanced_lighting,
423                                   distance_attenuation );
424
425     static const SGPropertyNode *groundlevel_nearplane
426         = fgGetNode("/sim/current-view/ground-level-nearplane-m");
427
428     FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
429
430     // update fog params
431     double actual_visibility;
432     if (fgGetBool("/environment/clouds/status")) {
433         actual_visibility = thesky->get_visibility();
434     } else {
435         actual_visibility = fgGetDouble("/environment/visibility-m");
436     }
437
438     static double last_visibility = -9999;
439     if ( actual_visibility != last_visibility ) {
440         last_visibility = actual_visibility;
441
442         fog_exp_density = m_log01 / actual_visibility;
443         fog_exp2_density = sqrt_m_log01 / actual_visibility;
444         ground_exp2_punch_through = sqrt_m_log01 / (actual_visibility * 1.5);
445         if ( actual_visibility < 8000 ) {
446             rwy_exp2_punch_through = sqrt_m_log01 / (actual_visibility * 2.5);
447             taxi_exp2_punch_through = sqrt_m_log01 / (actual_visibility * 1.5);
448         } else {
449             rwy_exp2_punch_through = sqrt_m_log01 / ( 8000 * 2.5 );
450             taxi_exp2_punch_through = sqrt_m_log01 / ( 8000 * 1.5 );
451         }
452         mFog->setDensity(fog_exp2_density);
453         mRunwayLightingFog->setDensity(rwy_exp2_punch_through);
454         mTaxiLightingFog->setDensity(taxi_exp2_punch_through);
455         mGroundLightingFog->setDensity(ground_exp2_punch_through);
456     }
457
458     // idle_state is now 1000 meaning we've finished all our
459     // initializations and are running the main loop, so this will
460     // now work without seg faulting the system.
461
462     FGViewer *current__view = globals->get_current_view();
463     // Force update of center dependent values ...
464     current__view->set_dirty();
465
466     if ( refresh_camera_settings ) {
467         // update view port
468         resize( fgGetInt("/sim/startup/xsize"),
469                 fgGetInt("/sim/startup/ysize") );
470
471         SGVec3d center = globals->get_scenery()->get_center();
472         SGVec3d position = current__view->getViewPosition();
473         SGQuatd attitude = current__view->getViewOrientation();
474         SGVec3d osgPosition = attitude.transform(center - position);
475         mCameraView->setPosition(osgPosition.osg());
476         mCameraView->setAttitude(inverse(attitude).osg());
477     }
478
479     if ( skyblend ) {
480         if ( fgGetBool("/sim/rendering/textures") ) {
481             SGVec4f clearColor(l->adj_fog_color());
482             mBackGroundCamera->setClearColor(clearColor.osg());
483         }
484     } else {
485         SGVec4f clearColor(l->sky_color());
486         mBackGroundCamera->setClearColor(clearColor.osg());
487     }
488
489     // update fog params if visibility has changed
490     double visibility_meters = fgGetDouble("/environment/visibility-m");
491     thesky->set_visibility(visibility_meters);
492
493     thesky->modify_vis( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER,
494                         ( global_multi_loop * fgGetInt("/sim/speed-up") )
495                         / (double)fgGetInt("/sim/model-hz") );
496
497     // update the sky dome
498     if ( skyblend ) {
499
500         // The sun and moon distances are scaled down versions
501         // of the actual distance to get both the moon and the sun
502         // within the range of the far clip plane.
503         // Moon distance:    384,467 kilometers
504         // Sun distance: 150,000,000 kilometers
505
506         double sun_horiz_eff, moon_horiz_eff;
507         if (fgGetBool("/sim/rendering/horizon-effect")) {
508            sun_horiz_eff = 0.67+pow(0.5+cos(l->get_sun_angle())*2/2, 0.33)/3;
509            moon_horiz_eff = 0.67+pow(0.5+cos(l->get_moon_angle())*2/2, 0.33)/3;
510         } else {
511            sun_horiz_eff = moon_horiz_eff = 1.0;
512         }
513
514         static SGSkyState sstate;
515
516         sstate.view_pos  = current__view->get_view_pos();
517         sstate.zero_elev = current__view->get_zero_elev();
518         sstate.view_up   = current__view->get_world_up();
519         sstate.lon       = current__view->getLongitude_deg()
520                             * SGD_DEGREES_TO_RADIANS;
521         sstate.lat       = current__view->getLatitude_deg()
522                             * SGD_DEGREES_TO_RADIANS;
523         sstate.alt       = current__view->getAltitudeASL_ft()
524                             * SG_FEET_TO_METER;
525         sstate.spin      = l->get_sun_rotation();
526         sstate.gst       = globals->get_time_params()->getGst();
527         sstate.sun_ra    = globals->get_ephem()->getSunRightAscension();
528         sstate.sun_dec   = globals->get_ephem()->getSunDeclination();
529         sstate.sun_dist  = 50000.0 * sun_horiz_eff;
530         sstate.moon_ra   = globals->get_ephem()->getMoonRightAscension();
531         sstate.moon_dec  = globals->get_ephem()->getMoonDeclination();
532         sstate.moon_dist = 40000.0 * moon_horiz_eff;
533         sstate.sun_angle = l->get_sun_angle();
534
535
536         /*
537          SG_LOG( SG_GENERAL, SG_BULK, "thesky->repaint() sky_color = "
538          << l->sky_color()[0] << " "
539          << l->sky_color()[1] << " "
540          << l->sky_color()[2] << " "
541          << l->sky_color()[3] );
542         SG_LOG( SG_GENERAL, SG_BULK, "    fog = "
543          << l->fog_color()[0] << " "
544          << l->fog_color()[1] << " "
545          << l->fog_color()[2] << " "
546          << l->fog_color()[3] );
547         SG_LOG( SG_GENERAL, SG_BULK,
548                 "    sun_angle = " << l->sun_angle
549          << "    moon_angle = " << l->moon_angle );
550         */
551
552         static SGSkyColor scolor;
553
554         scolor.sky_color   = SGVec3f(l->sky_color().data());
555         scolor.fog_color   = SGVec3f(l->adj_fog_color().data());
556         scolor.cloud_color = SGVec3f(l->cloud_color().data());
557         scolor.sun_angle   = l->get_sun_angle();
558         scolor.moon_angle  = l->get_moon_angle();
559         scolor.nplanets    = globals->get_ephem()->getNumPlanets();
560         scolor.nstars      = globals->get_ephem()->getNumStars();
561         scolor.planet_data = globals->get_ephem()->getPlanets();
562         scolor.star_data   = globals->get_ephem()->getStars();
563
564         thesky->reposition( sstate, delta_time_sec );
565         thesky->repaint( scolor );
566
567         /*
568         SG_LOG( SG_GENERAL, SG_BULK,
569                 "thesky->reposition( view_pos = " << view_pos[0] << " "
570          << view_pos[1] << " " << view_pos[2] );
571         SG_LOG( SG_GENERAL, SG_BULK,
572                 "    zero_elev = " << zero_elev[0] << " "
573          << zero_elev[1] << " " << zero_elev[2]
574          << " lon = " << cur_fdm_state->get_Longitude()
575          << " lat = " << cur_fdm_state->get_Latitude() );
576         SG_LOG( SG_GENERAL, SG_BULK,
577                 "    sun_rot = " << l->get_sun_rotation
578          << " gst = " << SGTime::cur_time_params->getGst() );
579         SG_LOG( SG_GENERAL, SG_BULK,
580              "    sun ra = " << globals->get_ephem()->getSunRightAscension()
581           << " sun dec = " << globals->get_ephem()->getSunDeclination()
582           << " moon ra = " << globals->get_ephem()->getMoonRightAscension()
583           << " moon dec = " << globals->get_ephem()->getMoonDeclination() );
584         */
585
586         //OSGFIXME
587 //         shadows->setupShadows(
588 //           current__view->getLongitude_deg(),
589 //           current__view->getLatitude_deg(),
590 //           globals->get_time_params()->getGst(),
591 //           globals->get_ephem()->getSunRightAscension(),
592 //           globals->get_ephem()->getSunDeclination(),
593 //           l->get_sun_angle());
594
595     }
596
597     if ( strcmp(fgGetString("/sim/rendering/fog"), "disabled") ) {
598         SGVec4f color(l->adj_fog_color());
599         mFog->setColor(color.osg());
600         mRunwayLightingFog->setColor(color.osg());
601         mTaxiLightingFog->setColor(color.osg());
602         mGroundLightingFog->setColor(color.osg());
603     }
604
605
606 //     sgEnviro.setLight(l->adj_fog_color());
607
608     // texture parameters
609     glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
610
611     double agl = current__view->getAltitudeASL_ft()*SG_FEET_TO_METER
612       - current__view->getSGLocation()->get_cur_elev_m();
613
614     float scene_nearplane, scene_farplane;
615     if ( agl > 10.0 ) {
616         scene_nearplane = 10.0f;
617         scene_farplane = 120000.0f;
618     } else {
619         scene_nearplane = groundlevel_nearplane->getDoubleValue();
620         scene_farplane = 120000.0f;
621     }
622
623     setNearFar( scene_nearplane, scene_farplane );
624
625 //     sgEnviro.startOfFrame(current__view->get_view_pos(), 
626 //         current__view->get_world_up(),
627 //         current__view->getLongitude_deg(),
628 //         current__view->getLatitude_deg(),
629 //         current__view->getAltitudeASL_ft() * SG_FEET_TO_METER,
630 //         delta_time_sec);
631
632     // OSGFIXME
633 //     sgEnviro.drawLightning();
634
635 //        double current_view_origin_airspeed_horiz_kt =
636 //         fgGetDouble("/velocities/airspeed-kt", 0.0)
637 //                        * cos( fgGetDouble("/orientation/pitch-deg", 0.0)
638 //                                * SGD_DEGREES_TO_RADIANS);
639        // TODO:find the real view speed, not the AC one
640 //     sgEnviro.drawPrecipitation(
641 //         fgGetDouble("/environment/metar/rain-norm", 0.0),
642 //         fgGetDouble("/environment/metar/snow-norm", 0.0),
643 //         fgGetDouble("/environment/metar/hail-norm", 0.0),
644 //         current__view->getPitch_deg() + current__view->getPitchOffset_deg(),
645 //         current__view->getRoll_deg() + current__view->getRollOffset_deg(),
646 //         - current__view->getHeadingOffset_deg(),
647 //                current_view_origin_airspeed_horiz_kt
648 //                );
649
650     // OSGFIXME
651 //     if( is_internal )
652 //         shadows->endOfFrame();
653
654     // need to call the update visitor once
655     globals->get_aircraft_model()->select( true );
656     FGTileMgr::set_tile_filter( true );
657     mFrameStamp->setReferenceTime(globals->get_sim_time_sec());
658     mFrameStamp->setFrameNumber(1+mFrameStamp->getFrameNumber());
659     mFrameStamp->setCalendarTime(*globals->get_time_params()->getGmt());
660     sceneView->update();
661     sceneView->cull();
662     sceneView->draw();
663
664     glPushAttrib(GL_ALL_ATTRIB_BITS);
665     glPushClientAttrib(~0u);
666
667     // display HUD && Panel
668     glDisable( GL_FOG );
669     glDisable( GL_DEPTH_TEST );
670
671     fgCockpitUpdate(sceneView->getState());
672
673     FGInstrumentMgr *instr = static_cast<FGInstrumentMgr*>(globals->get_subsystem("instrumentation"));
674     HUD *hud = static_cast<HUD*>(instr->get_subsystem("hud"));
675     hud->draw(*sceneView->getState());
676
677     // update the panel subsystem
678     if ( globals->get_current_panel() != NULL )
679         globals->get_current_panel()->update(*sceneView->getState());
680     // We don't need a state here - can be safely removed when we can pick
681     // correctly
682     fgUpdate3DPanels();
683
684     if((fgGetBool("/sim/atc/enabled"))
685        || (fgGetBool("/sim/ai-traffic/enabled")))
686       globals->get_ATC_display()->update(delta_time_sec,
687                                          *sceneView->getState());
688
689     // We can do translucent menus, so why not. :-)
690     glDisable( GL_TEXTURE_2D ) ;
691     glDisable( GL_CULL_FACE ) ;
692     glEnable( GL_BLEND ) ;
693     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
694     puDisplay();
695
696     // Fade out the splash screen over the first three seconds.
697     double t = globals->get_sim_time_sec();
698     if (t <= 2.5)
699         fgSplashUpdate((2.5 - t) / 2.5);
700
701     glPopClientAttrib();
702     glPopAttrib();
703 }
704
705
706
707 // options.cxx needs to see this for toggle_panel()
708 // Handle new window size or exposure
709 void
710 FGRenderer::resize( int width, int height ) {
711     int view_h;
712
713     if ( (!fgGetBool("/sim/virtual-cockpit"))
714          && fgPanelVisible() && idle_state == 1000 ) {
715         view_h = (int)(height * (globals->get_current_panel()->getViewHeight() -
716                              globals->get_current_panel()->getYOffset()) / 768.0);
717     } else {
718         view_h = height;
719     }
720
721     sceneView->getViewport()->setViewport(0, height - view_h, width, view_h);
722
723     static int lastwidth = 0;
724     static int lastheight = 0;
725     if (width != lastwidth)
726         fgSetInt("/sim/startup/xsize", lastwidth = width);
727     if (height != lastheight)
728         fgSetInt("/sim/startup/ysize", lastheight = height);
729
730     guiInitMouse(width, height);
731
732     // for all views
733     FGViewMgr *viewmgr = globals->get_viewmgr();
734     if (viewmgr) {
735       for ( int i = 0; i < viewmgr->size(); ++i ) {
736         viewmgr->get_view(i)->
737           set_aspect_ratio((float)view_h / (float)width);
738       }
739
740       setFOV( viewmgr->get_current_view()->get_h_fov(),
741               viewmgr->get_current_view()->get_v_fov() );
742       // cout << "setFOV(" << viewmgr->get_current_view()->get_h_fov()
743       //      << ", " << viewmgr->get_current_view()->get_v_fov() << ")"
744       //      << endl;
745     }
746 }
747
748
749 // These are wrapper functions around ssgSetNearFar() and ssgSetFOV()
750 // which will post process and rewrite the resulting frustum if we
751 // want to do asymmetric view frustums.
752
753 static void fgHackFrustum() {
754
755     // specify a percent of the configured view frustum to actually
756     // display.  This is a bit of a hack to achieve asymmetric view
757     // frustums.  For instance, if you want to display two monitors
758     // side by side, you could specify each with a double fov, a 0.5
759     // aspect ratio multiplier, and then the left side monitor would
760     // have a left_pct = 0.0, a right_pct = 0.5, a bottom_pct = 0.0,
761     // and a top_pct = 1.0.  The right side monitor would have a
762     // left_pct = 0.5 and a right_pct = 1.0.
763
764     static SGPropertyNode *left_pct
765         = fgGetNode("/sim/current-view/frustum-left-pct");
766     static SGPropertyNode *right_pct
767         = fgGetNode("/sim/current-view/frustum-right-pct");
768     static SGPropertyNode *bottom_pct
769         = fgGetNode("/sim/current-view/frustum-bottom-pct");
770     static SGPropertyNode *top_pct
771         = fgGetNode("/sim/current-view/frustum-top-pct");
772
773     double left, right;
774     double bottom, top;
775     double zNear, zFar;
776     sceneView->getProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);
777     // cout << " l = " << f->getLeft()
778     //      << " r = " << f->getRight()
779     //      << " b = " << f->getBot()
780     //      << " t = " << f->getTop()
781     //      << " n = " << f->getNear()
782     //      << " f = " << f->getFar()
783     //      << endl;
784
785     double width = right - left;
786     double height = top - bottom;
787
788     double l, r, t, b;
789
790     if ( left_pct != NULL ) {
791         l = left + width * left_pct->getDoubleValue();
792     } else {
793         l = left;
794     }
795
796     if ( right_pct != NULL ) {
797         r = left + width * right_pct->getDoubleValue();
798     } else {
799         r = right;
800     }
801
802     if ( bottom_pct != NULL ) {
803         b = bottom + height * bottom_pct->getDoubleValue();
804     } else {
805         b = bottom;
806     }
807
808     if ( top_pct != NULL ) {
809         t = bottom + height * top_pct->getDoubleValue();
810     } else {
811         t = top;
812     }
813
814     sceneView->setProjectionMatrixAsFrustum(l, r, b, t, zNear, zFar);
815 }
816
817
818 // we need some static storage space for these values.  However, we
819 // can't store it in a renderer class object because the functions
820 // that manipulate these are static.  They are static so they can
821 // interface to the display callback system.  There's probably a
822 // better way, there has to be a better way, but I'm not seeing it
823 // right now.
824 static float fov_width = 55.0;
825 static float fov_height = 42.0;
826 static float fov_near = 1.0;
827 static float fov_far = 1000.0;
828
829
830 /** FlightGear code should use this routine to set the FOV rather than
831  *  calling the ssg routine directly
832  */
833 void FGRenderer::setFOV( float w, float h ) {
834     fov_width = w;
835     fov_height = h;
836
837     sceneView->setProjectionMatrixAsPerspective(fov_height,
838                                                 fov_width/fov_height,
839                                                 fov_near, fov_far);
840     // fully specify the view frustum before hacking it (so we don't
841     // accumulate hacked effects
842     fgHackFrustum();
843 //     sgEnviro.setFOV( w, h );
844 }
845
846
847 /** FlightGear code should use this routine to set the Near/Far clip
848  *  planes rather than calling the ssg routine directly
849  */
850 void FGRenderer::setNearFar( float n, float f ) {
851 // OSGFIXME: we have currently too much z-buffer fights
852 n = 0.2;
853     fov_near = n;
854     fov_far = f;
855
856     sceneView->setProjectionMatrixAsPerspective(fov_height,
857                                                 fov_width/fov_height,
858                                                 fov_near, fov_far);
859
860     sceneView->getCamera()->setNearFarRatio(fov_near/fov_far);
861     mSceneCamera->setNearFarRatio(fov_near/fov_far);
862
863     // fully specify the view frustum before hacking it (so we don't
864     // accumulate hacked effects
865     fgHackFrustum();
866 }
867
868 bool FGRenderer::getPickInfo( SGVec3d& pt, SGVec3d& dir,
869                               unsigned x, unsigned y )
870 {
871   // Get the matrices involved in the transform from global to screen
872   // coordinates.
873   osg::Matrix pm = sceneView->getCamera()->getProjectionMatrix();
874
875   osg::Matrix mv;
876   osg::NodePathList paths;
877   paths = globals->get_scenery()->get_scene_graph()->getParentalNodePaths();
878   if (!paths.empty()) {
879     // Ok, we know that this should not have multiple parents ...
880     // FIXME: is this allways true?
881     mv = osg::computeLocalToEye(sceneView->getCamera()->getViewMatrix(),
882                                 paths.front(), false);
883   }
884   
885   // Compose and invert
886   osg::Matrix m = osg::Matrix::inverse(mv*pm);
887   
888   // Get the width and height of the display to be able to normalize the
889   // mouse coordinate
890   float width = fgGetInt("/sim/startup/xsize");
891   float height = fgGetInt("/sim/startup/ysize");
892   
893   // Compute some coordinates of in the line from the eyepoint to the
894   // mouse click coodinates.
895   // First build the normalized projection coordinates
896   osg::Vec4 normPt((2*x - width)/width, -(2*y - height)/height, 1, 1);
897   // Transform them into the real world
898   osg::Vec4 worldPt4 = m.preMult(normPt);
899   if (fabs(worldPt4[3]) < SGLimitsf::min())
900     return false;
901   SGVec3f worldPt(worldPt4[0]/worldPt4[3],
902                   worldPt4[1]/worldPt4[3],
903                   worldPt4[2]/worldPt4[3]);
904
905   // Now build a direction from the point
906   FGViewer* view = globals->get_current_view();
907   dir = normalize(toVec3d(worldPt - SGVec3f(view->get_view_pos())));
908
909   // Copy the start point
910   pt = SGVec3d(view->get_absolute_view_pos());
911
912   // OSGFIXME: ist this sufficient??? especially the precision problems here??
913 // bool mSceneView->projectWindowXYIntoObject(int x,int y,osg::Vec3& near_point,osg::Vec3& far_point) const;
914
915
916   return true;
917 }
918
919 // end of renderer.cxx
920