1 // splash.cxx -- draws the initial splash screen
3 // Written by Curtis Olson, started July 1998. (With a little looking
4 // at Freidemann's panel code.) :-)
6 // Copyright (C) 1997 Michele F. America - nomimarketing@mail.telepac.pt
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.
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.
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.
29 #include <osg/BlendFunc>
32 #include <osg/Geometry>
34 #include <osg/NodeCallback>
35 #include <osg/NodeVisitor>
36 #include <osg/StateSet>
38 #include <osg/Texture2D>
39 #include <osgUtil/CullVisitor>
40 #include <osgText/Text>
41 #include <osgDB/ReadFile>
43 #include <simgear/compiler.h>
45 #include <simgear/debug/logstream.hxx>
46 #include <simgear/math/sg_random.h>
47 #include <simgear/misc/sg_path.hxx>
49 #include <GUI/new_gui.hxx>
51 #include "globals.hxx"
52 #include "fg_props.hxx"
54 #include "renderer.hxx"
57 class FGSplashUpdateCallback : public osg::Drawable::UpdateCallback {
59 FGSplashUpdateCallback(osg::Vec4Array* colorArray, SGPropertyNode* prop) :
60 _colorArray(colorArray),
62 _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true))
64 virtual void update(osg::NodeVisitor*, osg::Drawable*)
68 c.merge(_colorProperty);
69 (*_colorArray)[0][0] = c.red();
70 (*_colorArray)[0][1] = c.green();
71 (*_colorArray)[0][2] = c.blue();
73 (*_colorArray)[0][3] = _alphaProperty->getFloatValue();
77 osg::ref_ptr<osg::Vec4Array> _colorArray;
78 SGSharedPtr<const SGPropertyNode> _colorProperty;
79 SGSharedPtr<const SGPropertyNode> _alphaProperty;
82 class FGSplashTextUpdateCallback : public osg::Drawable::UpdateCallback {
84 FGSplashTextUpdateCallback(const SGPropertyNode* prop) :
86 _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true)),
87 _styleProperty(fgGetNode("/sim/gui/style[0]", true))
89 virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
91 assert(dynamic_cast<osgText::Text*>(drawable));
92 osgText::Text* text = static_cast<osgText::Text*>(drawable);
94 FGColor c(1.0, 0.9, 0.0);
95 c.merge(_styleProperty->getNode("colors/splash-font"));
96 float alpha = _alphaProperty->getFloatValue();
97 text->setColor(osg::Vec4(c.red(), c.green(), c.blue(), alpha));
99 const char* s = _textProperty->getStringValue();
100 if (s && fgGetBool("/sim/startup/splash-progress", true))
106 SGSharedPtr<const SGPropertyNode> _textProperty;
107 SGSharedPtr<const SGPropertyNode> _alphaProperty;
108 SGSharedPtr<const SGPropertyNode> _styleProperty;
113 class FGSplashContentProjectionCalback : public osg::NodeCallback {
115 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
117 assert(dynamic_cast<osgUtil::CullVisitor*>(nv));
118 osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
120 // adjust the projection matrix in a way that preserves the aspect ratio
121 // of the content ...
122 const osg::Viewport* viewport = cullVisitor->getViewport();
123 float viewportAspect = float(viewport->height())/float(viewport->width());
126 if (viewportAspect < 1) {
128 width = 1/viewportAspect;
130 height = viewportAspect;
134 osg::RefMatrix* matrix = new osg::RefMatrix;
135 matrix->makeOrtho2D(-width, width, -height, height);
137 // The trick is to have the projection matrix adapted independent
138 // of the scenegraph but dependent on the viewport of this current
139 // camera we cull for. Therefore we do not put that projection matrix into
140 // an additional camera rather than from within that cull callback.
141 cullVisitor->pushProjectionMatrix(matrix);
143 cullVisitor->popProjectionMatrix();
147 char *genNameString()
149 string website = "http://www.flightgear.org";
150 string programName = "FlightGear";
151 char *name = new char[26];
181 static osg::Node* fgCreateSplashCamera()
183 const char* splash_texture = fgGetString("/sim/startup/splash-texture");
184 SGSharedPtr<SGPropertyNode> style = fgGetNode("/sim/gui/style[0]", true);
186 char *namestring = genNameString();
187 fgSetString("/sim/startup/program-name", namestring);
189 SGPath tpath( globals->get_fg_root() );
190 if (splash_texture == NULL || !strcmp(splash_texture, "")) {
191 // load in the texture data
192 int num = (int)(sg_random() * 5.0 + 1.0);
194 snprintf(num_str, 4, "%d", num);
196 tpath.append( "Textures/Splash" );
197 tpath.concat( num_str );
198 tpath.concat( ".png" );
200 tpath.append( splash_texture );
202 osg::Texture2D* splashTexture = new osg::Texture2D;
203 splashTexture->setImage(osgDB::readImageFile(tpath.c_str()));
205 osg::Camera* camera = new osg::Camera;
206 camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
207 camera->setProjectionMatrix(osg::Matrix::ortho2D(-1, 1, -1, 1));
208 camera->setViewMatrix(osg::Matrix::identity());
209 camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
210 camera->setClearMask(0);
211 camera->setAllowEventFocus(false);
212 camera->setCullingActive(false);
214 osg::StateSet* stateSet = camera->getOrCreateStateSet();
215 stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
216 stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
217 stateSet->setAttribute(new osg::BlendFunc);
218 stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
219 stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
220 stateSet->setAttribute(new osg::Depth(osg::Depth::ALWAYS, 0, 1, false));
221 stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
224 osg::Geometry* geometry = new osg::Geometry;
225 geometry->setSupportsDisplayList(false);
227 osg::Vec3Array* vertexArray = new osg::Vec3Array;
228 vertexArray->push_back(osg::Vec3(-1, -1, 0));
229 vertexArray->push_back(osg::Vec3( 1, -1, 0));
230 vertexArray->push_back(osg::Vec3( 1, 1, 0));
231 vertexArray->push_back(osg::Vec3(-1, 1, 0));
232 geometry->setVertexArray(vertexArray);
233 osg::Vec4Array* colorArray = new osg::Vec4Array;
234 colorArray->push_back(osg::Vec4(0, 0, 0, 1));
235 geometry->setColorArray(colorArray);
236 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
237 geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
238 geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray,
239 style->getNode("colors/splash-screen")));
241 osg::Geode* geode = new osg::Geode;
242 geode->addDrawable(geometry);
244 stateSet = geode->getOrCreateStateSet();
245 stateSet->setRenderBinDetails(1, "RenderBin");
246 camera->addChild(geode);
249 // The group is needed because of osg is handling the cull callbacks in a
250 // different way for groups than for a geode. It does not hurt here ...
251 osg::Group* group = new osg::Group;
252 group->setCullCallback(new FGSplashContentProjectionCalback);
253 camera->addChild(group);
255 geode = new osg::Geode;
256 stateSet = geode->getOrCreateStateSet();
257 stateSet->setRenderBinDetails(2, "RenderBin");
258 group->addChild(geode);
261 geometry = new osg::Geometry;
262 geometry->setSupportsDisplayList(false);
264 vertexArray = new osg::Vec3Array;
265 vertexArray->push_back(osg::Vec3(-0.84, -0.84, 0));
266 vertexArray->push_back(osg::Vec3( 0.84, -0.84, 0));
267 vertexArray->push_back(osg::Vec3( 0.84, 0.84, 0));
268 vertexArray->push_back(osg::Vec3(-0.84, 0.84, 0));
269 geometry->setVertexArray(vertexArray);
270 osg::Vec2Array* texCoordArray = new osg::Vec2Array;
271 texCoordArray->push_back(osg::Vec2(0, 0));
272 texCoordArray->push_back(osg::Vec2(1, 0));
273 texCoordArray->push_back(osg::Vec2(1, 1));
274 texCoordArray->push_back(osg::Vec2(0, 1));
275 geometry->setTexCoordArray(0, texCoordArray);
276 colorArray = new osg::Vec4Array;
277 colorArray->push_back(osg::Vec4(1, 1, 1, 1));
278 geometry->setColorArray(colorArray);
279 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
280 geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
281 geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray, 0));
282 stateSet = geometry->getOrCreateStateSet();
283 stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
284 stateSet->setTextureAttribute(0, splashTexture);
285 geode->addDrawable(geometry);
288 osgText::Text* text = new osgText::Text;
289 std::string fn = style->getStringValue("fonts/splash", "");
290 text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
291 text->setCharacterSize(0.06);
292 text->setColor(osg::Vec4(1, 1, 1, 1));
293 text->setPosition(osg::Vec3(0, -0.92, 0));
294 text->setAlignment(osgText::Text::CENTER_CENTER);
295 SGPropertyNode* prop = fgGetNode("/sim/startup/splash-progress-text", true);
296 text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
297 geode->addDrawable(text);
299 text = new osgText::Text;
300 text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
301 text->setCharacterSize(0.08);
302 text->setColor(osg::Vec4(1, 1, 1, 1));
303 text->setPosition(osg::Vec3(0, 0.92, 0));
304 text->setAlignment(osgText::Text::CENTER_CENTER);
305 prop = fgGetNode("/sim/startup/program-name", "FlightGear");
307 text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
308 geode->addDrawable(text);
311 text = new osgText::Text;
312 text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
313 text->setCharacterSize(0.06);
314 text->setColor(osg::Vec4(1, 1, 1, 1));
315 text->setPosition(osg::Vec3(0, 0.82, 0));
316 text->setAlignment(osgText::Text::CENTER_CENTER);
317 prop = fgGetNode("/sim/startup/splash-title", true);
318 text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
319 geode->addDrawable(text);
324 // update callback for the switch node guarding that splash
325 class FGSplashGroupUpdateCallback : public osg::NodeCallback {
327 FGSplashGroupUpdateCallback() :
328 _splashAlphaNode(fgGetNode("/sim/startup/splash-alpha", true))
330 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
332 assert(dynamic_cast<osg::Group*>(node));
333 osg::Group* group = static_cast<osg::Group*>(node);
335 double alpha = _splashAlphaNode->getDoubleValue();
336 if (alpha <= 0 || !fgGetBool("/sim/startup/splash-screen"))
337 group->removeChild(0, group->getNumChildren());
338 else if (group->getNumChildren() == 0)
339 group->addChild(fgCreateSplashCamera());
344 SGSharedPtr<const SGPropertyNode> _splashAlphaNode;
347 osg::Node* fgCreateSplashNode() {
348 osg::Group* group = new osg::Group;
349 group->setUpdateCallback(new FGSplashGroupUpdateCallback);
353 // Initialize the splash screen
354 void fgSplashInit () {
355 SG_LOG( SG_GENERAL, SG_INFO, "Initializing splash screen" );
356 globals->get_renderer()->splashinit();
360 void fgSplashProgress ( const char *text ) {
361 SG_LOG( SG_GENERAL, SG_INFO, "Splash screen progress " << text );
362 fgSetString("/sim/startup/splash-progress-text", text);