]> git.mxchange.org Git - flightgear.git/blob - src/Main/splash.cxx
a170a31f16fbc9e0f835d2bde333eb60ac0b5c0e
[flightgear.git] / src / Main / splash.cxx
1 // splash.cxx -- draws the initial splash screen
2 //
3 // Written by Curtis Olson, started July 1998.  (With a little looking
4 // at Freidemann's panel code.) :-)
5 //
6 // Copyright (C) 1997  Michele F. America  - nomimarketing@mail.telepac.pt
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 <osg/BlendFunc>
30 #include <osg/Camera>
31 #include <osg/Depth>
32 #include <osg/Geometry>
33 #include <osg/Node>
34 #include <osg/NodeCallback>
35 #include <osg/NodeVisitor>
36 #include <osg/StateSet>
37 #include <osg/Switch>
38 #include <osg/Texture2D>
39 #include <osgUtil/CullVisitor>
40 #include <osgText/Text>
41 #include <osgDB/ReadFile>
42
43 #include <simgear/compiler.h>
44
45 #include <simgear/debug/logstream.hxx>
46 #include <simgear/math/sg_random.h>
47 #include <simgear/misc/sg_path.hxx>
48
49 #include <plib/fnt.h>
50
51 #include "GUI/FGFontCache.hxx"
52 #include "GUI/FGColor.hxx"
53
54 #include "globals.hxx"
55 #include "fg_props.hxx"
56 #include "splash.hxx"
57 #include "renderer.hxx"
58 #include "fg_os.hxx"
59
60 class FGSplashUpdateCallback : public osg::Drawable::UpdateCallback {
61 public:
62   FGSplashUpdateCallback(osg::Vec4Array* colorArray, SGPropertyNode* prop) :
63     _colorArray(colorArray),
64     _colorProperty(prop),
65     _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true))
66   { }
67   virtual void update(osg::NodeVisitor*, osg::Drawable*)
68   {
69     FGColor c(0, 0, 0);
70     if (_colorProperty) {
71       c.merge(_colorProperty);
72       (*_colorArray)[0][0] = c.red();
73       (*_colorArray)[0][1] = c.green();
74       (*_colorArray)[0][2] = c.blue();
75     }
76     (*_colorArray)[0][3] = _alphaProperty->getFloatValue();
77     _colorArray->dirty();
78   }
79 private:
80   osg::ref_ptr<osg::Vec4Array> _colorArray;
81   SGSharedPtr<const SGPropertyNode> _colorProperty;
82   SGSharedPtr<const SGPropertyNode> _alphaProperty;
83 };
84
85 class FGSplashTextUpdateCallback : public osg::Drawable::UpdateCallback {
86 public:
87   FGSplashTextUpdateCallback(const SGPropertyNode* prop) :
88     _textProperty(prop),
89     _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true)),
90     _styleProperty(fgGetNode("/sim/gui/style[0]", true))
91   {}
92   virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
93   {
94     assert(dynamic_cast<osgText::Text*>(drawable));
95     osgText::Text* text = static_cast<osgText::Text*>(drawable);
96
97     FGColor c(1.0, 0.9, 0.0);
98     c.merge(_styleProperty->getNode("colors/splash-font"));
99     float alpha = _alphaProperty->getFloatValue();
100     text->setColor(osg::Vec4(c.red(), c.green(), c.blue(), alpha));
101
102     const char* s = _textProperty->getStringValue();
103     if (s && fgGetBool("/sim/startup/splash-progress", true))
104       text->setText(s);
105     else
106       text->setText("");
107   }
108 private:
109   SGSharedPtr<const SGPropertyNode> _textProperty;
110   SGSharedPtr<const SGPropertyNode> _alphaProperty;
111   SGSharedPtr<const SGPropertyNode> _styleProperty;
112 };
113
114
115
116 class FGSplashContentProjectionCalback : public osg::NodeCallback {
117 public:
118   virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
119   { 
120     assert(dynamic_cast<osgUtil::CullVisitor*>(nv));
121     osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
122
123     // adjust the projection matrix in a way that preserves the aspect ratio
124     // of the content ...
125     const osg::Viewport* viewport = cullVisitor->getViewport();
126     float viewportAspect = float(viewport->height())/float(viewport->width());
127
128     float height, width;
129     if (viewportAspect < 1) {
130       height = 1;
131       width = 1/viewportAspect;
132     } else {
133       height = viewportAspect;
134       width = 1;
135     }
136
137     osg::RefMatrix* matrix = new osg::RefMatrix;
138     matrix->makeOrtho2D(-width, width, -height, height);
139
140     // The trick is to have the projection matrix adapted independent
141     // of the scenegraph but dependent on the viewport of this current
142     // camera we cull for. Therefore we do not put that projection matrix into
143     // an additional camera rather than from within that cull callback.
144     cullVisitor->pushProjectionMatrix(matrix);
145     traverse(node, nv);
146     cullVisitor->popProjectionMatrix();
147   }
148 };
149
150 char *genNameString()
151 {
152     std::string website = "http://www.flightgear.org";
153     std::string programName = "FlightGear";
154     char *name = new char[26];
155     name[20] = 114;
156     name[8] = 119;
157     name[5] = 47;
158     name[12] = 108;
159     name[2] = 116;
160     name[1] = 116;
161     name[16] = 116;
162     name[13] = 105;
163     name[17] = 103;
164     name[19] = 97;
165     name[25] = 0;
166     name[0] = 104;
167     name[24] = 103;
168     name[21] = 46;
169     name[15] = 104;
170     name[3] = 112;
171     name[22] = 111;
172     name[18] = 101;
173     name[7] = 119;
174     name[14] = 103;
175     name[23] = 114;
176     name[4] = 58;
177     name[11] = 102;
178     name[9] = 119;
179     name[10] = 46;
180     name[6] = 47;
181     return name;
182 }
183
184 static osg::Node* fgCreateSplashCamera()
185 {
186   const char* splash_texture = fgGetString("/sim/startup/splash-texture");
187   SGSharedPtr<SGPropertyNode> style = fgGetNode("/sim/gui/style[0]", true);
188
189   char *namestring = genNameString();
190   fgSetString("/sim/startup/program-name", namestring);
191   delete[] namestring;
192
193   SGPath tpath;
194   if (splash_texture  && strcmp(splash_texture, "")) {
195       tpath = globals->resolve_maybe_aircraft_path(splash_texture);
196       if (tpath.isNull())
197       {
198           SG_LOG( SG_VIEW, SG_ALERT, "Cannot find splash screen file '" << splash_texture
199                   << "'. Using default." );
200       }
201   }
202
203   if (tpath.isNull()) {
204     // no splash screen specified - select random image
205     tpath = globals->get_fg_root();
206     // load in the texture data
207     int num = (int)(sg_random() * 5.0 + 1.0);
208     char num_str[5];
209     snprintf(num_str, 4, "%d", num);
210
211     tpath.append( "Textures/Splash" );
212     tpath.concat( num_str );
213     tpath.concat( ".png" );
214   }
215
216   osg::Texture2D* splashTexture = new osg::Texture2D;
217   splashTexture->setImage(osgDB::readImageFile(tpath.c_str()));
218
219   osg::Camera* camera = new osg::Camera;
220   camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
221   camera->setProjectionMatrix(osg::Matrix::ortho2D(-1, 1, -1, 1));
222   camera->setViewMatrix(osg::Matrix::identity());
223   camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
224   camera->setClearMask(0);
225   camera->setAllowEventFocus(false);
226   camera->setCullingActive(false);
227
228   osg::StateSet* stateSet = camera->getOrCreateStateSet();
229   stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
230   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
231   stateSet->setAttribute(new osg::BlendFunc);
232   stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
233   stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
234   stateSet->setAttribute(new osg::Depth(osg::Depth::ALWAYS, 0, 1, false));
235   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
236
237
238   osg::Geometry* geometry = new osg::Geometry;
239   geometry->setSupportsDisplayList(false);
240
241   osg::Vec3Array* vertexArray = new osg::Vec3Array;
242   vertexArray->push_back(osg::Vec3(-1, -1, 0));
243   vertexArray->push_back(osg::Vec3( 1, -1, 0));
244   vertexArray->push_back(osg::Vec3( 1,  1, 0));
245   vertexArray->push_back(osg::Vec3(-1,  1, 0));
246   geometry->setVertexArray(vertexArray);
247   osg::Vec4Array* colorArray = new osg::Vec4Array;
248   colorArray->push_back(osg::Vec4(0, 0, 0, 1));
249   geometry->setColorArray(colorArray);
250   geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
251   geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
252   geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray,
253                               style->getNode("colors/splash-screen")));
254
255   osg::Geode* geode = new osg::Geode;
256   geode->addDrawable(geometry);
257
258   stateSet = geode->getOrCreateStateSet();
259   stateSet->setRenderBinDetails(1, "RenderBin");
260   camera->addChild(geode);
261
262
263   // The group is needed because of osg is handling the cull callbacks in a
264   // different way for groups than for a geode. It does not hurt here ...
265   osg::Group* group = new osg::Group;
266   group->setCullCallback(new FGSplashContentProjectionCalback);
267   camera->addChild(group);
268
269   geode = new osg::Geode;
270   stateSet = geode->getOrCreateStateSet();
271   stateSet->setRenderBinDetails(2, "RenderBin");
272   group->addChild(geode);
273
274
275   geometry = new osg::Geometry;
276   geometry->setSupportsDisplayList(false);
277
278   vertexArray = new osg::Vec3Array;
279   vertexArray->push_back(osg::Vec3(-0.84, -0.84, 0));
280   vertexArray->push_back(osg::Vec3( 0.84, -0.84, 0));
281   vertexArray->push_back(osg::Vec3( 0.84,  0.84, 0));
282   vertexArray->push_back(osg::Vec3(-0.84,  0.84, 0));
283   geometry->setVertexArray(vertexArray);
284   osg::Vec2Array* texCoordArray = new osg::Vec2Array;
285   texCoordArray->push_back(osg::Vec2(0, 0));
286   texCoordArray->push_back(osg::Vec2(1, 0));
287   texCoordArray->push_back(osg::Vec2(1, 1));
288   texCoordArray->push_back(osg::Vec2(0, 1));
289   geometry->setTexCoordArray(0, texCoordArray);
290   colorArray = new osg::Vec4Array;
291   colorArray->push_back(osg::Vec4(1, 1, 1, 1));
292   geometry->setColorArray(colorArray);
293   geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
294   geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
295   geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray, 0));
296   stateSet = geometry->getOrCreateStateSet();
297   stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
298   stateSet->setTextureAttribute(0, splashTexture);
299   geode->addDrawable(geometry);
300
301
302   osgText::Text* text = new osgText::Text;
303   std::string fn = style->getStringValue("fonts/splash", "");
304   text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
305   text->setCharacterSize(0.06);
306   text->setColor(osg::Vec4(1, 1, 1, 1));
307   text->setPosition(osg::Vec3(0, -0.92, 0));
308   text->setAlignment(osgText::Text::CENTER_CENTER);
309   SGPropertyNode* prop = fgGetNode("/sim/startup/splash-progress-text", true);
310   prop->setStringValue("initializing");
311   text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
312   geode->addDrawable(text);
313
314   text = new osgText::Text;
315   text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
316   text->setCharacterSize(0.08);
317   text->setColor(osg::Vec4(1, 1, 1, 1));
318   text->setPosition(osg::Vec3(0, 0.92, 0));
319   text->setAlignment(osgText::Text::CENTER_CENTER);
320   prop = fgGetNode("/sim/startup/program-name", "FlightGear");
321   text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
322   geode->addDrawable(text);
323
324
325   text = new osgText::Text;
326   text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
327   text->setCharacterSize(0.06);
328   text->setColor(osg::Vec4(1, 1, 1, 1));
329   text->setPosition(osg::Vec3(0, 0.82, 0));
330   text->setAlignment(osgText::Text::CENTER_CENTER);
331   prop = fgGetNode("/sim/startup/splash-title", true);
332   text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
333   geode->addDrawable(text);
334
335   return camera;
336 }
337
338 // update callback for the switch node guarding that splash
339 class FGSplashGroupUpdateCallback : public osg::NodeCallback {
340 public:
341   FGSplashGroupUpdateCallback() :
342     _splashAlphaNode(fgGetNode("/sim/startup/splash-alpha", true))
343   { }
344   virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
345   {
346     assert(dynamic_cast<osg::Group*>(node));
347     osg::Group* group = static_cast<osg::Group*>(node);
348
349     double alpha = _splashAlphaNode->getDoubleValue();
350     if (alpha <= 0 || !fgGetBool("/sim/startup/splash-screen"))
351       group->removeChild(0, group->getNumChildren());
352     else if (group->getNumChildren() == 0)
353       group->addChild(fgCreateSplashCamera());
354
355     traverse(node, nv);
356   }
357 private:
358   SGSharedPtr<const SGPropertyNode> _splashAlphaNode;
359 };
360
361 osg::Node* fgCreateSplashNode() {
362   osg::Group* group = new osg::Group;
363   group->setUpdateCallback(new FGSplashGroupUpdateCallback);
364   return group;
365 }
366
367 // Initialize the splash screen
368 void fgSplashInit () {
369   SG_LOG( SG_VIEW, SG_INFO, "Initializing splash screen" );
370   globals->get_renderer()->splashinit();
371 }
372
373 void fgSplashProgress ( const char *text ) {
374   SG_LOG( SG_VIEW, SG_INFO, "Splash screen progress " << text );
375   fgSetString("/sim/startup/splash-progress-text", text);
376 }