glPopClientAttrib();
glPopAttrib();
- // Fade out the splash screen over the first three seconds.
- double t = globals->get_sim_time_sec();
- if (t <= 2.5) {
- glPushAttrib(GL_ALL_ATTRIB_BITS);
- glPushClientAttrib(~0u);
-
- fgSplashUpdate((2.5 - t) / 2.5);
-
- glPopClientAttrib();
- glPopAttrib();
- } else {
- fgSplashExit();
- }
-
state.popStateSet();
state.dirtyAllModes();
state.dirtyAllAttributes();
SGSharedPtr<SGPropertyNode> mFogEnabled;
};
+// update callback for the switch node guarding that splash
+class FGScenerySwitchCallback : public osg::NodeCallback {
+public:
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+ {
+ assert(dynamic_cast<osg::Switch*>(node));
+ osg::Switch* sw = static_cast<osg::Switch*>(node);
+
+ double t = globals->get_sim_time_sec();
+ bool enabled = 0 < t;
+ sw->setValue(0, enabled);
+ if (!enabled)
+ return;
+ traverse(node, nv);
+ }
+};
+
// fog constants. I'm a little nervous about putting actual code out
// here but it seems to work (?)
static const double m_log01 = -log( 0.01 );
static osg::ref_ptr<osg::FrameStamp> mFrameStamp = new osg::FrameStamp;
static osg::ref_ptr<SGUpdateVisitor> mUpdateVisitor= new SGUpdateVisitor;
+static osg::ref_ptr<osg::Group> mRealRoot = new osg::Group;
+
static osg::ref_ptr<osg::Group> mRoot = new osg::Group;
static osg::ref_ptr<osg::CameraView> mCameraView = new osg::CameraView;
}
// Initialize various GL/view parameters
+void
+FGRenderer::splashinit( void ) {
+ // Add the splash screen node
+ mRealRoot->addChild(fgCreateSplashNode());
+ sceneView->setSceneData(mRealRoot.get());
+
+ sceneView->setDefaults(osgUtil::SceneView::COMPILE_GLOBJECTS_AT_INIT);
+ sceneView->setFrameStamp(mFrameStamp.get());
+ sceneView->setUpdateVisitor(mUpdateVisitor.get());
+}
+
void
FGRenderer::init( void ) {
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
- sceneView->setDefaults(osgUtil::SceneView::COMPILE_GLOBJECTS_AT_INIT);
-
mFog->setMode(osg::Fog::EXP2);
mRunwayLightingFog->setMode(osg::Fog::EXP2);
mTaxiLightingFog->setMode(osg::Fog::EXP2);
mGroundLightingFog->setMode(osg::Fog::EXP2);
- sceneView->setFrameStamp(mFrameStamp.get());
-
- mUpdateVisitor = new SGUpdateVisitor;
- sceneView->setUpdateVisitor(mUpdateVisitor.get());
-
sceneView->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
sceneView->getCamera()->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
guiCamera->setInheritanceMask(inheritanceMask);
guiCamera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
guiCamera->setCullingMode(osg::CullSettings::NO_CULLING);
- mRoot->addChild(guiCamera);
osg::Geode* geode = new osg::Geode;
geode->addDrawable(new SGPuDrawable);
geode->addDrawable(new SGHUDAndPanelDrawable);
stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
mCameraView->addChild(mRoot.get());
- sceneView->setSceneData(mCameraView.get());
-// sceneView->getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE);
+ osg::Switch* sw = new osg::Switch;
+ sw->setUpdateCallback(new FGScenerySwitchCallback);
+ sw->addChild(mCameraView.get());
+
+ mRealRoot->addChild(sw);
+ mRealRoot->addChild(guiCamera);
}
|| fgGetBool("sim/sceneryloaded-override");
if ( idle_state < 1000 || !scenery_loaded ) {
- if (sceneView.valid() && sceneView->getState()) {
- sceneView->getState()->setActiveTextureUnit(0);
- sceneView->getState()->setClientActiveTextureUnit(0);
- sceneView->getState()->disableAllVertexArrays();
- }
- // still initializing, draw the splash screen
- glPushAttrib(GL_ALL_ATTRIB_BITS);
- glPushClientAttrib(~0u);
-
- fgSplashUpdate(1.0);
-
- glPopClientAttrib();
- glPopAttrib();
+ fgSetDouble("/sim/startup/splash-alpha", 1.0);
// Keep resetting sim time while the sim is initializing
globals->set_sim_time_sec( 0.0 );
+
+ // the splash screen is now in the scenegraph
+ sceneView->update();
+ sceneView->cull();
+ sceneView->draw();
+
return;
}
+ // Fade out the splash screen over the first three seconds.
+ double sAlpha = SGMiscd::max(0, (2.5 - globals->get_sim_time_sec()) / 2.5);
+ fgSetDouble("/sim/startup/splash-alpha", sAlpha);
+
bool skyblend = fgGetBool("/sim/rendering/skyblend");
bool use_point_sprites = fgGetBool("/sim/rendering/point-sprites");
bool enhanced_lighting = fgGetBool("/sim/rendering/enhanced-lighting");
# include <config.h>
#endif
-#ifdef SG_MATH_EXCEPTION_CLASH
-# include <math.h>
-#endif
-
-#ifdef HAVE_WINDOWS_H
-# include <windows.h>
-#endif
-
-#include <string.h>
+#include <osg/BlendFunc>
+#include <osg/Camera>
+#include <osg/Depth>
+#include <osg/Geometry>
+#include <osg/Node>
+#include <osg/NodeCallback>
+#include <osg/NodeVisitor>
+#include <osg/StateSet>
+#include <osg/Switch>
+#include <osg/Texture2D>
+#include <osgUtil/CullVisitor>
+#include <osgText/Text>
+#include <osgDB/ReadFile>
-#include <plib/pu.h>
#include <simgear/compiler.h>
-#include SG_GLU_H
-
#include <simgear/debug/logstream.hxx>
-#include <simgear/screen/texture.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/misc/sg_path.hxx>
#include "globals.hxx"
#include "fg_props.hxx"
#include "splash.hxx"
-#include "fg_os.hxx"
#include "renderer.hxx"
+#include "fg_os.hxx"
-static const char *progress_text = 0;
-static SGTexture *splash = new SGTexture;
-SGPropertyNode_ptr style = 0;
-
-
-// Initialize the splash screen
-void fgSplashInit ( const char *splash_texture ) {
- fgRequestRedraw();
-
- SG_LOG( SG_GENERAL, SG_INFO, "Initializing splash screen" );
-
- style = fgGetNode("/sim/gui/style[0]", true);
-
- if (!fgGetBool("/sim/startup/splash-screen"))
- return;
-
- splash->bind();
-
- SGPath tpath( globals->get_fg_root() );
- if (splash_texture == NULL || !strcmp(splash_texture, "")) {
- // load in the texture data
- int num = (int)(sg_random() * 5.0 + 1.0);
- char num_str[5];
- snprintf(num_str, 4, "%d", num);
-
- tpath.append( "Textures/Splash" );
- tpath.concat( num_str );
- tpath.concat( ".rgb" );
- } else
- tpath.append( splash_texture );
-
- splash->read_rgba_texture(tpath.c_str());
- if (!splash->usable())
- {
- // Try compressed
- SGPath fg_tpath = tpath;
- fg_tpath.concat( ".gz" );
-
- splash->read_rgba_texture(fg_tpath.c_str());
- if ( !splash->usable() )
- {
- SG_LOG( SG_GENERAL, SG_ALERT,
- "Error in loading splash screen texture " << tpath.str() );
- exit(-1);
- }
+class FGSplashUpdateCallback : public osg::Drawable::UpdateCallback {
+public:
+ FGSplashUpdateCallback(osg::Vec4Array* colorArray, SGPropertyNode* prop) :
+ _colorArray(colorArray),
+ _colorProperty(prop),
+ _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true))
+ { }
+ virtual void update(osg::NodeVisitor*, osg::Drawable*)
+ {
+ FGColor c(0, 0, 0);
+ if (_colorProperty) {
+ c.merge(_colorProperty);
+ (*_colorArray)[0][0] = c.red();
+ (*_colorArray)[0][1] = c.green();
+ (*_colorArray)[0][2] = c.blue();
+ }
+ (*_colorArray)[0][3] = _alphaProperty->getFloatValue();
+ _colorArray->dirty();
+ }
+private:
+ osg::ref_ptr<osg::Vec4Array> _colorArray;
+ SGSharedPtr<const SGPropertyNode> _colorProperty;
+ SGSharedPtr<const SGPropertyNode> _alphaProperty;
+};
+
+class FGSplashTextUpdateCallback : public osg::Drawable::UpdateCallback {
+public:
+ FGSplashTextUpdateCallback(const SGPropertyNode* prop) :
+ _textProperty(prop),
+ _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true)),
+ _styleProperty(fgGetNode("/sim/gui/style[0]", true))
+ {}
+ virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
+ {
+ assert(dynamic_cast<osgText::Text*>(drawable));
+ osgText::Text* text = static_cast<osgText::Text*>(drawable);
+
+ FGColor c(1.0, 0.9, 0.0);
+ c.merge(_styleProperty->getNode("colors/splash-font"));
+ float alpha = _alphaProperty->getFloatValue();
+ text->setColor(osg::Vec4(c.red(), c.green(), c.blue(), alpha));
+
+ const char* s = _textProperty->getStringValue();
+ if (s && fgGetBool("/sim/startup/splash-progress", true))
+ text->setText(s);
+ else
+ text->setText("");
+ }
+private:
+ SGSharedPtr<const SGPropertyNode> _textProperty;
+ SGSharedPtr<const SGPropertyNode> _alphaProperty;
+ SGSharedPtr<const SGPropertyNode> _styleProperty;
+};
+
+
+class FGSplashContentProjectionCalback : public osg::NodeCallback {
+public:
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+ {
+ assert(dynamic_cast<osgUtil::CullVisitor*>(nv));
+ osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
+
+ // adjust the projection matrix in a way that preserves the aspect ratio
+ // of the content ...
+ const osg::Viewport* viewport = cullVisitor->getViewport();
+ float viewportAspect = float(viewport->height())/float(viewport->width());
+
+ float height, width;
+ if (viewportAspect < 1) {
+ height = 1;
+ width = 1/viewportAspect;
+ } else {
+ height = viewportAspect;
+ width = 1;
}
- splash->select();
-}
+ osg::RefMatrix* matrix = new osg::RefMatrix;
+ matrix->makeOrtho2D(-width, width, -height, height);
+ // The trick is to have the projection matrix adapted independent
+ // of the scenegraph but dependent on the viewport of this current
+ // camera we cull for. Therefore we do not put that projection matrix into
+ // an additional camera rather than from within that cull callback.
+ cullVisitor->pushProjectionMatrix(matrix);
+ traverse(node, nv);
+ cullVisitor->popProjectionMatrix();
+ }
+};
-void fgSplashExit ()
+static osg::Node* fgCreateSplashCamera()
{
- delete splash;
- splash = 0;
+ const char* splash_texture = fgGetString("/sim/startup/splash-texture");
+ SGSharedPtr<SGPropertyNode> style = fgGetNode("/sim/gui/style[0]", true);
+
+ SGPath tpath( globals->get_fg_root() );
+ if (splash_texture == NULL || !strcmp(splash_texture, "")) {
+ // load in the texture data
+ int num = (int)(sg_random() * 5.0 + 1.0);
+ char num_str[5];
+ snprintf(num_str, 4, "%d", num);
+
+ tpath.append( "Textures/Splash" );
+ tpath.concat( num_str );
+ tpath.concat( ".rgb" );
+ } else
+ tpath.append( splash_texture );
+
+ osg::Texture2D* splashTexture = new osg::Texture2D;
+ splashTexture->setImage(osgDB::readImageFile(tpath.c_str()));
+
+ osg::Camera* camera = new osg::Camera;
+ camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+ camera->setProjectionMatrix(osg::Matrix::ortho2D(-1, 1, -1, 1));
+ camera->setViewMatrix(osg::Matrix::identity());
+ camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
+ camera->setClearMask(0);
+ camera->setAllowEventFocus(false);
+ camera->setCullingActive(false);
+
+ osg::StateSet* stateSet = camera->getOrCreateStateSet();
+ stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
+ stateSet->setAttribute(new osg::BlendFunc);
+ stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+ stateSet->setAttribute(new osg::Depth(osg::Depth::ALWAYS, 0, 1, false));
+ stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
+
+
+ osg::Geometry* geometry = new osg::Geometry;
+ geometry->setSupportsDisplayList(false);
+
+ osg::Vec3Array* vertexArray = new osg::Vec3Array;
+ vertexArray->push_back(osg::Vec3(-1, -1, 0));
+ vertexArray->push_back(osg::Vec3( 1, -1, 0));
+ vertexArray->push_back(osg::Vec3( 1, 1, 0));
+ vertexArray->push_back(osg::Vec3(-1, 1, 0));
+ geometry->setVertexArray(vertexArray);
+ osg::Vec4Array* colorArray = new osg::Vec4Array;
+ colorArray->push_back(osg::Vec4(0, 0, 0, 1));
+ geometry->setColorArray(colorArray);
+ geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+ geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
+ geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray,
+ style->getNode("colors/splash-screen")));
+
+ osg::Geode* geode = new osg::Geode;
+ geode->addDrawable(geometry);
+
+ stateSet = geode->getOrCreateStateSet();
+ stateSet->setRenderBinDetails(1, "RenderBin");
+ camera->addChild(geode);
+
+
+ // The group is needed because of osg is handling the cull callbacks in a
+ // different way for groups than for a geode. It does not hurt here ...
+ osg::Group* group = new osg::Group;
+ group->setCullCallback(new FGSplashContentProjectionCalback);
+ camera->addChild(group);
+
+ geode = new osg::Geode;
+ stateSet = geode->getOrCreateStateSet();
+ stateSet->setRenderBinDetails(2, "RenderBin");
+ group->addChild(geode);
+
+
+ geometry = new osg::Geometry;
+ geometry->setSupportsDisplayList(false);
+
+ vertexArray = new osg::Vec3Array;
+ vertexArray->push_back(osg::Vec3(-0.84, -0.84, 0));
+ vertexArray->push_back(osg::Vec3( 0.84, -0.84, 0));
+ vertexArray->push_back(osg::Vec3( 0.84, 0.84, 0));
+ vertexArray->push_back(osg::Vec3(-0.84, 0.84, 0));
+ geometry->setVertexArray(vertexArray);
+ osg::Vec2Array* texCoordArray = new osg::Vec2Array;
+ texCoordArray->push_back(osg::Vec2(0, 0));
+ texCoordArray->push_back(osg::Vec2(1, 0));
+ texCoordArray->push_back(osg::Vec2(1, 1));
+ texCoordArray->push_back(osg::Vec2(0, 1));
+ geometry->setTexCoordArray(0, texCoordArray);
+ colorArray = new osg::Vec4Array;
+ colorArray->push_back(osg::Vec4(1, 1, 1, 1));
+ geometry->setColorArray(colorArray);
+ geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+ geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
+ geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray, 0));
+ stateSet = geometry->getOrCreateStateSet();
+ stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
+ stateSet->setTextureAttribute(0, splashTexture);
+ geode->addDrawable(geometry);
+
+
+ osgText::Text* text = new osgText::Text;
+ std::string fn = style->getStringValue("fonts/splash", "");
+ text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
+ text->setCharacterSize(0.06);
+ text->setColor(osg::Vec4(1, 1, 1, 1));
+ text->setPosition(osg::Vec3(0, -0.92, 0));
+ text->setAlignment(osgText::Text::CENTER_CENTER);
+ SGPropertyNode* prop = fgGetNode("/sim/startup/splash-progress-text", true);
+ text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
+ geode->addDrawable(text);
+
+ text = new osgText::Text;
+ text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
+ text->setCharacterSize(0.06);
+ text->setColor(osg::Vec4(1, 1, 1, 1));
+ text->setPosition(osg::Vec3(0, 0.92, 0));
+ text->setAlignment(osgText::Text::CENTER_CENTER);
+ prop = fgGetNode("/sim/startup/splash-title", true);
+ text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
+ geode->addDrawable(text);
+
+ return camera;
}
-
-void fgSplashProgress ( const char *s )
-{
- progress_text = s;
- fgRequestRedraw();
+// update callback for the switch node guarding that splash
+class FGSplashGroupUpdateCallback : public osg::NodeCallback {
+public:
+ FGSplashGroupUpdateCallback() :
+ _splashAlphaNode(fgGetNode("/sim/startup/splash-alpha", true))
+ { }
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+ {
+ assert(dynamic_cast<osg::Group*>(node));
+ osg::Group* group = static_cast<osg::Group*>(node);
+
+ double alpha = _splashAlphaNode->getDoubleValue();
+ if (alpha <= 0 || !fgGetBool("/sim/startup/splash-screen"))
+ group->removeChild(0, group->getNumChildren());
+ else if (group->getNumChildren() == 0)
+ group->addChild(fgCreateSplashCamera());
+
+ traverse(node, nv);
+ }
+private:
+ SGSharedPtr<const SGPropertyNode> _splashAlphaNode;
+};
+
+osg::Node* fgCreateSplashNode() {
+ osg::Group* group = new osg::Group;
+ group->setUpdateCallback(new FGSplashGroupUpdateCallback);
+ return group;
}
-
-// Update the splash screen with alpha specified from 0.0 to 1.0
-void fgSplashUpdate ( float alpha ) {
- const int EMPTYSPACE = 80;
-
- int screen_width = fgGetInt("/sim/startup/xsize", 0);
- int screen_height = fgGetInt("/sim/startup/ysize", 0);
-
- if (!screen_width || !screen_height)
- return;
-
- globals->get_renderer()->resize(screen_width, screen_height);
- int size = screen_width < (screen_height - EMPTYSPACE)
- ? screen_width : screen_height - EMPTYSPACE;
- if (size > 512)
- size = 512;
-
- int xmin, ymin, xmax, ymax;
- xmin = (screen_width - size) / 2;
- xmax = xmin + size;
-
- ymin = (screen_height - size) / 2;
- ymax = ymin + size;
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- gluOrtho2D(0, screen_width, 0, screen_height);
- glViewport(0, 0, screen_width, screen_height);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_LIGHTING);
- glDisable(GL_CULL_FACE);
-
- // draw the background
- FGColor c(0.0, 0.0, 0.0);
- c.merge(style->getNode("colors/splash-screen"));
- glColor4f(c.red(), c.green(), c.blue(), alpha );
- glBegin(GL_POLYGON);
- glVertex2f(0.0, 0.0);
- glVertex2f(screen_width, 0.0);
- glVertex2f(screen_width, screen_height);
- glVertex2f(0.0, screen_height);
- glEnd();
-
- glEnable(GL_ALPHA_TEST);
- glEnable(GL_BLEND);
- glAlphaFunc(GL_GREATER, 0.1f);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- // now draw the logo
- if (fgGetBool("/sim/startup/splash-screen", true)) {
- glEnable(GL_TEXTURE_2D);
- splash->bind();
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
- glColor4f( 1.0, 1.0, 1.0, alpha );
- glBegin(GL_POLYGON);
- glTexCoord2f(0.0, 0.0); glVertex2f(xmin, ymin);
- glTexCoord2f(1.0, 0.0); glVertex2f(xmax, ymin);
- glTexCoord2f(1.0, 1.0); glVertex2f(xmax, ymax);
- glTexCoord2f(0.0, 1.0); glVertex2f(xmin, ymax);
- glEnd();
- glDisable(GL_TEXTURE_2D);
- }
-
- if (progress_text && fgGetBool("/sim/startup/splash-progress", true)) {
- puFont *fnt = globals->get_fontcache()->get(style->getNode("fonts/splash"));
-
- FGColor c(1.0, 0.9, 0.0);
- c.merge(style->getNode("colors/splash-font"));
- glColor4f(c.red(), c.green(), c.blue(), alpha);
-
- float height = fnt->getStringHeight("/M$");
- float descender = fnt->getStringDescender();
- float width = fnt->getFloatStringWidth(progress_text);
- fnt->drawString(progress_text, int((screen_width - width) / 2), int(10 + descender));
-
- const char *title = fgGetString("/sim/startup/splash-title", "");
- width = fnt->getFloatStringWidth(title);
- fnt->drawString(title, int((screen_width - width) / 2), int(screen_height - 10 - height));
- }
-
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_LIGHTING);
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
+// Initialize the splash screen
+void fgSplashInit () {
+ SG_LOG( SG_GENERAL, SG_INFO, "Initializing splash screen" );
+ globals->get_renderer()->splashinit();
+ fgRequestRedraw();
}
-
+void fgSplashProgress ( const char *text ) {
+ SG_LOG( SG_GENERAL, SG_INFO, "Splash screen progress " << text );
+ fgSetString("/sim/startup/splash-progress-text", text);
+ fgRequestRedraw();
+}