]> git.mxchange.org Git - flightgear.git/blob - src/Main/splash.cxx
Merge branch 'jt/runway' into next
[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 <GUI/new_gui.hxx>
50
51 #include "globals.hxx"
52 #include "fg_props.hxx"
53 #include "splash.hxx"
54 #include "renderer.hxx"
55 #include "fg_os.hxx"
56
57 class FGSplashUpdateCallback : public osg::Drawable::UpdateCallback {
58 public:
59   FGSplashUpdateCallback(osg::Vec4Array* colorArray, SGPropertyNode* prop) :
60     _colorArray(colorArray),
61     _colorProperty(prop),
62     _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true))
63   { }
64   virtual void update(osg::NodeVisitor*, osg::Drawable*)
65   {
66     FGColor c(0, 0, 0);
67     if (_colorProperty) {
68       c.merge(_colorProperty);
69       (*_colorArray)[0][0] = c.red();
70       (*_colorArray)[0][1] = c.green();
71       (*_colorArray)[0][2] = c.blue();
72     }
73     (*_colorArray)[0][3] = _alphaProperty->getFloatValue();
74     _colorArray->dirty();
75   }
76 private:
77   osg::ref_ptr<osg::Vec4Array> _colorArray;
78   SGSharedPtr<const SGPropertyNode> _colorProperty;
79   SGSharedPtr<const SGPropertyNode> _alphaProperty;
80 };
81
82 class FGSplashTextUpdateCallback : public osg::Drawable::UpdateCallback {
83 public:
84   FGSplashTextUpdateCallback(const SGPropertyNode* prop) :
85     _textProperty(prop),
86     _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true)),
87     _styleProperty(fgGetNode("/sim/gui/style[0]", true))
88   {}
89   virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
90   {
91     assert(dynamic_cast<osgText::Text*>(drawable));
92     osgText::Text* text = static_cast<osgText::Text*>(drawable);
93
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));
98
99     const char* s = _textProperty->getStringValue();
100     if (s && fgGetBool("/sim/startup/splash-progress", true))
101       text->setText(s);
102     else
103       text->setText("");
104   }
105 private:
106   SGSharedPtr<const SGPropertyNode> _textProperty;
107   SGSharedPtr<const SGPropertyNode> _alphaProperty;
108   SGSharedPtr<const SGPropertyNode> _styleProperty;
109 };
110
111
112 class FGSplashContentProjectionCalback : public osg::NodeCallback {
113 public:
114   virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
115   { 
116     assert(dynamic_cast<osgUtil::CullVisitor*>(nv));
117     osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
118
119     // adjust the projection matrix in a way that preserves the aspect ratio
120     // of the content ...
121     const osg::Viewport* viewport = cullVisitor->getViewport();
122     float viewportAspect = float(viewport->height())/float(viewport->width());
123
124     float height, width;
125     if (viewportAspect < 1) {
126       height = 1;
127       width = 1/viewportAspect;
128     } else {
129       height = viewportAspect;
130       width = 1;
131     }
132
133     osg::RefMatrix* matrix = new osg::RefMatrix;
134     matrix->makeOrtho2D(-width, width, -height, height);
135
136     // The trick is to have the projection matrix adapted independent
137     // of the scenegraph but dependent on the viewport of this current
138     // camera we cull for. Therefore we do not put that projection matrix into
139     // an additional camera rather than from within that cull callback.
140     cullVisitor->pushProjectionMatrix(matrix);
141     traverse(node, nv);
142     cullVisitor->popProjectionMatrix();
143   }
144 };
145
146 static osg::Node* fgCreateSplashCamera()
147 {
148   const char* splash_texture = fgGetString("/sim/startup/splash-texture");
149   SGSharedPtr<SGPropertyNode> style = fgGetNode("/sim/gui/style[0]", true);
150
151   SGPath tpath( globals->get_fg_root() );
152   if (splash_texture == NULL || !strcmp(splash_texture, "")) {
153     // load in the texture data
154     int num = (int)(sg_random() * 5.0 + 1.0);
155     char num_str[5];
156     snprintf(num_str, 4, "%d", num);
157
158     tpath.append( "Textures/Splash" );
159     tpath.concat( num_str );
160     tpath.concat( ".png" );
161   } else
162     tpath.append( splash_texture );
163
164   osg::Texture2D* splashTexture = new osg::Texture2D;
165   splashTexture->setImage(osgDB::readImageFile(tpath.c_str()));
166
167   osg::Camera* camera = new osg::Camera;
168   camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
169   camera->setProjectionMatrix(osg::Matrix::ortho2D(-1, 1, -1, 1));
170   camera->setViewMatrix(osg::Matrix::identity());
171   camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
172   camera->setClearMask(0);
173   camera->setAllowEventFocus(false);
174   camera->setCullingActive(false);
175
176   osg::StateSet* stateSet = camera->getOrCreateStateSet();
177   stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
178   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
179   stateSet->setAttribute(new osg::BlendFunc);
180   stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
181   stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
182   stateSet->setAttribute(new osg::Depth(osg::Depth::ALWAYS, 0, 1, false));
183   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
184
185
186   osg::Geometry* geometry = new osg::Geometry;
187   geometry->setSupportsDisplayList(false);
188
189   osg::Vec3Array* vertexArray = new osg::Vec3Array;
190   vertexArray->push_back(osg::Vec3(-1, -1, 0));
191   vertexArray->push_back(osg::Vec3( 1, -1, 0));
192   vertexArray->push_back(osg::Vec3( 1,  1, 0));
193   vertexArray->push_back(osg::Vec3(-1,  1, 0));
194   geometry->setVertexArray(vertexArray);
195   osg::Vec4Array* colorArray = new osg::Vec4Array;
196   colorArray->push_back(osg::Vec4(0, 0, 0, 1));
197   geometry->setColorArray(colorArray);
198   geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
199   geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
200   geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray,
201                               style->getNode("colors/splash-screen")));
202
203   osg::Geode* geode = new osg::Geode;
204   geode->addDrawable(geometry);
205
206   stateSet = geode->getOrCreateStateSet();
207   stateSet->setRenderBinDetails(1, "RenderBin");
208   camera->addChild(geode);
209
210
211   // The group is needed because of osg is handling the cull callbacks in a
212   // different way for groups than for a geode. It does not hurt here ...
213   osg::Group* group = new osg::Group;
214   group->setCullCallback(new FGSplashContentProjectionCalback);
215   camera->addChild(group);
216
217   geode = new osg::Geode;
218   stateSet = geode->getOrCreateStateSet();
219   stateSet->setRenderBinDetails(2, "RenderBin");
220   group->addChild(geode);
221
222
223   geometry = new osg::Geometry;
224   geometry->setSupportsDisplayList(false);
225
226   vertexArray = new osg::Vec3Array;
227   vertexArray->push_back(osg::Vec3(-0.84, -0.84, 0));
228   vertexArray->push_back(osg::Vec3( 0.84, -0.84, 0));
229   vertexArray->push_back(osg::Vec3( 0.84,  0.84, 0));
230   vertexArray->push_back(osg::Vec3(-0.84,  0.84, 0));
231   geometry->setVertexArray(vertexArray);
232   osg::Vec2Array* texCoordArray = new osg::Vec2Array;
233   texCoordArray->push_back(osg::Vec2(0, 0));
234   texCoordArray->push_back(osg::Vec2(1, 0));
235   texCoordArray->push_back(osg::Vec2(1, 1));
236   texCoordArray->push_back(osg::Vec2(0, 1));
237   geometry->setTexCoordArray(0, texCoordArray);
238   colorArray = new osg::Vec4Array;
239   colorArray->push_back(osg::Vec4(1, 1, 1, 1));
240   geometry->setColorArray(colorArray);
241   geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
242   geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
243   geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray, 0));
244   stateSet = geometry->getOrCreateStateSet();
245   stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
246   stateSet->setTextureAttribute(0, splashTexture);
247   geode->addDrawable(geometry);
248
249
250   osgText::Text* text = new osgText::Text;
251   std::string fn = style->getStringValue("fonts/splash", "");
252   text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
253   text->setCharacterSize(0.06);
254   text->setColor(osg::Vec4(1, 1, 1, 1));
255   text->setPosition(osg::Vec3(0, -0.92, 0));
256   text->setAlignment(osgText::Text::CENTER_CENTER);
257   SGPropertyNode* prop = fgGetNode("/sim/startup/splash-progress-text", true);
258   text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
259   geode->addDrawable(text);
260
261   text = new osgText::Text;
262   text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
263   text->setCharacterSize(0.06);
264   text->setColor(osg::Vec4(1, 1, 1, 1));
265   text->setPosition(osg::Vec3(0, 0.92, 0));
266   text->setAlignment(osgText::Text::CENTER_CENTER);
267   prop = fgGetNode("/sim/startup/splash-title", true);
268   text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
269   geode->addDrawable(text);
270
271   return camera;
272 }
273
274 // update callback for the switch node guarding that splash
275 class FGSplashGroupUpdateCallback : public osg::NodeCallback {
276 public:
277   FGSplashGroupUpdateCallback() :
278     _splashAlphaNode(fgGetNode("/sim/startup/splash-alpha", true))
279   { }
280   virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
281   {
282     assert(dynamic_cast<osg::Group*>(node));
283     osg::Group* group = static_cast<osg::Group*>(node);
284
285     double alpha = _splashAlphaNode->getDoubleValue();
286     if (alpha <= 0 || !fgGetBool("/sim/startup/splash-screen"))
287       group->removeChild(0, group->getNumChildren());
288     else if (group->getNumChildren() == 0)
289       group->addChild(fgCreateSplashCamera());
290
291     traverse(node, nv);
292   }
293 private:
294   SGSharedPtr<const SGPropertyNode> _splashAlphaNode;
295 };
296
297 osg::Node* fgCreateSplashNode() {
298   osg::Group* group = new osg::Group;
299   group->setUpdateCallback(new FGSplashGroupUpdateCallback);
300   return group;
301 }
302
303 // Initialize the splash screen
304 void fgSplashInit () {
305   SG_LOG( SG_GENERAL, SG_INFO, "Initializing splash screen" );
306   globals->get_renderer()->splashinit();
307   fgRequestRedraw();
308 }
309
310 void fgSplashProgress ( const char *text ) {
311   SG_LOG( SG_GENERAL, SG_INFO, "Splash screen progress " << text );
312   fgSetString("/sim/startup/splash-progress-text", text);
313   fgRequestRedraw();
314 }