New splash screen system.
Uses TTF fonts, and displays more information textually including the application version and current aircraft. Also rename FGRenderer::splashinit to preinit, as was suggested a long time ago.
This commit is contained in:
parent
17fe0460a9
commit
918db84ac4
6 changed files with 589 additions and 363 deletions
|
@ -1111,9 +1111,9 @@ void fgStartNewReset()
|
||||||
|
|
||||||
viewer->getDatabasePager()->setUpThreads(1, 1);
|
viewer->getDatabasePager()->setUpThreads(1, 1);
|
||||||
|
|
||||||
// must do this before splashinit for Rembrandt
|
// must do this before preinit for Rembrandt
|
||||||
flightgear::CameraGroup::buildDefaultGroup(viewer.get());
|
flightgear::CameraGroup::buildDefaultGroup(viewer.get());
|
||||||
render->splashinit();
|
render->preinit();
|
||||||
viewer->startThreading();
|
viewer->startThreading();
|
||||||
|
|
||||||
fgOSResetProperties();
|
fgOSResetProperties();
|
||||||
|
|
|
@ -534,9 +534,8 @@ int fgMainInit( int argc, char **argv )
|
||||||
fgOSOpenWindow(true /* request stencil buffer */);
|
fgOSOpenWindow(true /* request stencil buffer */);
|
||||||
fgOSResetProperties();
|
fgOSResetProperties();
|
||||||
|
|
||||||
// Initialize the splash screen right away
|
|
||||||
fntInit();
|
fntInit();
|
||||||
fgSplashInit();
|
globals->get_renderer()->preinit();
|
||||||
|
|
||||||
fgOutputSettings();
|
fgOutputSettings();
|
||||||
|
|
||||||
|
|
|
@ -433,10 +433,8 @@ FGRenderer::~FGRenderer()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize various GL/view parameters
|
// Initialize various GL/view parameters
|
||||||
// XXX This should be called "preinit" or something, as it initializes
|
|
||||||
// critical parts of the scene graph in addition to the splash screen.
|
|
||||||
void
|
void
|
||||||
FGRenderer::splashinit( void )
|
FGRenderer::preinit( void )
|
||||||
{
|
{
|
||||||
// important that we reset the viewer sceneData here, to ensure the reference
|
// important that we reset the viewer sceneData here, to ensure the reference
|
||||||
// time for everything is in sync; otherwise on reset the Viewer and
|
// time for everything is in sync; otherwise on reset the Viewer and
|
||||||
|
@ -446,10 +444,10 @@ FGRenderer::splashinit( void )
|
||||||
_viewerSceneRoot = new osg::Group;
|
_viewerSceneRoot = new osg::Group;
|
||||||
_viewerSceneRoot->setName("viewerSceneRoot");
|
_viewerSceneRoot->setName("viewerSceneRoot");
|
||||||
viewer->setSceneData(_viewerSceneRoot);
|
viewer->setSceneData(_viewerSceneRoot);
|
||||||
|
|
||||||
ref_ptr<Node> splashNode = fgCreateSplashNode();
|
_splash = new SplashScreen;
|
||||||
if (_classicalRenderer) {
|
if (_classicalRenderer) {
|
||||||
_viewerSceneRoot->addChild(splashNode.get());
|
_viewerSceneRoot->addChild(_splash);
|
||||||
} else {
|
} else {
|
||||||
for ( CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
|
for ( CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
|
||||||
ii != CameraGroup::getDefault()->camerasEnd();
|
ii != CameraGroup::getDefault()->camerasEnd();
|
||||||
|
@ -459,7 +457,7 @@ FGRenderer::splashinit( void )
|
||||||
Camera* camera = info->getCamera(DISPLAY_CAMERA);
|
Camera* camera = info->getCamera(DISPLAY_CAMERA);
|
||||||
if (camera == 0) continue;
|
if (camera == 0) continue;
|
||||||
|
|
||||||
camera->addChild(splashNode.get());
|
camera->addChild(_splash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1727,6 +1725,9 @@ FGRenderer::resize( int width, int height )
|
||||||
_xsize->setIntValue(width);
|
_xsize->setIntValue(width);
|
||||||
_ysize->setIntValue(height);
|
_ysize->setIntValue(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update splash node if present ?
|
||||||
|
_splash->resize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef osgUtil::LineSegmentIntersector::Intersection Intersection;
|
typedef osgUtil::LineSegmentIntersector::Intersection Intersection;
|
||||||
|
|
|
@ -43,6 +43,7 @@ class CameraGroup;
|
||||||
|
|
||||||
class SGSky;
|
class SGSky;
|
||||||
class SGUpdateVisitor;
|
class SGUpdateVisitor;
|
||||||
|
class SplashScreen;
|
||||||
|
|
||||||
typedef std::vector<SGSceneryPick> PickList;
|
typedef std::vector<SGSceneryPick> PickList;
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ public:
|
||||||
FGRenderer();
|
FGRenderer();
|
||||||
~FGRenderer();
|
~FGRenderer();
|
||||||
|
|
||||||
void splashinit();
|
void preinit();
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
void setupView();
|
void setupView();
|
||||||
|
@ -188,6 +189,8 @@ protected:
|
||||||
void updateSky();
|
void updateSky();
|
||||||
|
|
||||||
void setupRoot();
|
void setupRoot();
|
||||||
|
|
||||||
|
SplashScreen* _splash;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool fgDumpSceneGraphToFile(const char* filename);
|
bool fgDumpSceneGraphToFile(const char* filename);
|
||||||
|
|
|
@ -21,10 +21,7 @@
|
||||||
//
|
//
|
||||||
// $Id$
|
// $Id$
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <osg/BlendFunc>
|
#include <osg/BlendFunc>
|
||||||
#include <osg/Camera>
|
#include <osg/Camera>
|
||||||
|
@ -36,7 +33,8 @@
|
||||||
#include <osg/StateSet>
|
#include <osg/StateSet>
|
||||||
#include <osg/Switch>
|
#include <osg/Switch>
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
#include <osgUtil/CullVisitor>
|
#include <osg/TextureRectangle>
|
||||||
|
|
||||||
#include <osgText/Text>
|
#include <osgText/Text>
|
||||||
#include <osgDB/ReadFile>
|
#include <osgDB/ReadFile>
|
||||||
|
|
||||||
|
@ -46,11 +44,6 @@
|
||||||
#include <simgear/math/sg_random.h>
|
#include <simgear/math/sg_random.h>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
#include <plib/fnt.h>
|
|
||||||
|
|
||||||
#include "GUI/FGFontCache.hxx"
|
|
||||||
#include "GUI/FGColor.hxx"
|
|
||||||
|
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/fg_os.hxx>
|
#include <Main/fg_os.hxx>
|
||||||
|
@ -58,358 +51,530 @@
|
||||||
#include "splash.hxx"
|
#include "splash.hxx"
|
||||||
#include "renderer.hxx"
|
#include "renderer.hxx"
|
||||||
|
|
||||||
class FGSplashUpdateCallback : public osg::Drawable::UpdateCallback {
|
#include <sstream>
|
||||||
|
|
||||||
|
const char* LICENSE_URL_TEXT = "Licensed under the GNU GPL. See http://www.flightgear.org for more information";
|
||||||
|
|
||||||
|
class SplashScreenUpdateCallback : public osg::NodeCallback {
|
||||||
public:
|
public:
|
||||||
FGSplashUpdateCallback(osg::Vec4Array* colorArray, SGPropertyNode* prop) :
|
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||||
_colorArray(colorArray),
|
{
|
||||||
_colorProperty(prop),
|
SplashScreen* screen = static_cast<SplashScreen*>(node);
|
||||||
_alphaProperty(fgGetNode("/sim/startup/splash-alpha", true))
|
screen->doUpdate();
|
||||||
{ }
|
traverse(node, nv);
|
||||||
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 {
|
SplashScreen::SplashScreen() :
|
||||||
public:
|
_splashAlphaNode(fgGetNode("/sim/startup/splash-alpha", true))
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
char *genNameString()
|
|
||||||
{
|
{
|
||||||
std::string website = "http://www.flightgear.org";
|
setName("splashGroup");
|
||||||
std::string programName = "FlightGear";
|
setUpdateCallback(new SplashScreenUpdateCallback);
|
||||||
char *name = new char[26];
|
|
||||||
name[20] = 114;
|
|
||||||
name[8] = 119;
|
|
||||||
name[5] = 47;
|
|
||||||
name[12] = 108;
|
|
||||||
name[2] = 116;
|
|
||||||
name[1] = 116;
|
|
||||||
name[16] = 116;
|
|
||||||
name[13] = 105;
|
|
||||||
name[17] = 103;
|
|
||||||
name[19] = 97;
|
|
||||||
name[25] = 0;
|
|
||||||
name[0] = 104;
|
|
||||||
name[24] = 103;
|
|
||||||
name[21] = 46;
|
|
||||||
name[15] = 104;
|
|
||||||
name[3] = 112;
|
|
||||||
name[22] = 111;
|
|
||||||
name[18] = 101;
|
|
||||||
name[7] = 119;
|
|
||||||
name[14] = 103;
|
|
||||||
name[23] = 114;
|
|
||||||
name[4] = 58;
|
|
||||||
name[11] = 102;
|
|
||||||
name[9] = 119;
|
|
||||||
name[10] = 46;
|
|
||||||
name[6] = 47;
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static osg::Node* fgCreateSplashCamera()
|
SplashScreen::~SplashScreen()
|
||||||
{
|
{
|
||||||
char *namestring = genNameString();
|
}
|
||||||
fgSetString("/sim/startup/program-name", namestring);
|
|
||||||
delete[] namestring;
|
|
||||||
|
|
||||||
simgear::PropertyList textures = fgGetNode("/sim/startup", true)->getChildren("splash-texture");
|
void SplashScreen::createNodes()
|
||||||
std::vector<SGPath> useable_textures;
|
{
|
||||||
SGPath tpath;
|
_splashImage = osgDB::readImageFile(selectSplashImage());
|
||||||
|
|
||||||
// Build a list of textures that are usable; those whose path can be resolved
|
int width = _splashImage->s();
|
||||||
for (simgear::PropertyList::iterator it = textures.begin(); it != textures.end(); it++) {
|
int height = _splashImage->t();
|
||||||
std::string value = (*it)->getStringValue();
|
_splashImageAspectRatio = static_cast<double>(width) / height;
|
||||||
if (!value.empty()) {
|
|
||||||
tpath = globals->resolve_maybe_aircraft_path(value);
|
osg::TextureRectangle* splashTexture = new osg::TextureRectangle(_splashImage);
|
||||||
if (!tpath.isNull()) {
|
splashTexture->setTextureSize(width, height);
|
||||||
useable_textures.push_back(tpath);
|
splashTexture->setInternalFormat(GL_RGB);
|
||||||
}
|
splashTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||||
else {
|
splashTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||||
SG_LOG(SG_VIEW, SG_ALERT, "Cannot find splash screen file '" << value << "'");
|
splashTexture->setImage(_splashImage);
|
||||||
|
|
||||||
|
_splashFBOCamera = new osg::Camera;
|
||||||
|
_splashFBOCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||||
|
_splashFBOCamera->setViewMatrix(osg::Matrix::identity());
|
||||||
|
_splashFBOCamera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||||
|
_splashFBOCamera->setClearColor( osg::Vec4( 0., 0., 0., 0. ) );
|
||||||
|
_splashFBOCamera->setAllowEventFocus(false);
|
||||||
|
_splashFBOCamera->setCullingActive(false);
|
||||||
|
|
||||||
|
_splashFBOTexture = new osg::Texture2D;
|
||||||
|
_splashFBOTexture->setInternalFormat(GL_RGB);
|
||||||
|
_splashFBOTexture->setResizeNonPowerOfTwoHint(false);
|
||||||
|
_splashFBOTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||||
|
_splashFBOTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||||
|
_splashFBOCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
|
||||||
|
_splashFBOCamera->setRenderOrder(osg::Camera::PRE_RENDER);
|
||||||
|
_splashFBOCamera->attach(osg::Camera::COLOR_BUFFER, _splashFBOTexture);
|
||||||
|
|
||||||
|
addChild(_splashFBOCamera);
|
||||||
|
|
||||||
|
osg::StateSet* stateSet = _splashFBOCamera->getOrCreateStateSet();
|
||||||
|
stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
|
||||||
|
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);
|
||||||
|
|
||||||
|
_splashImageVertexArray = new osg::Vec3Array;
|
||||||
|
for (int i=0; i < 4; ++i) {
|
||||||
|
_splashImageVertexArray->push_back(osg::Vec3(0.0, 0.0, 0.0));
|
||||||
|
}
|
||||||
|
geometry->setVertexArray(_splashImageVertexArray);
|
||||||
|
|
||||||
|
osg::Vec2Array* imageTCs = new osg::Vec2Array;
|
||||||
|
imageTCs->push_back(osg::Vec2(0, 0));
|
||||||
|
imageTCs->push_back(osg::Vec2(width, 0));
|
||||||
|
imageTCs->push_back(osg::Vec2(width, height));
|
||||||
|
imageTCs->push_back(osg::Vec2(0, height));
|
||||||
|
geometry->setTexCoordArray(0, imageTCs);
|
||||||
|
|
||||||
|
osg::Vec4Array* 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));
|
||||||
|
|
||||||
|
stateSet = geometry->getOrCreateStateSet();
|
||||||
|
stateSet->setTextureMode(0, GL_TEXTURE_RECTANGLE, osg::StateAttribute::ON);
|
||||||
|
stateSet->setTextureAttribute(0, splashTexture);
|
||||||
|
|
||||||
|
osg::Geode* geode = new osg::Geode;
|
||||||
|
_splashFBOCamera->addChild(geode);
|
||||||
|
geode->addDrawable(geometry);
|
||||||
|
|
||||||
|
if (_legacySplashScreenMode) {
|
||||||
|
addText(geode, osg::Vec2(0.025, 0.025), 0.03,
|
||||||
|
std::string("FlightGear ") + fgGetString("/sim/version/flightgear") +
|
||||||
|
std::string(" ") + std::string(LICENSE_URL_TEXT),
|
||||||
|
osgText::Text::LEFT_TOP,
|
||||||
|
nullptr,
|
||||||
|
0.9);
|
||||||
|
} else {
|
||||||
|
setupLogoImage();
|
||||||
|
|
||||||
|
addText(geode, osg::Vec2(0.025, 0.025), 0.10, std::string("FlightGear ") + fgGetString("/sim/version/flightgear"), osgText::Text::LEFT_TOP);
|
||||||
|
addText(geode, osg::Vec2(0.025, 0.15), 0.03, LICENSE_URL_TEXT,
|
||||||
|
osgText::Text::LEFT_TOP,
|
||||||
|
nullptr,
|
||||||
|
0.6);
|
||||||
|
|
||||||
|
if (!_aircraftLogoVertexArray) {
|
||||||
|
addText(geode, osg::Vec2(0.025, 0.935), 0.10,
|
||||||
|
fgGetString("/sim/description"),
|
||||||
|
osgText::Text::LEFT_BOTTOM,
|
||||||
|
nullptr,
|
||||||
|
0.6);
|
||||||
|
_items.back().maxLineCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
addText(geode, osg::Vec2(0.025, 0.975), 0.03,
|
||||||
|
fgGetString("/sim/author"),
|
||||||
|
osgText::Text::LEFT_BOTTOM,
|
||||||
|
nullptr,
|
||||||
|
0.6);
|
||||||
|
_items.back().maxLineCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
addText(geode, osg::Vec2(0.975, 0.935), 0.03,
|
||||||
|
"loading status",
|
||||||
|
osgText::Text::RIGHT_BOTTOM,
|
||||||
|
fgGetNode("/sim/startup/splash-progress-text", true),
|
||||||
|
0.4);
|
||||||
|
|
||||||
|
addText(geode, osg::Vec2(0.975, 0.975), 0.03,
|
||||||
|
"spinner",
|
||||||
|
osgText::Text::RIGHT_BOTTOM,
|
||||||
|
fgGetNode("/sim/startup/splash-progress-spinner", true));
|
||||||
|
|
||||||
|
///////////
|
||||||
|
|
||||||
|
geometry = new osg::Geometry;
|
||||||
|
geometry->setSupportsDisplayList(false);
|
||||||
|
|
||||||
|
_splashSpinnerVertexArray = new osg::Vec3Array;
|
||||||
|
for (int i=0; i < 8; ++i) {
|
||||||
|
_splashSpinnerVertexArray->push_back(osg::Vec3(0.0, 0.0, -0.1));
|
||||||
|
}
|
||||||
|
geometry->setVertexArray(_splashSpinnerVertexArray);
|
||||||
|
|
||||||
|
// QColor buttonColor(27, 122, 211);
|
||||||
|
colorArray = new osg::Vec4Array;
|
||||||
|
colorArray->push_back(osg::Vec4(27 / 255.0, 122 / 255.0, 211 / 255.0, 0.75));
|
||||||
|
geometry->setColorArray(colorArray);
|
||||||
|
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||||
|
geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 8));
|
||||||
|
|
||||||
|
geode->addDrawable(geometry);
|
||||||
|
|
||||||
|
//// Full screen quad setup ////////////////////
|
||||||
|
|
||||||
|
_splashQuadCamera = new osg::Camera;
|
||||||
|
_splashQuadCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||||
|
_splashQuadCamera->setViewMatrix(osg::Matrix::identity());
|
||||||
|
_splashQuadCamera->setProjectionMatrixAsOrtho2D(0.0, 1.0, 0.0, 1.0);
|
||||||
|
_splashQuadCamera->setClearMask( 0 );
|
||||||
|
_splashQuadCamera->setAllowEventFocus(false);
|
||||||
|
_splashQuadCamera->setCullingActive(false);
|
||||||
|
_splashQuadCamera->setRenderOrder(osg::Camera::POST_RENDER, 20000);
|
||||||
|
|
||||||
|
stateSet = _splashQuadCamera->getOrCreateStateSet();
|
||||||
|
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||||
|
stateSet->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON);
|
||||||
|
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||||
|
stateSet->setRenderBinDetails(1, "RenderBin");
|
||||||
|
|
||||||
|
geometry = new osg::Geometry;
|
||||||
|
geometry->setSupportsDisplayList(false);
|
||||||
|
|
||||||
|
osg::Vec3Array* splashFullscreenQuadVertices = new osg::Vec3Array;
|
||||||
|
splashFullscreenQuadVertices->push_back(osg::Vec3(0.0, 0.0, 0.0));
|
||||||
|
splashFullscreenQuadVertices->push_back(osg::Vec3(1.0, 0.0, 0.0));
|
||||||
|
splashFullscreenQuadVertices->push_back(osg::Vec3(1.0, 1.0, 0.0));
|
||||||
|
splashFullscreenQuadVertices->push_back(osg::Vec3(0.0, 1.0, 0.0));
|
||||||
|
geometry->setVertexArray(splashFullscreenQuadVertices);
|
||||||
|
|
||||||
|
osg::Vec2Array* quadTexCoords = new osg::Vec2Array;
|
||||||
|
quadTexCoords->push_back(osg::Vec2(0, 0));
|
||||||
|
quadTexCoords->push_back(osg::Vec2(1.0f, 0));
|
||||||
|
quadTexCoords->push_back(osg::Vec2(1.0f, 1.0f));
|
||||||
|
quadTexCoords->push_back(osg::Vec2(0, 1.0f));
|
||||||
|
geometry->setTexCoordArray(0, quadTexCoords);
|
||||||
|
|
||||||
|
_splashFSQuadColor = new osg::Vec4Array;
|
||||||
|
_splashFSQuadColor->push_back(osg::Vec4(1, 1.0f, 1, 1));
|
||||||
|
geometry->setColorArray(_splashFSQuadColor);
|
||||||
|
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||||
|
geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
|
||||||
|
|
||||||
|
stateSet = geometry->getOrCreateStateSet();
|
||||||
|
stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
|
||||||
|
stateSet->setTextureAttribute(0, _splashFBOTexture);
|
||||||
|
|
||||||
|
geode = new osg::Geode;
|
||||||
|
geode->addDrawable(geometry);
|
||||||
|
|
||||||
|
_splashQuadCamera->addChild(geode);
|
||||||
|
addChild(_splashQuadCamera);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::setupLogoImage()
|
||||||
|
{
|
||||||
|
// check for a logo image, add underneath other text
|
||||||
|
SGPath logoPath = globals->resolve_maybe_aircraft_path(fgGetString("/sim/startup/splash-logo-image"));
|
||||||
|
if (!logoPath.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logoImage = osgDB::readImageFile(logoPath.utf8Str());
|
||||||
|
if (!_logoImage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Texture2D* logoTexture = new osg::Texture2D(_logoImage);
|
||||||
|
logoTexture->setResizeNonPowerOfTwoHint(false);
|
||||||
|
logoTexture->setInternalFormat(GL_RGBA);
|
||||||
|
logoTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||||
|
logoTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||||
|
|
||||||
|
osg::Geometry* geometry = new osg::Geometry;
|
||||||
|
geometry->setSupportsDisplayList(false);
|
||||||
|
|
||||||
|
_aircraftLogoVertexArray = new osg::Vec3Array;
|
||||||
|
for (int i=0; i < 4; ++i) {
|
||||||
|
_aircraftLogoVertexArray->push_back(osg::Vec3(0.0, 0.0, 0.0));
|
||||||
|
}
|
||||||
|
geometry->setVertexArray(_aircraftLogoVertexArray);
|
||||||
|
|
||||||
|
osg::Vec2Array* logoTCs = new osg::Vec2Array;
|
||||||
|
logoTCs->push_back(osg::Vec2(0, 0));
|
||||||
|
logoTCs->push_back(osg::Vec2(1.0, 0));
|
||||||
|
logoTCs->push_back(osg::Vec2(1.0, 1.0));
|
||||||
|
logoTCs->push_back(osg::Vec2(0, 1.0));
|
||||||
|
geometry->setTexCoordArray(0, logoTCs);
|
||||||
|
|
||||||
|
osg::Vec4Array* 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));
|
||||||
|
|
||||||
|
osg::StateSet* stateSet = geometry->getOrCreateStateSet();
|
||||||
|
stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
|
||||||
|
stateSet->setTextureAttribute(0, logoTexture);
|
||||||
|
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
osg::Geode* geode = new osg::Geode;
|
||||||
|
_splashFBOCamera->addChild(geode);
|
||||||
|
geode->addDrawable(geometry);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::addText(osg::Geode* geode ,
|
||||||
|
const osg::Vec2& pos, double size, const std::string& text,
|
||||||
|
const osgText::Text::AlignmentType alignment,
|
||||||
|
SGPropertyNode* dynamicValue,
|
||||||
|
double maxWidthFraction)
|
||||||
|
{
|
||||||
|
SGPath path = globals->resolve_resource_path("Fonts/LiberationFonts/LiberationSans-BoldItalic.ttf");
|
||||||
|
|
||||||
|
TextItem item;
|
||||||
|
osg::ref_ptr<osgText::Text> t = new osgText::Text;
|
||||||
|
item.textNode = t;
|
||||||
|
t->setFont(path.utf8Str());
|
||||||
|
t->setColor(osg::Vec4(1, 1, 1, 1));
|
||||||
|
t->setFontResolution(64, 64);
|
||||||
|
t->setText(text);
|
||||||
|
t->setBackdropType(osgText::Text::OUTLINE);
|
||||||
|
t->setBackdropColor(osg::Vec4(0.2, 0.2, 0.2, 1));
|
||||||
|
t->setBackdropOffset(0.04);
|
||||||
|
|
||||||
|
item.fractionalCharSize = size;
|
||||||
|
item.fractionalPosition = pos;
|
||||||
|
item.dynamicContent = dynamicValue;
|
||||||
|
item.textNode->setAlignment(alignment);
|
||||||
|
item.maxWidthFraction = maxWidthFraction;
|
||||||
|
geode->addDrawable(item.textNode);
|
||||||
|
|
||||||
|
_items.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::TextItem::reposition(int width, int height) const
|
||||||
|
{
|
||||||
|
const int halfWidth = width >> 1;
|
||||||
|
const int halfHeight = height >> 1;
|
||||||
|
osg::Vec3 pixelPos(fractionalPosition.x() * width - halfWidth,
|
||||||
|
(1.0 - fractionalPosition.y()) * height - halfHeight,
|
||||||
|
-0.1);
|
||||||
|
textNode->setPosition(pixelPos);
|
||||||
|
textNode->setCharacterSize(fractionalCharSize * height);
|
||||||
|
|
||||||
|
if (maxWidthFraction > 0.0) {
|
||||||
|
textNode->setMaximumWidth(maxWidthFraction * width);
|
||||||
|
}
|
||||||
|
|
||||||
|
recomputeSize(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::TextItem::recomputeSize(int height) const
|
||||||
|
{
|
||||||
|
if (maxLineCount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double baseSize = fractionalCharSize;
|
||||||
|
textNode->update();
|
||||||
|
while (textNode->getLineCount() > maxLineCount) {
|
||||||
|
baseSize *= 0.8; // 20% shrink each time
|
||||||
|
textNode->setCharacterSize(baseSize * height);
|
||||||
|
textNode->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SplashScreen::selectSplashImage()
|
||||||
|
{
|
||||||
|
sg_srandom_time(); // init random seed
|
||||||
|
|
||||||
|
simgear::PropertyList previewNodes = fgGetNode("/sim/previews", true)->getChildren("preview");
|
||||||
|
std::vector<SGPath> paths;
|
||||||
|
|
||||||
|
for (auto n : previewNodes) {
|
||||||
|
if (!n->getBoolValue("splash", false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGPath tpath = globals->resolve_maybe_aircraft_path(n->getStringValue("path"));
|
||||||
|
if (tpath.exists()) {
|
||||||
|
paths.push_back(tpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paths.empty()) {
|
||||||
|
// look for a legacy aircraft splash
|
||||||
|
simgear::PropertyList nodes = fgGetNode("/sim/startup", true)->getChildren("splash-texture");
|
||||||
|
for (auto n : nodes) {
|
||||||
|
SGPath tpath = globals->resolve_maybe_aircraft_path(n->getStringValue());
|
||||||
|
if (tpath.exists()) {
|
||||||
|
paths.push_back(tpath);
|
||||||
|
_legacySplashScreenMode = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seed the RNG in order to get randomness
|
if (!paths.empty()) {
|
||||||
sg_srandom_time();
|
|
||||||
|
|
||||||
if (!useable_textures.empty()) {
|
|
||||||
// Select a random useable texture
|
// Select a random useable texture
|
||||||
const int index = (int)(sg_random() * useable_textures.size());
|
const int index = (int)(sg_random() * paths.size());
|
||||||
tpath = useable_textures[index];
|
return paths.at(index).utf8Str();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tpath.isNull()) {
|
|
||||||
// no splash screen specified - select random image
|
// no splash screen specified - select random image
|
||||||
tpath = globals->get_fg_root();
|
SGPath tpath = globals->get_fg_root() / "Textures";
|
||||||
// load in the texture data
|
|
||||||
int num = (int)(sg_random() * 5.0 + 1.0);
|
int num = (int)(sg_random() * 5.0 + 1.0);
|
||||||
char num_str[5];
|
std::ostringstream oss;
|
||||||
snprintf(num_str, 4, "%d", num);
|
oss << "Splash" << num << ".png";
|
||||||
|
tpath.append(oss.str());
|
||||||
tpath.append( "Textures/Splash" );
|
return tpath.utf8Str();
|
||||||
tpath.concat( num_str );
|
|
||||||
tpath.concat( ".png" );
|
|
||||||
}
|
|
||||||
|
|
||||||
SGSharedPtr<SGPropertyNode> style = fgGetNode("/sim/gui/style[0]", true);
|
|
||||||
|
|
||||||
osg::Texture2D* splashTexture = new osg::Texture2D;
|
|
||||||
splashTexture->setImage(osgDB::readImageFile(tpath.local8BitStr()));
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
FGFontCache* fontCache = FGFontCache::instance();
|
|
||||||
osgText::Text* text = new osgText::Text;
|
|
||||||
std::string fn = style->getStringValue("fonts/splash", "");
|
|
||||||
text->setFont(fontCache->getfntpath(fn).local8BitStr());
|
|
||||||
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);
|
|
||||||
prop->setStringValue("");
|
|
||||||
text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
|
|
||||||
geode->addDrawable(text);
|
|
||||||
|
|
||||||
osgText::Text* spinnertext = new osgText::Text;
|
|
||||||
spinnertext->setFont(fontCache->getfntpath(fn).local8BitStr());
|
|
||||||
spinnertext->setCharacterSize(0.06);
|
|
||||||
spinnertext->setColor(osg::Vec4(1, 1, 1, 1));
|
|
||||||
spinnertext->setPosition(osg::Vec3(0, -0.97, 0));
|
|
||||||
spinnertext->setAlignment(osgText::Text::CENTER_CENTER);
|
|
||||||
prop = fgGetNode("/sim/startup/splash-progress-spinner", true);
|
|
||||||
prop->setStringValue("");
|
|
||||||
spinnertext->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
|
|
||||||
geode->addDrawable(spinnertext);
|
|
||||||
|
|
||||||
text = new osgText::Text;
|
|
||||||
text->setFont(fontCache->getfntpath(fn).local8BitStr());
|
|
||||||
text->setCharacterSize(0.08);
|
|
||||||
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/program-name", "FlightGear");
|
|
||||||
text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
|
|
||||||
geode->addDrawable(text);
|
|
||||||
|
|
||||||
|
|
||||||
text = new osgText::Text;
|
|
||||||
text->setFont(fontCache->getfntpath(fn).local8BitStr());
|
|
||||||
text->setCharacterSize(0.06);
|
|
||||||
text->setColor(osg::Vec4(1, 1, 1, 1));
|
|
||||||
text->setPosition(osg::Vec3(0, 0.82, 0));
|
|
||||||
text->setAlignment(osgText::Text::CENTER_CENTER);
|
|
||||||
prop = fgGetNode("/sim/startup/splash-title", true);
|
|
||||||
text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
|
|
||||||
geode->addDrawable(text);
|
|
||||||
|
|
||||||
fgSplashProgress("init");
|
|
||||||
|
|
||||||
return camera;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update callback for the switch node guarding that splash
|
void SplashScreen::doUpdate()
|
||||||
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->setName("splashGroup");
|
|
||||||
group->setUpdateCallback(new FGSplashGroupUpdateCallback);
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the splash screen
|
|
||||||
void fgSplashInit ()
|
|
||||||
{
|
{
|
||||||
globals->get_renderer()->splashinit();
|
double alpha = _splashAlphaNode->getDoubleValue();
|
||||||
|
|
||||||
|
if (alpha <= 0 || !fgGetBool("/sim/startup/splash-screen")) {
|
||||||
|
removeChild(0, getNumChildren());
|
||||||
|
_splashFBOCamera = nullptr;
|
||||||
|
_splashQuadCamera = nullptr;
|
||||||
|
} else if (getNumChildren() == 0) {
|
||||||
|
createNodes();
|
||||||
|
_splashStartTime.stamp();
|
||||||
|
resize(fgGetInt("/sim/startup/xsize"),
|
||||||
|
fgGetInt("/sim/startup/ysize"));
|
||||||
|
} else {
|
||||||
|
(*_splashFSQuadColor)[0] = osg::Vec4(1.0, 1.0, 1.0, _splashAlphaNode->getFloatValue());
|
||||||
|
_splashFSQuadColor->dirty();
|
||||||
|
|
||||||
|
for (const TextItem& item : _items) {
|
||||||
|
if (item.dynamicContent) {
|
||||||
|
item.textNode->setText(item.dynamicContent->getStringValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSplashSpinner();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fgSplashProgress( const char *identifier, unsigned int percent ) {
|
float scaleAndOffset(float v, float halfWidth)
|
||||||
const char* spinChars = "-\\|/";
|
{
|
||||||
static int spin_count = 0;
|
return halfWidth * ((v * 2.0) - 1.0);
|
||||||
std::string spin_status = std::string("");
|
}
|
||||||
|
|
||||||
if (identifier[0] != 0)
|
void SplashScreen::updateSplashSpinner()
|
||||||
spin_status += spinChars[spin_count++ % 4];
|
{
|
||||||
|
const int elapsedMsec = _splashStartTime.elapsedMSec();
|
||||||
|
float splashSpinnerPos = (elapsedMsec % 2000) / 2000.0f;
|
||||||
|
float endPos = splashSpinnerPos + 0.25f;
|
||||||
|
float wrapStartPos = 0.0f;
|
||||||
|
float wrapEndPos = 0.0f; // no wrapped quad
|
||||||
|
if (endPos > 1.0f) {
|
||||||
|
wrapEndPos = endPos - 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
fgSetString("/sim/startup/splash-progress-spinner", spin_status);
|
const float halfWidth = _width * 0.5f;
|
||||||
|
const float halfHeight = _height * 0.5f;
|
||||||
|
const float bottomY = -halfHeight;
|
||||||
|
const float topY = bottomY + 8;
|
||||||
|
const float z = -0.05f;
|
||||||
|
|
||||||
|
splashSpinnerPos = scaleAndOffset(splashSpinnerPos, halfWidth);
|
||||||
|
endPos = scaleAndOffset(endPos, halfWidth);
|
||||||
|
wrapStartPos = scaleAndOffset(wrapStartPos, halfWidth);
|
||||||
|
wrapEndPos = scaleAndOffset(wrapEndPos, halfWidth);
|
||||||
|
|
||||||
|
osg::Vec3 positions[8] = {
|
||||||
|
osg::Vec3(splashSpinnerPos, bottomY, z),
|
||||||
|
osg::Vec3(endPos, bottomY, z),
|
||||||
|
osg::Vec3(endPos,topY, z),
|
||||||
|
osg::Vec3(splashSpinnerPos, topY, z),
|
||||||
|
osg::Vec3(wrapStartPos, bottomY, z),
|
||||||
|
osg::Vec3(wrapEndPos, bottomY, z),
|
||||||
|
osg::Vec3(wrapEndPos,topY, z),
|
||||||
|
osg::Vec3(wrapStartPos, topY, z)
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i=0; i<8; ++i) {
|
||||||
|
(*_splashSpinnerVertexArray)[i] = positions[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
_splashSpinnerVertexArray->dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::resize( int width, int height )
|
||||||
|
{
|
||||||
|
if (getNumChildren() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_width = width;
|
||||||
|
_height = height;
|
||||||
|
_splashFBOCamera->setViewport(0, 0, width, height);
|
||||||
|
_splashFBOCamera->setProjectionMatrixAsOrtho2D(-width * 0.5, width * 0.5,
|
||||||
|
-height * 0.5, height * 0.5);
|
||||||
|
|
||||||
|
_splashQuadCamera->setViewport(0, 0, width, height);
|
||||||
|
_splashFBOCamera->resizeAttachments(width, height);
|
||||||
|
|
||||||
|
double halfWidth = width * 0.5;
|
||||||
|
double halfHeight = height * 0.5;
|
||||||
|
const double screenAspectRatio = static_cast<double>(width) / height;
|
||||||
|
|
||||||
|
if (_legacySplashScreenMode) {
|
||||||
|
halfWidth = width * 0.4;
|
||||||
|
halfHeight = height * 0.4;
|
||||||
|
|
||||||
|
if (screenAspectRatio > _splashImageAspectRatio) {
|
||||||
|
// screen is wider than our image
|
||||||
|
halfWidth = halfHeight;
|
||||||
|
} else {
|
||||||
|
// screen is taller than our image
|
||||||
|
halfHeight = halfWidth;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// adjust vertex positions; image covers entire area
|
||||||
|
if (screenAspectRatio > _splashImageAspectRatio) {
|
||||||
|
// screen is wider than our image
|
||||||
|
halfHeight = halfWidth / _splashImageAspectRatio;
|
||||||
|
} else {
|
||||||
|
// screen is taller than our image
|
||||||
|
halfWidth = halfHeight * _splashImageAspectRatio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust vertex positions and mark as dirty
|
||||||
|
osg::Vec3 positions[4] = {
|
||||||
|
osg::Vec3(-halfWidth, -halfHeight, 0.0),
|
||||||
|
osg::Vec3(halfWidth, -halfHeight, 0.0),
|
||||||
|
osg::Vec3(halfWidth, halfHeight, 0.0),
|
||||||
|
osg::Vec3(-halfWidth, halfHeight, 0.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i=0; i<4; ++i) {
|
||||||
|
(*_splashImageVertexArray)[i] = positions[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
_splashImageVertexArray->dirty();
|
||||||
|
|
||||||
|
if (_aircraftLogoVertexArray) {
|
||||||
|
float logoWidth = fgGetDouble("/sim/startup/splash-logo-width", 0.6) * width;
|
||||||
|
float logoHeight = _logoImage->t() * (logoWidth / _logoImage->s());
|
||||||
|
float originX = width * -0.5;
|
||||||
|
float originY = height * ((1.0 - 0.935) - 0.5);
|
||||||
|
osg::Vec3 positions[4] = {
|
||||||
|
osg::Vec3(originX, originY, 0.0),
|
||||||
|
osg::Vec3(originX + logoWidth, originY, 0.0),
|
||||||
|
osg::Vec3(originX + logoWidth, originY + logoHeight, 0.0),
|
||||||
|
osg::Vec3(originX, originY + logoHeight, 0.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i=0; i<4; ++i) {
|
||||||
|
(*_aircraftLogoVertexArray)[i] = positions[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
_aircraftLogoVertexArray->dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const TextItem& item : _items) {
|
||||||
|
item.reposition(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fgSplashProgress( const char *identifier, unsigned int percent )
|
||||||
|
{
|
||||||
|
fgSetString("/sim/startup/splash-progress-spinner", "");
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
if (identifier[0] != 0)
|
if (identifier[0] != 0)
|
||||||
|
@ -420,12 +585,11 @@ void fgSplashProgress( const char *identifier, unsigned int percent ) {
|
||||||
if( text.empty() )
|
if( text.empty() )
|
||||||
text = "<incomplete language resource>: " + id;
|
text = "<incomplete language resource>: " + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(identifier,"downloading-scenery")) {
|
if (!strcmp(identifier,"downloading-scenery")) {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
unsigned int kbytesPerSec = fgGetInt("/sim/terrasync/transfer-rate-bytes-sec") / 1024;
|
unsigned int kbytesPerSec = fgGetInt("/sim/terrasync/transfer-rate-bytes-sec") / 1024;
|
||||||
unsigned int kbytesPending = fgGetInt("/sim/terrasync/pending-kbytes");
|
unsigned int kbytesPending = fgGetInt("/sim/terrasync/pending-kbytes");
|
||||||
oss << text;
|
|
||||||
if (kbytesPending > 0) {
|
if (kbytesPending > 0) {
|
||||||
if (kbytesPending > 1024) {
|
if (kbytesPending > 1024) {
|
||||||
int mBytesPending = kbytesPending >> 10;
|
int mBytesPending = kbytesPending >> 10;
|
||||||
|
@ -442,8 +606,7 @@ void fgSplashProgress( const char *identifier, unsigned int percent ) {
|
||||||
oss << " - " << kbytesPerSec << " Kb/sec";
|
oss << " - " << kbytesPerSec << " Kb/sec";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fgSetString("/sim/startup/splash-progress-text", oss.str());
|
fgSetString("/sim/startup/splash-progress-spinner", oss.str());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// over-write the spinner
|
// over-write the spinner
|
||||||
|
@ -452,10 +615,10 @@ void fgSplashProgress( const char *identifier, unsigned int percent ) {
|
||||||
oss << percent << "% complete";
|
oss << percent << "% complete";
|
||||||
fgSetString("/sim/startup/splash-progress-spinner", oss.str());
|
fgSetString("/sim/startup/splash-progress-spinner", oss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if( fgGetString("/sim/startup/splash-progress-text") == text )
|
if( fgGetString("/sim/startup/splash-progress-text") == text )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SG_LOG( SG_VIEW, SG_INFO, "Splash screen progress " << identifier );
|
SG_LOG( SG_VIEW, SG_INFO, "Splash screen progress " << identifier );
|
||||||
fgSetString("/sim/startup/splash-progress-text", text);
|
fgSetString("/sim/startup/splash-progress-text", text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,22 +25,82 @@
|
||||||
#ifndef _SPLASH_HXX
|
#ifndef _SPLASH_HXX
|
||||||
#define _SPLASH_HXX
|
#define _SPLASH_HXX
|
||||||
|
|
||||||
#include <osg/Node>
|
#include <osg/Group>
|
||||||
|
#include <osgText/Text>
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#include <simgear/props/props.hxx>
|
||||||
# error This library requires C++
|
#include <simgear/timing/timestamp.hxx>
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Initialize the splash screen */
|
#include <vector>
|
||||||
void fgSplashInit ();
|
|
||||||
|
namespace osg
|
||||||
|
{
|
||||||
|
class Texture2D;
|
||||||
|
class Image;
|
||||||
|
class Camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SplashScreen : public osg::Group
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SplashScreen();
|
||||||
|
~SplashScreen();
|
||||||
|
|
||||||
|
void resize(int width, int height);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class SplashScreenUpdateCallback;
|
||||||
|
|
||||||
|
void createNodes();
|
||||||
|
void setupLogoImage();
|
||||||
|
|
||||||
|
void doUpdate();
|
||||||
|
void updateSplashSpinner();
|
||||||
|
|
||||||
|
std::string selectSplashImage();
|
||||||
|
|
||||||
|
void addText(osg::Geode* geode, const osg::Vec2& pos, double size, const std::string& text,
|
||||||
|
const osgText::Text::AlignmentType alignment,
|
||||||
|
SGPropertyNode* dynamicValue = nullptr,
|
||||||
|
double maxWidthFraction = -1.0);
|
||||||
|
|
||||||
|
bool _legacySplashScreenMode = false;
|
||||||
|
SGPropertyNode_ptr _splashAlphaNode;
|
||||||
|
osg::ref_ptr<osg::Camera> _splashFBOCamera;
|
||||||
|
double _splashImageAspectRatio; // stores width/height of the splash image we loaded
|
||||||
|
osg::Image* _splashImage = nullptr;
|
||||||
|
osg::Image* _logoImage = nullptr;
|
||||||
|
osg::Vec3Array* _splashImageVertexArray = nullptr;
|
||||||
|
osg::Vec3Array* _splashSpinnerVertexArray = nullptr;
|
||||||
|
osg::Vec3Array* _aircraftLogoVertexArray = nullptr;
|
||||||
|
|
||||||
|
int _width, _height;
|
||||||
|
|
||||||
|
osg::Texture2D* _splashFBOTexture;
|
||||||
|
osg::Vec4Array* _splashFSQuadColor;
|
||||||
|
osg::ref_ptr<osg::Camera> _splashQuadCamera;
|
||||||
|
|
||||||
|
struct TextItem
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osgText::Text> textNode;
|
||||||
|
SGPropertyNode_ptr dynamicContent;
|
||||||
|
osg::Vec2 fractionalPosition; // position in the 0.0 .. 1.0 range
|
||||||
|
double fractionalCharSize;
|
||||||
|
double maxWidthFraction = -1.0;
|
||||||
|
unsigned int maxLineCount = 0;
|
||||||
|
|
||||||
|
void recomputeSize(int height) const;
|
||||||
|
void reposition(int width, int height) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<TextItem> _items;
|
||||||
|
SGTimeStamp _splashStartTime;
|
||||||
|
};
|
||||||
|
|
||||||
/** Set progress information.
|
/** Set progress information.
|
||||||
* "identifier" references an element of the language resource. */
|
* "identifier" references an element of the language resource. */
|
||||||
void fgSplashProgress ( const char *identifier, unsigned int percent = 0 );
|
void fgSplashProgress ( const char *identifier, unsigned int percent = 0 );
|
||||||
|
|
||||||
/** Retrieve the splash screen node */
|
|
||||||
osg::Node* fgCreateSplashNode();
|
|
||||||
|
|
||||||
#endif // _SPLASH_HXX
|
#endif // _SPLASH_HXX
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue