Merge branch 'next' into durk-atc
This commit is contained in:
commit
3bd4e99d81
29 changed files with 4018 additions and 9 deletions
17
configure.ac
17
configure.ac
|
@ -296,6 +296,14 @@ if test "x$have_rti13" = "xyes" ; then
|
|||
AC_SUBST(HLA_LIBS, "-lsghla13 -lsghla $hla_libs")
|
||||
fi
|
||||
|
||||
dnl EXPERIMENTAL fgpanel application
|
||||
# defaults to no
|
||||
AC_ARG_WITH(fgpanel, [ --with-fgpanel Include fgpanel application (EXPERIMENTAL) [default=no]], [], [with_fgpanel=no])
|
||||
if test "x$with_fgpanel" = "xyes"; then
|
||||
AC_DEFINE([WITH_FGPANEL], 1, [Define to enable fgpanel application])
|
||||
fi
|
||||
AM_CONDITIONAL(WITH_FGPANEL, test "x$with_fgpanel" = "xyes")
|
||||
|
||||
dnl Used by JSBSim to conditionally compile in fgfs interface code
|
||||
AC_DEFINE([FGFS], 1, [Define so that JSBSim compiles in 'library' mode])
|
||||
|
||||
|
@ -940,7 +948,8 @@ AC_CONFIG_FILES([ \
|
|||
utils/propmerge/Makefile \
|
||||
utils/TerraSync/Makefile \
|
||||
utils/xmlgrep/Makefile \
|
||||
utils/fgviewer/Makefile
|
||||
utils/fgviewer/Makefile \
|
||||
utils/fgpanel/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
|
@ -977,6 +986,12 @@ else
|
|||
echo "Event input: no"
|
||||
fi
|
||||
|
||||
if test "x$with_fgpanel" = "xyes"; then
|
||||
echo "fgpanel: yes"
|
||||
else
|
||||
echo "fgpanel: no"
|
||||
fi
|
||||
|
||||
if test "x$enable_sp_fdms" != "xno"; then
|
||||
echo "Include special purpose flight models: yes"
|
||||
else
|
||||
|
|
|
@ -173,6 +173,8 @@ void FGCondition::InitializeConditionals(void)
|
|||
|
||||
FGCondition::~FGCondition(void)
|
||||
{
|
||||
delete TestParam1;
|
||||
delete TestParam2;
|
||||
for (unsigned int i=0; i<conditions.size(); i++) delete conditions[i];
|
||||
|
||||
Debug(1);
|
||||
|
|
|
@ -199,6 +199,9 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
|
|||
FGFCSComponent::~FGFCSComponent()
|
||||
{
|
||||
Debug(1);
|
||||
for (unsigned int i=0; i<InputNodes.size(); i++) {
|
||||
delete InputNodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -38,7 +38,7 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGJSBBase.h"
|
||||
#include "math/FGParameter.h"
|
||||
#include "math/FGPropertyValue.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -111,7 +111,7 @@ protected:
|
|||
std::vector <FGPropertyManager*> OutputNodes;
|
||||
FGPropertyManager* ClipMinPropertyNode;
|
||||
FGPropertyManager* ClipMaxPropertyNode;
|
||||
std::vector <FGParameter*> InputNodes;
|
||||
std::vector <FGPropertyValue*> InputNodes;
|
||||
std::vector <std::string> InputNames;
|
||||
std::vector <float> InputSigns;
|
||||
std::vector <double> output_array;
|
||||
|
|
|
@ -55,10 +55,15 @@ FGJoystickInput::joystick::joystick ()
|
|||
|
||||
FGJoystickInput::joystick::~joystick ()
|
||||
{
|
||||
// delete js? why not?
|
||||
// delete js;
|
||||
// delete js? no, since js == this - and we're in the destructor already.
|
||||
delete[] axes;
|
||||
delete[] buttons;
|
||||
jsnum = 0;
|
||||
js = NULL;
|
||||
naxes = 0;
|
||||
nbuttons = 0;
|
||||
axes = NULL;
|
||||
buttons = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -68,13 +73,24 @@ FGJoystickInput::FGJoystickInput()
|
|||
|
||||
FGJoystickInput::~FGJoystickInput()
|
||||
{
|
||||
_remove();
|
||||
}
|
||||
|
||||
void FGJoystickInput::_remove()
|
||||
{
|
||||
SGPropertyNode * js_nodes = fgGetNode("/input/joysticks", true);
|
||||
js_nodes->removeChildren("js", false);
|
||||
for (int i = 0; i < MAX_JOYSTICKS; i++)
|
||||
{
|
||||
if (bindings[i].js)
|
||||
delete bindings[i].js;
|
||||
bindings[i].js = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void FGJoystickInput::init()
|
||||
{
|
||||
jsInit();
|
||||
// TODO: zero the old bindings first.
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Initializing joystick bindings");
|
||||
SGPropertyNode * js_nodes = fgGetNode("/input/joysticks", true);
|
||||
|
||||
|
@ -121,8 +137,7 @@ void FGJoystickInput::init()
|
|||
|
||||
void FGJoystickInput::reinit() {
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Re-Initializing joystick bindings");
|
||||
SGPropertyNode * js_nodes = fgGetNode("/input/joysticks", true);
|
||||
js_nodes->removeChildren("js", false);
|
||||
_remove();
|
||||
FGJoystickInput::init();
|
||||
FGJoystickInput::postinit();
|
||||
}
|
||||
|
|
|
@ -52,6 +52,8 @@ public:
|
|||
static const int MAX_JOYSTICK_BUTTONS = 32;
|
||||
|
||||
private:
|
||||
void _remove();
|
||||
|
||||
/**
|
||||
* Settings for a single joystick axis.
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
DIST_SUBDIRS = GPSsmooth TerraSync Modeller js_server fgadmin xmlgrep propmerge fgviewer
|
||||
|
||||
SUBDIRS = GPSsmooth TerraSync Modeller js_server propmerge fgviewer
|
||||
SUBDIRS = GPSsmooth TerraSync Modeller js_server propmerge fgviewer fgpanel
|
||||
|
||||
|
|
7
utils/fgpanel/.gitignore
vendored
Normal file
7
utils/fgpanel/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
fgpanel
|
||||
*.o
|
||||
*.obj
|
||||
.deps
|
||||
*.Po
|
||||
Makefile
|
||||
Makefile.in
|
31
utils/fgpanel/ApplicationProperties.hxx
Normal file
31
utils/fgpanel/ApplicationProperties.hxx
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __APPLICATION_PROPERTIES
|
||||
#define __APPLICATION_PROPERTIES
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include "FGFontCache.hxx"
|
||||
class ApplicationProperties {
|
||||
public:
|
||||
static double getDouble( const char * name, double def = 0.0 );
|
||||
static SGPath GetRootPath( const char * subDir = NULL );
|
||||
static SGPropertyNode_ptr Properties;
|
||||
static std::string root;
|
||||
static FGFontCache fontCache;
|
||||
};
|
||||
#endif
|
208
utils/fgpanel/FGFontCache.cxx
Normal file
208
utils/fgpanel/FGFontCache.cxx
Normal file
|
@ -0,0 +1,208 @@
|
|||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include "ApplicationProperties.hxx"
|
||||
#include "FGFontCache.hxx"
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// FGFontCache class.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//extern puFont FONT_HELVETICA_14;
|
||||
//extern puFont FONT_SANS_12B;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct GuiFont
|
||||
{
|
||||
const char *name;
|
||||
puFont *font;
|
||||
struct Predicate
|
||||
: public std::unary_function<const GuiFont, bool>
|
||||
{
|
||||
Predicate(const char* name_) : name(name_) {}
|
||||
bool operator() (const GuiFont& f1) const
|
||||
{
|
||||
return ::strcmp(f1.name, name) == 0;
|
||||
}
|
||||
const char* name;
|
||||
};
|
||||
};
|
||||
|
||||
const GuiFont guifonts[] = {
|
||||
{ "default", &PUFONT_HELVETICA_12 },
|
||||
{ "FIXED_8x13", &PUFONT_8_BY_13 },
|
||||
{ "FIXED_9x15", &PUFONT_9_BY_15 },
|
||||
{ "TIMES_10", &PUFONT_TIMES_ROMAN_10 },
|
||||
{ "TIMES_24", &PUFONT_TIMES_ROMAN_24 },
|
||||
{ "HELVETICA_10", &PUFONT_HELVETICA_10 },
|
||||
{ "HELVETICA_12", &PUFONT_HELVETICA_12 },
|
||||
// { "HELVETICA_14", &FONT_HELVETICA_14 },
|
||||
{ "HELVETICA_18", &PUFONT_HELVETICA_18 }
|
||||
// { "SANS_12B", &FONT_SANS_12B }
|
||||
};
|
||||
|
||||
const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
|
||||
}
|
||||
|
||||
FGFontCache::FGFontCache() :
|
||||
_initialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
FGFontCache::~FGFontCache()
|
||||
{
|
||||
PuFontMap::iterator it, end = _puFonts.end();
|
||||
for (it = _puFonts.begin(); it != end; ++it)
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
inline bool FGFontCache::FntParamsLess::operator()(const FntParams& f1,
|
||||
const FntParams& f2) const
|
||||
{
|
||||
int comp = f1.name.compare(f2.name);
|
||||
if (comp < 0)
|
||||
return true;
|
||||
else if (comp > 0)
|
||||
return false;
|
||||
if (f1.size < f2.size)
|
||||
return true;
|
||||
else if (f1.size > f2.size)
|
||||
return false;
|
||||
return f1.slant < f2.slant;
|
||||
}
|
||||
|
||||
struct FGFontCache::fnt *
|
||||
FGFontCache::getfnt(const char *name, float size, float slant)
|
||||
{
|
||||
string fontName(name);
|
||||
FntParams fntParams(fontName, size, slant);
|
||||
PuFontMap::iterator i = _puFonts.find(fntParams);
|
||||
if (i != _puFonts.end())
|
||||
return i->second;
|
||||
// fntTexFont s are all preloaded into the _texFonts map
|
||||
TexFontMap::iterator texi = _texFonts.find(fontName);
|
||||
fntTexFont* texfont = 0;
|
||||
puFont* pufont = 0;
|
||||
if (texi != _texFonts.end()) {
|
||||
texfont = texi->second;
|
||||
} else {
|
||||
const GuiFont* guifont = std::find_if(&guifonts[0], guifontsEnd,
|
||||
GuiFont::Predicate(name));
|
||||
if (guifont != guifontsEnd) {
|
||||
pufont = guifont->font;
|
||||
}
|
||||
}
|
||||
fnt* f = new fnt;
|
||||
if (pufont) {
|
||||
f->pufont = pufont;
|
||||
} else if (texfont) {
|
||||
f->texfont = texfont;
|
||||
f->pufont = new puFont;
|
||||
f->pufont->initialize(static_cast<fntFont *>(f->texfont), size, slant);
|
||||
} else {
|
||||
f->pufont = guifonts[0].font;
|
||||
}
|
||||
_puFonts[fntParams] = f;
|
||||
return f;
|
||||
}
|
||||
|
||||
puFont *
|
||||
FGFontCache::get(const char *name, float size, float slant)
|
||||
{
|
||||
return getfnt(name, size, slant)->pufont;
|
||||
}
|
||||
|
||||
fntTexFont *
|
||||
FGFontCache::getTexFont(const char *name, float size, float slant)
|
||||
{
|
||||
init();
|
||||
return getfnt(name, size, slant)->texfont;
|
||||
}
|
||||
|
||||
puFont *
|
||||
FGFontCache::get(SGPropertyNode *node)
|
||||
{
|
||||
if (!node)
|
||||
return get("Helvetica.txf", 15.0, 0.0);
|
||||
|
||||
const char *name = node->getStringValue("name", "Helvetica.txf");
|
||||
float size = node->getFloatValue("size", 15.0);
|
||||
float slant = node->getFloatValue("slant", 0.0);
|
||||
|
||||
return get(name, size, slant);
|
||||
}
|
||||
|
||||
void FGFontCache::init()
|
||||
{
|
||||
if (!_initialized) {
|
||||
char *envp = ::getenv("FG_FONTS");
|
||||
if (envp != NULL) {
|
||||
_path.set(envp);
|
||||
} else {
|
||||
_path.set(ApplicationProperties::GetRootPath("Fonts").str());
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
SGPath
|
||||
FGFontCache::getfntpath(const char *name)
|
||||
{
|
||||
init();
|
||||
SGPath path(_path);
|
||||
if (name && std::string(name) != "") {
|
||||
path.append(name);
|
||||
if (path.exists())
|
||||
return path;
|
||||
}
|
||||
|
||||
path = SGPath(_path);
|
||||
path.append("Helvetica.txf");
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
bool FGFontCache::initializeFonts()
|
||||
{
|
||||
static string fontext("txf");
|
||||
init();
|
||||
ulDir* fontdir = ulOpenDir(_path.c_str());
|
||||
if (!fontdir)
|
||||
return false;
|
||||
const ulDirEnt *dirEntry;
|
||||
while ((dirEntry = ulReadDir(fontdir)) != 0) {
|
||||
SGPath path(_path);
|
||||
path.append(dirEntry->d_name);
|
||||
if (path.extension() == fontext) {
|
||||
fntTexFont* f = new fntTexFont;
|
||||
if (f->load((char *)path.c_str()))
|
||||
_texFonts[string(dirEntry->d_name)] = f;
|
||||
else
|
||||
delete f;
|
||||
}
|
||||
}
|
||||
ulCloseDir(fontdir);
|
||||
return true;
|
||||
}
|
||||
|
||||
// end of new_gui.cxx
|
||||
|
86
utils/fgpanel/FGFontCache.hxx
Normal file
86
utils/fgpanel/FGFontCache.hxx
Normal file
|
@ -0,0 +1,86 @@
|
|||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGFONTCACHE_HXX
|
||||
#define __FGFONTCACHE_HXX
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <plib/pu.h>
|
||||
/**
|
||||
* A class to keep all fonts available for future use.
|
||||
* This also assures a font isn't resident more than once.
|
||||
*/
|
||||
class FGFontCache {
|
||||
private:
|
||||
// The parameters of a request to the cache.
|
||||
struct FntParams
|
||||
{
|
||||
const std::string name;
|
||||
const float size;
|
||||
const float slant;
|
||||
FntParams() : size(0.0f), slant(0.0f) {}
|
||||
FntParams(const FntParams& rhs)
|
||||
: name(rhs.name), size(rhs.size), slant(rhs.slant)
|
||||
{
|
||||
}
|
||||
FntParams(const std::string& name_, float size_, float slant_)
|
||||
: name(name_), size(size_), slant(slant_)
|
||||
{
|
||||
}
|
||||
};
|
||||
struct FntParamsLess
|
||||
: public std::binary_function<const FntParams, const FntParams, bool>
|
||||
{
|
||||
bool operator() (const FntParams& f1, const FntParams& f2) const;
|
||||
};
|
||||
struct fnt {
|
||||
fnt(puFont *pu = 0) : pufont(pu), texfont(0) {}
|
||||
~fnt() { if (texfont) { delete pufont; delete texfont; } }
|
||||
// Font used by plib GUI code
|
||||
puFont *pufont;
|
||||
// TXF font
|
||||
fntTexFont *texfont;
|
||||
};
|
||||
// Path to the font directory
|
||||
SGPath _path;
|
||||
|
||||
typedef map<const string, fntTexFont*> TexFontMap;
|
||||
typedef map<const FntParams, fnt*, FntParamsLess> PuFontMap;
|
||||
TexFontMap _texFonts;
|
||||
PuFontMap _puFonts;
|
||||
|
||||
bool _initialized;
|
||||
struct fnt *getfnt(const char *name, float size, float slant);
|
||||
void init();
|
||||
|
||||
public:
|
||||
FGFontCache();
|
||||
~FGFontCache();
|
||||
|
||||
puFont *get(const char *name, float size=15.0, float slant=0.0);
|
||||
puFont *get(SGPropertyNode *node);
|
||||
|
||||
fntTexFont *getTexFont(const char *name, float size=15.0, float slant=0.0);
|
||||
|
||||
SGPath getfntpath(const char *name);
|
||||
/**
|
||||
* Preload all the fonts in the FlightGear font directory. It is
|
||||
* important to load the font textures early, with the proper
|
||||
* graphics context current, so that no plib (or our own) code
|
||||
* tries to load a font from disk when there's no current graphics
|
||||
* context.
|
||||
*/
|
||||
bool initializeFonts();
|
||||
};
|
||||
#endif
|
94
utils/fgpanel/FGGLApplication.cxx
Normal file
94
utils/fgpanel/FGGLApplication.cxx
Normal file
|
@ -0,0 +1,94 @@
|
|||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#include "FGGLApplication.hxx"
|
||||
#include "GL/gl.h"
|
||||
#include "GL/glut.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <stdio.h>
|
||||
|
||||
FGGLApplication * FGGLApplication::application = NULL;
|
||||
|
||||
FGGLApplication::FGGLApplication( const char * aName, int argc, char ** argv ) :
|
||||
gameMode(false),
|
||||
name( aName )
|
||||
{
|
||||
if( application != NULL ) {
|
||||
std::cerr << "Only one instance of FGGLApplication allowed!" << std::endl;
|
||||
throw std::exception();
|
||||
}
|
||||
application = this;
|
||||
|
||||
glutInit( &argc, argv );
|
||||
}
|
||||
|
||||
FGGLApplication::~FGGLApplication()
|
||||
{
|
||||
}
|
||||
|
||||
void FGGLApplication::DisplayCallback()
|
||||
{
|
||||
if( application ) application->Display();
|
||||
}
|
||||
|
||||
void FGGLApplication::IdleCallback()
|
||||
{
|
||||
if( application ) application->Idle();
|
||||
}
|
||||
|
||||
void FGGLApplication::KeyCallback( unsigned char key, int x, int y )
|
||||
{
|
||||
if( application ) application->Key( key, x, y );
|
||||
}
|
||||
|
||||
void FGGLApplication::ReshapeCallback( int width, int height )
|
||||
{
|
||||
if( application ) application->Reshape( width, height );
|
||||
}
|
||||
|
||||
void FGGLApplication::Run( int glutMode, bool gameMode, int width, int height, int bpp )
|
||||
{
|
||||
glutInitDisplayMode(glutMode);
|
||||
if( gameMode ) {
|
||||
width = glutGet(GLUT_SCREEN_WIDTH);
|
||||
height = glutGet(GLUT_SCREEN_HEIGHT);
|
||||
char game_mode_str[20];
|
||||
snprintf(game_mode_str, 20, "%dx%d:%d", width, height, bpp );
|
||||
glutGameModeString( game_mode_str );
|
||||
glutEnterGameMode();
|
||||
this->gameMode = gameMode;
|
||||
} else {
|
||||
if( width == -1 )
|
||||
width = glutGet(GLUT_SCREEN_WIDTH);
|
||||
|
||||
if( height == -1 )
|
||||
height = glutGet(GLUT_SCREEN_HEIGHT);
|
||||
|
||||
glutInitDisplayMode(glutMode);
|
||||
// glutInitWindowSize(width, height);
|
||||
windowId = glutCreateWindow(name);
|
||||
}
|
||||
Init();
|
||||
|
||||
glutKeyboardFunc(FGGLApplication::KeyCallback);
|
||||
glutIdleFunc(FGGLApplication::IdleCallback);
|
||||
glutDisplayFunc(FGGLApplication::DisplayCallback);
|
||||
glutReshapeFunc(FGGLApplication::ReshapeCallback);
|
||||
glutMainLoop();
|
||||
}
|
48
utils/fgpanel/FGGLApplication.hxx
Normal file
48
utils/fgpanel/FGGLApplication.hxx
Normal file
|
@ -0,0 +1,48 @@
|
|||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGGLAPPLICATION_HXX
|
||||
#define __FGGLAPPLICATION_HXX
|
||||
|
||||
class FGGLApplication {
|
||||
public:
|
||||
FGGLApplication( const char * name, int argc, char ** argv );
|
||||
virtual ~FGGLApplication();
|
||||
void Run( int glutMode, bool gameMode, int widht=-1, int height=-1, int bpp = 32 );
|
||||
protected:
|
||||
virtual void Key( unsigned char key, int x, int y ) {}
|
||||
virtual void Idle() {}
|
||||
virtual void Display() {}
|
||||
virtual void Reshape( int width, int height ) {}
|
||||
|
||||
virtual void Init() {}
|
||||
|
||||
int windowId;
|
||||
bool gameMode;
|
||||
|
||||
const char * name;
|
||||
|
||||
static FGGLApplication * application;
|
||||
private:
|
||||
static void KeyCallback( unsigned char key, int x, int y );
|
||||
static void IdleCallback();
|
||||
static void DisplayCallback();
|
||||
static void ReshapeCallback( int width, int height );
|
||||
|
||||
};
|
||||
|
||||
#endif
|
142
utils/fgpanel/FGPNGTextureLoader.cxx
Normal file
142
utils/fgpanel/FGPNGTextureLoader.cxx
Normal file
|
@ -0,0 +1,142 @@
|
|||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#include "FGPNGTextureLoader.hxx"
|
||||
|
||||
#include <GL/glu.h>
|
||||
#include <png.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
GLuint FGPNGTextureLoader::loadTexture( const string & filename )
|
||||
{
|
||||
//header for testing if it is a png
|
||||
png_byte header[8];
|
||||
|
||||
//open file as binary
|
||||
FILE *fp = fopen(filename.c_str(), "rb");
|
||||
if (!fp) {
|
||||
return NOTEXTURE;
|
||||
}
|
||||
|
||||
//read the header
|
||||
fread(header, 1, 8, fp);
|
||||
|
||||
//test if png
|
||||
int is_png = !png_sig_cmp(header, 0, 8);
|
||||
if (!is_png) {
|
||||
fclose(fp);
|
||||
return NOTEXTURE;
|
||||
}
|
||||
|
||||
//create png struct
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
|
||||
NULL, NULL);
|
||||
if (!png_ptr) {
|
||||
fclose(fp);
|
||||
return (NOTEXTURE);
|
||||
}
|
||||
|
||||
//create png info struct
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
|
||||
fclose(fp);
|
||||
return (NOTEXTURE);
|
||||
}
|
||||
|
||||
//create png info struct
|
||||
png_infop end_info = png_create_info_struct(png_ptr);
|
||||
if (!end_info) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
|
||||
fclose(fp);
|
||||
return (NOTEXTURE);
|
||||
}
|
||||
|
||||
//png error stuff, not sure libpng man suggests this.
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
fclose(fp);
|
||||
return (NOTEXTURE);
|
||||
}
|
||||
|
||||
//init png reading
|
||||
png_init_io(png_ptr, fp);
|
||||
|
||||
//let libpng know you already read the first 8 bytes
|
||||
png_set_sig_bytes(png_ptr, 8);
|
||||
|
||||
// read all the info up to the image data
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
//variables to pass to get info
|
||||
int bit_depth, color_type;
|
||||
png_uint_32 twidth, theight;
|
||||
|
||||
// get info about png
|
||||
png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
// Update the png info struct.
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
// Row size in bytes.
|
||||
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||
|
||||
// Allocate the image_data as a big block, to be given to opengl
|
||||
png_byte *image_data = new png_byte[rowbytes * theight];
|
||||
if (!image_data) {
|
||||
//clean up memory and close stuff
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
fclose(fp);
|
||||
return NOTEXTURE;
|
||||
}
|
||||
|
||||
//row_pointers is for pointing to image_data for reading the png with libpng
|
||||
png_bytep *row_pointers = new png_bytep[theight];
|
||||
if (!row_pointers) {
|
||||
//clean up memory and close stuff
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
delete[] image_data;
|
||||
fclose(fp);
|
||||
return NOTEXTURE;
|
||||
}
|
||||
// set the individual row_pointers to point at the correct offsets of image_data
|
||||
for (png_uint_32 i = 0; i < theight; ++i)
|
||||
row_pointers[theight - 1 - i] = image_data + i * rowbytes;
|
||||
|
||||
//read the png into image_data through row_pointers
|
||||
png_read_image(png_ptr, row_pointers);
|
||||
|
||||
//Now generate the OpenGL texture object
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
gluBuild2DMipmaps( GL_TEXTURE_2D, 4, twidth, theight, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)image_data );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
|
||||
// glTexImage2D(GL_TEXTURE_2D,0, GL_RGBA, twidth, theight, 0,
|
||||
// GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) image_data);
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
//clean up memory and close stuff
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
delete[] image_data;
|
||||
delete[] row_pointers;
|
||||
fclose(fp);
|
||||
return texture;
|
||||
}
|
26
utils/fgpanel/FGPNGTextureLoader.hxx
Normal file
26
utils/fgpanel/FGPNGTextureLoader.hxx
Normal file
|
@ -0,0 +1,26 @@
|
|||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGPNGTEXTURELOADER_HXX
|
||||
#define __FGPNGTEXTURELOADER_HXX
|
||||
|
||||
#include "FGTextureLoaderInterface.hxx"
|
||||
|
||||
class FGPNGTextureLoader : public FGTextureLoaderInterface {
|
||||
public:
|
||||
virtual GLuint loadTexture( const std::string & filename );
|
||||
|
||||
const static GLuint NOTEXTURE = 0;
|
||||
};
|
||||
#endif
|
279
utils/fgpanel/FGPanelApplication.cxx
Normal file
279
utils/fgpanel/FGPanelApplication.cxx
Normal file
|
@ -0,0 +1,279 @@
|
|||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#include "FGPanelApplication.hxx"
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glut.h>
|
||||
|
||||
#include <simgear/math/SGMisc.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "panel_io.hxx"
|
||||
#include "ApplicationProperties.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
inline static string ParseArgs( int argc, char ** argv, const string & token )
|
||||
{
|
||||
for( int i = 0; i < argc; i++ ) {
|
||||
string arg = argv[i];
|
||||
if( arg.find( token ) == 0 )
|
||||
return arg.substr( token.length() );
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
inline static string ParseArgs( int argc, char ** argv, const char * token )
|
||||
{
|
||||
string s = token;
|
||||
return ParseArgs( argc, argv, s );
|
||||
}
|
||||
|
||||
#include "FGPNGTextureLoader.hxx"
|
||||
#include "FGRGBTextureLoader.hxx"
|
||||
static FGPNGTextureLoader pngTextureLoader;
|
||||
static FGRGBTextureLoader rgbTextureLoader;
|
||||
|
||||
FGPanelApplication::FGPanelApplication( int argc, char ** argv ) :
|
||||
FGGLApplication( "FlightGear Panel", argc, argv )
|
||||
{
|
||||
sglog().setLogLevels( SG_ALL, SG_WARN );
|
||||
FGCroppedTexture::registerTextureLoader( "png", &pngTextureLoader );
|
||||
FGCroppedTexture::registerTextureLoader( "rgb", &rgbTextureLoader );
|
||||
|
||||
string panelFilename;
|
||||
string fgRoot;
|
||||
|
||||
for( int i = 1; i < argc; i++ ) {
|
||||
panelFilename = ParseArgs( argc, argv, "--panel=" );
|
||||
fgRoot = ParseArgs( argc, argv, "--fg-root=" );
|
||||
}
|
||||
|
||||
if( fgRoot.length() > 0 )
|
||||
ApplicationProperties::root = fgRoot;
|
||||
|
||||
if( panelFilename.length() == 0 ) {
|
||||
cerr << "Need a panel filename. Use --panel=path_to_filename" << endl;
|
||||
throw exception();
|
||||
}
|
||||
|
||||
try {
|
||||
SGPath tpath = ApplicationProperties::GetRootPath( panelFilename.c_str() );
|
||||
readProperties( tpath.str(), ApplicationProperties::Properties );
|
||||
}
|
||||
catch( sg_io_exception & e ) {
|
||||
cerr << e.getFormattedMessage() << endl;
|
||||
throw;
|
||||
}
|
||||
|
||||
for( int i = 1; i < argc; i++ ) {
|
||||
string arg = argv[i];
|
||||
if( arg.find( "--prop:" ) == 0 ) {
|
||||
string s2 = arg.substr( 7 );
|
||||
unsigned p = s2.find( "=" );
|
||||
if( p != string::npos ) {
|
||||
string propertyName = s2.substr( 0, p );
|
||||
string propertyValue = s2.substr( p+1 );
|
||||
ApplicationProperties::Properties->getNode( propertyName.c_str(), true )->setValue( propertyValue.c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SGPropertyNode_ptr n;
|
||||
if( (n = ApplicationProperties::Properties->getNode( "panel" )) != NULL )
|
||||
panel = FGReadablePanel::read( n );
|
||||
|
||||
protocol = new FGPanelProtocol( ApplicationProperties::Properties->getNode( "communication", true ) );
|
||||
protocol->init();
|
||||
}
|
||||
|
||||
FGPanelApplication::~FGPanelApplication()
|
||||
{
|
||||
}
|
||||
|
||||
void FGPanelApplication::Run()
|
||||
{
|
||||
int mode = GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE;
|
||||
int w = panel == NULL ? 0 : panel->getWidth();
|
||||
int h = panel == NULL ? 0 : panel->getHeight();
|
||||
if( w == 0 && h == 0 ) {
|
||||
w = 1024;
|
||||
h = 768;
|
||||
} else if( w == 0 ) {
|
||||
w = h / 0.75;
|
||||
} else if( h == 0 ) {
|
||||
h = w * 0.75;
|
||||
}
|
||||
|
||||
bool gameMode = ApplicationProperties::Properties->getNode( "game-mode", true )->getBoolValue();
|
||||
FGGLApplication::Run( mode, gameMode, w, h );
|
||||
}
|
||||
|
||||
void FGPanelApplication::Init()
|
||||
{
|
||||
glAlphaFunc(GL_GREATER, 0.1);
|
||||
glutSetCursor( GLUT_CURSOR_NONE );
|
||||
ApplicationProperties::fontCache.initializeFonts();
|
||||
}
|
||||
|
||||
void FGPanelApplication::Reshape( int width, int height )
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
glViewport(0, 0, (GLsizei) width, (GLsizei) height);
|
||||
}
|
||||
|
||||
void FGPanelApplication::Idle()
|
||||
{
|
||||
double d = glutGet(GLUT_ELAPSED_TIME);
|
||||
|
||||
double dt = Sleep();
|
||||
if( dt == 0 )
|
||||
return;
|
||||
|
||||
if( panel != NULL )
|
||||
panel->update( dt );
|
||||
|
||||
glutSwapBuffers();
|
||||
|
||||
if( protocol != NULL )
|
||||
protocol->update( dt );
|
||||
|
||||
static double dsum = 0.0;
|
||||
static unsigned cnt = 0;
|
||||
dsum += glutGet(GLUT_ELAPSED_TIME)-d;
|
||||
cnt++;
|
||||
if( dsum > 1000.0 ) {
|
||||
ApplicationProperties::Properties->getNode( "/sim/frame-rate", true )->setDoubleValue(cnt*1000.0/dsum );
|
||||
dsum = 0.0;
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FGPanelApplication::Key( unsigned char key, int x, int y )
|
||||
{
|
||||
switch( key ) {
|
||||
case 0x1b:
|
||||
if( gameMode ) glutLeaveGameMode();
|
||||
else glutDestroyWindow( windowId );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
double FGPanelApplication::Sleep()
|
||||
{
|
||||
SGTimeStamp current_time_stamp;
|
||||
static SGTimeStamp last_time_stamp;
|
||||
|
||||
if ( last_time_stamp.get_seconds() == 0 )
|
||||
last_time_stamp.stamp();
|
||||
|
||||
double model_hz = 60;
|
||||
double throttle_hz = ApplicationProperties::getDouble("/sim/frame-rate-throttle-hz", 0.0);
|
||||
if ( throttle_hz > 0.0 ) {
|
||||
// optionally throttle the frame rate (to get consistent frame
|
||||
// rates or reduce cpu usage.
|
||||
|
||||
double frame_us = 1.0e6 / throttle_hz;
|
||||
|
||||
// sleep based timing loop.
|
||||
//
|
||||
// Calling sleep, even usleep() on linux is less accurate than
|
||||
// we like, but it does free up the cpu for other tasks during
|
||||
// the sleep so it is desirable. Because of the way sleep()
|
||||
// is implemented in consumer operating systems like windows
|
||||
// and linux, you almost always sleep a little longer than the
|
||||
// requested amount.
|
||||
//
|
||||
// To combat the problem of sleeping too long, we calculate the
|
||||
// desired wait time and shorten it by 2000us (2ms) to avoid
|
||||
// [hopefully] over-sleep'ing. The 2ms value was arrived at
|
||||
// via experimentation. We follow this up at the end with a
|
||||
// simple busy-wait loop to get the final pause timing exactly
|
||||
// right.
|
||||
//
|
||||
// Assuming we don't oversleep by more than 2000us, this
|
||||
// should be a reasonable compromise between sleep based
|
||||
// waiting, and busy waiting.
|
||||
|
||||
// sleep() will always overshoot by a bit so undersleep by
|
||||
// 2000us in the hopes of never oversleeping.
|
||||
frame_us -= 2000.0;
|
||||
if ( frame_us < 0.0 ) {
|
||||
frame_us = 0.0;
|
||||
}
|
||||
current_time_stamp.stamp();
|
||||
|
||||
/* Convert to ms */
|
||||
double elapsed_us = (current_time_stamp - last_time_stamp).toUSecs();
|
||||
if ( elapsed_us < frame_us ) {
|
||||
double requested_us = frame_us - elapsed_us;
|
||||
usleep ( (useconds_t)(requested_us ) ) ;
|
||||
}
|
||||
// busy wait timing loop.
|
||||
//
|
||||
// This yields the most accurate timing. If the previous
|
||||
// usleep() call is omitted this will peg the cpu
|
||||
// (which is just fine if FG is the only app you care about.)
|
||||
current_time_stamp.stamp();
|
||||
SGTimeStamp next_time_stamp = last_time_stamp;
|
||||
next_time_stamp += SGTimeStamp::fromSec(1e-6*frame_us);
|
||||
while ( current_time_stamp < next_time_stamp ) {
|
||||
current_time_stamp.stamp();
|
||||
}
|
||||
|
||||
} else {
|
||||
current_time_stamp.stamp();
|
||||
}
|
||||
|
||||
double real_delta_time_sec = double(current_time_stamp.toUSecs() - last_time_stamp.toUSecs()) / 1000000.0;
|
||||
last_time_stamp = current_time_stamp;
|
||||
//fprintf(stdout,"\r%4.1lf ", 1/real_delta_time_sec );
|
||||
//fflush(stdout);
|
||||
|
||||
// round the real time down to a multiple of 1/model-hz.
|
||||
// this way all systems are updated the _same_ amount of dt.
|
||||
static double reminder = 0.0;
|
||||
static long global_multi_loop = 0;
|
||||
real_delta_time_sec += reminder;
|
||||
global_multi_loop = long(floor(real_delta_time_sec*model_hz));
|
||||
global_multi_loop = SGMisc<long>::max(0, global_multi_loop);
|
||||
reminder = real_delta_time_sec - double(global_multi_loop)/double(model_hz);
|
||||
return double(global_multi_loop)/double(model_hz);
|
||||
}
|
||||
|
||||
double ApplicationProperties::getDouble( const char * name, double def )
|
||||
{
|
||||
SGPropertyNode_ptr n = ApplicationProperties::Properties->getNode( name, false );
|
||||
if( n == NULL ) return def;
|
||||
return n->getDoubleValue();
|
||||
}
|
||||
SGPath ApplicationProperties::GetRootPath( const char * sub )
|
||||
{
|
||||
SGPath path( ApplicationProperties::root );
|
||||
if( sub != NULL )
|
||||
path.append( sub );
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string ApplicationProperties::root = ".";
|
||||
SGPropertyNode_ptr ApplicationProperties::Properties = new SGPropertyNode;
|
||||
FGFontCache ApplicationProperties::fontCache;
|
55
utils/fgpanel/FGPanelApplication.hxx
Normal file
55
utils/fgpanel/FGPanelApplication.hxx
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGPANELAPPLICATION_HXX
|
||||
#define __FGPANELAPPLICATION_HXX
|
||||
|
||||
#include "FGGLApplication.hxx"
|
||||
#include "FGPanelProtocol.hxx"
|
||||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "panel.hxx"
|
||||
|
||||
class FGPanelApplication : public FGGLApplication {
|
||||
public:
|
||||
FGPanelApplication( int argc, char ** argv );
|
||||
~FGPanelApplication();
|
||||
|
||||
void Run();
|
||||
|
||||
protected:
|
||||
virtual void Key( unsigned char key, int x, int y );
|
||||
virtual void Idle();
|
||||
// virtual void Display();
|
||||
virtual void Reshape( int width, int height );
|
||||
|
||||
virtual void Init();
|
||||
|
||||
double Sleep();
|
||||
|
||||
SGSharedPtr<FGPanel> panel;
|
||||
SGSharedPtr<FGPanelProtocol> protocol;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
#endif
|
154
utils/fgpanel/FGPanelProtocol.cxx
Normal file
154
utils/fgpanel/FGPanelProtocol.cxx
Normal file
|
@ -0,0 +1,154 @@
|
|||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#include "FGPanelProtocol.hxx"
|
||||
#include "ApplicationProperties.hxx"
|
||||
#include <simgear/io/sg_socket.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
|
||||
class PropertySetter {
|
||||
public:
|
||||
PropertySetter( SGPropertyNode_ptr node ) : _node(node) {}
|
||||
virtual void setValue( const char * value ) = 0;
|
||||
protected:
|
||||
SGPropertyNode_ptr _node;
|
||||
};
|
||||
|
||||
class BoolPropertySetter : public PropertySetter {
|
||||
public:
|
||||
BoolPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {}
|
||||
virtual void setValue( const char * value ) {
|
||||
_node->setBoolValue( atoi( value ) != 0 );
|
||||
}
|
||||
};
|
||||
|
||||
class IntPropertySetter : public PropertySetter {
|
||||
public:
|
||||
IntPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {}
|
||||
virtual void setValue( const char * value ) {
|
||||
_node->setIntValue( atol( value ) );
|
||||
}
|
||||
};
|
||||
|
||||
class FloatPropertySetter : public PropertySetter {
|
||||
public:
|
||||
FloatPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {}
|
||||
virtual void setValue( const char * value ) {
|
||||
_node->setFloatValue( strtof( value, NULL ) );
|
||||
}
|
||||
};
|
||||
|
||||
class DoublePropertySetter : public PropertySetter {
|
||||
public:
|
||||
DoublePropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {}
|
||||
virtual void setValue( const char * value ) {
|
||||
_node->setDoubleValue( strtod( value, NULL ) );
|
||||
}
|
||||
};
|
||||
|
||||
class StringPropertySetter : public PropertySetter {
|
||||
public:
|
||||
StringPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {}
|
||||
virtual void setValue( const char * value ) {
|
||||
_node->setStringValue( value );
|
||||
}
|
||||
};
|
||||
|
||||
FGPanelProtocol::FGPanelProtocol( SGPropertyNode_ptr aRoot )
|
||||
: SGSubsystem(),
|
||||
root(aRoot),
|
||||
io(NULL)
|
||||
{
|
||||
SGPropertyNode_ptr outputNode = root->getNode( "protocol/generic/output" );
|
||||
if( outputNode ) {
|
||||
vector<SGPropertyNode_ptr> chunks = outputNode->getChildren( "chunk" );
|
||||
for( vector<SGPropertyNode_ptr>::size_type i = 0; i < chunks.size(); i++ ) {
|
||||
SGPropertyNode_ptr chunk = chunks[i];
|
||||
|
||||
SGPropertyNode_ptr nodeNode = chunk->getNode("node", false );
|
||||
if( nodeNode == NULL )
|
||||
continue;
|
||||
|
||||
SGPropertyNode_ptr node = ApplicationProperties::Properties->getNode( nodeNode->getStringValue(), true );
|
||||
|
||||
string type = "";
|
||||
SGPropertyNode_ptr typeNode = chunk->getNode( "type", false );
|
||||
if( typeNode != NULL ) type = typeNode->getStringValue();
|
||||
if( type == "float" ) {
|
||||
propertySetterVector.push_back( new FloatPropertySetter( node ) );
|
||||
} else if( type == "double" || type == "fixed" ) {
|
||||
propertySetterVector.push_back( new DoublePropertySetter( node ) );
|
||||
} else if( type == "bool" || type == "boolean" ) {
|
||||
propertySetterVector.push_back( new BoolPropertySetter( node ) );
|
||||
} else if( type == "string" ) {
|
||||
propertySetterVector.push_back( new StringPropertySetter( node ) );
|
||||
} else {
|
||||
propertySetterVector.push_back( new IntPropertySetter( node ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FGPanelProtocol::~FGPanelProtocol()
|
||||
{
|
||||
for( PropertySetterVector::size_type i = 0; i < propertySetterVector.size(); i++ )
|
||||
delete propertySetterVector[i];
|
||||
}
|
||||
|
||||
void FGPanelProtocol::update( double dt )
|
||||
{
|
||||
char buf[8192];
|
||||
|
||||
if( io == NULL )
|
||||
return;
|
||||
|
||||
int length = io->readline( buf, sizeof(buf)-1 );
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
if ( length > 0 ) {
|
||||
vector<string> tokens = simgear::strutils::split( buf, "," );
|
||||
for( vector<string>::size_type i = 0; i < tokens.size(); i++ ) {
|
||||
if( i < propertySetterVector.size() )
|
||||
propertySetterVector[i]->setValue( tokens[i].c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FGPanelProtocol::init()
|
||||
{
|
||||
SGPropertyNode_ptr listenNode = root->getNode( "listen" );
|
||||
if( listenNode == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
string hostname = listenNode->getNode( "host", true )->getStringValue();
|
||||
string port = listenNode->getNode( "port", true )->getStringValue();
|
||||
string style = listenNode->getNode( "style", true )->getStringValue();
|
||||
|
||||
if( io != NULL )
|
||||
delete io;
|
||||
|
||||
io = new SGSocket( hostname, port, style );
|
||||
|
||||
if( !io->open( SG_IO_IN ) ) {
|
||||
cerr << "can't open socket " << style << ":" << hostname << ":" << port << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void FGPanelProtocol::reinit()
|
||||
{
|
||||
init();
|
||||
}
|
41
utils/fgpanel/FGPanelProtocol.hxx
Normal file
41
utils/fgpanel/FGPanelProtocol.hxx
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGPANELPROTOCOL_HXX
|
||||
#define __FGPANELPROTOCOL_HXX
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/io/iochannel.hxx>
|
||||
class PropertySetter;
|
||||
|
||||
typedef vector<PropertySetter*> PropertySetterVector;
|
||||
class FGPanelProtocol : public SGSubsystem {
|
||||
public:
|
||||
FGPanelProtocol( SGPropertyNode_ptr root );
|
||||
virtual ~FGPanelProtocol();
|
||||
virtual void init();
|
||||
virtual void reinit();
|
||||
virtual void update( double dt );
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
SGPropertyNode_ptr root;
|
||||
SGIOChannel * io;
|
||||
PropertySetterVector propertySetterVector;
|
||||
};
|
||||
#endif
|
504
utils/fgpanel/FGRGBTextureLoader.cxx
Normal file
504
utils/fgpanel/FGRGBTextureLoader.cxx
Normal file
|
@ -0,0 +1,504 @@
|
|||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// From the OpenSceneGraph distribution ReaderWriterRGB.cpp
|
||||
// Reader for sgi's .rgb format.
|
||||
// specification can be found at http://local.wasp.uwa.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html
|
||||
|
||||
#include "FGRGBTextureLoader.hxx"
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
typedef struct _rawImageRec
|
||||
{
|
||||
unsigned short imagic;
|
||||
unsigned short type;
|
||||
unsigned short dim;
|
||||
unsigned short sizeX, sizeY, sizeZ;
|
||||
unsigned long min, max;
|
||||
unsigned long wasteBytes;
|
||||
char name[80];
|
||||
unsigned long colorMap;
|
||||
std::istream *file;
|
||||
unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
|
||||
unsigned long rleEnd;
|
||||
GLuint *rowStart;
|
||||
GLint *rowSize;
|
||||
GLenum swapFlag;
|
||||
short bpc;
|
||||
|
||||
typedef unsigned char * BytePtr;
|
||||
|
||||
bool needsBytesSwapped()
|
||||
{
|
||||
union {
|
||||
int testWord;
|
||||
char testByte[sizeof(int)];
|
||||
}endianTest;
|
||||
endianTest.testWord = 1;
|
||||
if( endianTest.testByte[0] == 1 )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void swapBytes( T &s )
|
||||
{
|
||||
if( sizeof( T ) == 1 )
|
||||
return;
|
||||
|
||||
T d = s;
|
||||
BytePtr sptr = (BytePtr)&s;
|
||||
BytePtr dptr = &(((BytePtr)&d)[sizeof(T)-1]);
|
||||
|
||||
for( unsigned int i = 0; i < sizeof(T); i++ )
|
||||
*(sptr++) = *(dptr--);
|
||||
}
|
||||
|
||||
void swapBytes()
|
||||
{
|
||||
swapBytes( imagic );
|
||||
swapBytes( type );
|
||||
swapBytes( dim );
|
||||
swapBytes( sizeX );
|
||||
swapBytes( sizeY );
|
||||
swapBytes( sizeZ );
|
||||
swapBytes( wasteBytes );
|
||||
swapBytes( min );
|
||||
swapBytes( max );
|
||||
swapBytes( colorMap );
|
||||
}
|
||||
} rawImageRec;
|
||||
|
||||
static void ConvertShort(unsigned short *array, long length)
|
||||
{
|
||||
unsigned long b1, b2;
|
||||
unsigned char *ptr;
|
||||
|
||||
ptr = (unsigned char *)array;
|
||||
while (length--)
|
||||
{
|
||||
b1 = *ptr++;
|
||||
b2 = *ptr++;
|
||||
*array++ = (unsigned short) ((b1 << 8) | (b2));
|
||||
}
|
||||
}
|
||||
|
||||
static void ConvertLong(GLuint *array, long length)
|
||||
{
|
||||
unsigned long b1, b2, b3, b4;
|
||||
unsigned char *ptr;
|
||||
|
||||
ptr = (unsigned char *)array;
|
||||
while (length--)
|
||||
{
|
||||
b1 = *ptr++;
|
||||
b2 = *ptr++;
|
||||
b3 = *ptr++;
|
||||
b4 = *ptr++;
|
||||
*array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void RawImageClose(rawImageRec *raw)
|
||||
{
|
||||
if (raw)
|
||||
{
|
||||
|
||||
if (raw->tmp) delete [] raw->tmp;
|
||||
if (raw->tmpR) delete [] raw->tmpR;
|
||||
if (raw->tmpG) delete [] raw->tmpG;
|
||||
if (raw->tmpB) delete [] raw->tmpB;
|
||||
if (raw->tmpA) delete [] raw->tmpA;
|
||||
|
||||
if (raw->rowStart) delete [] raw->rowStart;
|
||||
if (raw->rowSize) delete [] raw->rowSize;
|
||||
|
||||
delete raw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static rawImageRec *RawImageOpen(std::istream& fin)
|
||||
{
|
||||
union
|
||||
{
|
||||
int testWord;
|
||||
char testByte[4];
|
||||
} endianTest;
|
||||
rawImageRec *raw;
|
||||
int x;
|
||||
|
||||
raw = new rawImageRec;
|
||||
if (raw == NULL)
|
||||
{
|
||||
// notify(WARN)<< "Out of memory!"<< std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Set istream pointer
|
||||
raw->file = &fin;
|
||||
|
||||
endianTest.testWord = 1;
|
||||
if (endianTest.testByte[0] == 1)
|
||||
{
|
||||
raw->swapFlag = GL_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
raw->swapFlag = GL_FALSE;
|
||||
}
|
||||
|
||||
fin.read((char*)raw,12);
|
||||
if (!fin.good())
|
||||
return NULL;
|
||||
|
||||
if (raw->swapFlag)
|
||||
{
|
||||
ConvertShort(&raw->imagic, 6);
|
||||
}
|
||||
|
||||
raw->tmp = raw->tmpR = raw->tmpG = raw->tmpB = raw->tmpA = 0L;
|
||||
raw->rowStart = 0;
|
||||
raw->rowSize = 0;
|
||||
raw->bpc = (raw->type & 0x00FF);
|
||||
|
||||
raw->tmp = new unsigned char [raw->sizeX*256*raw->bpc];
|
||||
if (raw->tmp == NULL )
|
||||
{
|
||||
// notify(FATAL)<< "Out of memory!"<< std::endl;
|
||||
RawImageClose(raw);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( raw->sizeZ >= 1 )
|
||||
{
|
||||
if( (raw->tmpR = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
|
||||
{
|
||||
// notify(FATAL)<< "Out of memory!"<< std::endl;
|
||||
RawImageClose(raw);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if( raw->sizeZ >= 2 )
|
||||
{
|
||||
if( (raw->tmpG = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
|
||||
{
|
||||
// notify(FATAL)<< "Out of memory!"<< std::endl;
|
||||
RawImageClose(raw);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if( raw->sizeZ >= 3 )
|
||||
{
|
||||
if( (raw->tmpB = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
|
||||
{
|
||||
// notify(FATAL)<< "Out of memory!"<< std::endl;
|
||||
RawImageClose(raw);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (raw->sizeZ >= 4)
|
||||
{
|
||||
if( (raw->tmpA = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
|
||||
{
|
||||
// notify(FATAL)<< "Out of memory!"<< std::endl;
|
||||
RawImageClose(raw);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((raw->type & 0xFF00) == 0x0100)
|
||||
{
|
||||
unsigned int ybyz = raw->sizeY * raw->sizeZ;
|
||||
if ( (raw->rowStart = new GLuint [ybyz]) == NULL )
|
||||
{
|
||||
// notify(FATAL)<< "Out of memory!"<< std::endl;
|
||||
RawImageClose(raw);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (raw->rowSize = new GLint [ybyz]) == NULL )
|
||||
{
|
||||
// notify(FATAL)<< "Out of memory!"<< std::endl;
|
||||
RawImageClose(raw);
|
||||
return NULL;
|
||||
}
|
||||
x = ybyz * sizeof(GLuint);
|
||||
raw->rleEnd = 512 + (2 * x);
|
||||
fin.seekg(512,std::ios::beg);
|
||||
fin.read((char*)raw->rowStart,x);
|
||||
fin.read((char*)raw->rowSize,x);
|
||||
if (raw->swapFlag)
|
||||
{
|
||||
ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint)));
|
||||
ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint)));
|
||||
}
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
|
||||
static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z)
|
||||
{
|
||||
unsigned char *iPtr, *oPtr;
|
||||
unsigned short pixel;
|
||||
int count, done = 0;
|
||||
unsigned short *tempShort;
|
||||
|
||||
if ((raw->type & 0xFF00) == 0x0100)
|
||||
{
|
||||
raw->file->seekg((long) raw->rowStart[y+z*raw->sizeY], std::ios::beg);
|
||||
raw->file->read((char*)raw->tmp, (unsigned int)raw->rowSize[y+z*raw->sizeY]);
|
||||
|
||||
iPtr = raw->tmp;
|
||||
oPtr = buf;
|
||||
while (!done)
|
||||
{
|
||||
if (raw->bpc == 1)
|
||||
pixel = *iPtr++;
|
||||
else
|
||||
{
|
||||
tempShort = reinterpret_cast<unsigned short*>(iPtr);
|
||||
pixel = *tempShort;
|
||||
tempShort++;
|
||||
iPtr = reinterpret_cast<unsigned char *>(tempShort);
|
||||
}
|
||||
|
||||
if(raw->bpc != 1)
|
||||
ConvertShort(&pixel, 1);
|
||||
|
||||
count = (int)(pixel & 0x7F);
|
||||
|
||||
// limit the count value to the remiaing row size
|
||||
if (oPtr + count*raw->bpc > buf + raw->sizeX*raw->bpc)
|
||||
{
|
||||
count = ( (buf + raw->sizeX*raw->bpc) - oPtr ) / raw->bpc;
|
||||
}
|
||||
|
||||
if (count<=0)
|
||||
{
|
||||
done = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pixel & 0x80)
|
||||
{
|
||||
while (count--)
|
||||
{
|
||||
if(raw->bpc == 1)
|
||||
*oPtr++ = *iPtr++;
|
||||
else{
|
||||
tempShort = reinterpret_cast<unsigned short*>(iPtr);
|
||||
pixel = *tempShort;
|
||||
tempShort++;
|
||||
iPtr = reinterpret_cast<unsigned char *>(tempShort);
|
||||
|
||||
ConvertShort(&pixel, 1);
|
||||
|
||||
tempShort = reinterpret_cast<unsigned short*>(oPtr);
|
||||
*tempShort = pixel;
|
||||
tempShort++;
|
||||
oPtr = reinterpret_cast<unsigned char *>(tempShort);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (raw->bpc == 1)
|
||||
{
|
||||
pixel = *iPtr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempShort = reinterpret_cast<unsigned short*>(iPtr);
|
||||
pixel = *tempShort;
|
||||
tempShort++;
|
||||
iPtr = reinterpret_cast<unsigned char *>(tempShort);
|
||||
}
|
||||
if(raw->bpc != 1)
|
||||
ConvertShort(&pixel, 1);
|
||||
while (count--)
|
||||
{
|
||||
if(raw->bpc == 1)
|
||||
*oPtr++ = pixel;
|
||||
else
|
||||
{
|
||||
tempShort = reinterpret_cast<unsigned short*>(oPtr);
|
||||
*tempShort = pixel;
|
||||
tempShort++;
|
||||
oPtr = reinterpret_cast<unsigned char *>(tempShort);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
raw->file->seekg(512+(y*raw->sizeX*raw->bpc)+(z*raw->sizeX*raw->sizeY*raw->bpc),std::ios::beg);
|
||||
raw->file->read((char*)buf, raw->sizeX*raw->bpc);
|
||||
if(raw->swapFlag && raw->bpc != 1){
|
||||
ConvertShort(reinterpret_cast<unsigned short*>(buf), raw->sizeX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void RawImageGetData(rawImageRec *raw, unsigned char **data )
|
||||
{
|
||||
unsigned char *ptr;
|
||||
int i, j;
|
||||
unsigned short *tempShort;
|
||||
|
||||
// // round the width to a factor 4
|
||||
// int width = (int)(floorf((float)raw->sizeX/4.0f)*4.0f);
|
||||
// if (width!=raw->sizeX) width += 4;
|
||||
|
||||
// byte aligned.
|
||||
|
||||
// osg::notify(osg::INFO)<<"raw->sizeX = "<<raw->sizeX<<std::endl;
|
||||
// osg::notify(osg::INFO)<<"raw->sizeY = "<<raw->sizeY<<std::endl;
|
||||
// osg::notify(osg::INFO)<<"raw->sizeZ = "<<raw->sizeZ<<std::endl;
|
||||
// osg::notify(osg::INFO)<<"raw->bpc = "<<raw->bpc<<std::endl;
|
||||
|
||||
*data = new unsigned char [(raw->sizeX)*(raw->sizeY)*(raw->sizeZ)*(raw->bpc)];
|
||||
|
||||
ptr = *data;
|
||||
for (i = 0; i < (int)(raw->sizeY); i++)
|
||||
{
|
||||
if( raw->sizeZ >= 1 )
|
||||
RawImageGetRow(raw, raw->tmpR, i, 0);
|
||||
if( raw->sizeZ >= 2 )
|
||||
RawImageGetRow(raw, raw->tmpG, i, 1);
|
||||
if( raw->sizeZ >= 3 )
|
||||
RawImageGetRow(raw, raw->tmpB, i, 2);
|
||||
if( raw->sizeZ >= 4 )
|
||||
RawImageGetRow(raw, raw->tmpA, i, 3);
|
||||
for (j = 0; j < (int)(raw->sizeX); j++)
|
||||
{
|
||||
if(raw->bpc == 1){
|
||||
if( raw->sizeZ >= 1 )
|
||||
*ptr++ = *(raw->tmpR + j);
|
||||
if( raw->sizeZ >= 2 )
|
||||
*ptr++ = *(raw->tmpG + j);
|
||||
if( raw->sizeZ >= 3 )
|
||||
*ptr++ = *(raw->tmpB + j);
|
||||
if( raw->sizeZ >= 4 )
|
||||
*ptr++ = *(raw->tmpA + j);
|
||||
}else{
|
||||
if( raw->sizeZ >= 1 )
|
||||
{
|
||||
tempShort = reinterpret_cast<unsigned short*>(ptr);
|
||||
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpR) + j);
|
||||
tempShort++;
|
||||
ptr = reinterpret_cast<unsigned char *>(tempShort);
|
||||
}
|
||||
if( raw->sizeZ >= 2 )
|
||||
{
|
||||
tempShort = reinterpret_cast<unsigned short*>(ptr);
|
||||
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpG) + j);
|
||||
tempShort++;
|
||||
ptr = reinterpret_cast<unsigned char *>(tempShort);
|
||||
}
|
||||
if( raw->sizeZ >= 3 )
|
||||
{
|
||||
tempShort = reinterpret_cast<unsigned short*>(ptr);
|
||||
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpB) + j);
|
||||
tempShort++;
|
||||
ptr = reinterpret_cast<unsigned char *>(tempShort);
|
||||
}
|
||||
if( raw->sizeZ >= 4 )
|
||||
{
|
||||
tempShort = reinterpret_cast<unsigned short*>(ptr);
|
||||
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpA) + j);
|
||||
tempShort++;
|
||||
ptr = reinterpret_cast<unsigned char *>(tempShort);
|
||||
}
|
||||
}
|
||||
}
|
||||
// // pad the image width with blanks to bring it up to the rounded width.
|
||||
// for(;j<width;++j) *ptr++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// supportsExtension("rgb","rgb image format");
|
||||
// supportsExtension("rgba","rgba image format");
|
||||
// supportsExtension("sgi","sgi image format");
|
||||
// supportsExtension("int","int image format");
|
||||
// supportsExtension("inta","inta image format");
|
||||
// supportsExtension("bw","bw image format");
|
||||
|
||||
GLuint readRGBStream(std::istream& fin)
|
||||
{
|
||||
rawImageRec *raw;
|
||||
|
||||
if( (raw = RawImageOpen(fin)) == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s = raw->sizeX;
|
||||
int t = raw->sizeY;
|
||||
// int r = 1;
|
||||
|
||||
#if 0
|
||||
int internalFormat = raw->sizeZ == 3 ? GL_RGB5 :
|
||||
raw->sizeZ == 4 ? GL_RGB5_A1 : GL_RGB;
|
||||
#else
|
||||
// int internalFormat = raw->sizeZ;
|
||||
#endif
|
||||
unsigned int pixelFormat =
|
||||
raw->sizeZ == 1 ? GL_LUMINANCE :
|
||||
raw->sizeZ == 2 ? GL_LUMINANCE_ALPHA :
|
||||
raw->sizeZ == 3 ? GL_RGB :
|
||||
raw->sizeZ == 4 ? GL_RGBA : (GLenum)-1;
|
||||
GLint component = raw->sizeZ;
|
||||
|
||||
unsigned int dataType = raw->bpc == 1 ? GL_UNSIGNED_BYTE :
|
||||
GL_UNSIGNED_SHORT;
|
||||
|
||||
unsigned char *data;
|
||||
RawImageGetData(raw, &data);
|
||||
RawImageClose(raw);
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
gluBuild2DMipmaps( GL_TEXTURE_2D, component, s, t, pixelFormat, dataType, (GLvoid*)data );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
|
||||
|
||||
delete []data;
|
||||
return texture;
|
||||
}
|
||||
|
||||
GLuint FGRGBTextureLoader::loadTexture( const std::string & filename )
|
||||
{
|
||||
GLuint texture = NOTEXTURE;
|
||||
std::ifstream istream(filename.c_str(), std::ios::in | std::ios::binary );
|
||||
texture = readRGBStream(istream);
|
||||
istream.close();
|
||||
return texture;
|
||||
}
|
||||
|
26
utils/fgpanel/FGRGBTextureLoader.hxx
Normal file
26
utils/fgpanel/FGRGBTextureLoader.hxx
Normal file
|
@ -0,0 +1,26 @@
|
|||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGRGBTEXTURELOADER_HXX
|
||||
#define __FGRGBTEXTURELOADER_HXX
|
||||
|
||||
#include "FGTextureLoaderInterface.hxx"
|
||||
|
||||
class FGRGBTextureLoader : public FGTextureLoaderInterface {
|
||||
public:
|
||||
virtual GLuint loadTexture( const std::string & filename );
|
||||
|
||||
const static GLuint NOTEXTURE = 0;
|
||||
};
|
||||
#endif
|
27
utils/fgpanel/FGTextureLoaderInterface.hxx
Normal file
27
utils/fgpanel/FGTextureLoaderInterface.hxx
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGTEXTURELOADERINTERFACE_HXX
|
||||
#define __FGTEXTURELOADERINTERFACE_HXX
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <string>
|
||||
class FGTextureLoaderInterface {
|
||||
public:
|
||||
virtual GLuint loadTexture( const std::string & filename ) = 0;
|
||||
};
|
||||
#endif
|
22
utils/fgpanel/Makefile.am
Normal file
22
utils/fgpanel/Makefile.am
Normal file
|
@ -0,0 +1,22 @@
|
|||
if WITH_FGPANEL
|
||||
AM_CXXFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\"
|
||||
|
||||
bin_PROGRAMS = fgpanel
|
||||
|
||||
fgpanel_SOURCES = main.cxx \
|
||||
FGGLApplication.cxx FGGLApplication.hxx \
|
||||
FGPanelApplication.cxx FGPanelApplication.hxx \
|
||||
FGPNGTextureLoader.cxx FGPNGTextureLoader.hxx FGTextureLoaderInterface.hxx \
|
||||
FGRGBTextureLoader.cxx FGRGBTextureLoader.hxx \
|
||||
FGPanelProtocol.cxx \
|
||||
FGFontCache.cxx \
|
||||
panel.cxx panel.hxx \
|
||||
panel_io.cxx panel_io.hxx
|
||||
|
||||
#LIBS =
|
||||
|
||||
fgpanel_LDADD = \
|
||||
-lGLU -lglut -lsgmath -lsgprops -lsgio -lsgdebug -lsgmisc -lsgstructure -lsgxml -lsgtiming \
|
||||
-lplibpu -lplibfnt -lplibul \
|
||||
-lrt -lpng
|
||||
endif
|
148
utils/fgpanel/README
Normal file
148
utils/fgpanel/README
Normal file
|
@ -0,0 +1,148 @@
|
|||
=====================================================================
|
||||
This is fgpanel - basically the stripped down 2D-Panel code from
|
||||
FlightGear. It is designed as a standalone lightweight panel
|
||||
rendering engine to draw 2d panels on a lowcost computer/graphic card
|
||||
without 3d acceleration at reasonablel framerates.
|
||||
|
||||
=====================================================================
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
=====================================================================
|
||||
Usage
|
||||
start fgpanel with
|
||||
fgpanel --fg-root=/path/to/fg/data --panel=Aircraft/MyAircraft/Panels/MyPanel.xml
|
||||
with the command args set to
|
||||
--fg-root shall point to the directory where your FGDATA lives
|
||||
NOTE: you don't need a full copy of FGDATA, just the panel definition files for
|
||||
your aircraft, e.g.
|
||||
- Aircraft/MyAircraft/Panels/*
|
||||
- Aircraft/Instruments/* (if referenced)
|
||||
|
||||
-panel shall point to a panel-configuration file, relative to FGDATA
|
||||
|
||||
start flightgear with
|
||||
fgfs --generic=socket,out,10,239.24.10.64,5432,udp,../Aircraft/MyAircraft/Panels/SampleProtocol
|
||||
|
||||
=====================================================================
|
||||
Sample:
|
||||
|
||||
Create the sample files within your aicraft directory, preferrable under Panels
|
||||
MyPanel.xml
|
||||
sample-2d-panel.xml
|
||||
SampleProtocol.xml
|
||||
|
||||
=====================================================================
|
||||
Sample panel configuration file (MyPanel.xml)
|
||||
<PropertyList>
|
||||
|
||||
<!-- true: run full-screen, false; run in window -->
|
||||
<game-mode type="bool">false</game-mode>
|
||||
|
||||
<!-- include the panel definitions (2d-panel syntax)-->
|
||||
<panel include="sample-2d-panel.xml"/>
|
||||
|
||||
<!-- compose your property-tree here -->
|
||||
<sim>
|
||||
<panel>
|
||||
<flip-x type="bool">false</flip-x>
|
||||
</panel>
|
||||
<instrument-options>
|
||||
<omit-knobs type="bool">true</omit-knobs>
|
||||
</instrument-options>
|
||||
</sim>
|
||||
|
||||
<!-- network communication settings -->
|
||||
<communication>
|
||||
<listen>
|
||||
<!-- interface to bind to,
|
||||
leave empty for all interfaces -->
|
||||
<host>239.24.10.64</host> <!-- multicast address! -->
|
||||
<port>5432</port> <!-- tcp port to listen to -->
|
||||
<style>udp</style> <!-- udp or tcp (forget about tcp!) -->
|
||||
</listen>
|
||||
|
||||
<!-- the generic protocol definition
|
||||
same as used for fgfs --generic=foobar option
|
||||
-->
|
||||
<protocol include="SampleProtocol.xml"/>
|
||||
</communication>
|
||||
</PropertyList>
|
||||
|
||||
=====================================================================
|
||||
Sampe 2d-panel configuration file sample-2d-panel.xml
|
||||
To be included from the panel configuration file
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<PropertyList>
|
||||
<name>Sample Instrument Panel</name>
|
||||
<w>375</w> <!-- screen width: 375mm -->
|
||||
<h>305</h> <!-- screen height: 305mm -->
|
||||
<instruments>
|
||||
<!-- use FlightGear's c172 attitude indicator -->
|
||||
<instrument include="../../Instruments/ati-c172s.xml">
|
||||
<name>Attitude Gyro</name>
|
||||
<x alias="../../../params/col-2"/>
|
||||
<y alias="../../../params/row-1"/>
|
||||
<w>80</w>
|
||||
<h>80</h>
|
||||
</instrument>
|
||||
</instruments>
|
||||
</PropertyList>
|
||||
|
||||
=====================================================================
|
||||
Sample protocol configuration file to drive the AI (SampleProtocol.xml)
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<PropertyList>
|
||||
<generic>
|
||||
|
||||
<output>
|
||||
<line_separator>newline</line_separator>
|
||||
<var_separator>,</var_separator>
|
||||
|
||||
<chunk>
|
||||
<type>float</type>
|
||||
<format>%.2f</format>
|
||||
<node>/position/altitude-agl-ft</node>
|
||||
</chunk>
|
||||
|
||||
<chunk>
|
||||
<type>float</type>
|
||||
<format>%.2f</format>
|
||||
<node>/instrumentation/attitude-indicator/indicated-roll-deg</node>
|
||||
</chunk>
|
||||
|
||||
<chunk>
|
||||
<type>float</type>
|
||||
<format>%.2f</format>
|
||||
<node>/instrumentation/attitude-indicator/indicated-pitch-deg</node>
|
||||
</chunk>
|
||||
|
||||
<chunk>
|
||||
<type>float</type>
|
||||
<format>%.2f</format>
|
||||
<node>/instrumentation/attitude-indicator/horizon-offset-deg</node>
|
||||
</chunk>
|
||||
|
||||
<chunk>
|
||||
<type>float</type>
|
||||
<format>%.4e</format>
|
||||
<node>/instrumentation/attitude-indicator/spin</node>
|
||||
</chunk>
|
||||
</output>
|
||||
</generic>
|
||||
</PropertyList>
|
||||
|
||||
=====================================================================
|
30
utils/fgpanel/main.cxx
Normal file
30
utils/fgpanel/main.cxx
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#include "FGPanelApplication.hxx"
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
try {
|
||||
FGPanelApplication app(argc,argv);
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
||||
catch( ... ) {
|
||||
cerr << "Sorry, your program terminated." << endl;
|
||||
}
|
||||
}
|
962
utils/fgpanel/panel.cxx
Normal file
962
utils/fgpanel/panel.cxx
Normal file
|
@ -0,0 +1,962 @@
|
|||
// panel.cxx - default, 2D single-engine prop instrument panel
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id: panel.cxx,v 1.44 2006/09/05 20:28:48 curt Exp $
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h> // sprintf
|
||||
#include <string.h>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <GL/glut.h>
|
||||
|
||||
#include <plib/fnt.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include "panel.hxx"
|
||||
#include "ApplicationProperties.hxx"
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Local functions.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FGDummyTextureLoader : public FGTextureLoaderInterface {
|
||||
public:
|
||||
virtual GLuint loadTexture( const string & filename );
|
||||
};
|
||||
|
||||
GLuint FGDummyTextureLoader::loadTexture( const string & filename )
|
||||
{
|
||||
GLuint _texture = 0;
|
||||
glGenTextures( 1, &_texture );
|
||||
glBindTexture( GL_TEXTURE_2D, _texture );
|
||||
|
||||
// glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
|
||||
// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) ;
|
||||
// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ) ;
|
||||
// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ) ;
|
||||
// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ) ;
|
||||
|
||||
GLubyte image[ 2 * 2 * 3 ] ;
|
||||
|
||||
/* Red and white chequerboard */
|
||||
image [ 0 ] = 255 ; image [ 1 ] = 0 ; image [ 2 ] = 0 ;
|
||||
image [ 3 ] = 255 ; image [ 4 ] = 255 ; image [ 5 ] = 255 ;
|
||||
image [ 6 ] = 255 ; image [ 7 ] = 255 ; image [ 8 ] = 255 ;
|
||||
image [ 9 ] = 255 ; image [ 10] = 0 ; image [ 11] = 0 ;
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D,0, GL_RGB, 2, 2, 0,
|
||||
GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) image);
|
||||
|
||||
return _texture;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGCropped Texture.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLuint FGCroppedTexture::current_bound_texture = 0;
|
||||
map<string,GLuint> FGCroppedTexture::cache;
|
||||
map<string,FGTextureLoaderInterface*> FGCroppedTexture::textureLoader;
|
||||
static FGDummyTextureLoader dummyTextureLoader;
|
||||
|
||||
FGCroppedTexture::FGCroppedTexture (const string &path,
|
||||
float minX, float minY,
|
||||
float maxX, float maxY)
|
||||
: _path(path),
|
||||
_minX(minX), _minY(minY), _maxX(maxX), _maxY(maxY), _texture(0)
|
||||
{
|
||||
}
|
||||
|
||||
FGCroppedTexture::~FGCroppedTexture ()
|
||||
{
|
||||
}
|
||||
|
||||
void FGCroppedTexture::bind( bool doGLBind )
|
||||
{
|
||||
if( _texture == 0 ) {
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "First bind of texture " << _path );
|
||||
if( cache.count(_path) > 0 ) {
|
||||
_texture = cache[_path];
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Using texture " << _path << " from cache (#" << _texture << ")" );
|
||||
} else {
|
||||
SGPath tpath = ApplicationProperties::GetRootPath(_path.c_str());
|
||||
string extension = tpath.extension();
|
||||
FGTextureLoaderInterface * loader = &dummyTextureLoader;
|
||||
if( textureLoader.count( extension ) == 0 ) {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "Can't handle textures of type " << extension );
|
||||
} else {
|
||||
loader = textureLoader[extension];
|
||||
}
|
||||
|
||||
_texture = loader->loadTexture( tpath.c_str() );
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Texture " << tpath.c_str() << " loaded from file as #" << _texture );
|
||||
|
||||
cache[_path] = _texture;
|
||||
}
|
||||
}
|
||||
|
||||
if( !doGLBind || current_bound_texture == _texture )
|
||||
return;
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, _texture );
|
||||
current_bound_texture = _texture;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGPanel.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
FGPanel::FGPanel ( SGPropertyNode_ptr root)
|
||||
: _root(root),
|
||||
_flipx(root->getNode("/sim/panel/flip-x", true)),
|
||||
_rotate(root->getNode("/sim/panel/rotate-deg", true)),
|
||||
_bg_width(1.0), _bg_height(1.0),
|
||||
initDisplayList(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
FGPanel::~FGPanel ()
|
||||
{
|
||||
for (instrument_list_type::iterator it = _instruments.begin();
|
||||
it != _instruments.end();
|
||||
it++) {
|
||||
delete *it;
|
||||
*it = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add an instrument to the panel.
|
||||
*/
|
||||
void
|
||||
FGPanel::addInstrument (FGPanelInstrument * instrument)
|
||||
{
|
||||
_instruments.push_back(instrument);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the panel.
|
||||
*/
|
||||
void
|
||||
FGPanel::init ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bind panel properties.
|
||||
*/
|
||||
void
|
||||
FGPanel::bind ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unbind panel properties.
|
||||
*/
|
||||
void
|
||||
FGPanel::unbind ()
|
||||
{
|
||||
}
|
||||
|
||||
GLuint FGPanel::getInitDisplayList()
|
||||
{
|
||||
if( initDisplayList != 0 ) return initDisplayList;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
if ( _flipx->getBoolValue() ) {
|
||||
gluOrtho2D( _width, 0, _height, 0 ); /* up side down */
|
||||
} else {
|
||||
gluOrtho2D( 0, _width, 0, _height ); /* right side up */
|
||||
}
|
||||
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glClear( GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// save some state
|
||||
glPushAttrib( GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT
|
||||
| GL_TEXTURE_BIT | GL_PIXEL_MODE_BIT | GL_CULL_FACE
|
||||
| GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
// Draw the background
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (_bg != NULL) {
|
||||
_bg->bind();
|
||||
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex2f(0, 0);
|
||||
glTexCoord2f(_bg_width, 0.0); glVertex2f(_width, 0);
|
||||
glTexCoord2f(_bg_width, _bg_height); glVertex2f(_width, _height);
|
||||
glTexCoord2f(0.0, _bg_height); glVertex2f(0, _height);
|
||||
glEnd();
|
||||
} else if( _mbg[0] != NULL ) {
|
||||
for (int i = 0; i < 4; i ++) {
|
||||
// top row of textures...(1,3,5,7)
|
||||
_mbg[i*2]->bind();
|
||||
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex2f(i*_width/4, _height/2);
|
||||
glTexCoord2f(1.0, 0.0); glVertex2f((i+1)*_width/4, _height/2);
|
||||
glTexCoord2f(1.0, 1.0); glVertex2f((i+1)*_width/4, _height);
|
||||
glTexCoord2f(0.0, 1.0); glVertex2f(i*_width/4, _height);
|
||||
glEnd();
|
||||
// bottom row of textures...(2,4,6,8)
|
||||
_mbg[i*2+1]->bind();
|
||||
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex2f( i*_width/4, 0);
|
||||
glTexCoord2f(1.0, 0.0); glVertex2f( (i+1)*_width/4, 0);
|
||||
glTexCoord2f(1.0, 1.0); glVertex2f( (i+1)*_width/4, _height/2);
|
||||
glTexCoord2f(0.0, 1.0); glVertex2f( i*_width/4, _height/2);
|
||||
glEnd();
|
||||
}
|
||||
} else {
|
||||
float c[4];
|
||||
glGetFloatv( GL_CURRENT_COLOR, c );
|
||||
glColor4f( 0.0, 0.0, 0.0, 1.0 );
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(0, 0);
|
||||
glVertex2f(_width, 0);
|
||||
glVertex2f(_width, _height);
|
||||
glVertex2f(0, _height);
|
||||
glEnd();
|
||||
glColor4fv( c );
|
||||
}
|
||||
|
||||
|
||||
return initDisplayList;
|
||||
}
|
||||
|
||||
void
|
||||
FGPanel::update (double dt)
|
||||
{
|
||||
glCallList(getInitDisplayList());
|
||||
|
||||
// Draw the instruments.
|
||||
// Syd Adams: added instrument clipping
|
||||
instrument_list_type::const_iterator current = _instruments.begin();
|
||||
instrument_list_type::const_iterator end = _instruments.end();
|
||||
|
||||
GLdouble blx[4]={1.0,0.0,0.0,0.0};
|
||||
GLdouble bly[4]={0.0,1.0,0.0,0.0};
|
||||
GLdouble urx[4]={-1.0,0.0,0.0,0.0};
|
||||
GLdouble ury[4]={0.0,-1.0,0.0,0.0};
|
||||
|
||||
for ( ; current != end; current++) {
|
||||
FGPanelInstrument * instr = *current;
|
||||
glPushMatrix();
|
||||
glTranslated(instr->getXPos(), instr->getYPos(), 0);
|
||||
|
||||
int ix= instr->getWidth();
|
||||
int iy= instr->getHeight();
|
||||
glPushMatrix();
|
||||
glTranslated(-ix/2,-iy/2,0);
|
||||
glClipPlane(GL_CLIP_PLANE0,blx);
|
||||
glClipPlane(GL_CLIP_PLANE1,bly);
|
||||
glEnable(GL_CLIP_PLANE0);
|
||||
glEnable(GL_CLIP_PLANE1);
|
||||
|
||||
glTranslated(ix,iy,0);
|
||||
glClipPlane(GL_CLIP_PLANE2,urx);
|
||||
glClipPlane(GL_CLIP_PLANE3,ury);
|
||||
glEnable(GL_CLIP_PLANE2);
|
||||
glEnable(GL_CLIP_PLANE3);
|
||||
glPopMatrix();
|
||||
instr->draw();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glDisable(GL_CLIP_PLANE0);
|
||||
glDisable(GL_CLIP_PLANE1);
|
||||
glDisable(GL_CLIP_PLANE2);
|
||||
glDisable(GL_CLIP_PLANE3);
|
||||
|
||||
// restore some original state
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Update the panel.
|
||||
*/
|
||||
void
|
||||
FGPanel::update (double dt)
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
if ( _flipx->getBoolValue() ) {
|
||||
gluOrtho2D( _width, 0, _height, 0 ); /* up side down */
|
||||
} else {
|
||||
gluOrtho2D( 0, _width, 0, _height ); /* right side up */
|
||||
}
|
||||
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
void FGPanel::draw()
|
||||
{
|
||||
glClear( GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// save some state
|
||||
glPushAttrib( GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT
|
||||
| GL_TEXTURE_BIT | GL_PIXEL_MODE_BIT | GL_CULL_FACE
|
||||
| GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
// Draw the background
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (_bg != NULL) {
|
||||
_bg->bind();
|
||||
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex2f(0, 0);
|
||||
glTexCoord2f(_bg_width, 0.0); glVertex2f(_width, 0);
|
||||
glTexCoord2f(_bg_width, _bg_height); glVertex2f(_width, _height);
|
||||
glTexCoord2f(0.0, _bg_height); glVertex2f(0, _height);
|
||||
glEnd();
|
||||
} else if( _mbg[0] != NULL ) {
|
||||
for (int i = 0; i < 4; i ++) {
|
||||
// top row of textures...(1,3,5,7)
|
||||
_mbg[i*2]->bind();
|
||||
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex2f(i*_width/4, _height/2);
|
||||
glTexCoord2f(1.0, 0.0); glVertex2f((i+1)*_width/4, _height/2);
|
||||
glTexCoord2f(1.0, 1.0); glVertex2f((i+1)*_width/4, _height);
|
||||
glTexCoord2f(0.0, 1.0); glVertex2f(i*_width/4, _height);
|
||||
glEnd();
|
||||
// bottom row of textures...(2,4,6,8)
|
||||
_mbg[i*2+1]->bind();
|
||||
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex2f( i*_width/4, 0);
|
||||
glTexCoord2f(1.0, 0.0); glVertex2f( (i+1)*_width/4, 0);
|
||||
glTexCoord2f(1.0, 1.0); glVertex2f( (i+1)*_width/4, _height/2);
|
||||
glTexCoord2f(0.0, 1.0); glVertex2f( i*_width/4, _height/2);
|
||||
glEnd();
|
||||
}
|
||||
} else {
|
||||
float c[4];
|
||||
glGetFloatv( GL_CURRENT_COLOR, c );
|
||||
glColor4f( 0.0, 0.0, 0.0, 1.0 );
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(0, 0);
|
||||
glVertex2f(_width, 0);
|
||||
glVertex2f(_width, _height);
|
||||
glVertex2f(0, _height);
|
||||
glEnd();
|
||||
glColor4fv( c );
|
||||
}
|
||||
|
||||
// Draw the instruments.
|
||||
// Syd Adams: added instrument clipping
|
||||
instrument_list_type::const_iterator current = _instruments.begin();
|
||||
instrument_list_type::const_iterator end = _instruments.end();
|
||||
|
||||
GLdouble blx[4]={1.0,0.0,0.0,0.0};
|
||||
GLdouble bly[4]={0.0,1.0,0.0,0.0};
|
||||
GLdouble urx[4]={-1.0,0.0,0.0,0.0};
|
||||
GLdouble ury[4]={0.0,-1.0,0.0,0.0};
|
||||
|
||||
for ( ; current != end; current++) {
|
||||
FGPanelInstrument * instr = *current;
|
||||
glPushMatrix();
|
||||
glTranslated(instr->getXPos(), instr->getYPos(), 0);
|
||||
|
||||
int ix= instr->getWidth();
|
||||
int iy= instr->getHeight();
|
||||
glPushMatrix();
|
||||
glTranslated(-ix/2,-iy/2,0);
|
||||
glClipPlane(GL_CLIP_PLANE0,blx);
|
||||
glClipPlane(GL_CLIP_PLANE1,bly);
|
||||
glEnable(GL_CLIP_PLANE0);
|
||||
glEnable(GL_CLIP_PLANE1);
|
||||
|
||||
glTranslated(ix,iy,0);
|
||||
glClipPlane(GL_CLIP_PLANE2,urx);
|
||||
glClipPlane(GL_CLIP_PLANE3,ury);
|
||||
glEnable(GL_CLIP_PLANE2);
|
||||
glEnable(GL_CLIP_PLANE3);
|
||||
glPopMatrix();
|
||||
instr->draw();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glDisable(GL_CLIP_PLANE0);
|
||||
glDisable(GL_CLIP_PLANE1);
|
||||
glDisable(GL_CLIP_PLANE2);
|
||||
glDisable(GL_CLIP_PLANE3);
|
||||
|
||||
// restore some original state
|
||||
glPopAttrib();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set the panel's background texture.
|
||||
*/
|
||||
void
|
||||
FGPanel::setBackground (FGCroppedTexture_ptr texture)
|
||||
{
|
||||
_bg = texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the panel's multiple background textures.
|
||||
*/
|
||||
void
|
||||
FGPanel::setMultiBackground (FGCroppedTexture_ptr texture, int idx)
|
||||
{
|
||||
_bg = 0;
|
||||
_mbg[idx] = texture;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGPanelTransformation.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGPanelTransformation::FGPanelTransformation ()
|
||||
: table(0)
|
||||
{
|
||||
}
|
||||
|
||||
FGPanelTransformation::~FGPanelTransformation ()
|
||||
{
|
||||
delete table;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGPanelInstrument.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
FGPanelInstrument::FGPanelInstrument ()
|
||||
{
|
||||
setPosition(0, 0);
|
||||
setSize(0, 0);
|
||||
}
|
||||
|
||||
FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
|
||||
{
|
||||
setPosition(x, y);
|
||||
setSize(w, h);
|
||||
}
|
||||
|
||||
FGPanelInstrument::~FGPanelInstrument ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelInstrument::setPosition (int x, int y)
|
||||
{
|
||||
_x = x;
|
||||
_y = y;
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelInstrument::setSize (int w, int h)
|
||||
{
|
||||
_w = w;
|
||||
_h = h;
|
||||
}
|
||||
|
||||
int
|
||||
FGPanelInstrument::getXPos () const
|
||||
{
|
||||
return _x;
|
||||
}
|
||||
|
||||
int
|
||||
FGPanelInstrument::getYPos () const
|
||||
{
|
||||
return _y;
|
||||
}
|
||||
|
||||
int
|
||||
FGPanelInstrument::getWidth () const
|
||||
{
|
||||
return _w;
|
||||
}
|
||||
|
||||
int
|
||||
FGPanelInstrument::getHeight () const
|
||||
{
|
||||
return _h;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGLayeredInstrument.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
|
||||
: FGPanelInstrument(x, y, w, h)
|
||||
{
|
||||
}
|
||||
|
||||
FGLayeredInstrument::~FGLayeredInstrument ()
|
||||
{
|
||||
for (layer_list::iterator it = _layers.begin(); it != _layers.end(); it++) {
|
||||
delete *it;
|
||||
*it = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGLayeredInstrument::draw ()
|
||||
{
|
||||
if (!test())
|
||||
return;
|
||||
|
||||
for (int i = 0; i < (int)_layers.size(); i++) {
|
||||
glPushMatrix();
|
||||
_layers[i]->draw();
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
|
||||
{
|
||||
int n = _layers.size();
|
||||
if (layer->getWidth() == -1) {
|
||||
layer->setWidth(getWidth());
|
||||
}
|
||||
if (layer->getHeight() == -1) {
|
||||
layer->setHeight(getHeight());
|
||||
}
|
||||
_layers.push_back(layer);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
FGLayeredInstrument::addLayer (FGCroppedTexture_ptr texture, int w, int h)
|
||||
{
|
||||
return addLayer(new FGTexturedLayer(texture, w, h));
|
||||
}
|
||||
|
||||
void
|
||||
FGLayeredInstrument::addTransformation (FGPanelTransformation * transformation)
|
||||
{
|
||||
int layer = _layers.size() - 1;
|
||||
_layers[layer]->addTransformation(transformation);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGInstrumentLayer.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGInstrumentLayer::FGInstrumentLayer (int w, int h)
|
||||
: _w(w),
|
||||
_h(h)
|
||||
{
|
||||
}
|
||||
|
||||
FGInstrumentLayer::~FGInstrumentLayer ()
|
||||
{
|
||||
for (transformation_list::iterator it = _transformations.begin();
|
||||
it != _transformations.end();
|
||||
it++) {
|
||||
delete *it;
|
||||
*it = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGInstrumentLayer::transform () const
|
||||
{
|
||||
transformation_list::const_iterator it = _transformations.begin();
|
||||
transformation_list::const_iterator last = _transformations.end();
|
||||
while (it != last) {
|
||||
FGPanelTransformation *t = *it;
|
||||
if (t->test()) {
|
||||
float val = (t->node == 0 ? 0.0 : t->node->getFloatValue());
|
||||
|
||||
if (t->has_mod)
|
||||
val = fmod(val, t->mod);
|
||||
if (val < t->min) {
|
||||
val = t->min;
|
||||
} else if (val > t->max) {
|
||||
val = t->max;
|
||||
}
|
||||
|
||||
if (t->table==0) {
|
||||
val = val * t->factor + t->offset;
|
||||
} else {
|
||||
val = t->table->interpolate(val) * t->factor + t->offset;
|
||||
}
|
||||
|
||||
switch (t->type) {
|
||||
case FGPanelTransformation::XSHIFT:
|
||||
glTranslatef(val, 0.0, 0.0);
|
||||
break;
|
||||
case FGPanelTransformation::YSHIFT:
|
||||
glTranslatef(0.0, val, 0.0);
|
||||
break;
|
||||
case FGPanelTransformation::ROTATION:
|
||||
glRotatef(-val, 0.0, 0.0, 1.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGInstrumentLayer::addTransformation (FGPanelTransformation * transformation)
|
||||
{
|
||||
_transformations.push_back(transformation);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGGroupLayer.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGGroupLayer::FGGroupLayer ()
|
||||
{
|
||||
}
|
||||
|
||||
FGGroupLayer::~FGGroupLayer ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _layers.size(); i++)
|
||||
delete _layers[i];
|
||||
}
|
||||
|
||||
void
|
||||
FGGroupLayer::draw ()
|
||||
{
|
||||
if (test()) {
|
||||
transform();
|
||||
int nLayers = _layers.size();
|
||||
for (int i = 0; i < nLayers; i++)
|
||||
_layers[i]->draw( );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGGroupLayer::addLayer (FGInstrumentLayer * layer)
|
||||
{
|
||||
_layers.push_back(layer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGTexturedLayer.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
FGTexturedLayer::FGTexturedLayer (FGCroppedTexture_ptr texture, int w, int h)
|
||||
: FGInstrumentLayer(w, h),
|
||||
_emissive(false),
|
||||
displayList(0)
|
||||
{
|
||||
setTexture(texture);
|
||||
}
|
||||
|
||||
|
||||
FGTexturedLayer::~FGTexturedLayer ()
|
||||
{
|
||||
}
|
||||
|
||||
GLuint
|
||||
FGTexturedLayer::getDisplayList()
|
||||
{
|
||||
if( displayList != 0 )
|
||||
return displayList;
|
||||
|
||||
int w2 = _w / 2;
|
||||
int h2 = _h / 2;
|
||||
|
||||
_texture->bind( false );
|
||||
displayList = glGenLists(1);
|
||||
glNewList(displayList,GL_COMPILE_AND_EXECUTE);
|
||||
glBindTexture( GL_TEXTURE_2D, _texture->getTexture() );
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(_texture->getMinX(), _texture->getMinY()); glVertex2f(-w2, -h2);
|
||||
glTexCoord2f(_texture->getMaxX(), _texture->getMinY()); glVertex2f(w2, -h2);
|
||||
glTexCoord2f(_texture->getMaxX(), _texture->getMaxY()); glVertex2f(w2, h2);
|
||||
glTexCoord2f(_texture->getMinX(), _texture->getMaxY()); glVertex2f(-w2, h2);
|
||||
glEnd();
|
||||
glEndList();
|
||||
|
||||
return displayList;
|
||||
}
|
||||
|
||||
void
|
||||
FGTexturedLayer::draw ( )
|
||||
{
|
||||
if (test()) {
|
||||
transform();
|
||||
glCallList(getDisplayList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGTextLayer.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fntRenderer FGTextLayer::text_renderer;
|
||||
|
||||
FGTextLayer::FGTextLayer (int w, int h)
|
||||
: FGInstrumentLayer(w, h), _pointSize(14.0), _font_name("Helvetica.txf")
|
||||
{
|
||||
_then.stamp();
|
||||
_color[0] = _color[1] = _color[2] = 0.0;
|
||||
_color[3] = 1.0;
|
||||
}
|
||||
|
||||
FGTextLayer::~FGTextLayer ()
|
||||
{
|
||||
chunk_list::iterator it = _chunks.begin();
|
||||
chunk_list::iterator last = _chunks.end();
|
||||
for ( ; it != last; it++) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::draw ()
|
||||
{
|
||||
if (test()) {
|
||||
float c[4];
|
||||
glGetFloatv( GL_CURRENT_COLOR, c );
|
||||
glColor4fv(_color);
|
||||
transform();
|
||||
|
||||
text_renderer.setFont(ApplicationProperties::fontCache.getTexFont(_font_name.c_str()));
|
||||
|
||||
text_renderer.setPointSize(_pointSize);
|
||||
text_renderer.begin();
|
||||
text_renderer.start3f(0, 0, 0);
|
||||
|
||||
_now.stamp();
|
||||
long diff = (_now - _then).toUSecs();
|
||||
|
||||
if (diff > 100000 || diff < 0 ) {
|
||||
// ( diff < 0 ) is a sanity check and indicates our time stamp
|
||||
// difference math probably overflowed. We can handle a max
|
||||
// difference of 35.8 minutes since the returned value is in
|
||||
// usec. So if the panel is left off longer than that we can
|
||||
// over flow the math with it is turned back on. This (diff <
|
||||
// 0) catches that situation, get's us out of trouble, and
|
||||
// back on track.
|
||||
recalc_value();
|
||||
_then = _now;
|
||||
}
|
||||
|
||||
// Something is goofy. The code in this file renders only CCW
|
||||
// polygons, and I have verified that the font code in plib
|
||||
// renders only CCW trianbles. Yet they come out backwards.
|
||||
// Something around here or in plib is either changing the winding
|
||||
// order or (more likely) pushing a left-handed matrix onto the
|
||||
// stack. But I can't find it; get out the chainsaw...
|
||||
glFrontFace(GL_CW);
|
||||
text_renderer.puts((char *)(_value.c_str()));
|
||||
glFrontFace(GL_CCW);
|
||||
|
||||
text_renderer.end();
|
||||
glColor4fv( c );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::addChunk (FGTextLayer::Chunk * chunk)
|
||||
{
|
||||
_chunks.push_back(chunk);
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::setColor (float r, float g, float b)
|
||||
{
|
||||
_color[0] = r;
|
||||
_color[1] = g;
|
||||
_color[2] = b;
|
||||
_color[3] = 1.0;
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::setPointSize (float size)
|
||||
{
|
||||
_pointSize = size;
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::setFontName(const string &name)
|
||||
{
|
||||
_font_name = name + ".txf";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FGTextLayer::setFont(fntFont * font)
|
||||
{
|
||||
FGTextLayer::text_renderer.setFont(font);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FGTextLayer::recalc_value () const
|
||||
{
|
||||
_value = "";
|
||||
chunk_list::const_iterator it = _chunks.begin();
|
||||
chunk_list::const_iterator last = _chunks.end();
|
||||
for ( ; it != last; it++) {
|
||||
_value += (*it)->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGTextLayer::Chunk.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGTextLayer::Chunk::Chunk (const string &text, const string &fmt)
|
||||
: _type(FGTextLayer::TEXT), _fmt(fmt)
|
||||
{
|
||||
_text = text;
|
||||
if (_fmt.empty())
|
||||
_fmt = "%s";
|
||||
}
|
||||
|
||||
FGTextLayer::Chunk::Chunk (ChunkType type, const SGPropertyNode * node,
|
||||
const string &fmt, float mult, float offs,
|
||||
bool truncation)
|
||||
: _type(type), _fmt(fmt), _mult(mult), _offs(offs), _trunc(truncation)
|
||||
{
|
||||
if (_fmt.empty()) {
|
||||
if (type == TEXT_VALUE)
|
||||
_fmt = "%s";
|
||||
else
|
||||
_fmt = "%.2f";
|
||||
}
|
||||
_node = node;
|
||||
}
|
||||
|
||||
const char *
|
||||
FGTextLayer::Chunk::getValue () const
|
||||
{
|
||||
if (test()) {
|
||||
_buf[0] = '\0';
|
||||
switch (_type) {
|
||||
case TEXT:
|
||||
sprintf(_buf, _fmt.c_str(), _text.c_str());
|
||||
return _buf;
|
||||
case TEXT_VALUE:
|
||||
sprintf(_buf, _fmt.c_str(), _node->getStringValue());
|
||||
break;
|
||||
case DOUBLE_VALUE:
|
||||
double d = _offs + _node->getFloatValue() * _mult;
|
||||
if (_trunc) d = (d < 0) ? -floor(-d) : floor(d);
|
||||
sprintf(_buf, _fmt.c_str(), d);
|
||||
break;
|
||||
}
|
||||
return _buf;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGSwitchLayer.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGSwitchLayer::FGSwitchLayer ()
|
||||
: FGGroupLayer()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FGSwitchLayer::draw ()
|
||||
{
|
||||
if (test()) {
|
||||
transform();
|
||||
int nLayers = _layers.size();
|
||||
for (int i = 0; i < nLayers; i++) {
|
||||
if (_layers[i]->test()) {
|
||||
_layers[i]->draw();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// end of panel.cxx
|
451
utils/fgpanel/panel.hxx
Normal file
451
utils/fgpanel/panel.hxx
Normal file
|
@ -0,0 +1,451 @@
|
|||
// panel.hxx - generic support classes for a 2D panel.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef __PANEL_HXX
|
||||
#define __PANEL_HXX
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <plib/fnt.h>
|
||||
|
||||
#include <simgear/props/condition.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/math/interpolater.hxx>
|
||||
#include <simgear/sg_inlines.h>
|
||||
#include "FGTextureLoaderInterface.hxx"
|
||||
|
||||
class FGPanelInstrument;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Texture management.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FGCroppedTexture;
|
||||
typedef SGSharedPtr<FGCroppedTexture> FGCroppedTexture_ptr;
|
||||
/**
|
||||
* Cropped texture (should migrate out into FGFS).
|
||||
*
|
||||
* This structure wraps an SSG texture with cropping information.
|
||||
*/
|
||||
class FGCroppedTexture : public SGReferenced
|
||||
{
|
||||
public:
|
||||
FGCroppedTexture (const string &path,
|
||||
float _minX = 0.0, float _minY = 0.0,
|
||||
float _maxX = 1.0, float _maxY = 1.0);
|
||||
|
||||
virtual ~FGCroppedTexture ();
|
||||
|
||||
virtual void setPath (const string &path) { _path = path; }
|
||||
|
||||
virtual const string &getPath () const { return _path; }
|
||||
|
||||
virtual void setCrop (float minX, float minY, float maxX, float maxY) {
|
||||
_minX = minX; _minY = minY; _maxX = maxX; _maxY = maxY;
|
||||
}
|
||||
|
||||
static void registerTextureLoader( const string & extension, FGTextureLoaderInterface * loader ) {
|
||||
if( textureLoader.count( extension ) == 0 )
|
||||
textureLoader[extension] = loader;
|
||||
}
|
||||
|
||||
virtual float getMinX () const { return _minX; }
|
||||
virtual float getMinY () const { return _minY; }
|
||||
virtual float getMaxX () const { return _maxX; }
|
||||
virtual float getMaxY () const { return _maxY; }
|
||||
GLuint getTexture() const { return _texture; }
|
||||
|
||||
virtual void bind( bool doGLBind = true );
|
||||
|
||||
private:
|
||||
string _path;
|
||||
float _minX, _minY, _maxX, _maxY;
|
||||
|
||||
GLuint _texture;
|
||||
static GLuint current_bound_texture;
|
||||
static map<string,GLuint> cache;
|
||||
static map<string,FGTextureLoaderInterface*> textureLoader;
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Top-level panel.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Instrument panel class.
|
||||
*
|
||||
* The panel is a container that has a background texture and holds
|
||||
* zero or more instruments. The panel will order the instruments to
|
||||
* redraw themselves when necessary, and will pass mouse clicks on to
|
||||
* the appropriate instruments for processing.
|
||||
*/
|
||||
class FGPanel : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
|
||||
FGPanel ( SGPropertyNode_ptr root );
|
||||
virtual ~FGPanel ();
|
||||
|
||||
// Update the panel (every frame).
|
||||
virtual void init ();
|
||||
virtual void bind ();
|
||||
virtual void unbind ();
|
||||
// virtual void draw ();
|
||||
virtual void update (double dt);
|
||||
|
||||
// transfer pointer ownership!!!
|
||||
virtual void addInstrument (FGPanelInstrument * instrument);
|
||||
|
||||
// Background texture.
|
||||
virtual void setBackground (FGCroppedTexture_ptr texture);
|
||||
inline void setBackgroundWidth( double d ) {
|
||||
_bg_width = d;
|
||||
}
|
||||
|
||||
inline void setBackgroundHeight( double d ) {
|
||||
_bg_height = d;
|
||||
}
|
||||
|
||||
// Background multiple textures.
|
||||
virtual void setMultiBackground (FGCroppedTexture_ptr texture , int idx);
|
||||
|
||||
// Full width of panel.
|
||||
virtual void setWidth (int width) { _width = width; }
|
||||
virtual int getWidth () const { return _width; }
|
||||
|
||||
// Full height of panel.
|
||||
virtual void setHeight (int height) { _height = height; }
|
||||
virtual int getHeight () const { return _height; }
|
||||
|
||||
private:
|
||||
|
||||
typedef vector<FGPanelInstrument *> instrument_list_type;
|
||||
int _width;
|
||||
int _height;
|
||||
|
||||
SGPropertyNode_ptr _root;
|
||||
SGPropertyNode_ptr _flipx;
|
||||
SGPropertyNode_ptr _rotate;
|
||||
|
||||
FGCroppedTexture_ptr _bg;
|
||||
double _bg_width;
|
||||
double _bg_height;
|
||||
FGCroppedTexture_ptr _mbg[8];
|
||||
// List of instruments in panel.
|
||||
instrument_list_type _instruments;
|
||||
|
||||
GLuint initDisplayList;
|
||||
|
||||
GLuint getInitDisplayList();
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Transformations.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* A transformation for a layer.
|
||||
*/
|
||||
class FGPanelTransformation : public SGConditional
|
||||
{
|
||||
public:
|
||||
|
||||
enum Type {
|
||||
XSHIFT,
|
||||
YSHIFT,
|
||||
ROTATION
|
||||
};
|
||||
|
||||
FGPanelTransformation ();
|
||||
virtual ~FGPanelTransformation ();
|
||||
|
||||
Type type;
|
||||
SGConstPropertyNode_ptr node;
|
||||
float min;
|
||||
float max;
|
||||
bool has_mod;
|
||||
float mod;
|
||||
float factor;
|
||||
float offset;
|
||||
SGInterpTable * table;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Layers
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* A single layer of a multi-layered instrument.
|
||||
*
|
||||
* Each layer can be subject to a series of transformations based
|
||||
* on current FGFS instrument readings: for example, a texture
|
||||
* representing a needle can rotate to show the airspeed.
|
||||
*/
|
||||
class FGInstrumentLayer : public SGConditional
|
||||
{
|
||||
public:
|
||||
|
||||
FGInstrumentLayer (int w = -1, int h = -1);
|
||||
virtual ~FGInstrumentLayer ();
|
||||
|
||||
virtual void draw () = 0;
|
||||
virtual void transform () const;
|
||||
|
||||
virtual int getWidth () const { return _w; }
|
||||
virtual int getHeight () const { return _h; }
|
||||
virtual void setWidth (int w) { _w = w; }
|
||||
virtual void setHeight (int h) { _h = h; }
|
||||
|
||||
// Transfer pointer ownership!!
|
||||
// DEPRECATED
|
||||
virtual void addTransformation (FGPanelTransformation * transformation);
|
||||
|
||||
protected:
|
||||
int _w, _h;
|
||||
|
||||
typedef vector<FGPanelTransformation *> transformation_list;
|
||||
transformation_list _transformations;
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Instruments.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Abstract base class for a panel instrument.
|
||||
*
|
||||
* A panel instrument consists of zero or more actions, associated
|
||||
* with mouse clicks in rectangular areas. Currently, the only
|
||||
* concrete class derived from this is FGLayeredInstrument, but others
|
||||
* may show up in the future (some complex instruments could be
|
||||
* entirely hand-coded, for example).
|
||||
*/
|
||||
class FGPanelInstrument : public SGConditional
|
||||
{
|
||||
public:
|
||||
FGPanelInstrument ();
|
||||
FGPanelInstrument (int x, int y, int w, int h);
|
||||
virtual ~FGPanelInstrument ();
|
||||
|
||||
virtual void draw () = 0;
|
||||
|
||||
virtual void setPosition(int x, int y);
|
||||
virtual void setSize(int w, int h);
|
||||
|
||||
virtual int getXPos () const;
|
||||
virtual int getYPos () const;
|
||||
virtual int getWidth () const;
|
||||
virtual int getHeight () const;
|
||||
|
||||
protected:
|
||||
int _x, _y, _w, _h;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An instrument constructed of multiple layers.
|
||||
*
|
||||
* Each individual layer can be rotated or shifted to correspond
|
||||
* to internal FGFS instrument readings.
|
||||
*/
|
||||
class FGLayeredInstrument : public FGPanelInstrument
|
||||
{
|
||||
public:
|
||||
FGLayeredInstrument (int x, int y, int w, int h);
|
||||
virtual ~FGLayeredInstrument ();
|
||||
|
||||
virtual void draw ();
|
||||
|
||||
// Transfer pointer ownership!!
|
||||
virtual int addLayer (FGInstrumentLayer *layer);
|
||||
virtual int addLayer (FGCroppedTexture_ptr texture, int w = -1, int h = -1);
|
||||
|
||||
// Transfer pointer ownership!!
|
||||
virtual void addTransformation (FGPanelTransformation * transformation);
|
||||
|
||||
protected:
|
||||
typedef vector<FGInstrumentLayer *> layer_list;
|
||||
layer_list _layers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An instrument layer containing a group of sublayers.
|
||||
*
|
||||
* This class is useful for gathering together a group of related
|
||||
* layers, either to hold in an external file or to work under
|
||||
* the same condition.
|
||||
*/
|
||||
class FGGroupLayer : public FGInstrumentLayer
|
||||
{
|
||||
public:
|
||||
FGGroupLayer ();
|
||||
virtual ~FGGroupLayer ();
|
||||
virtual void draw ();
|
||||
// transfer pointer ownership
|
||||
virtual void addLayer (FGInstrumentLayer * layer);
|
||||
protected:
|
||||
vector<FGInstrumentLayer *> _layers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A textured layer of an instrument.
|
||||
*
|
||||
* This is a layer holding a single texture. Normally, the texture's
|
||||
* backgound should be transparent so that lower layers and the panel
|
||||
* background can show through.
|
||||
*/
|
||||
class FGTexturedLayer : public FGInstrumentLayer
|
||||
{
|
||||
public:
|
||||
FGTexturedLayer (int w = -1, int h = -1) : FGInstrumentLayer(w, h) {}
|
||||
FGTexturedLayer (FGCroppedTexture_ptr texture, int w = -1, int h = -1);
|
||||
virtual ~FGTexturedLayer ();
|
||||
|
||||
virtual void draw ();
|
||||
|
||||
virtual void setTexture (FGCroppedTexture_ptr texture) {
|
||||
_texture = texture;
|
||||
}
|
||||
FGCroppedTexture_ptr getTexture() { return _texture; }
|
||||
|
||||
void setEmissive(bool e) { _emissive = e; }
|
||||
|
||||
private:
|
||||
GLuint getDisplayList();
|
||||
|
||||
FGCroppedTexture_ptr _texture;
|
||||
bool _emissive;
|
||||
GLuint displayList;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A text layer of an instrument.
|
||||
*
|
||||
* This is a layer holding a string of static and/or generated text.
|
||||
* It is useful for instruments that have text displays, such as
|
||||
* a chronometer, GPS, or NavCom radio.
|
||||
*/
|
||||
class FGTextLayer : public FGInstrumentLayer
|
||||
{
|
||||
public:
|
||||
enum ChunkType {
|
||||
TEXT,
|
||||
TEXT_VALUE,
|
||||
DOUBLE_VALUE
|
||||
};
|
||||
|
||||
class Chunk : public SGConditional
|
||||
{
|
||||
public:
|
||||
Chunk (const string &text, const string &fmt = "%s");
|
||||
Chunk (ChunkType type, const SGPropertyNode * node,
|
||||
const string &fmt = "", float mult = 1.0, float offs = 0.0,
|
||||
bool truncation = false);
|
||||
|
||||
const char * getValue () const;
|
||||
private:
|
||||
ChunkType _type;
|
||||
string _text;
|
||||
SGConstPropertyNode_ptr _node;
|
||||
string _fmt;
|
||||
float _mult;
|
||||
float _offs;
|
||||
bool _trunc;
|
||||
mutable char _buf[1024];
|
||||
|
||||
};
|
||||
|
||||
FGTextLayer (int w = -1, int h = -1);
|
||||
virtual ~FGTextLayer ();
|
||||
|
||||
virtual void draw ();
|
||||
|
||||
// Transfer pointer!!
|
||||
virtual void addChunk (Chunk * chunk);
|
||||
virtual void setColor (float r, float g, float b);
|
||||
virtual void setPointSize (float size);
|
||||
virtual void setFontName ( const string &name );
|
||||
virtual void setFont (fntFont * font);
|
||||
|
||||
private:
|
||||
|
||||
void recalc_value () const;
|
||||
|
||||
typedef vector<Chunk *> chunk_list;
|
||||
chunk_list _chunks;
|
||||
float _color[4];
|
||||
|
||||
float _pointSize;
|
||||
mutable string _font_name;
|
||||
mutable string _value;
|
||||
mutable SGTimeStamp _then;
|
||||
mutable SGTimeStamp _now;
|
||||
|
||||
static fntRenderer text_renderer;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A group layer that switches among its children.
|
||||
*
|
||||
* The first layer that passes its condition will be drawn, and
|
||||
* any following layers will be ignored.
|
||||
*/
|
||||
class FGSwitchLayer : public FGGroupLayer
|
||||
{
|
||||
public:
|
||||
// Transfer pointers!!
|
||||
FGSwitchLayer ();
|
||||
virtual void draw ();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // __PANEL_HXX
|
||||
|
||||
// end of panel.hxx
|
||||
|
||||
|
||||
|
591
utils/fgpanel/panel_io.cxx
Normal file
591
utils/fgpanel/panel_io.cxx
Normal file
|
@ -0,0 +1,591 @@
|
|||
// panel_io.cxx - I/O for 2D panel.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id: panel_io.cxx,v 1.26 2006/08/10 11:12:39 mfranz Exp $
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <string.h> // for strcmp()
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/props/condition.hxx>
|
||||
|
||||
#include "panel.hxx"
|
||||
#include "panel_io.hxx"
|
||||
#include "ApplicationProperties.hxx"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Read and construct a panel.
|
||||
//
|
||||
// The panel is specified as a regular property list, and each of the
|
||||
// instruments is its own, separate property list (and thus, a separate
|
||||
// XML document). The functions in this section read in the files
|
||||
// as property lists, then extract properties to set up the panel
|
||||
// itself.
|
||||
//
|
||||
// A panel contains zero or more instruments.
|
||||
//
|
||||
// An instrument contains one or more layers and zero or more actions.
|
||||
//
|
||||
// A layer contains zero or more transformations.
|
||||
//
|
||||
// Some special types of layers also contain other objects, such as
|
||||
// chunks of text or other layers.
|
||||
//
|
||||
// There are currently four types of layers:
|
||||
//
|
||||
// 1. Textured Layer (type="texture"), the default
|
||||
// 2. Text Layer (type="text")
|
||||
// 3. Switch Layer (type="switch")
|
||||
// 4. Built-in Layer (type="built-in", must also specify class)
|
||||
//
|
||||
// The only built-in layer so far is the ribbon for the magnetic compass
|
||||
// (class="compass-ribbon").
|
||||
//
|
||||
// There are three types of actions:
|
||||
//
|
||||
// 1. Adjust (type="adjust"), the default
|
||||
// 2. Swap (type="swap")
|
||||
// 3. Toggle (type="toggle")
|
||||
//
|
||||
// There are three types of transformations:
|
||||
//
|
||||
// 1. X shift (type="x-shift"), the default
|
||||
// 2. Y shift (type="y-shift")
|
||||
// 3. Rotation (type="rotation")
|
||||
//
|
||||
// Each of these may be associated with a property, so that a needle
|
||||
// will rotate with the airspeed, for example, or may have a fixed
|
||||
// floating-point value.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Read a cropped texture from the instrument's property list.
|
||||
*
|
||||
* The x1 and y1 properties give the starting position of the texture
|
||||
* (between 0.0 and 1.0), and the the x2 and y2 properties give the
|
||||
* ending position. For example, to use the bottom-left quarter of a
|
||||
* texture, x1=0.0, y1=0.0, x2=0.5, y2=0.5.
|
||||
*/
|
||||
static FGCroppedTexture_ptr
|
||||
readTexture (const SGPropertyNode * node)
|
||||
{
|
||||
return new FGCroppedTexture(node->getStringValue("path"),
|
||||
node->getFloatValue("x1"),
|
||||
node->getFloatValue("y1"),
|
||||
node->getFloatValue("x2", 1.0),
|
||||
node->getFloatValue("y2", 1.0));
|
||||
SG_LOG(SG_COCKPIT, SG_DEBUG, "Read texture " << node->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a condition in the current node.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Read a condition and use it if necessary.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void
|
||||
readConditions (SGConditional *component, const SGPropertyNode *node)
|
||||
{
|
||||
const SGPropertyNode * conditionNode = node->getChild("condition");
|
||||
if (conditionNode != 0)
|
||||
// The top level is implicitly AND
|
||||
component->setCondition(sgReadCondition(ApplicationProperties::Properties,
|
||||
conditionNode) );
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a transformation from the instrument's property list.
|
||||
*
|
||||
* The panel module uses the transformations to slide or spin needles,
|
||||
* knobs, and other indicators, and to place layers in the correct
|
||||
* positions. Every layer starts centered exactly on the x,y co-ordinate,
|
||||
* and many layers need to be moved or rotated simply to display the
|
||||
* instrument correctly.
|
||||
*
|
||||
* There are three types of transformations:
|
||||
*
|
||||
* "x-shift" - move the layer horizontally.
|
||||
*
|
||||
* "y-shift" - move the layer vertically.
|
||||
*
|
||||
* "rotation" - rotate the layer.
|
||||
*
|
||||
* Each transformation may have a fixed offset, and may also have
|
||||
* a floating-point property value to add to the offset. The
|
||||
* floating-point property may be clamped to a minimum and/or
|
||||
* maximum range and scaled (after clamping).
|
||||
*
|
||||
* Note that because of the way OpenGL works, transformations will
|
||||
* appear to be applied backwards.
|
||||
*/
|
||||
static FGPanelTransformation *
|
||||
readTransformation (const SGPropertyNode * node, float w_scale, float h_scale)
|
||||
{
|
||||
FGPanelTransformation * t = new FGPanelTransformation;
|
||||
|
||||
string name = node->getName();
|
||||
string type = node->getStringValue("type");
|
||||
string propName = node->getStringValue("property", "");
|
||||
const SGPropertyNode * target = 0;
|
||||
|
||||
if (type.empty()) {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO,
|
||||
"No type supplied for transformation " << name
|
||||
<< " assuming \"rotation\"" );
|
||||
type = "rotation";
|
||||
}
|
||||
|
||||
if (!propName.empty())
|
||||
target = ApplicationProperties::Properties->getNode(propName.c_str(), true);
|
||||
|
||||
t->node = target;
|
||||
t->min = node->getFloatValue("min", -9999999);
|
||||
t->max = node->getFloatValue("max", 99999999);
|
||||
t->has_mod = node->hasChild("modulator");
|
||||
if (t->has_mod)
|
||||
t->mod = node->getFloatValue("modulator");
|
||||
t->factor = node->getFloatValue("scale", 1.0);
|
||||
t->offset = node->getFloatValue("offset", 0.0);
|
||||
|
||||
|
||||
// Check for an interpolation table
|
||||
const SGPropertyNode * trans_table = node->getNode("interpolation");
|
||||
if (trans_table != 0) {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Found interpolation table with "
|
||||
<< trans_table->nChildren() << " children" );
|
||||
t->table = new SGInterpTable();
|
||||
for (int i = 0; i < trans_table->nChildren(); i++) {
|
||||
const SGPropertyNode * node = trans_table->getChild(i);
|
||||
if (!strcmp(node->getName(), "entry")) {
|
||||
double ind = node->getDoubleValue("ind", 0.0);
|
||||
double dep = node->getDoubleValue("dep", 0.0);
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Adding interpolation entry "
|
||||
<< ind << "==>" << dep );
|
||||
t->table->addEntry(ind, dep);
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
|
||||
<< " in interpolation" );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t->table = 0;
|
||||
}
|
||||
|
||||
// Move the layer horizontally.
|
||||
if (type == "x-shift") {
|
||||
t->type = FGPanelTransformation::XSHIFT;
|
||||
// t->min *= w_scale; //removed by Martin Dressler
|
||||
// t->max *= w_scale; //removed by Martin Dressler
|
||||
t->offset *= w_scale;
|
||||
t->factor *= w_scale; //Added by Martin Dressler
|
||||
}
|
||||
|
||||
// Move the layer vertically.
|
||||
else if (type == "y-shift") {
|
||||
t->type = FGPanelTransformation::YSHIFT;
|
||||
//t->min *= h_scale; //removed
|
||||
//t->max *= h_scale; //removed
|
||||
t->offset *= h_scale;
|
||||
t->factor *= h_scale; //Added
|
||||
}
|
||||
|
||||
// Rotate the layer. The rotation
|
||||
// is in degrees, and does not need
|
||||
// to scale with the instrument size.
|
||||
else if (type == "rotation") {
|
||||
t->type = FGPanelTransformation::ROTATION;
|
||||
}
|
||||
|
||||
else {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized transformation type " << type );
|
||||
delete t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
readConditions(t, node);
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Read transformation " << name );
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a chunk of text from the instrument's property list.
|
||||
*
|
||||
* A text layer consists of one or more chunks of text. All chunks
|
||||
* share the same font size and color (and eventually, font), but
|
||||
* each can come from a different source. There are three types of
|
||||
* text chunks:
|
||||
*
|
||||
* "literal" - a literal text string (the default)
|
||||
*
|
||||
* "text-value" - the current value of a string property
|
||||
*
|
||||
* "number-value" - the current value of a floating-point property.
|
||||
*
|
||||
* All three may also include a printf-style format string.
|
||||
*/
|
||||
FGTextLayer::Chunk *
|
||||
readTextChunk (const SGPropertyNode * node)
|
||||
{
|
||||
FGTextLayer::Chunk * chunk;
|
||||
string name = node->getStringValue("name");
|
||||
string type = node->getStringValue("type");
|
||||
string format = node->getStringValue("format");
|
||||
|
||||
// Default to literal text.
|
||||
if (type.empty()) {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "No type provided for text chunk " << name
|
||||
<< " assuming \"literal\"");
|
||||
type = "literal";
|
||||
}
|
||||
|
||||
// A literal text string.
|
||||
if (type == "literal") {
|
||||
string text = node->getStringValue("text");
|
||||
chunk = new FGTextLayer::Chunk(text, format);
|
||||
}
|
||||
|
||||
// The value of a string property.
|
||||
else if (type == "text-value") {
|
||||
SGPropertyNode * target =
|
||||
ApplicationProperties::Properties->getNode( node->getStringValue("property"), true);
|
||||
chunk = new FGTextLayer::Chunk(FGTextLayer::TEXT_VALUE, target, format);
|
||||
}
|
||||
|
||||
// The value of a float property.
|
||||
else if (type == "number-value") {
|
||||
string propName = node->getStringValue("property");
|
||||
float scale = node->getFloatValue("scale", 1.0);
|
||||
float offset = node->getFloatValue("offset", 0.0);
|
||||
bool truncation = node->getBoolValue("truncate", false);
|
||||
SGPropertyNode * target = ApplicationProperties::Properties->getNode(propName.c_str(), true);
|
||||
chunk = new FGTextLayer::Chunk(FGTextLayer::DOUBLE_VALUE, target,
|
||||
format, scale, offset, truncation);
|
||||
}
|
||||
|
||||
// Unknown type.
|
||||
else {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized type " << type
|
||||
<< " for text chunk " << name );
|
||||
return 0;
|
||||
}
|
||||
|
||||
readConditions(chunk, node);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a single layer from an instrument's property list.
|
||||
*
|
||||
* Each instrument consists of one or more layers stacked on top
|
||||
* of each other; the lower layers show through only where the upper
|
||||
* layers contain an alpha component. Each layer can be moved
|
||||
* horizontally and vertically and rotated using transformations.
|
||||
*
|
||||
* This module currently recognizes four kinds of layers:
|
||||
*
|
||||
* "texture" - a layer containing a texture (the default)
|
||||
*
|
||||
* "text" - a layer containing text
|
||||
*
|
||||
* "switch" - a layer that switches between two other layers
|
||||
* based on the current value of a boolean property.
|
||||
*
|
||||
* "built-in" - a hard-coded layer supported by C++ code in FlightGear.
|
||||
*
|
||||
* Currently, the only built-in layer class is "compass-ribbon".
|
||||
*/
|
||||
static FGInstrumentLayer *
|
||||
readLayer (const SGPropertyNode * node, float w_scale, float h_scale)
|
||||
{
|
||||
FGInstrumentLayer * layer = NULL;
|
||||
string name = node->getStringValue("name");
|
||||
string type = node->getStringValue("type");
|
||||
int w = node->getIntValue("w", -1);
|
||||
int h = node->getIntValue("h", -1);
|
||||
bool emissive = node->getBoolValue("emissive", false);
|
||||
if (w != -1)
|
||||
w = int(w * w_scale);
|
||||
if (h != -1)
|
||||
h = int(h * h_scale);
|
||||
|
||||
|
||||
if (type.empty()) {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO,
|
||||
"No type supplied for layer " << name
|
||||
<< " assuming \"texture\"" );
|
||||
type = "texture";
|
||||
}
|
||||
|
||||
|
||||
// A textured instrument layer.
|
||||
if (type == "texture") {
|
||||
FGCroppedTexture_ptr texture = readTexture(node->getNode("texture"));
|
||||
layer = new FGTexturedLayer(texture, w, h);
|
||||
if (emissive) {
|
||||
FGTexturedLayer *tl=(FGTexturedLayer*)layer;
|
||||
tl->setEmissive(true);
|
||||
}
|
||||
|
||||
}
|
||||
// A group of sublayers.
|
||||
else if (type == "group") {
|
||||
layer = new FGGroupLayer();
|
||||
for (int i = 0; i < node->nChildren(); i++) {
|
||||
const SGPropertyNode * child = node->getChild(i);
|
||||
if (!strcmp(child->getName(), "layer"))
|
||||
((FGGroupLayer *)layer)->addLayer(readLayer(child, w_scale, h_scale));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A textual instrument layer.
|
||||
else if (type == "text") {
|
||||
FGTextLayer * tlayer = new FGTextLayer(w, h); // FIXME
|
||||
|
||||
// Set the text color.
|
||||
float red = node->getFloatValue("color/red", 0.0);
|
||||
float green = node->getFloatValue("color/green", 0.0);
|
||||
float blue = node->getFloatValue("color/blue", 0.0);
|
||||
tlayer->setColor(red, green, blue);
|
||||
|
||||
// Set the point size.
|
||||
float pointSize = node->getFloatValue("point-size", 10.0) * w_scale;
|
||||
tlayer->setPointSize(pointSize);
|
||||
|
||||
// Set the font.
|
||||
string fontName = node->getStringValue("font", "Helvetica");
|
||||
tlayer->setFontName(fontName);
|
||||
|
||||
const SGPropertyNode * chunk_group = node->getNode("chunks");
|
||||
if (chunk_group != 0) {
|
||||
int nChunks = chunk_group->nChildren();
|
||||
for (int i = 0; i < nChunks; i++) {
|
||||
const SGPropertyNode * node = chunk_group->getChild(i);
|
||||
if (!strcmp(node->getName(), "chunk")) {
|
||||
FGTextLayer::Chunk * chunk = readTextChunk(node);
|
||||
if (chunk != 0)
|
||||
tlayer->addChunk(chunk);
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
|
||||
<< " in chunks" );
|
||||
}
|
||||
}
|
||||
layer = tlayer;
|
||||
}
|
||||
}
|
||||
|
||||
// A switch instrument layer.
|
||||
else if (type == "switch") {
|
||||
layer = new FGSwitchLayer();
|
||||
for (int i = 0; i < node->nChildren(); i++) {
|
||||
const SGPropertyNode * child = node->getChild(i);
|
||||
if (!strcmp(child->getName(), "layer"))
|
||||
((FGGroupLayer *)layer)->addLayer(readLayer(child, w_scale, h_scale));
|
||||
}
|
||||
}
|
||||
|
||||
// An unknown type.
|
||||
else {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized layer type " << type );
|
||||
delete layer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the transformations for each layer.
|
||||
//
|
||||
const SGPropertyNode * trans_group = node->getNode("transformations");
|
||||
if (trans_group != 0) {
|
||||
int nTransformations = trans_group->nChildren();
|
||||
for (int i = 0; i < nTransformations; i++) {
|
||||
const SGPropertyNode * node = trans_group->getChild(i);
|
||||
if (!strcmp(node->getName(), "transformation")) {
|
||||
FGPanelTransformation * t = readTransformation(node, w_scale, h_scale);
|
||||
if (t != 0)
|
||||
layer->addTransformation(t);
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
|
||||
<< " in transformations" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readConditions(layer, node);
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Read layer " << name );
|
||||
return layer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read an instrument from a property list.
|
||||
*
|
||||
* The instrument consists of a preferred width and height
|
||||
* (the panel may override these), together with a list of layers
|
||||
* and a list of actions to be performed when the user clicks
|
||||
* the mouse over the instrument. All co-ordinates are relative
|
||||
* to the instrument's position, so instruments are fully relocatable;
|
||||
* likewise, co-ordinates for actions and transformations will be
|
||||
* scaled automatically if the instrument is not at its preferred size.
|
||||
*/
|
||||
static FGPanelInstrument *
|
||||
readInstrument (const SGPropertyNode * node)
|
||||
{
|
||||
const string name = node->getStringValue("name");
|
||||
int x = node->getIntValue("x", -1);
|
||||
int y = node->getIntValue("y", -1);
|
||||
int real_w = node->getIntValue("w", -1);
|
||||
int real_h = node->getIntValue("h", -1);
|
||||
int w = node->getIntValue("w-base", -1);
|
||||
int h = node->getIntValue("h-base", -1);
|
||||
|
||||
if (x == -1 || y == -1) {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT,
|
||||
"x and y positions must be specified and > 0" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
float w_scale = 1.0;
|
||||
float h_scale = 1.0;
|
||||
if (real_w != -1) {
|
||||
w_scale = float(real_w) / float(w);
|
||||
w = real_w;
|
||||
}
|
||||
if (real_h != -1) {
|
||||
h_scale = float(real_h) / float(h);
|
||||
h = real_h;
|
||||
}
|
||||
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Reading instrument " << name );
|
||||
|
||||
FGLayeredInstrument * instrument =
|
||||
new FGLayeredInstrument(x, y, w, h);
|
||||
|
||||
//
|
||||
// Get the layers for the instrument.
|
||||
//
|
||||
const SGPropertyNode * layer_group = node->getNode("layers");
|
||||
if (layer_group != 0) {
|
||||
int nLayers = layer_group->nChildren();
|
||||
for (int i = 0; i < nLayers; i++) {
|
||||
const SGPropertyNode * node = layer_group->getChild(i);
|
||||
if (!strcmp(node->getName(), "layer")) {
|
||||
FGInstrumentLayer * layer = readLayer(node, w_scale, h_scale);
|
||||
if (layer != 0)
|
||||
instrument->addLayer(layer);
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
|
||||
<< " in layers" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readConditions(instrument, node);
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Done reading instrument " << name );
|
||||
return instrument;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct the panel from a property tree.
|
||||
*/
|
||||
SGSharedPtr<FGPanel>
|
||||
FGReadablePanel::read(SGPropertyNode_ptr root)
|
||||
{
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Reading properties for panel " <<
|
||||
root->getStringValue("name", "[Unnamed Panel]") );
|
||||
|
||||
FGPanel * panel = new FGPanel(root);
|
||||
panel->setWidth(root->getIntValue("w", 1024));
|
||||
panel->setHeight(root->getIntValue("h", 443));
|
||||
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Size=" << panel->getWidth() << "x" << panel->getHeight() );
|
||||
|
||||
// Assign the background texture, if any, or a bogus chequerboard.
|
||||
//
|
||||
string bgTexture = root->getStringValue("background");
|
||||
if( !bgTexture.empty() )
|
||||
panel->setBackground( new FGCroppedTexture( bgTexture ) );
|
||||
panel->setBackgroundWidth( root->getDoubleValue( "background-width", 1.0 ) );
|
||||
panel->setBackgroundHeight( root->getDoubleValue( "background-height", 1.0 ) );
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Set background texture to " << bgTexture );
|
||||
|
||||
//
|
||||
// Get multibackground if any...
|
||||
//
|
||||
for( int i = 0; i < 8; i++ ) {
|
||||
SGPropertyNode * mbgNode = root->getChild( "multibackground", i );
|
||||
string mbgTexture;
|
||||
if( mbgNode != NULL ) mbgTexture = mbgNode->getStringValue();
|
||||
if( mbgTexture.empty() ) {
|
||||
if( i == 0 ) break; // if first texture is missing, ignore the rest
|
||||
else mbgTexture = "FOO"; // if others are missing - set default texture
|
||||
}
|
||||
panel->setMultiBackground( new FGCroppedTexture(mbgTexture), i );
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Set multi-background texture" << i << " to " << mbgTexture );
|
||||
}
|
||||
//
|
||||
// Create each instrument.
|
||||
//
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Reading panel instruments" );
|
||||
const SGPropertyNode * instrument_group = root->getChild("instruments");
|
||||
if (instrument_group != 0) {
|
||||
int nInstruments = instrument_group->nChildren();
|
||||
for (int i = 0; i < nInstruments; i++) {
|
||||
const SGPropertyNode * node = instrument_group->getChild(i);
|
||||
if (!strcmp(node->getName(), "instrument")) {
|
||||
FGPanelInstrument * instrument = readInstrument(node);
|
||||
if (instrument != 0)
|
||||
panel->addInstrument(instrument);
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
|
||||
<< " in instruments section" );
|
||||
}
|
||||
}
|
||||
}
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Done reading panel instruments" );
|
||||
|
||||
|
||||
//
|
||||
// Return the new panel.
|
||||
//
|
||||
return panel;
|
||||
}
|
||||
|
||||
// end of panel_io.cxx
|
||||
|
||||
|
||||
|
40
utils/fgpanel/panel_io.hxx
Normal file
40
utils/fgpanel/panel_io.hxx
Normal file
|
@ -0,0 +1,40 @@
|
|||
// panel_io.cxx - I/O for 2D panel.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id: panel_io.hxx,v 1.6 2006/04/17 13:03:43 mfranz Exp $
|
||||
|
||||
#ifndef __PANEL_IO_HXX
|
||||
#define __PANEL_IO_HXX
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "panel.hxx"
|
||||
|
||||
class FGReadablePanel : public FGPanel {
|
||||
public:
|
||||
static SGSharedPtr<FGPanel> read(SGPropertyNode_ptr root);
|
||||
};
|
||||
|
||||
|
||||
#endif // __PANEL_IO_HXX
|
Loading…
Reference in a new issue