]> git.mxchange.org Git - flightgear.git/blob - src/Main/renderer.cxx
Cleanup of camera code in preperation for shadows
[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 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25
26 #ifdef HAVE_WINDOWS_H
27 #  include <windows.h>
28 #endif
29
30 #include <simgear/compiler.h>
31
32 #include <osg/ref_ptr>
33 #include <osg/AlphaFunc>
34 #include <osg/BlendFunc>
35 #include <osg/Camera>
36 #include <osg/CullFace>
37 #include <osg/Depth>
38 #include <osg/Fog>
39 #include <osg/Group>
40 #include <osg/Hint>
41 #include <osg/Light>
42 #include <osg/LightModel>
43 #include <osg/LightSource>
44 #include <osg/Material>
45 #include <osg/Math>
46 #include <osg/NodeCallback>
47 #include <osg/Notify>
48 #include <osg/PolygonMode>
49 #include <osg/PolygonOffset>
50 #include <osg/Version>
51 #include <osg/TexEnv>
52
53 #include <osgUtil/LineSegmentIntersector>
54
55 #include <osg/io_utils>
56 #include <osgDB/WriteFile>
57
58 #include <simgear/math/SGMath.hxx>
59 #include <simgear/screen/extensions.hxx>
60 #include <simgear/scene/material/matlib.hxx>
61 #include <simgear/scene/model/animation.hxx>
62 #include <simgear/scene/model/placement.hxx>
63 #include <simgear/scene/sky/sky.hxx>
64 #include <simgear/scene/util/SGUpdateVisitor.hxx>
65 #include <simgear/scene/util/RenderConstants.hxx>
66 #include <simgear/scene/tgdb/GroundLightManager.hxx>
67 #include <simgear/scene/tgdb/pt_lights.hxx>
68 #include <simgear/props/props.hxx>
69 #include <simgear/timing/sg_time.hxx>
70 #include <simgear/ephemeris/ephemeris.hxx>
71 #include <simgear/math/sg_random.h>
72 #ifdef FG_JPEG_SERVER
73 #include <simgear/screen/jpgfactory.hxx>
74 #endif
75
76 #include <simgear/environment/visual_enviro.hxx>
77
78 #include <Time/light.hxx>
79 #include <Time/light.hxx>
80 #include <Aircraft/aircraft.hxx>
81 #include <Cockpit/panel.hxx>
82 #include <Cockpit/cockpit.hxx>
83 #include <Cockpit/hud.hxx>
84 #include <Model/panelnode.hxx>
85 #include <Model/modelmgr.hxx>
86 #include <Model/acmodel.hxx>
87 #include <Scenery/scenery.hxx>
88 #include <Scenery/redout.hxx>
89 #include <Scenery/tilemgr.hxx>
90 #include <GUI/new_gui.hxx>
91 #include <Instrumentation/instrument_mgr.hxx>
92 #include <Instrumentation/HUD/HUD.hxx>
93 #include <Environment/precipitation_mgr.hxx>
94
95 #include <Include/general.hxx>
96 #include "splash.hxx"
97 #include "renderer.hxx"
98 #include "main.hxx"
99 #include "CameraGroup.hxx"
100 #include "FGEventHandler.hxx"
101
102 // XXX Make this go away when OSG 2.2 is released.
103 #if (FG_OSG_VERSION >= 21004)
104 #define UPDATE_VISITOR_IN_VIEWER 1
105 #endif
106
107 using namespace osg;
108 using namespace simgear;
109 using namespace flightgear;
110
111 class FGHintUpdateCallback : public osg::StateAttribute::Callback {
112 public:
113   FGHintUpdateCallback(const char* configNode) :
114     mConfigNode(fgGetNode(configNode, true))
115   { }
116   virtual void operator()(osg::StateAttribute* stateAttribute,
117                           osg::NodeVisitor*)
118   {
119     assert(dynamic_cast<osg::Hint*>(stateAttribute));
120     osg::Hint* hint = static_cast<osg::Hint*>(stateAttribute);
121
122     const char* value = mConfigNode->getStringValue();
123     if (!value)
124       hint->setMode(GL_DONT_CARE);
125     else if (0 == strcmp(value, "nicest"))
126       hint->setMode(GL_NICEST);
127     else if (0 == strcmp(value, "fastest"))
128       hint->setMode(GL_FASTEST);
129     else
130       hint->setMode(GL_DONT_CARE);
131   }
132 private:
133   SGSharedPtr<SGPropertyNode> mConfigNode;
134 };
135
136
137 class SGPuDrawable : public osg::Drawable {
138 public:
139   SGPuDrawable()
140   {
141     // Dynamic stuff, do not store geometry
142     setUseDisplayList(false);
143
144     osg::StateSet* stateSet = getOrCreateStateSet();
145     stateSet->setRenderBinDetails(1001, "RenderBin");
146     // speed optimization?
147     stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
148     // We can do translucent menus, so why not. :-)
149     stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
150     stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
151     stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
152
153     stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
154
155     stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
156     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
157   }
158   virtual void drawImplementation(osg::RenderInfo& renderInfo) const
159   { drawImplementation(*renderInfo.getState()); }
160   void drawImplementation(osg::State& state) const
161   {
162     state.setActiveTextureUnit(0);
163     state.setClientActiveTextureUnit(0);
164
165     state.disableAllVertexArrays();
166
167     glPushAttrib(GL_ALL_ATTRIB_BITS);
168     glPushClientAttrib(~0u);
169
170     puDisplay();
171
172     glPopClientAttrib();
173     glPopAttrib();
174   }
175
176   virtual osg::Object* cloneType() const { return new SGPuDrawable; }
177   virtual osg::Object* clone(const osg::CopyOp&) const { return new SGPuDrawable; }
178   
179 private:
180 };
181
182 class SGHUDAndPanelDrawable : public osg::Drawable {
183 public:
184   SGHUDAndPanelDrawable()
185   {
186     // Dynamic stuff, do not store geometry
187     setUseDisplayList(false);
188
189     osg::StateSet* stateSet = getOrCreateStateSet();
190     stateSet->setRenderBinDetails(1000, "RenderBin");
191
192     // speed optimization?
193     stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
194     stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
195     stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
196     stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
197     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
198
199     stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
200   }
201   virtual void drawImplementation(osg::RenderInfo& renderInfo) const
202   { drawImplementation(*renderInfo.getState()); }
203   void drawImplementation(osg::State& state) const
204   {
205     state.setActiveTextureUnit(0);
206     state.setClientActiveTextureUnit(0);
207     state.disableAllVertexArrays();
208
209     glPushAttrib(GL_ALL_ATTRIB_BITS);
210     glPushClientAttrib(~0u);
211
212     fgCockpitUpdate(&state);
213
214     FGInstrumentMgr *instr = static_cast<FGInstrumentMgr*>(globals->get_subsystem("instrumentation"));
215     HUD *hud = static_cast<HUD*>(instr->get_subsystem("hud"));
216     hud->draw(state);
217
218     // update the panel subsystem
219     if ( globals->get_current_panel() != NULL )
220         globals->get_current_panel()->update(state);
221     // We don't need a state here - can be safely removed when we can pick
222     // correctly
223     fgUpdate3DPanels();
224
225     glPopClientAttrib();
226     glPopAttrib();
227
228   }
229
230   virtual osg::Object* cloneType() const { return new SGHUDAndPanelDrawable; }
231   virtual osg::Object* clone(const osg::CopyOp&) const { return new SGHUDAndPanelDrawable; }
232   
233 private:
234 };
235
236 class FGLightSourceUpdateCallback : public osg::NodeCallback {
237 public:
238   virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
239   {
240     assert(dynamic_cast<osg::LightSource*>(node));
241     osg::LightSource* lightSource = static_cast<osg::LightSource*>(node);
242     osg::Light* light = lightSource->getLight();
243     
244     FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
245     light->setAmbient(l->scene_ambient().osg());
246     light->setDiffuse(l->scene_diffuse().osg());
247     light->setSpecular(l->scene_specular().osg());
248     SGVec4f position(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2], 0);
249     light->setPosition(position.osg());
250     SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]);
251     light->setDirection(direction.osg());
252     light->setSpotExponent(0);
253     light->setSpotCutoff(180);
254     light->setConstantAttenuation(1);
255     light->setLinearAttenuation(0);
256     light->setQuadraticAttenuation(0);
257
258     traverse(node, nv);
259   }
260 };
261
262 class FGWireFrameModeUpdateCallback : public osg::StateAttribute::Callback {
263 public:
264   FGWireFrameModeUpdateCallback() :
265     mWireframe(fgGetNode("/sim/rendering/wireframe"))
266   { }
267   virtual void operator()(osg::StateAttribute* stateAttribute,
268                           osg::NodeVisitor*)
269   {
270     assert(dynamic_cast<osg::PolygonMode*>(stateAttribute));
271     osg::PolygonMode* polygonMode;
272     polygonMode = static_cast<osg::PolygonMode*>(stateAttribute);
273
274     if (mWireframe->getBoolValue())
275       polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
276                            osg::PolygonMode::LINE);
277     else
278       polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
279                            osg::PolygonMode::FILL);
280   }
281 private:
282   SGSharedPtr<SGPropertyNode> mWireframe;
283 };
284
285 class FGLightModelUpdateCallback : public osg::StateAttribute::Callback {
286 public:
287   FGLightModelUpdateCallback() :
288     mHighlights(fgGetNode("/sim/rendering/specular-highlight"))
289   { }
290   virtual void operator()(osg::StateAttribute* stateAttribute,
291                           osg::NodeVisitor*)
292   {
293     assert(dynamic_cast<osg::LightModel*>(stateAttribute));
294     osg::LightModel* lightModel;
295     lightModel = static_cast<osg::LightModel*>(stateAttribute);
296
297 #if 0
298     FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
299     lightModel->setAmbientIntensity(l->scene_ambient().osg());
300 #else
301     lightModel->setAmbientIntensity(osg::Vec4(0, 0, 0, 1));
302 #endif
303     lightModel->setTwoSided(true);
304     lightModel->setLocalViewer(false);
305
306     if (mHighlights->getBoolValue()) {
307       lightModel->setColorControl(osg::LightModel::SEPARATE_SPECULAR_COLOR);
308     } else {
309       lightModel->setColorControl(osg::LightModel::SINGLE_COLOR);
310     }
311   }
312 private:
313   SGSharedPtr<SGPropertyNode> mHighlights;
314 };
315
316 class FGFogEnableUpdateCallback : public osg::StateSet::Callback {
317 public:
318   FGFogEnableUpdateCallback() :
319     mFogEnabled(fgGetNode("/sim/rendering/fog"))
320   { }
321   virtual void operator()(osg::StateSet* stateSet, osg::NodeVisitor*)
322   {
323     if (strcmp(mFogEnabled->getStringValue(), "disabled") == 0) {
324       stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
325     } else {
326       stateSet->setMode(GL_FOG, osg::StateAttribute::ON);
327     }
328   }
329 private:
330   SGSharedPtr<SGPropertyNode> mFogEnabled;
331 };
332
333 class FGFogUpdateCallback : public osg::StateAttribute::Callback {
334 public:
335   virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
336   {
337     assert(dynamic_cast<SGUpdateVisitor*>(nv));
338     assert(dynamic_cast<osg::Fog*>(sa));
339     SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
340     osg::Fog* fog = static_cast<osg::Fog*>(sa);
341     fog->setMode(osg::Fog::EXP2);
342     fog->setColor(updateVisitor->getFogColor().osg());
343     fog->setDensity(updateVisitor->getFogExp2Density());
344   }
345 };
346
347 // update callback for the switch node guarding that splash
348 class FGScenerySwitchCallback : public osg::NodeCallback {
349 public:
350   virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
351   {
352     assert(dynamic_cast<osg::Switch*>(node));
353     osg::Switch* sw = static_cast<osg::Switch*>(node);
354
355     double t = globals->get_sim_time_sec();
356     bool enabled = 0 < t;
357     sw->setValue(0, enabled);
358     if (!enabled)
359       return;
360     traverse(node, nv);
361   }
362 };
363
364 // Sky structures
365 SGSky *thesky;
366
367 static osg::ref_ptr<osg::FrameStamp> mFrameStamp = new osg::FrameStamp;
368 static osg::ref_ptr<SGUpdateVisitor> mUpdateVisitor= new SGUpdateVisitor;
369
370 static osg::ref_ptr<osg::Group> mRealRoot = new osg::Group;
371
372 static osg::ref_ptr<osg::Group> mRoot = new osg::Group;
373
374 FGRenderer::FGRenderer()
375 {
376 #ifdef FG_JPEG_SERVER
377    jpgRenderFrame = FGRenderer::update;
378 #endif
379    eventHandler = new FGEventHandler;
380 }
381
382 FGRenderer::~FGRenderer()
383 {
384 #ifdef FG_JPEG_SERVER
385    jpgRenderFrame = NULL;
386 #endif
387 }
388
389 // Initialize various GL/view parameters
390 // XXX This should be called "preinit" or something, as it initializes
391 // critical parts of the scene graph in addition to the splash screen.
392 void
393 FGRenderer::splashinit( void ) {
394     osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
395     mRealRoot = dynamic_cast<osg::Group*>(viewer->getSceneData());
396     mRealRoot->addChild(fgCreateSplashNode());
397     mFrameStamp = viewer->getFrameStamp();
398     // Scene doesn't seem to pass the frame stamp to the update
399     // visitor automatically.
400     mUpdateVisitor->setFrameStamp(mFrameStamp.get());
401 #ifdef UPDATE_VISITOR_IN_VIEWER
402     viewer->setUpdateVisitor(mUpdateVisitor.get());
403 #else
404     osgViewer::Scene* scene = viewer->getScene();
405     scene->setUpdateVisitor(mUpdateVisitor.get());
406 #endif
407 }
408
409 void
410 FGRenderer::init( void )
411 {
412     osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
413     osg::initNotifyLevel();
414
415     // The number of polygon-offset "units" to place between layers.  In
416     // principle, one is supposed to be enough.  In practice, I find that
417     // my hardware/driver requires many more.
418     osg::PolygonOffset::setUnitsMultiplier(1);
419     osg::PolygonOffset::setFactorMultiplier(1);
420
421     // Go full screen if requested ...
422     if ( fgGetBool("/sim/startup/fullscreen") )
423         fgOSFullScreen();
424
425     viewer->getCamera()
426         ->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
427     
428     osg::StateSet* stateSet = mRoot->getOrCreateStateSet();
429
430     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
431     
432     stateSet->setAttribute(new osg::Depth(osg::Depth::LESS));
433     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
434
435     stateSet->setAttribute(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01));
436     stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
437     stateSet->setAttribute(new osg::BlendFunc);
438     stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
439
440     stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
441     
442     // this will be set below
443     stateSet->setMode(GL_NORMALIZE, osg::StateAttribute::OFF);
444
445     osg::Material* material = new osg::Material;
446     stateSet->setAttribute(material);
447     
448     stateSet->setTextureAttribute(0, new osg::TexEnv);
449     stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
450
451     osg::Hint* hint = new osg::Hint(GL_FOG_HINT, GL_DONT_CARE);
452     hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/fog"));
453     stateSet->setAttribute(hint);
454     hint = new osg::Hint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
455     hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/polygon-smooth"));
456     stateSet->setAttribute(hint);
457     hint = new osg::Hint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
458     hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/line-smooth"));
459     stateSet->setAttribute(hint);
460     hint = new osg::Hint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
461     hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/point-smooth"));
462     stateSet->setAttribute(hint);
463     hint = new osg::Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
464     hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/perspective-correction"));
465     stateSet->setAttribute(hint);
466
467     osg::Group* sceneGroup = new osg::Group;
468     sceneGroup->addChild(globals->get_scenery()->get_scene_graph());
469     sceneGroup->setNodeMask(~simgear::BACKGROUND_BIT);
470
471     //sceneGroup->addChild(thesky->getCloudRoot());
472
473     stateSet = sceneGroup->getOrCreateStateSet();
474     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
475
476     // need to update the light on every frame
477     osg::LightSource* lightSource = new osg::LightSource;
478     lightSource->setUpdateCallback(new FGLightSourceUpdateCallback);
479     // relative because of CameraView being just a clever transform node
480     lightSource->setReferenceFrame(osg::LightSource::RELATIVE_RF);
481     lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
482     
483     lightSource->addChild(sceneGroup);
484     lightSource->addChild(thesky->getPreRoot());
485     mRoot->addChild(lightSource);
486
487     stateSet = globals->get_scenery()->get_scene_graph()->getOrCreateStateSet();
488     stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
489     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
490     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
491
492     // enable disable specular highlights.
493     // is the place where we might plug in an other fragment shader ...
494     osg::LightModel* lightModel = new osg::LightModel;
495     lightModel->setUpdateCallback(new FGLightModelUpdateCallback);
496     stateSet->setAttribute(lightModel);
497
498     // switch to enable wireframe
499     osg::PolygonMode* polygonMode = new osg::PolygonMode;
500     polygonMode->setUpdateCallback(new FGWireFrameModeUpdateCallback);
501     stateSet->setAttributeAndModes(polygonMode);
502
503     // scene fog handling
504     osg::Fog* fog = new osg::Fog;
505     fog->setUpdateCallback(new FGFogUpdateCallback);
506     stateSet->setAttributeAndModes(fog);
507     stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
508
509     // plug in the GUI
510     osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
511     if (guiCamera) {
512         osg::Geode* geode = new osg::Geode;
513         geode->addDrawable(new SGPuDrawable);
514         geode->addDrawable(new SGHUDAndPanelDrawable);
515         guiCamera->addChild(geode);
516     }
517     osg::Switch* sw = new osg::Switch;
518     sw->setUpdateCallback(new FGScenerySwitchCallback);
519     sw->addChild(mRoot.get());
520     mRealRoot->addChild(sw);
521     mRealRoot->addChild(thesky->getCloudRoot());
522     mRealRoot->addChild(FGCreateRedoutNode());
523 }
524
525
526 // Update all Visuals (redraws anything graphics related)
527 void
528 FGRenderer::update( bool refresh_camera_settings ) {
529     bool scenery_loaded = fgGetBool("sim/sceneryloaded")
530                           || fgGetBool("sim/sceneryloaded-override");
531     osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
532     if ( idle_state < 1000 || !scenery_loaded ) {
533         fgSetDouble("/sim/startup/splash-alpha", 1.0);
534
535         // Keep resetting sim time while the sim is initializing
536         // the splash screen is now in the scenegraph
537         globals->set_sim_time_sec( 0.0 );
538         return;
539     }
540
541     // Fade out the splash screen over the first three seconds.
542     double sAlpha = SGMiscd::max(0, (2.5 - globals->get_sim_time_sec()) / 2.5);
543     fgSetDouble("/sim/startup/splash-alpha", sAlpha);
544
545     bool skyblend = fgGetBool("/sim/rendering/skyblend");
546     bool use_point_sprites = fgGetBool("/sim/rendering/point-sprites");
547     bool enhanced_lighting = fgGetBool("/sim/rendering/enhanced-lighting");
548     bool distance_attenuation
549         = fgGetBool("/sim/rendering/distance-attenuation");
550     // OSGFIXME
551     SGConfigureDirectionalLights( use_point_sprites, enhanced_lighting,
552                                   distance_attenuation );
553
554     static const SGPropertyNode *groundlevel_nearplane
555         = fgGetNode("/sim/current-view/ground-level-nearplane-m");
556
557     FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
558
559     // update fog params
560     double actual_visibility;
561     if (fgGetBool("/environment/clouds/status")) {
562         actual_visibility = thesky->get_visibility();
563     } else {
564         actual_visibility = fgGetDouble("/environment/visibility-m");
565     }
566
567     // idle_state is now 1000 meaning we've finished all our
568     // initializations and are running the main loop, so this will
569     // now work without seg faulting the system.
570
571     FGViewer *current__view = globals->get_current_view();
572     // Force update of center dependent values ...
573     current__view->set_dirty();
574
575     if ( refresh_camera_settings ) {
576         // update view port
577         resize( fgGetInt("/sim/startup/xsize"),
578                 fgGetInt("/sim/startup/ysize") );
579     }
580     osg::Camera *camera = viewer->getCamera();
581
582     if ( skyblend ) {
583         
584         if ( fgGetBool("/sim/rendering/textures") ) {
585             SGVec4f clearColor(l->adj_fog_color());
586             camera->setClearColor(clearColor.osg());
587         }
588     } else {
589         SGVec4f clearColor(l->sky_color());
590         camera->setClearColor(clearColor.osg());
591     }
592
593     // update fog params if visibility has changed
594     double visibility_meters = fgGetDouble("/environment/visibility-m");
595     thesky->set_visibility(visibility_meters);
596
597     thesky->modify_vis( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER,
598                         ( global_multi_loop * fgGetInt("/sim/speed-up") )
599                         / (double)fgGetInt("/sim/model-hz") );
600
601     // update the sky dome
602     if ( skyblend ) {
603
604         // The sun and moon distances are scaled down versions
605         // of the actual distance to get both the moon and the sun
606         // within the range of the far clip plane.
607         // Moon distance:    384,467 kilometers
608         // Sun distance: 150,000,000 kilometers
609
610         double sun_horiz_eff, moon_horiz_eff;
611         if (fgGetBool("/sim/rendering/horizon-effect")) {
612             sun_horiz_eff
613                 = 0.67 + pow(osg::clampAbove(0.5 + cos(l->get_sun_angle()),
614                                              0.0),
615                              0.33) / 3.0;
616             moon_horiz_eff
617                 = 0.67 + pow(osg::clampAbove(0.5 + cos(l->get_moon_angle()),
618                                              0.0),
619                              0.33)/3.0;
620         } else {
621            sun_horiz_eff = moon_horiz_eff = 1.0;
622         }
623
624         static SGSkyState sstate;
625
626         sstate.view_pos  = toVec3f(current__view->get_view_pos());
627         sstate.zero_elev = toVec3f(current__view->get_zero_elev());
628         sstate.view_up   = current__view->get_world_up();
629         sstate.lon       = current__view->getLongitude_deg()
630                             * SGD_DEGREES_TO_RADIANS;
631         sstate.lat       = current__view->getLatitude_deg()
632                             * SGD_DEGREES_TO_RADIANS;
633         sstate.alt       = current__view->getAltitudeASL_ft()
634                             * SG_FEET_TO_METER;
635         sstate.spin      = l->get_sun_rotation();
636         sstate.gst       = globals->get_time_params()->getGst();
637         sstate.sun_ra    = globals->get_ephem()->getSunRightAscension();
638         sstate.sun_dec   = globals->get_ephem()->getSunDeclination();
639         sstate.sun_dist  = 50000.0 * sun_horiz_eff;
640         sstate.moon_ra   = globals->get_ephem()->getMoonRightAscension();
641         sstate.moon_dec  = globals->get_ephem()->getMoonDeclination();
642         sstate.moon_dist = 40000.0 * moon_horiz_eff;
643         sstate.sun_angle = l->get_sun_angle();
644
645
646         /*
647          SG_LOG( SG_GENERAL, SG_BULK, "thesky->repaint() sky_color = "
648          << l->sky_color()[0] << " "
649          << l->sky_color()[1] << " "
650          << l->sky_color()[2] << " "
651          << l->sky_color()[3] );
652         SG_LOG( SG_GENERAL, SG_BULK, "    fog = "
653          << l->fog_color()[0] << " "
654          << l->fog_color()[1] << " "
655          << l->fog_color()[2] << " "
656          << l->fog_color()[3] );
657         SG_LOG( SG_GENERAL, SG_BULK,
658                 "    sun_angle = " << l->sun_angle
659          << "    moon_angle = " << l->moon_angle );
660         */
661
662         static SGSkyColor scolor;
663
664         scolor.sky_color   = SGVec3f(l->sky_color().data());
665         scolor.fog_color   = SGVec3f(l->adj_fog_color().data());
666         scolor.cloud_color = SGVec3f(l->cloud_color().data());
667         scolor.sun_angle   = l->get_sun_angle();
668         scolor.moon_angle  = l->get_moon_angle();
669         scolor.nplanets    = globals->get_ephem()->getNumPlanets();
670         scolor.nstars      = globals->get_ephem()->getNumStars();
671         scolor.planet_data = globals->get_ephem()->getPlanets();
672         scolor.star_data   = globals->get_ephem()->getStars();
673
674         thesky->reposition( sstate, delta_time_sec );
675         thesky->repaint( scolor );
676
677         /*
678         SG_LOG( SG_GENERAL, SG_BULK,
679                 "thesky->reposition( view_pos = " << view_pos[0] << " "
680          << view_pos[1] << " " << view_pos[2] );
681         SG_LOG( SG_GENERAL, SG_BULK,
682                 "    zero_elev = " << zero_elev[0] << " "
683          << zero_elev[1] << " " << zero_elev[2]
684          << " lon = " << cur_fdm_state->get_Longitude()
685          << " lat = " << cur_fdm_state->get_Latitude() );
686         SG_LOG( SG_GENERAL, SG_BULK,
687                 "    sun_rot = " << l->get_sun_rotation
688          << " gst = " << SGTime::cur_time_params->getGst() );
689         SG_LOG( SG_GENERAL, SG_BULK,
690              "    sun ra = " << globals->get_ephem()->getSunRightAscension()
691           << " sun dec = " << globals->get_ephem()->getSunDeclination()
692           << " moon ra = " << globals->get_ephem()->getMoonRightAscension()
693           << " moon dec = " << globals->get_ephem()->getMoonDeclination() );
694         */
695
696         //OSGFIXME
697 //         shadows->setupShadows(
698 //           current__view->getLongitude_deg(),
699 //           current__view->getLatitude_deg(),
700 //           globals->get_time_params()->getGst(),
701 //           globals->get_ephem()->getSunRightAscension(),
702 //           globals->get_ephem()->getSunDeclination(),
703 //           l->get_sun_angle());
704
705     }
706
707 //     sgEnviro.setLight(l->adj_fog_color());
708 //     sgEnviro.startOfFrame(current__view->get_view_pos(), 
709 //         current__view->get_world_up(),
710 //         current__view->getLongitude_deg(),
711 //         current__view->getLatitude_deg(),
712 //         current__view->getAltitudeASL_ft() * SG_FEET_TO_METER,
713 //         delta_time_sec);
714
715     // OSGFIXME
716 //     sgEnviro.drawLightning();
717
718 //        double current_view_origin_airspeed_horiz_kt =
719 //         fgGetDouble("/velocities/airspeed-kt", 0.0)
720 //                        * cos( fgGetDouble("/orientation/pitch-deg", 0.0)
721 //                                * SGD_DEGREES_TO_RADIANS);
722
723     // OSGFIXME
724 //     if( is_internal )
725 //         shadows->endOfFrame();
726
727     // need to call the update visitor once
728     mFrameStamp->setCalendarTime(*globals->get_time_params()->getGmt());
729     mUpdateVisitor->setViewData(current__view->getViewPosition(),
730                                 current__view->getViewOrientation());
731     SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]);
732     mUpdateVisitor->setLight(direction, l->scene_ambient(),
733                              l->scene_diffuse(), l->scene_specular(),
734                              l->adj_fog_color(),
735                              l->get_sun_angle()*SGD_RADIANS_TO_DEGREES);
736     mUpdateVisitor->setVisibility(actual_visibility);
737     simgear::GroundLightManager::instance()->update(mUpdateVisitor.get());
738     bool hotspots = fgGetBool("/sim/panel-hotspots");
739     osg::Node::NodeMask cullMask = ~simgear::LIGHTS_BITS & ~simgear::PICK_BIT;
740     cullMask |= simgear::GroundLightManager::instance()
741         ->getLightNodeMask(mUpdateVisitor.get());
742     if (hotspots)
743         cullMask |= simgear::PICK_BIT;
744     CameraGroup::getDefault()->setCameraCullMasks(cullMask);
745 }
746
747
748
749 // options.cxx needs to see this for toggle_panel()
750 // Handle new window size or exposure
751 void
752 FGRenderer::resize( int width, int height ) {
753     int view_h;
754
755     if ( (!fgGetBool("/sim/virtual-cockpit"))
756          && fgPanelVisible() && idle_state == 1000 ) {
757         view_h = (int)(height * (globals->get_current_panel()->getViewHeight() -
758                              globals->get_current_panel()->getYOffset()) / 768.0);
759     } else {
760         view_h = height;
761     }
762
763     static int lastwidth = 0;
764     static int lastheight = 0;
765     if (width != lastwidth)
766         fgSetInt("/sim/startup/xsize", lastwidth = width);
767     if (height != lastheight)
768         fgSetInt("/sim/startup/ysize", lastheight = height);
769
770     // for all views
771     FGViewMgr *viewmgr = globals->get_viewmgr();
772     if (viewmgr) {
773       for ( int i = 0; i < viewmgr->size(); ++i ) {
774         viewmgr->get_view(i)->
775           set_aspect_ratio((float)view_h / (float)width);
776       }
777     }
778 }
779
780 void FGRenderer::setCameraParameters(float vfov, float aspectRatio,
781                                      float zNear, float zFar)
782 {
783     zNear = .1;
784     osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
785     viewer->getCamera()->setProjectionMatrixAsPerspective(vfov,
786                                                           1.0f / aspectRatio,
787                                                           zNear, zFar);
788     
789 }
790 bool
791 FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
792                  const osgGA::GUIEventAdapter* ea)
793 {
794     osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
795     // wipe out the return ...
796     pickList.clear();
797     typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
798     Intersections intersections;
799
800     if (!computeIntersections(CameraGroup::getDefault(), ea, intersections))
801         return false;
802     for (Intersections::iterator hit = intersections.begin(),
803              e = intersections.end();
804          hit != e;
805          ++hit) {
806         const osg::NodePath& np = hit->nodePath;
807         osg::NodePath::const_reverse_iterator npi;
808         for (npi = np.rbegin(); npi != np.rend(); ++npi) {
809             SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi);
810             if (!ud)
811                 continue;
812             for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) {
813                 SGPickCallback* pickCallback = ud->getPickCallback(i);
814                 if (!pickCallback)
815                     continue;
816                 SGSceneryPick sceneryPick;
817                 sceneryPick.info.local = SGVec3d(hit->getLocalIntersectPoint());
818                 sceneryPick.info.wgs84 = SGVec3d(hit->getWorldIntersectPoint());
819                 sceneryPick.callback = pickCallback;
820                 pickList.push_back(sceneryPick);
821             }
822         }
823     }
824     return !pickList.empty();
825 }
826
827 void
828 FGRenderer::setViewer(osgViewer::Viewer* viewer_)
829 {
830     viewer = viewer_;
831 }
832
833 void
834 FGRenderer::setEventHandler(FGEventHandler* eventHandler_)
835 {
836     eventHandler = eventHandler_;
837 }
838
839 void
840 FGRenderer::addCamera(osg::Camera* camera, bool useSceneData)
841 {
842     mRealRoot->addChild(camera);
843 }
844
845 bool
846 fgDumpSceneGraphToFile(const char* filename)
847 {
848     return osgDB::writeNodeFile(*mRealRoot.get(), filename);
849 }
850
851 bool
852 fgDumpTerrainBranchToFile(const char* filename)
853 {
854     return osgDB::writeNodeFile( *globals->get_scenery()->get_terrain_branch(),
855                                  filename );
856 }
857
858 // For debugging
859 bool
860 fgDumpNodeToFile(osg::Node* node, const char* filename)
861 {
862     return osgDB::writeNodeFile(*node, filename);
863 }
864 // end of renderer.cxx
865