1
0
Fork 0

Update FGPanel:

- use OpenGL 2.0 instead of OpenGL 1.0;
- port to Raspberry Pi;
- remove PLib dependencies.
This commit is contained in:
gallaert 2016-12-04 18:36:53 +00:00 committed by James Turner
parent c9b01b1d69
commit effca9da5e
48 changed files with 4471 additions and 2835 deletions

View file

@ -0,0 +1,69 @@
//
// 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 "ApplicationProperties.hxx"
double
ApplicationProperties::getDouble (const char *name, const double def) {
const SGPropertyNode_ptr n (ApplicationProperties::Properties->getNode (name, false));
if (n == NULL) {
return def;
}
return n->getDoubleValue ();
}
SGPath
ApplicationProperties::GetCwd () {
SGPath path (".");
char buf[512];
char *cwd (getcwd (buf, 511));
buf[511] = '\0';
if (cwd) {
path = SGPath::fromLocal8Bit (cwd);
}
return path;
}
SGPath
ApplicationProperties::GetRootPath (const char *sub) {
if (sub != NULL) {
const SGPath subpath (sub);
// relative path to current working dir?
if (subpath.isRelative ()) {
SGPath path (GetCwd ());
path.append (sub);
if (path.exists ()) {
return path;
}
} else if (subpath.exists ()) {
// absolute path
return subpath;
}
}
// default: relative path to FGROOT
SGPath path (ApplicationProperties::root);
if (sub != NULL) {
path.append (sub);
}
return path;
}
string ApplicationProperties::root = ".";
SGPropertyNode_ptr ApplicationProperties::Properties = new SGPropertyNode;

View file

@ -5,7 +5,7 @@
// 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
@ -17,16 +17,19 @@
//
#ifndef __APPLICATION_PROPERTIES
#define __APPLICATION_PROPERTIES
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include "FGFontCache.hxx"
using namespace std;
class ApplicationProperties {
public:
static double getDouble( const char * name, double def = 0.0 );
static SGPath GetRootPath( const char * subDir = NULL );
static SGPath GetCwd();
static double getDouble (const char *name, const double def = 0.0);
static SGPath GetRootPath (const char *subDir = NULL);
static SGPath GetCwd ();
static SGPropertyNode_ptr Properties;
static std::string root;
static FGFontCache fontCache;
static string root;
};
#endif

View file

@ -1,40 +1,103 @@
find_package(PNG REQUIRED)
find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)
if(GLUT_FOUND)
message(STATUS "found glut")
find_path(BCMHOST_INCLUDE_DIR
NAMES bcm_host.h
PATHS /opt/vc/include
NO_DEFAULT_PATH
)
add_executable(fgpanel main.cxx
ApplicationProperties.hxx
FGGLApplication.cxx
FGGLApplication.hxx
FGPanelApplication.cxx
FGPanelApplication.hxx
FGPNGTextureLoader.cxx
FGPNGTextureLoader.hxx
FGRGBTextureLoader.cxx
FGRGBTextureLoader.hxx
FGPanelProtocol.cxx
FGPanelProtocol.hxx
FGFontCache.cxx
FGFontCache.hxx
panel.cxx
panel.hxx
panel_io.cxx
panel_io.hxx
)
include_directories(
/usr/include/freetype2
${PNG_INCLUDE_DIR}
)
target_link_libraries(fgpanel
${PNG_LIBRARIES}
${GLUT_LIBRARIES}
SimGearCore
${OPENGL_LIBRARIES}
${PLIB_LIBRARIES}
)
include_directories(${PNG_INCLUDE_DIR})
install(TARGETS fgpanel RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if(${BCMHOST_INCLUDE_DIR} STREQUAL "BCMHOST_INCLUDE_DIR-NOTFOUND")
else()
message(STATUS "glut NOT found, can't build fgpanel")
# CMAKE > 3.1 : target_sources(fgpanel
set(TARGET_SOURCES
GLES_utils.cxx
GLES_utils.hxx
)
endif()
add_executable(fgpanel
main.cxx
ApplicationProperties.hxx
ApplicationProperties.cxx
FGCroppedTexture.hxx
FGCroppedTexture.cxx
FGDummyTextureLoader.hxx
FGDummyTextureLoader.cxx
FGFontCache.cxx
FGFontCache.hxx
FGGLApplication.cxx
FGGLApplication.hxx
FGGroupLayer.cxx
FGGroupLayer.hxx
FGInstrumentLayer.cxx
FGInstrumentLayer.hxx
FGLayeredInstrument.cxx
FGLayeredInstrument.hxx
FGPanel.cxx
FGPanel.hxx
FGPanelApplication.cxx
FGPanelApplication.hxx
FGPanelInstrument.cxx
FGPanelInstrument.hxx
FGPanelProtocol.cxx
FGPanelProtocol.hxx
FGPanelTransformation.cxx
FGPanelTransformation.hxx
FGPNGTextureLoader.cxx
FGPNGTextureLoader.hxx
FGRGBTextureLoader.cxx
FGRGBTextureLoader.hxx
FGSwitchLayer.cxx
FGSwitchLayer.hxx
FGTextLayer.cxx
FGTextLayer.hxx
FGTexturedLayer.cxx
FGTexturedLayer.hxx
panel_io.cxx
panel_io.hxx
GL_utils.cxx
GL_utils.hxx
${TARGET_SOURCES}
)
target_link_libraries(fgpanel
${PNG_LIBRARIES}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
-lfreetype
)
if(${BCMHOST_INCLUDE_DIR} STREQUAL "BCMHOST_INCLUDE_DIR-NOTFOUND")
find_package(GLUT REQUIRED)
if(GLUT_FOUND)
message(STATUS "found glut")
target_link_libraries(fgpanel
${GLUT_LIBRARIES}
-lGLEW ${OPENGL_LIBRARIES}
)
else(GLUT_FOUND)
message(STATUS "glut NOT found, can't build fgpanel")
endif(GLUT_FOUND)
else()
message(STATUS "found Raspberry Pi")
target_link_libraries(fgpanel
-lGLESv2 -lEGL -lm -lbcm_host -L/opt/vc/lib
)
include_directories(
${BCMHOST_INCLUDE_DIR}
${BCMHOST_INCLUDE_DIR}/interface/vcos/pthreads
${BCMHOST_INCLUDE_DIR}/interface/vmcs_host/linux
)
add_definitions(-D_GLES2 -D_RPI)
endif()
install(TARGETS fgpanel RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

View file

@ -0,0 +1,127 @@
//
// 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.
//
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include "ApplicationProperties.hxx"
#include "FGCroppedTexture.hxx"
GLuint FGCroppedTexture::s_current_bound_texture = 0;
map <string, GLuint> FGCroppedTexture::s_cache;
map <string, FGTextureLoaderInterface*> FGCroppedTexture::s_TextureLoader;
FGDummyTextureLoader FGCroppedTexture::s_DummyTextureLoader;
FGCroppedTexture::FGCroppedTexture (const string &path,
const float minX, const float minY,
const float maxX, const float maxY) :
m_path (path),
m_minX (minX), m_minY (minY),
m_maxX (maxX), m_maxY (maxY),
m_texture(0) {
}
FGCroppedTexture::~FGCroppedTexture () {
}
void
FGCroppedTexture::setPath (const string &path) {
m_path = path;
}
const string &
FGCroppedTexture::getPath () const {
return m_path;
}
void
FGCroppedTexture::setCrop (const float minX, const float minY, const float maxX, const float maxY) {
m_minX = minX; m_minY = minY; m_maxX = maxX; m_maxY = maxY;
}
void
FGCroppedTexture::registerTextureLoader (const string &extension,
FGTextureLoaderInterface * const loader) {
if (s_TextureLoader.count (extension) == 0) {
s_TextureLoader[extension] = loader;
}
}
float
FGCroppedTexture::getMinX () const {
return m_minX;
}
float
FGCroppedTexture::getMinY () const {
return m_minY;
}
float
FGCroppedTexture::getMaxX () const {
return m_maxX;
}
float
FGCroppedTexture::getMaxY () const {
return m_maxY;
}
GLuint
FGCroppedTexture::getTexture () const {
return m_texture;
}
void
FGCroppedTexture::bind (const GLint Textured_Layer_Sampler_Loc) {
if (m_texture == 0) {
SG_LOG (SG_COCKPIT,
SG_DEBUG,
"First bind of texture " << m_path);
if (s_cache.count (m_path) > 0 ) {
m_texture = s_cache[m_path];
SG_LOG (SG_COCKPIT,
SG_DEBUG,
"Using texture " << m_path << " from cache (#" << m_texture << ")");
} else {
const SGPath path (ApplicationProperties::GetRootPath (m_path.c_str ()));
const string extension (path.extension ());
FGTextureLoaderInterface *loader (&s_DummyTextureLoader);
if (s_TextureLoader.count (extension) == 0) {
SG_LOG (SG_COCKPIT,
SG_ALERT,
"Can't handle textures of type " << extension);
} else {
loader = s_TextureLoader[extension];
}
m_texture = loader->loadTexture (path.local8BitStr ());
SG_LOG (SG_COCKPIT,
SG_DEBUG,
"Texture " << path << " loaded from file as #" << m_texture);
s_cache[m_path] = m_texture;
}
}
if (s_current_bound_texture != m_texture) {
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, m_texture);
glUniform1i (Textured_Layer_Sampler_Loc, 0);
s_current_bound_texture = m_texture;
}
}

View file

@ -0,0 +1,69 @@
//
// 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.
//
#ifndef FGCROPPEDTEXTURE_HXX
#define FGCROPPEDTEXTURE_HXX
#include <map>
#include <simgear/structure/SGSharedPtr.hxx>
#include "FGDummyTextureLoader.hxx"
/**
* 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,
const float minX = 0.0, const float minY = 0.0,
const float maxX = 1.0, const float maxY = 1.0);
virtual ~FGCroppedTexture ();
virtual void setPath (const string &path);
virtual const string &getPath () const;
virtual void setCrop (const float minX, const float minY, const float maxX, const float maxY);
static void registerTextureLoader (const string &extension,
FGTextureLoaderInterface * const loader);
virtual float getMinX () const;
virtual float getMinY () const;
virtual float getMaxX () const;
virtual float getMaxY () const;
GLuint getTexture () const;
virtual void bind (const GLint Textured_Layer_Sampler_Loc);
private:
string m_path;
float m_minX, m_minY, m_maxX, m_maxY;
GLuint m_texture;
static GLuint s_current_bound_texture;
static map <string, GLuint> s_cache;
static map <string, FGTextureLoaderInterface*> s_TextureLoader;
static FGDummyTextureLoader s_DummyTextureLoader;
};
typedef SGSharedPtr <FGCroppedTexture> FGCroppedTexture_ptr;
#endif

View file

@ -0,0 +1,41 @@
//
// 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.
//
#include "FGDummyTextureLoader.hxx"
GLuint
FGDummyTextureLoader::loadTexture (const string& filename) {
GLuint texture;
glGenTextures (1, &texture);
glBindTexture (GL_TEXTURE_2D, texture);
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);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
return texture;
}

View file

@ -0,0 +1,32 @@
//
// 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.
//
#ifndef FGDUMMYTEXTURELOADER_HXX
#define FGDUMMYTEXTURELOADER_HXX
#include <string.h>
#include "FGTextureLoaderInterface.hxx"
using namespace std;
class FGDummyTextureLoader : public FGTextureLoaderInterface {
public:
virtual GLuint loadTexture (const string& filename);
};
#endif

View file

@ -3,7 +3,7 @@
// 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
@ -17,213 +17,170 @@
# include <config.h>
#endif
#include "FGGLApplication.hxx"
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include <map>
#include <algorithm>
#include <plib/fnt.h>
#include <plib/pu.h>
#include <math.h>
#include "FGGLApplication.hxx"
#include "ApplicationProperties.hxx"
#include "FGFontCache.hxx"
////////////////////////////////////////////////////////////////////////
// FGFontCache class.
////////////////////////////////////////////////////////////////////////
//extern puFont FONT_HELVETICA_14;
//extern puFont FONT_SANS_12B;
const unsigned short FGFontCache::First_Printable_Char = 32;
const unsigned short FGFontCache::Last_Printable_Char = 127;
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 },
{ 0 }
};
const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])-1];
FGFontCache::FGFontCache () :
m_Face_Map (),
m_Current_Face_Ptr (NULL),
m_Pos_Map (),
m_Current_Pos (0) {
if (FT_Init_FreeType (&m_Ft)) {
SG_LOG (SG_COCKPIT, SG_ALERT, "Could not init freetype library");
}
for (unsigned int Index = 0; Index < Texture_Size * Texture_Size; ++Index) {
m_Texture[Index] = char (0);
}
glGenTextures (1, &m_Glyph_Texture);
}
FGFontCache::fnt::~fnt()
{
if (texfont) {
delete pufont;
delete texfont;
FGFontCache::~FGFontCache () {
for (Face_Map_Type::iterator It = m_Face_Map.begin (); It != m_Face_Map.end (); ++It) {
delete (It->second);
}
m_Face_Map.clear ();
glDeleteTextures (1, &m_Glyph_Texture);
}
bool
FGFontCache::Set_Font (const string& Font_Name,
const float Size,
GLuint &Glyph_Texture) {
if (m_Face_Map.find (Font_Name) != m_Face_Map.end ()) {
m_Current_Face_Ptr = m_Face_Map[Font_Name];
} else {
FT_Face * const Face_Ptr (new FT_Face);
if (FT_New_Face (m_Ft, Font_Name.c_str (), 0, Face_Ptr)) {
SG_LOG (SG_COCKPIT, SG_ALERT, "Could not open font : " + Font_Name);
return false;
}
m_Face_Map.insert (pair <string, FT_Face *> (Font_Name, Face_Ptr));
m_Current_Face_Ptr = Face_Ptr;
}
if (m_Current_Face_Ptr != NULL) {
FT_Set_Pixel_Sizes (*m_Current_Face_Ptr, 0, Size);
} else {
return false;
}
const string Key_Str (Font_Name + "_" + Get_Size (Size));
if (m_Pos_Map.find (Key_Str) != m_Pos_Map.end ()) {
m_Current_Pos = m_Pos_Map[Key_Str];
} else {
m_Current_Pos = m_Pos_Map.size ();
for (unsigned short ASCII_Code = First_Printable_Char;
ASCII_Code < Last_Printable_Char;
++ASCII_Code) {
if (FT_Load_Char (*m_Current_Face_Ptr, char (ASCII_Code), FT_LOAD_RENDER)) {
SG_LOG (SG_COCKPIT, SG_ALERT, "Could not load character : " << char (ASCII_Code));
} else {
unsigned int Line;
unsigned int Column;
const FT_GlyphSlot Glyph ((*m_Current_Face_Ptr)->glyph);
for (unsigned int Row = 0; Row < Glyph->bitmap.rows; ++Row) {
for (unsigned int Width = 0; Width < Glyph->bitmap.width; ++Width) {
Get_Pos (ASCII_Code, Row, Width, Line, Column);
m_Texture[Line * Texture_Size + Column] =
Glyph->bitmap.buffer[Row * Glyph->bitmap.width + Width];
}
}
}
}
glBindTexture (GL_TEXTURE_2D, m_Glyph_Texture);
/* We require 1 byte alignment when uploading texture data */
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
/* Clamping to edges is important to prevent artifacts when scaling */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
/* Linear filtering usually looks best for text */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D (GL_TEXTURE_2D,
0,
GL_ALPHA,
Texture_Size,
Texture_Size,
0,
GL_ALPHA,
GL_UNSIGNED_BYTE,
m_Texture);
m_Pos_Map.insert (pair <string, unsigned int> (Key_Str, m_Current_Pos));
}
Glyph_Texture = m_Glyph_Texture;
return true;
}
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)
{
std::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;
bool
FGFontCache::Get_Char (const char Char,
int &X, int &Y,
int &Left, int &Bottom,
int &W, int &H,
double &X1, double &Y1,
double &X2, double &Y2) const {
if (m_Current_Face_Ptr != NULL) {
if (FT_Load_Char (*m_Current_Face_Ptr, Char, FT_LOAD_RENDER)) {
SG_LOG (SG_COCKPIT, SG_ALERT, "Could not load character : " + Char);
return false;
} else {
const GuiFont* guifont = std::find_if(&guifonts[0], guifontsEnd,
GuiFont::Predicate(name));
if (guifont != guifontsEnd) {
pufont = guifont->font;
}
const FT_GlyphSlot Glyph ((*m_Current_Face_Ptr)->glyph);
Left = Glyph->bitmap_left;
W = Glyph->bitmap.width;
H = Glyph->bitmap.rows;
Bottom = Glyph->bitmap_top - H;
X += (Glyph->advance.x >> 6);
Y += (Glyph->advance.y >> 6);
Get_Relative_Pos (int (Char), 0, 0, X1, Y1);
Get_Relative_Pos (int (Char), Glyph->bitmap.rows, Glyph->bitmap.width, X2, Y2);
return true;
}
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;
} else {
return false;
}
}
puFont *
FGFontCache::get(const char *name, float size, float slant)
{
return getfnt(name, size, slant)->pufont;
void
FGFontCache::Get_Pos (const unsigned short ASCII_Code,
const unsigned short Row,
const unsigned short Width,
unsigned int &Line,
unsigned int &Column) const {
const unsigned short Font_Size (32);
Line = (((((ASCII_Code - First_Printable_Char) * Font_Size) / Texture_Size) + 3 * m_Current_Pos) * Font_Size) + Row;
Column = (((ASCII_Code - First_Printable_Char) * Font_Size) % Texture_Size) + Width;
}
fntTexFont *
FGFontCache::getTexFont(const char *name, float size, float slant)
{
init();
return getfnt(name, size, slant)->texfont;
void
FGFontCache::Get_Relative_Pos (const unsigned short ASCII_Code,
const unsigned short Row,
const unsigned short Width,
double &X,
double &Y) const {
unsigned int Line;
unsigned int Column;
Get_Pos (ASCII_Code, Row, Width, Line, Column);
X = double (Column) / double (Texture_Size);
Y = double (Line) / double (Texture_Size);
}
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);
string
FGFontCache::Get_Size (const float Size) {
const int Half_Size (int (round (2.0 * Size)));
const int Int_Part (Half_Size / 2);
const int Dec_Part ((Half_Size % 2) ? 5 : 0);
stringstream Result_SS;
Result_SS << Int_Part << "." << Dec_Part;
return Result_SS.str ();
}
void FGFontCache::init()
{
if (!_initialized) {
char *envp = ::getenv("FG_FONTS");
if (envp != NULL) {
_path = SGPath::fromEnv("FG_FONTS");
} else {
_path = ApplicationProperties::GetRootPath("Fonts");
}
_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 std::string fontext("txf");
init();
std::string pdata = _path.local8BitStr();
ulDir* fontdir = ulOpenDir(pdata.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) {
std::string fdata = path.local8BitStr();
fntTexFont* f = new fntTexFont;
if (f->load((char *)fdata.c_str()))
_texFonts[std::string(dirEntry->d_name)] = f;
else
delete f;
}
}
ulCloseDir(fontdir);
return true;
}
// end of new_gui.cxx

View file

@ -1,8 +1,9 @@
//
// 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
@ -15,78 +16,65 @@
#ifndef __FGFONTCACHE_HXX
#define __FGFONTCACHE_HXX
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <string>
#include <map>
#include <ft2build.h>
#include FT_FREETYPE_H
#if defined (SG_MAC)
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#elif defined (_GLES2)
#include <GLES2/gl2.h>
#else
#include <GL/glew.h> // Must be included before <GL/gl.h>
#include <GL/gl.h>
#include <GL/glut.h>
#endif
// forward declare only!
class puFont;
class fntTexFont;
using namespace std;
/**
* 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();
// Font used by plib GUI code
puFont *pufont;
// TXF font
fntTexFont *texfont;
};
// Path to the font directory
SGPath _path;
typedef std::map<const std::string, fntTexFont*> TexFontMap;
typedef std::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();
FGFontCache ();
~FGFontCache ();
bool Set_Font (const string& Font_Name,
const float Size,
GLuint &Glyph_Texture);
bool Get_Char (const char Char,
int &X, int &Y,
int &Left, int &Bottom,
int &W, int &H,
double &X1, double &Y1, // Top (Y1) left (X1)
double &X2, double &Y2) const; // Bottom (Y2) right (X2)
private:
void Get_Pos (const unsigned short ASCII_Code,
const unsigned short Row,
const unsigned short Width,
unsigned int &Line,
unsigned int &Column) const;
void Get_Relative_Pos (const unsigned short ASCII_Code,
const unsigned short Row,
const unsigned short Width,
double &X,
double &Y) const;
static string Get_Size (const float Size);
static const unsigned short First_Printable_Char;
static const unsigned short Last_Printable_Char;
static const unsigned int Texture_Size = 1024;
FT_Library m_Ft;
typedef map <string, FT_Face *> Face_Map_Type;
Face_Map_Type m_Face_Map;
FT_Face *m_Current_Face_Ptr;
char m_Texture[Texture_Size * Texture_Size];
typedef map <string, unsigned int> Pos_Map_Type;
Pos_Map_Type m_Pos_Map;
unsigned int m_Current_Pos;
GLuint m_Glyph_Texture;
};
#endif

View file

@ -5,7 +5,7 @@
// 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
@ -20,93 +20,137 @@
# include <config.h>
#endif
#include "FGGLApplication.hxx"
#include <simgear/compiler.h>
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#if defined (SG_MAC)
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glut.h>
#endif
#include <iostream>
#include <exception>
#include <stdio.h>
FGGLApplication * FGGLApplication::application = NULL;
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#if defined (SG_MAC)
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#elif defined (_GLES2)
#include <GLES2/gl2.h>
#include "GLES_utils.hxx"
#else
#include <GL/glew.h> // Must be included before <GL/gl.h>
#include <GL/gl.h>
#include <GL/freeglut.h>
#endif
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();
#include <simgear/compiler.h>
#include "FGGLApplication.hxx"
using namespace std;
FGGLApplication *FGGLApplication::application = NULL;
FGGLApplication::FGGLApplication (const char * a_name, int argc, char **argv) :
gameMode (false),
name (a_name) {
if (application != NULL ) {
cerr << "Only one instance of FGGLApplication allowed!" << endl;
throw exception ();
}
application = this;
application = this;
glutInit( &argc, argv );
#ifdef _GLES2
GLES_utils::instance ().init ("FG Panel");
#else
glutInit (&argc, argv);
glutInitContextVersion (2, 1);
glutInitContextFlags (GLUT_CORE_PROFILE);
#endif
}
FGGLApplication::~FGGLApplication()
{
if (gameMode)
glutLeaveGameMode();
FGGLApplication::~FGGLApplication () {
#ifndef _GLES2
if (gameMode) {
glutLeaveGameMode ();
}
#endif
}
void FGGLApplication::DisplayCallback()
{
if( application ) application->Display();
void
FGGLApplication::DisplayCallback () {
if (application) {
application->Display ();
}
}
void FGGLApplication::IdleCallback()
{
if( application ) application->Idle();
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::KeyCallback (const unsigned char key, const int x, const int y) {
if (application) {
application->Key (key, x, y);
}
}
void FGGLApplication::ReshapeCallback( int width, int height )
{
if( application ) application->Reshape( width, height );
void
FGGLApplication::ReshapeCallback (const int width, const 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);
void
FGGLApplication::Run (const int glutMode,
const bool gameMode,
int width,
int height,
const int bpp) {
#ifndef _GLES2
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();
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);
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();
const GLenum GLEW_err (glewInit ());
if (GLEW_OK != GLEW_err) {
cerr << "Unable to initialize GLEW " << glewGetErrorString (GLEW_err) << endl;
exit (1);
}
if (!GLEW_VERSION_2_1) { // check that the machine supports the 2.1 API.
cerr << "GLEW version 2.1 not supported : " << glewGetString (GLEW_VERSION) << endl;
exit (1);
}
cout << "OpenGL version = " << glGetString (GL_VERSION) << endl;
#endif
Init ();
#ifdef _GLES2
GLES_utils::instance ().register_keyboard_func (FGGLApplication::KeyCallback);
GLES_utils::instance ().register_idle_func (FGGLApplication::IdleCallback);
GLES_utils::instance ().register_display_func (FGGLApplication::DisplayCallback);
GLES_utils::instance ().register_reshape_func (FGGLApplication::ReshapeCallback);
GLES_utils::instance ().main_loop ();
#else
glutKeyboardFunc (FGGLApplication::KeyCallback);
glutIdleFunc (FGGLApplication::IdleCallback);
glutDisplayFunc (FGGLApplication::DisplayCallback);
glutReshapeFunc (FGGLApplication::ReshapeCallback);
glutMainLoop ();
#endif
}

View file

@ -5,7 +5,7 @@
// 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
@ -20,28 +20,32 @@
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 );
FGGLApplication (const char *a_name, int argc, char **argv);
virtual ~FGGLApplication ();
void Run (const int glutMode,
const bool gameMode,
int widht = -1,
int height = -1,
const 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 Key (const unsigned char key, const int x, const int y) {}
virtual void Idle () {}
virtual void Display () {}
virtual void Reshape (const int width, const int height) {}
virtual void Init() {}
virtual void Init () {}
int windowId;
bool gameMode;
const char * name;
const char *name;
static FGGLApplication * application;
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 );
static void KeyCallback (const unsigned char key, const int x, const int y);
static void IdleCallback ();
static void DisplayCallback ();
static void ReshapeCallback (const int width, const int height);
};

View file

@ -0,0 +1,43 @@
//
// 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.
//
#include "FGGroupLayer.hxx"
FGGroupLayer::FGGroupLayer () {
}
FGGroupLayer::~FGGroupLayer () {
for (unsigned int i = 0; i < m_layers.size (); ++i)
delete m_layers[i];
}
void
FGGroupLayer::draw () {
if (test ()) {
transform ();
for (unsigned int i = 0; i < m_layers.size (); ++i) {
m_layers[i]->draw ();
}
}
}
void
FGGroupLayer::addLayer (FGInstrumentLayer * const layer) {
m_layers.push_back (layer);
}

View file

@ -0,0 +1,43 @@
//
// 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.
//
#ifndef FGGROUPLAYER_HXX
#define FGGROUPLAYER_HXX
#include "FGInstrumentLayer.hxx"
/**
* 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 * const layer);
protected:
vector <FGInstrumentLayer *> m_layers;
};
#endif

View file

@ -0,0 +1,100 @@
//
// 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.
//
#include <math.h>
#include <simgear/props/props.hxx>
#include "GL_utils.hxx"
#include "FGInstrumentLayer.hxx"
FGInstrumentLayer::FGInstrumentLayer (const int w, const int h) :
m_w (w), m_h (h) {
}
FGInstrumentLayer::~FGInstrumentLayer () {
for (transformation_list::iterator it = m_transformations.begin ();
it != m_transformations.end ();
++it) {
delete *it;
*it = 0;
}
}
void
FGInstrumentLayer::transform () const {
for (transformation_list::const_iterator it = m_transformations.begin ();
it != m_transformations.end ();
++it) {
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:
GL_utils::instance ().glTranslatef (val, 0.0, 0.0);
break;
case FGPanelTransformation::YSHIFT:
GL_utils::instance ().glTranslatef (0.0, val, 0.0);
break;
case FGPanelTransformation::ROTATION:
GL_utils::instance ().glRotatef (-val, 0.0, 0.0, 1.0);
break;
}
}
}
}
int
FGInstrumentLayer::getWidth () const {
return m_w;
}
int
FGInstrumentLayer::getHeight () const {
return m_h;
}
void
FGInstrumentLayer::setWidth (const int w) {
m_w = w;
}
void
FGInstrumentLayer::setHeight (const int h) {
m_h = h;
}
void
FGInstrumentLayer::addTransformation (FGPanelTransformation * const transformation) {
m_transformations.push_back (transformation);
}

View file

@ -0,0 +1,61 @@
//
// 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.
//
#ifndef FGINSTRUMENTLAYER_HXX
#define FGINSTRUMENTLAYER_HXX
#include <vector>
#include <simgear/props/condition.hxx>
#include "FGPanelTransformation.hxx"
using namespace std;
/**
* 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 (const int w = -1, const int h = -1);
virtual ~FGInstrumentLayer ();
virtual void draw () = 0;
virtual void transform () const;
virtual int getWidth () const;
virtual int getHeight () const;
virtual void setWidth (const int w);
virtual void setHeight (const int h);
// Transfer pointer ownership!!
// DEPRECATED
virtual void addTransformation (FGPanelTransformation * const transformation);
protected:
int m_w, m_h;
typedef vector <FGPanelTransformation *> transformation_list;
transformation_list m_transformations;
};
#endif

View file

@ -0,0 +1,70 @@
//
// 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.
//
#include "GL_utils.hxx"
#include "FGLayeredInstrument.hxx"
#include "FGTexturedLayer.hxx"
FGLayeredInstrument::FGLayeredInstrument (const int x, const int y, const int w, const int h) :
FGPanelInstrument (x, y, w, h) {
}
FGLayeredInstrument::~FGLayeredInstrument () {
for (layer_list::iterator it = m_layers.begin();
it != m_layers.end();
++it) {
delete *it;
*it = 0;
}
}
void
FGLayeredInstrument::draw () {
if (test ()) {
for (unsigned int i = 0; i < m_layers.size (); ++i) {
GL_utils::instance ().glPushMatrix ();
m_layers[i]->draw ();
GL_utils::instance ().glPopMatrix ();
}
}
}
int
FGLayeredInstrument::addLayer (FGInstrumentLayer * const layer) {
const int n (m_layers.size ());
if (layer->getWidth () == -1) {
layer->setWidth (getWidth ());
}
if (layer->getHeight () == -1) {
layer->setHeight (getHeight ());
}
m_layers.push_back (layer);
return n;
}
int
FGLayeredInstrument::addLayer (const FGCroppedTexture_ptr texture, const int w, const int h) {
return addLayer (new FGTexturedLayer (texture, w, h));
}
void
FGLayeredInstrument::addTransformation (FGPanelTransformation * const transformation) {
const int layer (m_layers.size () - 1);
m_layers[layer]->addTransformation (transformation);
}

View file

@ -0,0 +1,54 @@
//
// 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.
//
#ifndef FGLAYEREDINSTRUMENT_HXX
#define FGLAYEREDINSTRUMENT_HXX
#include "FGCroppedTexture.hxx"
#include "FGInstrumentLayer.hxx"
#include "FGPanelInstrument.hxx"
using namespace std;
/**
* 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 (const int x, const int y, const int w, const int h);
virtual ~FGLayeredInstrument ();
virtual void draw ();
// Transfer pointer ownership!!
virtual int addLayer (FGInstrumentLayer * const layer);
virtual int addLayer (const FGCroppedTexture_ptr texture, const int w = -1, const int h = -1);
// Transfer pointer ownership!!
virtual void addTransformation (FGPanelTransformation * const transformation);
private:
typedef vector <FGInstrumentLayer *> layer_list;
layer_list m_layers;
};
#endif

View file

@ -3,7 +3,7 @@
// 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
@ -20,134 +20,137 @@
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include "FGPNGTextureLoader.hxx"
#if defined (SG_MAC)
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#elif defined (_GLES2)
#include <GLES2/gl2.h>
#else
#include <GL/glew.h> // Must be included before <GL/gl.h>
#include <GL/gl.h>
#include <GL/glut.h>
#endif
#include <png.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include "FGPNGTextureLoader.hxx"
using namespace std;
GLuint FGPNGTextureLoader::loadTexture( const string & filename )
{
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");
FILE * const fp (fopen (filename.c_str (), "rb"));
if (!fp) {
return NOTEXTURE;
}
//read the header
fread(header, 1, 8, fp);
fread (header, 1, 8, fp);
//test if png
int is_png = !png_sig_cmp(header, 0, 8);
const int is_png (!png_sig_cmp (header, 0, 8));
if (!is_png) {
fclose(fp);
fclose (fp);
return NOTEXTURE;
}
//create png struct
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
NULL, NULL);
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);
fclose (fp);
return NOTEXTURE;
}
//create png info struct
png_infop end_info = png_create_info_struct(png_ptr);
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_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);
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);
// 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);
png_read_info (png_ptr, info_ptr);
//variables to pass to get info
// 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);
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);
png_read_update_info (png_ptr, info_ptr);
// Row size in bytes.
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
const 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];
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);
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];
// 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);
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)
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);
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);
glGenTextures (1, &texture);
glBindTexture (GL_TEXTURE_2D, texture);
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);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
delete []image_data;
delete []row_pointers;
fclose (fp);
return texture;
}

View file

@ -1,8 +1,9 @@
//
// 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
@ -19,8 +20,9 @@
class FGPNGTextureLoader : public FGTextureLoaderInterface {
public:
virtual GLuint loadTexture( const std::string & filename );
virtual GLuint loadTexture (const string &filename);
const static GLuint NOTEXTURE = 0;
};
#endif

434
utils/fgpanel/FGPanel.cxx Normal file
View file

@ -0,0 +1,434 @@
// FGPanel.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: FGPanel.cxx,v 1.1 2016/07/20 22:01:30 allaert 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 <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#if defined (SG_MAC)
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#elif defined (_GLES2)
#include <GLES2/gl2.h>
#else
#include <GL/glew.h> // Must be included before <GL/gl.h>
#include <GL/gl.h>
#include <GL/glut.h>
#endif
#include "GL_utils.hxx"
#include "FGPanel.hxx"
#include "FGTextLayer.hxx"
#include "FGTexturedLayer.hxx"
////////////////////////////////////////////////////////////////////////
// Local functions.
////////////////////////////////////////////////////////////////////////
GLuint FGPanel::Textured_Layer_Program_Object (0);
GLint FGPanel::Textured_Layer_Position_Loc (0);
GLint FGPanel::Textured_Layer_Tex_Coord_Loc (0);
GLint FGPanel::Textured_Layer_MVP_Loc (0);
GLint FGPanel::Textured_Layer_Sampler_Loc (0);
////////////////////////////////////////////////////////////////////////
// Implementation of FGPanel.
////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
FGPanel::FGPanel (const SGPropertyNode_ptr root) :
m_flipx (root->getNode ("/sim/panel/flip-x", true)),
m_bg_width (1.0), m_bg_height (1.0) {
}
/**
* Destructor.
*/
FGPanel::~FGPanel () {
for (instrument_list_type::iterator it = m_instruments.begin ();
it != m_instruments.end ();
++it) {
delete *it;
*it = 0;
}
}
/**
* Initialize the panel.
*/
void
FGPanel::init () {
// Textured Layer Shaders
const char V_Textured_Layer_Shader_Str[] =
#ifdef _GLES2
"attribute vec4 a_position; \n"
"attribute vec2 a_tex_coord; \n"
"varying vec2 v_tex_coord; \n"
#else
"#version 330 \n"
"in vec4 a_position; \n"
"in vec2 a_tex_coord; \n"
"out vec2 v_tex_coord; \n"
#endif
"uniform mat4 u_mvp_matrix; \n"
"void main () { \n"
" gl_Position = u_mvp_matrix * a_position; \n"
" v_tex_coord = a_tex_coord; \n"
"} \n";
const char F_Textured_Layer_Shader_Str[] =
#ifdef _GLES2
"precision mediump float; \n"
"varying vec2 v_tex_coord; \n"
#else
"#version 330 \n"
"in vec2 v_tex_coord; \n"
"out vec4 gl_FragColor; \n"
#endif
"uniform sampler2D u_texture; \n"
"void main () { \n"
" vec4 base_color = texture2D (u_texture, v_tex_coord); \n"
" if (base_color.a <= 0.1) { \n"
" discard; \n"
" } \n"
" gl_FragColor = base_color; \n"
"} \n";
Textured_Layer_Program_Object = GL_utils::instance ().load_program (V_Textured_Layer_Shader_Str,
F_Textured_Layer_Shader_Str);
if (Textured_Layer_Program_Object == 0) {
terminate ();
}
// Get the attribute locations
Textured_Layer_Position_Loc = glGetAttribLocation (Textured_Layer_Program_Object, "a_position");
Textured_Layer_Tex_Coord_Loc = glGetAttribLocation (Textured_Layer_Program_Object, "a_tex_coord");
// Get the uniform locations
Textured_Layer_MVP_Loc = glGetUniformLocation (Textured_Layer_Program_Object, "u_mvp_matrix");
// Get the sampler location
Textured_Layer_Sampler_Loc = glGetUniformLocation (Textured_Layer_Program_Object, "u_texture");
FGTexturedLayer::Init (Textured_Layer_Program_Object,
Textured_Layer_Position_Loc,
Textured_Layer_Tex_Coord_Loc,
Textured_Layer_MVP_Loc,
Textured_Layer_Sampler_Loc);
// Text Layer Shaders
if (!FGTextLayer::Init ()) {
terminate ();
}
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
}
/**
* Bind panel properties.
*/
void
FGPanel::bind () {
}
/**
* Unbind panel properties.
*/
void
FGPanel::unbind () {
}
void
FGPanel::update (const double dt) {
getInitDisplayList ();
// Draw the instruments.
// Syd Adams: added instrument clipping
for (instrument_list_type::const_iterator current = m_instruments.begin ();
current != m_instruments.end ();
++current) {
FGPanelInstrument *instr = *current;
GL_utils::instance ().glPushMatrix ();
GL_utils::instance ().glTranslatef (instr->getXPos (), instr->getYPos (), 0);
instr->draw();
GL_utils::instance ().glPopMatrix ();
}
#ifndef _GLES2
// restore some original state
//glPopAttrib ();
#endif
}
/**
* Add an instrument to the panel.
*/
void
FGPanel::addInstrument (FGPanelInstrument * const instrument) {
m_instruments.push_back (instrument);
}
/**
* Set the panel's background texture.
*/
void
FGPanel::setBackground (const FGCroppedTexture_ptr texture) {
m_bg = texture;
}
void
FGPanel::setBackgroundWidth (const double d) {
m_bg_width = d;
}
void
FGPanel::setBackgroundHeight (const double d) {
m_bg_height = d;
}
/**
* Set the panel's multiple background textures.
*/
void
FGPanel::setMultiBackground (const FGCroppedTexture_ptr texture, const int idx) {
m_bg = 0;
m_mbg[idx] = texture;
}
void
FGPanel::setWidth (const int width) {
m_width = width;
}
int
FGPanel::getWidth () const {
return m_width;
}
void
FGPanel::setHeight (const int height) {
m_height = height;
}
int
FGPanel::getHeight () const {
return m_height;
}
void
FGPanel::getInitDisplayList () {
glUseProgram (Textured_Layer_Program_Object);
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
GL_utils::instance ().glLoadIdentity ();
if (m_flipx->getBoolValue ()) {
GL_utils::instance ().gluOrtho2D (m_width, 0, m_height, 0);
} else {
GL_utils::instance ().gluOrtho2D (0, m_width, 0, m_height);
}
GL_utils::instance ().glTranslatef (-1.0f, -1.0f, 0.0f);
GL_utils::instance ().glScalef (2.0f / GLfloat (m_width), 2.0f / GLfloat (m_height), 1.0f);
#ifndef _GLES2
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
#endif
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
GL_utils::instance ().glLoadIdentity ();
glClear (GL_COLOR_BUFFER_BIT);
glUseProgram (Textured_Layer_Program_Object);
#ifndef _GLES2
// 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 );
#endif
// Draw the background
glEnable (GL_TEXTURE_2D);
#ifndef _GLES2
glDisable (GL_LIGHTING);
#endif
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#ifndef _GLES2
glEnable (GL_COLOR_MATERIAL);
#endif
glEnable (GL_CULL_FACE);
glCullFace (GL_BACK);
glDisable (GL_DEPTH_TEST);
if (m_bg != NULL) {
m_bg->bind (Textured_Layer_Sampler_Loc);
const GLfloat v_Vertices[] = {
0.0f, 0.0f, 0.0f, // Position 0 (bottom left corner)
0.0f, 0.0f, // TexCoord 0 (bottom left corner)
float (m_width), 0.0f, 0.0f, // Position 1 (bottom right corner)
float (m_bg_width), 0.0f, // TexCoord 1 (bottom right corner)
float (m_width), float (m_height), 0.0f, // Position 2 (top right corner)
float (m_bg_width), float (m_bg_height), // TexCoord 2 (top right corner)
0.0f, float (m_height), 0.0f, // Position 3 (top left corner)
0.0f, float (m_bg_height) }; // TexCoord 3 (top left corner)
glVertexAttribPointer (Textured_Layer_Position_Loc,
3,
GL_FLOAT,
GL_FALSE,
5 * sizeof (GLfloat),
v_Vertices);
glVertexAttribPointer (Textured_Layer_Tex_Coord_Loc,
2,
GL_FLOAT,
GL_FALSE,
5 * sizeof (GLfloat),
&v_Vertices[3]);
glEnableVertexAttribArray (Textured_Layer_Position_Loc);
glEnableVertexAttribArray (Textured_Layer_Tex_Coord_Loc);
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
GL_utils::instance ().glPushMatrix ();
GL_utils::instance ().glMultMatrixf
(*reinterpret_cast <GLfloat (*)[4][4]>
(GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_MODELVIEW)));
glUniformMatrix4fv (Textured_Layer_MVP_Loc,
1,
GL_FALSE,
GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_PROJECTION));
const GLushort indices[] = {0, 1, 2, 0, 2, 3};
glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
GL_utils::instance ().glPopMatrix ();
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
} else if (m_mbg[0] != NULL) {
for (int i = 0; i < 4; ++i) {
// top row of textures...(1,3,5,7)
m_mbg[i*2]->bind (Textured_Layer_Sampler_Loc);
const GLfloat v_Vertices_Top[] = {
float (i * m_width / 4), float (m_height / 2), 0.0f, // Position 0 (bottom left corner)
0.0f, 0.0f, // TexCoord 0 (bottom left corner)
float ((i + 1) * m_width / 4), float (m_height / 2), 0.0f, // Position 1 (bottom right corner)
1.0f, 0.0f, // TexCoord 1 (bottom right corner)
float ((i + 1) * m_width / 4), float (m_height), 0.0f, // Position 2 (top right corner)
1.0f, 1.0f, // TexCoord 2 (top right corner)
float (i * m_width / 4), float (m_height), 0.0f, // Position 3 (top left corner)
0.0f, 1.0f }; // TexCoord 3 (top left corner)
glVertexAttribPointer (Textured_Layer_Position_Loc,
3,
GL_FLOAT,
GL_FALSE,
5 * sizeof (GLfloat),
v_Vertices_Top);
glVertexAttribPointer (Textured_Layer_Tex_Coord_Loc,
2,
GL_FLOAT,
GL_FALSE,
5 * sizeof (GLfloat),
&v_Vertices_Top[3]);
glEnableVertexAttribArray (Textured_Layer_Position_Loc);
glEnableVertexAttribArray (Textured_Layer_Tex_Coord_Loc);
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
GL_utils::instance ().glPushMatrix ();
GL_utils::instance ().glMultMatrixf
(*reinterpret_cast <GLfloat (*)[4][4]>
(GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_MODELVIEW)));
glUniformMatrix4fv (Textured_Layer_MVP_Loc,
1,
GL_FALSE,
GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_PROJECTION));
const GLushort indices[] = {0, 1, 2, 0, 2, 3};
glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
GL_utils::instance ().glPopMatrix ();
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
// bottom row of textures...(2,4,6,8)
m_mbg[i*2+1]->bind (Textured_Layer_Sampler_Loc);
const GLfloat v_Vertices_Bot[] = {
float (i * m_width / 4), 0.0f, 0.0f, // Position 0 (bottom left corner)
0.0f, 0.0f, // TexCoord 0 (bottom left corner)
float ((i + 1) * m_width / 4), 0.0f, 0.0f, // Position 1 (bottom right corner)
1.0f, 0.0f, // TexCoord 1 (bottom right corner)
float ((i + 1) * m_width / 4), float (m_height / 2), 0.0f, // Position 2 (top right corner)
1.0f, 1.0f, // TexCoord 2 (top right corner)
float (i * m_width / 4), float (m_height / 2), 0.0f, // Position 3 (top left corner)
0.0f, 1.0f }; // TexCoord 3 (top left corner)
glVertexAttribPointer (Textured_Layer_Position_Loc,
3,
GL_FLOAT,
GL_FALSE,
5 * sizeof (GLfloat),
v_Vertices_Bot);
glVertexAttribPointer (Textured_Layer_Tex_Coord_Loc,
2,
GL_FLOAT,
GL_FALSE,
5 * sizeof (GLfloat),
&v_Vertices_Bot[3]);
glEnableVertexAttribArray (Textured_Layer_Position_Loc);
glEnableVertexAttribArray (Textured_Layer_Tex_Coord_Loc);
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
GL_utils::instance ().glPushMatrix ();
GL_utils::instance ().glMultMatrixf
(*reinterpret_cast <GLfloat (*)[4][4]>
(GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_MODELVIEW)));
glUniformMatrix4fv (Textured_Layer_MVP_Loc,
1,
GL_FALSE,
GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_PROJECTION));
glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
GL_utils::instance ().glPopMatrix ();
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
}
} else {
#ifndef _GLES2
glUseProgram (0);
float c[4];
glGetFloatv (GL_CURRENT_COLOR, c);
glColor4f (1.0, 0.0, 0.0, 1.0);
glBegin (GL_QUADS);
glVertex2f (0, 0);
glVertex2f (m_width, 0);
glVertex2f (m_width, m_height);
glVertex2f (0, m_height);
glEnd ();
glColor4fv (c);
glUseProgram (Textured_Layer_Program_Object);
#endif
}
}

109
utils/fgpanel/FGPanel.hxx Normal file
View file

@ -0,0 +1,109 @@
// FGPanel.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: FGPanel.hxx,v 1.1 2016/07/20 22:01:30 allaert Exp $
#ifndef FGPANEL_HXX
#define FGPANEL_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <simgear/props/propsfwd.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include "FGCroppedTexture.hxx"
#include "FGPanelInstrument.hxx"
using namespace std;
////////////////////////////////////////////////////////////////////////
// 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 (const 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 (const double dt);
// transfer pointer ownership!!!
virtual void addInstrument (FGPanelInstrument * const instrument);
// Background texture.
virtual void setBackground (const FGCroppedTexture_ptr texture);
void setBackgroundWidth (const double d);
void setBackgroundHeight (const double d);
// Background multiple textures.
virtual void setMultiBackground (const FGCroppedTexture_ptr texture , const int idx);
// Full width of panel.
virtual void setWidth (const int width);
virtual int getWidth () const;
// Full height of panel.
virtual void setHeight (const int height);
virtual int getHeight () const;
private:
typedef vector <FGPanelInstrument *> instrument_list_type;
int m_width;
int m_height;
SGPropertyNode_ptr m_flipx;
FGCroppedTexture_ptr m_bg;
double m_bg_width;
double m_bg_height;
FGCroppedTexture_ptr m_mbg[8];
// List of instruments in panel.
instrument_list_type m_instruments;
void getInitDisplayList ();
static GLuint Textured_Layer_Program_Object;
static GLint Textured_Layer_Position_Loc;
static GLint Textured_Layer_Tex_Coord_Loc;
static GLint Textured_Layer_MVP_Loc;
static GLint Textured_Layer_Sampler_Loc;
};
#endif

View file

@ -5,7 +5,7 @@
// 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
@ -29,245 +29,238 @@
# include <CoreFoundation/CoreFoundation.h>
#endif
#include "FGGLApplication.hxx"
#include "FGPanelApplication.hxx"
#include <iostream>
#if defined (SG_MAC)
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#elif defined (_GLES2)
#include <GLES2/gl2.h>
#include "GLES_utils.hxx"
#else
#include <GL/glew.h> // Must be included before <GL/gl.h>
#include <GL/gl.h>
#include <GL/glut.h>
#endif
#include "FGGLApplication.hxx"
#include "FGPanelApplication.hxx"
#include <simgear/math/SGMisc.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/ResourceManager.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() );
inline static string
ParseArgs (int argc, char **argv, const string &token) {
for (int i = 0; i < argc; i++) {
const 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 );
}
// define default location of fgdata (use the same as for fgfs)
inline static SGPath
platformDefaultRoot () {
#if defined(__CYGWIN__)
inline static SGPath platformDefaultRoot()
{
return SGPath("../data");
}
return SGPath ("../data");
#elif defined(_WIN32)
inline static SGPath platformDefaultRoot()
{
return SGPath("..\\data");
}
return SGPath ("..\\data");
#elif defined(__APPLE__)
inline static SGPath platformDefaultRoot()
{
/*
The following code looks for the base package inside the application
bundle, in the standard Contents/Resources location.
*/
CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL (CFBundleGetMainBundle ());
// look for a 'data' subdir
CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent(NULL, resourcesUrl, CFSTR("data"), true);
CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent (NULL, resourcesUrl, CFSTR ("data"), true);
// now convert down to a path, and the a c-string
CFStringRef path = CFURLCopyFileSystemPath(dataDir, kCFURLPOSIXPathStyle);
string root = CFStringGetCStringPtr(path, CFStringGetSystemEncoding());
CFStringRef path = CFURLCopyFileSystemPath (dataDir, kCFURLPOSIXPathStyle);
string root = CFStringGetCStringPtr (path, CFStringGetSystemEncoding ());
CFRelease(resourcesUrl);
CFRelease(dataDir);
CFRelease(path);
CFRelease (resourcesUrl);
CFRelease (dataDir);
CFRelease (path);
return SGPath(root);
}
return SGPath (root);
#else
inline static SGPath platformDefaultRoot()
{
return SGPath(PKGLIBDIR);
}
return SGPath (PKGLIBDIR);
#endif
}
#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 );
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);
ApplicationProperties::root = platformDefaultRoot().local8BitStr();
ApplicationProperties::root = platformDefaultRoot ().local8BitStr ();
string panelFilename;
string fgRoot;
const string panelFilename (ParseArgs (argc, argv, "--panel="));
const string fgRoot (ParseArgs (argc, argv, "--fg-root="));
for( int i = 1; i < argc; i++ ) {
panelFilename = ParseArgs( argc, argv, "--panel=" );
fgRoot = ParseArgs( argc, argv, "--fg-root=" );
}
if( fgRoot.length() > 0 )
if (fgRoot.length () > 0) {
ApplicationProperties::root = fgRoot;
}
simgear::ResourceManager::instance ()->addBasePath (ApplicationProperties::root);
simgear::ResourceManager::instance()->addBasePath(ApplicationProperties::root);
if( panelFilename.length() == 0 ) {
cerr << "Need a panel filename. Use --panel=path_to_filename" << endl;
throw exception();
if (panelFilename.length () == 0 ) {
cerr << "Need a panel filename. Use --panel=path_to_filename" << endl;
throw exception ();
}
// see if we got a valid fgdata path
SGPath BaseCheck(ApplicationProperties::root);
BaseCheck.append("version");
if (!BaseCheck.exists())
{
cerr << "Missing base package. Use --fg-root=path_to_fgdata" << endl;
throw exception();
SGPath BaseCheck (ApplicationProperties::root);
BaseCheck.append ("version");
if (!BaseCheck.exists ()) {
cerr << "Missing base package. Use --fg-root=path_to_fgdata" << endl;
throw exception ();
}
try {
SGPath tpath = ApplicationProperties::GetRootPath( panelFilename.c_str() );
readProperties( tpath, ApplicationProperties::Properties );
const SGPath tpath (ApplicationProperties::GetRootPath (panelFilename.c_str ()));
readProperties (tpath, ApplicationProperties::Properties);
}
catch( sg_io_exception & e ) {
cerr << e.getFormattedMessage() << endl;
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 );
string::size_type 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() );
for (int i = 1; i < argc; i++) {
const string arg (argv[i]);
if (arg.find ("--prop:") == 0 ) {
const string s2 (arg.substr (7));
string::size_type p (s2.find ("="));
if (p != string::npos) {
const string propertyName (s2.substr (0, p));
const 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();
const SGPropertyNode_ptr n (ApplicationProperties::Properties->getNode ("panel"));
if (n != NULL) {
panel = FGReadablePanel::read (n);
}
protocol = new FGPanelProtocol (ApplicationProperties::Properties->getNode ("communication", true));
protocol->init ();
}
FGPanelApplication::~FGPanelApplication()
{
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 ) {
void
FGPanelApplication::Run () {
#ifdef _GLES2
const int mode (0);
#else
const int mode (GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
#endif
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 ) {
} else if (w == 0) {
w = h / 0.75;
} else if( h == 0 ) {
} else if (h == 0) {
h = w * 0.75;
}
bool gameMode = ApplicationProperties::Properties->getNode( "game-mode", true )->getBoolValue();
FGGLApplication::Run( mode, gameMode, w, h );
const 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::Init () {
#ifndef _GLES2
glutSetCursor (GLUT_CURSOR_NONE);
#endif
if (panel != NULL) {
panel->init ();
}
}
void FGPanelApplication::Reshape( int width, int height )
{
void
FGPanelApplication::Reshape (const int width, const int height) {
this->width = width;
this->height = height;
glViewport(0, 0, (GLsizei) width, (GLsizei) height);
glViewport (0, 0, GLsizei (width), GLsizei (height));
}
void FGPanelApplication::Idle()
{
double d = glutGet(GLUT_ELAPSED_TIME);
double dt = Sleep();
if( dt == 0 )
void
FGPanelApplication::Idle () {
#ifndef _GLES2
const double d (glutGet (GLUT_ELAPSED_TIME));
#endif
const double dt (Sleep ());
if (dt == 0) {
return;
if( panel != NULL )
panel->update( dt );
glutSwapBuffers();
if( protocol != NULL )
protocol->update( dt );
}
if (panel != NULL) {
panel->update (dt);
}
#ifndef _GLES2
glutSwapBuffers ();
#endif
if (protocol != NULL) {
protocol->update (dt);
}
#ifndef _GLES2
static double dsum = 0.0;
static unsigned cnt = 0;
dsum += glutGet(GLUT_ELAPSED_TIME)-d;
dsum += glutGet (GLUT_ELAPSED_TIME) - d;
cnt++;
if( dsum > 1000.0 ) {
ApplicationProperties::Properties->getNode( "/sim/frame-rate", true )->setDoubleValue(cnt*1000.0/dsum );
if (dsum > 1000.0) {
ApplicationProperties::Properties->getNode ("/sim/frame-rate", true)->setDoubleValue (cnt * 1000.0 / dsum);
dsum = 0.0;
cnt = 0;
}
#endif
}
void FGPanelApplication::Key( unsigned char key, int x, int y )
{
switch( key ) {
case 0x1b:
exit(0);
break;
void
FGPanelApplication::Key (const unsigned char key, const int x, const int y) {
switch (key) {
case 0x1b:
exit(0);
break;
}
}
double FGPanelApplication::Sleep()
{
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 ) {
if (last_time_stamp.get_seconds () == 0) {
last_time_stamp.stamp ();
}
const double model_hz (60);
const 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;
double frame_us (1.0e6 / throttle_hz);
// sleep based timing loop.
//
@ -292,19 +285,19 @@ double FGPanelApplication::Sleep()
// 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 ) {
if (frame_us < 0.0) {
frame_us = 0.0;
}
current_time_stamp.stamp();
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;
const double elapsed_us ((current_time_stamp - last_time_stamp).toUSecs ());
if (elapsed_us < frame_us) {
const double requested_us (frame_us - elapsed_us);
#ifdef _WIN32
::Sleep ((int)(requested_us / 1000.0)) ;
::Sleep (int (requested_us / 1000.0));
#else
usleep ( (useconds_t)(requested_us ) ) ;
usleep (useconds_t (requested_us));
#endif
}
// busy wait timing loop.
@ -312,82 +305,27 @@ double FGPanelApplication::Sleep()
// 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();
current_time_stamp.stamp ();
const SGTimeStamp next_time_stamp (last_time_stamp + SGTimeStamp::fromSec (1e-6*frame_us));
while (current_time_stamp < next_time_stamp) {
current_time_stamp.stamp ();
}
} else {
current_time_stamp.stamp();
current_time_stamp.stamp ();
}
double real_delta_time_sec = double(current_time_stamp.toUSecs() - last_time_stamp.toUSecs()) / 1000000.0;
static double reminder = 0.0;
static long global_multi_loop = 0;
const double real_delta_time_sec ((double (current_time_stamp.toUSecs () - last_time_stamp.toUSecs ()) / 1000000.0) + reminder);
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);
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::GetCwd()
{
SGPath path(".");
char buf[512], *cwd = getcwd(buf, 511);
buf[511] = '\0';
if (cwd)
{
path = SGPath::fromLocal8Bit(cwd);
}
return path;
}
SGPath ApplicationProperties::GetRootPath( const char * sub )
{
if( sub != NULL )
{
SGPath subpath( sub );
// relative path to current working dir?
if (subpath.isRelative())
{
SGPath path = GetCwd();
path.append( sub );
if (path.exists())
return path;
}
else
if ( subpath.exists() )
{
// absolute path
return subpath;
}
}
// default: relative path to FGROOT
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;

View file

@ -5,7 +5,7 @@
// 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
@ -18,32 +18,28 @@
#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"
#include "FGGLApplication.hxx"
#include "FGPanel.hxx"
#include "FGPanelProtocol.hxx"
class FGPanelApplication : public FGGLApplication {
public:
FGPanelApplication( int argc, char ** argv );
~FGPanelApplication();
FGPanelApplication (int argc, char **argv);
~FGPanelApplication ();
void Run();
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 Key (const unsigned char key, const int x, const int y);
virtual void Idle ();
// !!! virtual void Display ();
virtual void Reshape (const int width, const int height);
virtual void Init();
virtual void Init ();
double Sleep();
double Sleep ();
SGSharedPtr<FGPanel> panel;
SGSharedPtr<FGPanelProtocol> protocol;

View file

@ -0,0 +1,65 @@
//
// 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.
//
#include "FGPanelInstrument.hxx"
FGPanelInstrument::FGPanelInstrument () {
setPosition (0, 0);
setSize (0, 0);
}
FGPanelInstrument::FGPanelInstrument (const int x, const int y, const int w, const int h) {
setPosition (x, y);
setSize (w, h);
}
FGPanelInstrument::~FGPanelInstrument () {
}
void
FGPanelInstrument::setPosition (const int x, const int y) {
m_x = x;
m_y = y;
}
void
FGPanelInstrument::setSize (const int w, const int h) {
m_w = w;
m_h = h;
}
int
FGPanelInstrument::getXPos () const {
return m_x;
}
int
FGPanelInstrument::getYPos () const {
return m_y;
}
int
FGPanelInstrument::getWidth () const {
return m_w;
}
int
FGPanelInstrument::getHeight () const {
return m_h;
}

View file

@ -0,0 +1,56 @@
//
// 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.
//
#ifndef FGPANELINSTRUMENT_HXX
#define FGPANELINSTRUMENT_HXX
#include <simgear/props/condition.hxx>
using namespace std;
/**
* 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 (const int x, const int y, const int w, const int h);
virtual ~FGPanelInstrument ();
virtual void draw () = 0;
virtual void setPosition (const int x, const int y);
virtual void setSize (const int w, const int h);
virtual int getXPos () const;
virtual int getYPos () const;
virtual int getWidth () const;
virtual int getHeight () const;
private:
int m_x, m_y, m_w, m_h;
};
#endif

View file

@ -5,7 +5,7 @@
// 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
@ -27,92 +27,92 @@
#define strtof strtod
#endif
#include "FGPanelProtocol.hxx"
#include "ApplicationProperties.hxx"
#include <simgear/io/sg_socket.hxx>
#include <simgear/misc/strutils.hxx>
using namespace std;
#include "ApplicationProperties.hxx"
#include "FGPanelProtocol.hxx"
class PropertySetter {
public:
PropertySetter( SGPropertyNode_ptr node ) : _node(node) {}
virtual void setValue( const char * value ) = 0;
virtual ~PropertySetter() {};
PropertySetter (SGPropertyNode_ptr node) : _node (node) {}
virtual void setValue (const char *value) = 0;
virtual ~PropertySetter () {};
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 );
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 ) );
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 ) );
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 ) );
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 );
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];
FGPanelProtocol::FGPanelProtocol (SGPropertyNode_ptr a_Root) :
SGSubsystem (),
root (a_Root),
io (NULL) {
const SGPropertyNode_ptr outputNode (root->getNode ("protocol/generic/output"));
if (outputNode) {
const vector<SGPropertyNode_ptr> chunks (outputNode->getChildren ("chunk"));
for (vector<SGPropertyNode_ptr>::size_type i = 0; i < chunks.size (); i++) {
const SGPropertyNode_ptr chunk (chunks[i]);
SGPropertyNode_ptr nodeNode = chunk->getNode("node", false );
if( nodeNode == NULL )
const SGPropertyNode_ptr nodeNode (chunk->getNode ("node", false));
if (nodeNode == NULL) {
continue;
}
const SGPropertyNode_ptr node (ApplicationProperties::Properties->getNode (nodeNode->getStringValue (), true));
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 ) );
string type;
const 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 ) );
propertySetterVector.push_back (new IntPropertySetter (node));
}
}
}
@ -120,60 +120,60 @@ FGPanelProtocol::FGPanelProtocol( SGPropertyNode_ptr aRoot )
FGPanelProtocol::~FGPanelProtocol()
{
for( PropertySetterVector::size_type i = 0; i < propertySetterVector.size(); i++ )
for (PropertySetterVector::size_type i = 0; i < propertySetterVector.size(); i++) {
delete propertySetterVector[i];
}
}
void FGPanelProtocol::update( double dt )
{
void
FGPanelProtocol::update (double dt) {
char buf[2][8192];
if( io == NULL )
if (io == NULL) {
return;
}
// read all available lines, keep last one
int Page = 0;
bool HaveData = false;
while ( io->readline( buf[Page], sizeof(buf[Page])-1 ) > 0 )
{
HaveData = true;
Page ^= 1;
int Page (0);
bool HaveData (false);
while (io->readline (buf[Page], sizeof (buf[Page]) - 1) > 0) {
HaveData = true;
Page ^= 1;
}
if ( HaveData ) {
if (HaveData) {
// process most recent line of data
Page ^= 1;
buf[Page][sizeof(buf[Page])-1] = 0;
vector<string> tokens = simgear::strutils::split( buf[Page], "," );
for( vector<string>::size_type i = 0; i < tokens.size(); i++ ) {
if( i < propertySetterVector.size() )
propertySetterVector[i]->setValue( tokens[i].c_str() );
buf[Page][sizeof (buf[Page]) - 1] = 0;
const vector<string> tokens (simgear::strutils::split (buf[Page], ","));
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 ) {
void
FGPanelProtocol::init () {
const SGPropertyNode_ptr listenNode (root->getNode ("listen"));
if (listenNode == NULL) {
return;
}
const string hostname (listenNode->getNode ("host", true)->getStringValue ());
const string port (listenNode->getNode ("port", true)->getStringValue ());
const string style (listenNode->getNode ("style", true)->getStringValue ());
string hostname = listenNode->getNode( "host", true )->getStringValue();
string port = listenNode->getNode( "port", true )->getStringValue();
string style = listenNode->getNode( "style", true )->getStringValue();
if( io != NULL )
if (io != NULL) {
delete io;
}
io = new SGSocket (hostname, port, style);
io = new SGSocket( hostname, port, style );
if( !io->open( SG_IO_IN ) ) {
if (!io->open (SG_IO_IN)) {
cerr << "can't open socket " << style << ":" << hostname << ":" << port << endl;
}
}
void FGPanelProtocol::reinit()
{
init();
void
FGPanelProtocol::reinit () {
init ();
}

View file

@ -5,7 +5,7 @@
// 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
@ -17,25 +17,31 @@
//
#ifndef __FGPANELPROTOCOL_HXX
#define __FGPANELPROTOCOL_HXX
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
#include <simgear/io/iochannel.hxx>
using namespace std;
class PropertySetter;
typedef std::vector<PropertySetter*> PropertySetterVector;
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 );
FGPanelProtocol (SGPropertyNode_ptr a_Root);
virtual ~FGPanelProtocol ();
virtual void init ();
virtual void reinit ();
virtual void update (double dt);
protected:
private:
SGPropertyNode_ptr root;
SGIOChannel * io;
SGIOChannel *io;
PropertySetterVector propertySetterVector;
};
#endif

View file

@ -0,0 +1,28 @@
//
// 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.
//
#include "FGPanelTransformation.hxx"
FGPanelTransformation::FGPanelTransformation () :
table (0) {
}
FGPanelTransformation::~FGPanelTransformation () {
delete table;
}

View file

@ -0,0 +1,52 @@
//
// 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.
//
#ifndef FGPANELTRANSFORMATION_HXX
#define FGPANELTRANSFORMATION_HXX
#include <simgear/math/interpolater.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
/**
* 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;
};
#endif

View file

@ -3,7 +3,7 @@
// 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
@ -25,23 +25,25 @@
#include <windows.h>
#endif
#include "FGRGBTextureLoader.hxx"
#if defined (SG_MAC)
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#elif defined (_GLES2)
#include <GLES2/gl2.h>
#else
#include <GL/glew.h> // Must be included before <GL/gl.h>
#include <GL/gl.h>
#include <GL/glut.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
typedef struct _rawImageRec
{
#include "FGRGBTextureLoader.hxx"
typedef struct _rawImageRec {
unsigned short imagic;
unsigned short type;
unsigned short dim;
@ -50,145 +52,138 @@ typedef struct _rawImageRec
unsigned long wasteBytes;
char name[80];
unsigned long colorMap;
std::istream *file;
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()
{
typedef unsigned char *BytePtr;
bool needsBytesSwapped () {
union {
int testWord;
char testByte[sizeof(int)];
}endianTest;
char testByte[sizeof (int)];
} endianTest;
endianTest.testWord = 1;
if( endianTest.testByte[0] == 1 )
if (endianTest.testByte[0] == 1) {
return true;
else
} else {
return false;
}
}
template <class T>
inline void swapBytes( T &s )
{
if( sizeof( T ) == 1 )
return;
inline void swapBytes (T &s) {
if (sizeof (T) == 1) {
return;
}
T d = s;
BytePtr sptr ((BytePtr) &s);
BytePtr dptr = &(((BytePtr) &d)[sizeof (T) - 1]);
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--);
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 );
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)
{
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));
unsigned char *ptr ((unsigned char *) array);
while (length--) {
b1 = *ptr++;
b2 = *ptr++;
*array++ = (unsigned short) ((b1 << 8) | (b2));
}
}
static void ConvertLong(GLuint *array, long length)
{
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);
unsigned char *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 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];
static rawImageRec *
RawImageOpen (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;
rawImageRec *raw = new rawImageRec;
if (raw == NULL) {
// notify(WARN)<< "Out of memory!"<< 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;
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);
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;
@ -196,259 +191,228 @@ static rawImageRec *RawImageOpen(std::istream& fin)
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);
raw->tmp = new unsigned char[raw->sizeX * 256 * raw->bpc];
if (raw->tmp == NULL ) {
// notify(FATAL)<< "Out of memory!"<< 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!"<< 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!"<< 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!"<< 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!"<< 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->type & 0xFF00) == 0x0100) {
unsigned int ybyz (raw->sizeY * raw->sizeZ);
if ((raw->rowStart = new GLuint[ybyz]) == NULL) {
// notify(FATAL)<< "Out of memory!"<< 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)));
}
if ((raw->rowSize = new GLint[ybyz]) == NULL) {
// notify(FATAL)<< "Out of memory!"<< endl;
RawImageClose (raw);
return NULL;
}
int x (ybyz * sizeof (GLuint));
raw->rleEnd = 512 + (2 * x);
fin.seekg (512, 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;
static void
RawImageGetRow (rawImageRec *raw, unsigned char *buf, const int y, const int z) {
unsigned short pixel;
int count, done = 0;
int 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]);
if ((raw->type & 0xFF00) == 0x0100) {
raw->file->seekg (long (raw->rowStart[y + z * raw->sizeY]), 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);
}
}
}
unsigned char *iPtr = raw->tmp;
unsigned char *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);
}
}
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);
if (raw->bpc != 1) {
ConvertShort (&pixel, 1);
}
int 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), 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;
static void
RawImageGetData (rawImageRec *raw, unsigned char **data) {
// // 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);
}
// osg::notify(osg::INFO)<<"raw->sizeX = "<<raw->sizeX<<endl;
// osg::notify(osg::INFO)<<"raw->sizeY = "<<raw->sizeY<<endl;
// osg::notify(osg::INFO)<<"raw->sizeZ = "<<raw->sizeZ<<endl;
// osg::notify(osg::INFO)<<"raw->bpc = "<<raw->bpc<<endl;
*data = new unsigned char [(raw->sizeX) * (raw->sizeY) * (raw->sizeZ) * (raw->bpc)];
unsigned char *ptr (*data);
for (int 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 (int 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 {
unsigned short *tempShort;
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;
}
@ -461,57 +425,53 @@ static void RawImageGetData(rawImageRec *raw, unsigned char **data )
// 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;
}
GLuint
readRGBStream (istream &fin) {
rawImageRec * const raw (RawImageOpen (fin));
int s = raw->sizeX;
int t = raw->sizeY;
// int r = 1;
if (raw == NULL) {
return 0;
}
#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;
const int s (raw->sizeX);
const int t (raw->sizeY);
// int r = 1;
unsigned int dataType = raw->bpc == 1 ? GL_UNSIGNED_BYTE :
GL_UNSIGNED_SHORT;
#if 0
int internalFormat = raw->sizeZ == 3 ? GL_RGB5 :
raw->sizeZ == 4 ? GL_RGB5_A1 : GL_RGB;
#else
// int internalFormat = raw->sizeZ;
#endif
const 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);
unsigned char *data;
RawImageGetData(raw, &data);
RawImageClose(raw);
const 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 );
glGenTextures (1, &texture);
glBindTexture (GL_TEXTURE_2D, texture);
glTexImage2D (GL_TEXTURE_2D, 0, pixelFormat, s, t, 0, pixelFormat, dataType, (GLvoid*) data);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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();
delete []data;
return texture;
}
GLuint
FGRGBTextureLoader::loadTexture (const string &filename) {
GLuint texture = NOTEXTURE;
ifstream istream (filename.c_str (), ios::in | ios::binary);
texture = readRGBStream (istream);
istream.close ();
return texture;
}

View file

@ -1,8 +1,9 @@
//
// 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
@ -19,8 +20,9 @@
class FGRGBTextureLoader : public FGTextureLoaderInterface {
public:
virtual GLuint loadTexture( const std::string & filename );
virtual GLuint loadTexture (const string &filename);
const static GLuint NOTEXTURE = 0;
};
#endif

View file

@ -0,0 +1,37 @@
//
// 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.
//
#include "FGSwitchLayer.hxx"
FGSwitchLayer::FGSwitchLayer () :
FGGroupLayer () {
}
void
FGSwitchLayer::draw () {
if (test ()) {
transform ();
for (unsigned int i = 0; i < m_layers.size (); ++i) {
if (m_layers[i]->test ()) {
m_layers[i]->draw ();
return;
}
}
}
}

View file

@ -0,0 +1,38 @@
//
// 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.
//
#ifndef FGSWITCHLAYER_HXX
#define FGSWITCHLAYER_HXX
#include "FGGroupLayer.hxx"
/**
* 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

View file

@ -0,0 +1,301 @@
//
// 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.
//
#include "ApplicationProperties.hxx"
#include "GL_utils.hxx"
#include "FGTextLayer.hxx"
SGPath FGTextLayer::The_Font_Path;
FGFontCache FGTextLayer::The_Font_Cache;
GLuint FGTextLayer::Text_Layer_Program_Object (0);
GLint FGTextLayer::Text_Layer_Position_Loc (0);
GLint FGTextLayer::Text_Layer_Tex_Coord_Loc (0);
GLint FGTextLayer::Text_Layer_MVP_Loc (0);
GLint FGTextLayer::Text_Layer_Sampler_Loc (0);
GLint FGTextLayer::Text_Layer_Color_Loc (0);
bool
FGTextLayer::Init () {
const char V_Text_Layer_Shader_Str[] =
#ifdef _GLES2
"attribute vec4 a_position; \n"
"attribute vec2 a_tex_coord; \n"
#else
"#version 330 \n"
"in vec4 a_position; \n"
"in vec2 a_tex_coord; \n"
#endif
"uniform mat4 u_mvp_matrix; \n"
"varying vec2 v_tex_coord; \n"
"void main () { \n"
" gl_Position = u_mvp_matrix * a_position; \n"
" v_tex_coord = a_tex_coord; \n"
"} \n";
const char F_Text_Layer_Shader_Str[] =
#ifdef _GLES2
"precision mediump float; \n"
#endif
"varying vec2 v_tex_coord; \n"
"uniform sampler2D u_texture; \n"
"uniform vec4 u_color; \n"
"void main () { \n"
" gl_FragColor = vec4 (1, 1, 1, \n"
" texture2D (u_texture, v_tex_coord).a) * \n"
" u_color; \n"
"} \n";
Text_Layer_Program_Object = GL_utils::instance ().load_program (V_Text_Layer_Shader_Str,
F_Text_Layer_Shader_Str);
if (Text_Layer_Program_Object == 0) {
return false;
}
// Get the attribute locations
Text_Layer_Position_Loc = glGetAttribLocation (Text_Layer_Program_Object, "a_position");
Text_Layer_Tex_Coord_Loc = glGetAttribLocation (Text_Layer_Program_Object, "a_tex_coord");
// Get the uniform locations
Text_Layer_MVP_Loc = glGetUniformLocation (Text_Layer_Program_Object, "u_mvp_matrix");
// Get the sampler location
Text_Layer_Sampler_Loc = glGetUniformLocation (Text_Layer_Program_Object, "u_texture");
// Get the color location
Text_Layer_Color_Loc = glGetUniformLocation (Text_Layer_Program_Object, "u_color");
return true;
}
FGTextLayer::FGTextLayer (const int w, const int h) :
FGInstrumentLayer (w, h),
m_pointSize (0.0),
m_font_name () {
m_then.stamp ();
m_color[0] = m_color[1] = m_color[2] = 0.0;
m_color[3] = 1.0;
}
FGTextLayer::~FGTextLayer () {
for (chunk_list::iterator It = m_chunks.begin ();
It != m_chunks.end ();
++It) {
delete *It;
}
}
void
FGTextLayer::draw () {
if (test ()) {
glUseProgram (Text_Layer_Program_Object);
glUniform4fv (Text_Layer_Color_Loc, 1, m_color);
transform ();
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
GL_utils::instance ().glPushMatrix ();
GL_utils::instance ().glMultMatrixf
(*reinterpret_cast <GLfloat (*)[4][4]>
(GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_MODELVIEW)));
glUniformMatrix4fv (Text_Layer_MVP_Loc,
1,
GL_FALSE,
GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_PROJECTION));
GLuint Glyph_Texture;
if (!The_Font_Cache.Set_Font (m_font_name, m_pointSize, Glyph_Texture)) {
SG_LOG (SG_COCKPIT, SG_ALERT, "Missing font : " << m_font_name << " " << m_pointSize);
}
m_now.stamp ();
const long diff ((m_now - m_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 ();
m_then = m_now;
}
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, Glyph_Texture);
glUniform1i (Text_Layer_Sampler_Loc, 0);
int X (0);
int Y (0);
int Previous_X (0);
int Previous_Y (0);
int Left, Bottom, W, H;
double X1, Y1, X2, Y2;
for (string::iterator It = m_value.begin (); It != m_value.end (); ++It) {
if (The_Font_Cache.Get_Char (*It,
X, Y,
Left, Bottom,
W, H,
X1, Y1,
X2, Y2)) {
const GLfloat v_Vertices[] = {
float (Previous_X + Left), float (Previous_Y + Bottom), 0.0f, // Position 0 (bottom left corner)
float (X1), float (Y2), // TexCoord 0 (bottom left corner)
float (Previous_X + Left + W), float (Previous_Y + Bottom), 0.0f, // Position 1 (bottom right corner)
float (X2), float (Y2), // TexCoord 1 (bottom right corner)
float (Previous_X + Left + W), float (Previous_Y + Bottom + H), 0.0f, // Position 2 (top right corner)
float (X2), float (Y1), // TexCoord 2 (top right corner)
float (Previous_X + Left), float (Previous_Y + Bottom + H), 0.0f, // Position 3 (top left corner)
float (X1), float (Y1) }; // TexCoord 3 (top left corner)
glVertexAttribPointer (Text_Layer_Position_Loc,
3,
GL_FLOAT,
GL_FALSE,
5 * sizeof (GLfloat),
v_Vertices);
glVertexAttribPointer (Text_Layer_Tex_Coord_Loc,
2,
GL_FLOAT,
GL_FALSE,
5 * sizeof (GLfloat),
&v_Vertices[3]);
glEnableVertexAttribArray (Text_Layer_Position_Loc);
glEnableVertexAttribArray (Text_Layer_Tex_Coord_Loc);
const GLushort indices[] = {0, 1, 2, 0, 2, 3};
glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
Previous_X = X;
Previous_Y = Y;
}
}
GL_utils::instance ().glPopMatrix ();
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
}
}
void
FGTextLayer::addChunk (FGTextLayer::Chunk * const chunk) {
m_chunks.push_back (chunk);
}
void
FGTextLayer::setColor (const float r,
const float g,
const float b) {
m_color[0] = r;
m_color[1] = g;
m_color[2] = b;
m_color[3] = 1.0;
}
void
FGTextLayer::setPointSize (const float size) {
m_pointSize = size;
}
void
FGTextLayer::setFontName (const string &name) {
if (The_Font_Path.isNull ()) {
char *Env_Path = ::getenv ("FG_FONTS");
if (Env_Path != NULL) {
The_Font_Path = SGPath::fromEnv (Env_Path);
} else {
The_Font_Path = ApplicationProperties::GetRootPath ("Fonts");
}
}
m_font_name = The_Font_Path.local8BitStr () + "/" + name + ".ttf";
}
void
FGTextLayer::recalc_value () const {
m_value = "";
for (chunk_list::const_iterator It = m_chunks.begin ();
It != m_chunks.end ();
++It) {
m_value += (*It)->getValue ();
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGTextLayer::Chunk.
////////////////////////////////////////////////////////////////////////
FGTextLayer::Chunk::Chunk (const string &text,
const string &fmt) :
m_type (FGTextLayer::TEXT),
m_text (text),
m_fmt (fmt),
m_mult (1.0),
m_offs (0.0),
m_trunc (false) {
if (m_fmt.empty ()) {
m_fmt = "%s";
}
}
FGTextLayer::Chunk::Chunk (const ChunkType type,
const SGPropertyNode *node,
const string &fmt,
const float mult,
const float offs,
const bool truncation) :
m_type (type),
m_node (node),
m_fmt (fmt),
m_mult (mult),
m_offs (offs),
m_trunc (truncation) {
if (m_fmt.empty ()) {
if (type == TEXT_VALUE) {
m_fmt = "%s";
} else {
m_fmt = "%.2f";
}
}
}
const char *
FGTextLayer::Chunk::getValue () const {
if (test ()) {
m_buf[0] = '\0';
switch (m_type) {
case TEXT:
sprintf (m_buf, m_fmt.c_str (), m_text.c_str ());
break;
case TEXT_VALUE:
sprintf (m_buf, m_fmt.c_str (), m_node->getStringValue ());
break;
case DOUBLE_VALUE:
double d (m_offs + m_node->getFloatValue() * m_mult);
if (m_trunc) {
d = (d < 0) ? -floor (-d) : floor (d);
}
sprintf (m_buf, m_fmt.c_str(), d);
break;
}
return m_buf;
} else {
return "";
}
}

View file

@ -0,0 +1,111 @@
//
// 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.
//
#ifndef FGTEXTLAYER_HXX
#define FGTEXTLAYER_HXX
#include <string>
#include <simgear/timing/timestamp.hxx>
#include "FGFontCache.hxx"
#include "FGInstrumentLayer.hxx"
using namespace std;
/**
* 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 (const ChunkType type,
const SGPropertyNode *node,
const string &fmt = "",
const float mult = 1.0,
const float offs = 0.0,
const bool truncation = false);
const char *getValue () const;
private:
ChunkType m_type;
string m_text;
SGConstPropertyNode_ptr m_node;
string m_fmt;
float m_mult;
float m_offs;
bool m_trunc;
mutable char m_buf[1024];
};
static bool Init ();
FGTextLayer (const int w = -1, const int h = -1);
virtual ~FGTextLayer ();
virtual void draw ();
// Transfer pointer!!
virtual void addChunk (Chunk * const chunk);
virtual void setColor (const float r,
const float g,
const float b);
virtual void setPointSize (const float size);
virtual void setFontName (const string &name);
private:
void recalc_value () const;
typedef vector<Chunk *> chunk_list;
chunk_list m_chunks;
float m_color[4];
float m_pointSize;
static SGPath The_Font_Path;
mutable string m_font_name;
mutable string m_value;
mutable SGTimeStamp m_then;
mutable SGTimeStamp m_now;
static FGFontCache The_Font_Cache;
static GLuint Text_Layer_Program_Object;
static GLint Text_Layer_Position_Loc;
static GLint Text_Layer_Tex_Coord_Loc;
static GLint Text_Layer_MVP_Loc;
static GLint Text_Layer_Sampler_Loc;
static GLint Text_Layer_Color_Loc;
};
#endif

View file

@ -5,7 +5,7 @@
// 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
@ -17,15 +17,25 @@
//
#ifndef __FGTEXTURELOADERINTERFACE_HXX
#define __FGTEXTURELOADERINTERFACE_HXX
#include <simgear/compiler.h>
#include <string>
#if defined (SG_MAC)
#include <OpenGL/gl.h>
#elif defined (_GLES2)
#include <GLES2/gl2.h>
#else
#include <GL/glew.h> // Must be included before <GL/gl.h>
#include <GL/gl.h>
#endif
#include <string>
#include <simgear/compiler.h>
using namespace std;
class FGTextureLoaderInterface {
public:
virtual GLuint loadTexture( const std::string & filename ) = 0;
virtual GLuint loadTexture (const string &filename) = 0;
};
#endif

View file

@ -0,0 +1,124 @@
//
// 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.
//
#include "GL_utils.hxx"
#include "FGTexturedLayer.hxx"
GLuint FGTexturedLayer::Textured_Layer_Program_Object (0);
GLint FGTexturedLayer::Textured_Layer_Position_Loc (0);
GLint FGTexturedLayer::Textured_Layer_Tex_Coord_Loc (0);
GLint FGTexturedLayer::Textured_Layer_MVP_Loc (0);
GLint FGTexturedLayer::Textured_Layer_Sampler_Loc (0);
void
FGTexturedLayer::Init (const GLuint Program_Object,
const GLint Position_Loc,
const GLint Tex_Coord_Loc,
const GLint MVP_Loc,
const GLint Sampler_Loc) {
Textured_Layer_Program_Object = Program_Object;
Textured_Layer_Position_Loc = Position_Loc;
Textured_Layer_Tex_Coord_Loc = Tex_Coord_Loc;
Textured_Layer_MVP_Loc = MVP_Loc;
Textured_Layer_Sampler_Loc = Sampler_Loc;
}
FGTexturedLayer::FGTexturedLayer (const int w, const int h) :
FGInstrumentLayer (w, h) {
}
FGTexturedLayer::FGTexturedLayer (const FGCroppedTexture_ptr texture, const int w, const int h) :
FGInstrumentLayer (w, h),
m_texture (texture),
m_emissive (false) {
}
FGTexturedLayer::~FGTexturedLayer () {
}
void
FGTexturedLayer::draw () {
if (test ()) {
transform ();
getDisplayList ();
}
}
void
FGTexturedLayer::setTexture (const FGCroppedTexture_ptr texture) {
m_texture = texture;
}
FGCroppedTexture_ptr
FGTexturedLayer::getTexture () const {
return m_texture;
}
void
FGTexturedLayer::setEmissive (const bool emissive) {
m_emissive = emissive;
}
void
FGTexturedLayer::getDisplayList () {
int w2 = m_w / 2;
int h2 = m_h / 2;
glUseProgram (Textured_Layer_Program_Object);
m_texture->bind (Textured_Layer_Sampler_Loc);
const GLfloat v_Vertices[] = {
float (-w2), float (-h2), 0.0f, // Position 0 (bottom left corner)
m_texture->getMinX (), m_texture->getMinY (), // TexCoord 0 (bottom left corner)
float ( w2), float (-h2), 0.0f, // Position 1 (bottom right corner)
m_texture->getMaxX (), m_texture->getMinY (), // TexCoord 1 (bottom right corner)
float ( w2), float ( h2), 0.0f, // Position 2 (top right corner)
m_texture->getMaxX (), m_texture->getMaxY (), // TexCoord 2 (top right corner)
float (-w2), float ( h2), 0.0f, // Position 3 (top left corner)
m_texture->getMinX (), m_texture->getMaxY () }; // TexCoord 3 (top left corner)
glVertexAttribPointer (Textured_Layer_Position_Loc,
3,
GL_FLOAT,
GL_FALSE,
5 * sizeof (GLfloat),
v_Vertices);
glVertexAttribPointer (Textured_Layer_Tex_Coord_Loc,
2,
GL_FLOAT,
GL_FALSE,
5 * sizeof (GLfloat),
&v_Vertices[3]);
glEnableVertexAttribArray (Textured_Layer_Position_Loc);
glEnableVertexAttribArray (Textured_Layer_Tex_Coord_Loc);
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
GL_utils::instance ().glPushMatrix ();
GL_utils::instance ().glMultMatrixf
(*reinterpret_cast <GLfloat (*)[4][4]>
(GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_MODELVIEW)));
glUniformMatrix4fv (Textured_Layer_MVP_Loc,
1,
GL_FALSE,
GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_PROJECTION));
const GLushort indices[] = {0, 1, 2, 0, 2, 3};
glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
GL_utils::instance ().glPopMatrix ();
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
}

View file

@ -0,0 +1,65 @@
//
// 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.
//
#ifndef FGTEXTUREDLAYER_HXX
#define FGTEXTUREDLAYER_HXX
#include "FGCroppedTexture.hxx"
#include "FGInstrumentLayer.hxx"
/**
* 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:
static void Init (const GLuint Program_Object,
const GLint Position_Loc,
const GLint Tex_Coord_Loc,
const GLint MVP_Loc,
const GLint Sampler_Loc);
FGTexturedLayer (const int w = -1, const int h = -1);
FGTexturedLayer (const FGCroppedTexture_ptr texture, const int w = -1, const int h = -1);
virtual ~FGTexturedLayer ();
virtual void draw ();
virtual void setTexture (const FGCroppedTexture_ptr texture);
FGCroppedTexture_ptr getTexture () const;
void setEmissive (const bool emissive);
private:
void getDisplayList ();
FGCroppedTexture_ptr m_texture;
bool m_emissive;
static GLuint Textured_Layer_Program_Object;
static GLint Textured_Layer_Position_Loc;
static GLint Textured_Layer_Tex_Coord_Loc;
static GLint Textured_Layer_MVP_Loc;
static GLint Textured_Layer_Sampler_Loc;
};
#endif

View file

@ -0,0 +1,385 @@
//
// 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 <assert.h>
#include <iostream>
#include <string.h>
#include <sys/time.h>
#ifdef _RPI
#include <bcm_host.h>
#else
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#endif
#include "GLES_utils.hxx"
/// esCreateWindow flag - RGB color buffer
#define GLES_UTILS_WINDOW_RGB 0
/// esCreateWindow flag - ALPHA color buffer
#define GLES_UTILS_WINDOW_ALPHA 1
/// esCreateWindow flag - depth buffer
#define GLES_UTILS_WINDOW_DEPTH 2
/// esCreateWindow flag - stencil buffer
#define GLES_UTILS_WINDOW_STENCIL 4
/// esCreateWindow flat - multi-sample buffer
#define GLES_UTILS_WINDOW_MULTISAMPLE 8
GLES_utils::GLES_utils () :
m_State (),
display_func (NULL),
idle_func (NULL),
keyboard_func (NULL),
reshape_func (NULL) {}
GLES_utils::~GLES_utils () {}
GLES_utils&
GLES_utils::instance () {
static GLES_utils* const The_Instance (new GLES_utils);
return *The_Instance;
}
void
GLES_utils::init (const string &title) {
#ifdef _RPI
bcm_host_init ();
init_dispmanx (m_State.native_window);
#else
init_display (m_State, title);
#endif
init_egl (m_State, GLES_UTILS_WINDOW_RGB);
}
void
GLES_utils::print_config_info (const int n, const EGLDisplay &display, EGLConfig &config) {
int size;
cout << "EGL Configuration " << n << " is" << endl;
eglGetConfigAttrib (display, config, EGL_RED_SIZE, &size);
cout << "EGL Red size is " << size << endl;
eglGetConfigAttrib (display, config, EGL_BLUE_SIZE, &size);
cout << "EGL Blue size is " << size << endl;
eglGetConfigAttrib (display, config, EGL_GREEN_SIZE, &size);
cout << "EGL Green size is " << size << endl;
eglGetConfigAttrib (display, config, EGL_BUFFER_SIZE, &size);
cout << "EGL Buffer size is " << size << endl;
eglGetConfigAttrib (display, config, EGL_BIND_TO_TEXTURE_RGB , &size);
if (size == EGL_TRUE) {
cout << "EGL Can be bound to RGB texture" << endl;
} else {
cout << "EGL Can't be bound to RGB texture" << endl;
}
eglGetConfigAttrib (display, config, EGL_BIND_TO_TEXTURE_RGBA , &size);
if (size == EGL_TRUE) {
cout << "EGL Can be bound to RGBA texture" << endl;
} else {
cout << "EGL Can't be bound to RGBA texture" << endl;
}
}
void
GLES_utils::init_egl (EGL_STATE_T &state, const GLuint flags) {
EGLBoolean result;
static const EGLint attribute_list[] = {
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
EGL_ALPHA_SIZE, (flags & GLES_UTILS_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE,
EGL_DEPTH_SIZE, (flags & GLES_UTILS_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE,
EGL_STENCIL_SIZE, (flags & GLES_UTILS_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE,
EGL_SAMPLE_BUFFERS, (flags & GLES_UTILS_WINDOW_MULTISAMPLE) ? 1 : 0,
EGL_NONE
};
static const EGLint context_attributes[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
#ifndef _RPI
, EGL_NONE
#endif
};
EGLConfig *configs;
// get an EGL display connection
#ifdef _RPI
state.display = eglGetDisplay (EGL_DEFAULT_DISPLAY);
#else
state.display = eglGetDisplay ((EGLNativeDisplayType) state.x_display);
#endif
assert (state.display != EGL_NO_DISPLAY);
// initialize the EGL display connection
result = eglInitialize (state.display, &(state.major_version), &(state.minor_version));
assert (result != EGL_FALSE);
result = eglGetConfigs (state.display, NULL, 0, &(state.num_configs));
assert (result != EGL_FALSE);
configs = (EGLConfig *) calloc (state.num_configs, sizeof (*configs));
result = eglGetConfigs (state.display, configs, state.num_configs, &(state.num_configs));
assert (result != EGL_FALSE);
cout << "EGL version = " << state.major_version << "." << state.minor_version << endl;
cout << "EGL has " << state.num_configs << " configs" << endl;
for (int i = 0; i < state.num_configs; ++i) {
print_config_info (i, state.display, configs[i]);
}
// get an appropriate EGL frame buffer configuration
result = eglChooseConfig (state.display, attribute_list, &(state.config), 1, &(state.num_configs));
assert (result != EGL_FALSE);
// Choose the OpenGL ES API
result = eglBindAPI (EGL_OPENGL_ES_API);
assert (result != EGL_FALSE);
#ifdef _RPI
state.surface = eglCreateWindowSurface (state.display,
state.config,
(EGLNativeWindowType) &(state.native_window),
NULL);
#else
state.surface = eglCreateWindowSurface (state.display,
state.config,
state.native_window,
NULL);
#endif
assert (state.surface != EGL_NO_SURFACE);
// create an EGL rendering context
state.context = eglCreateContext (state.display, state.config, EGL_NO_CONTEXT, context_attributes);
assert (state.context != EGL_NO_CONTEXT);
// connect the context to the surface
result = eglMakeCurrent (state.display, state.surface, state.surface, state.context);
assert (result != EGL_FALSE);
}
#ifdef _RPI
void
GLES_utils::init_dispmanx (EGL_DISPMANX_WINDOW_T &native_window) {
int32_t success = 0;
uint32_t screen_width;
uint32_t screen_height;
DISPMANX_ELEMENT_HANDLE_T dispman_element;
DISPMANX_DISPLAY_HANDLE_T dispman_display;
DISPMANX_UPDATE_HANDLE_T dispman_update;
VC_RECT_T dst_rect;
VC_RECT_T src_rect;
// create an EGL window surface
success = graphics_get_display_size (0 /* LCD */,
&screen_width,
&screen_height);
assert (success >= 0);
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = screen_width;
dst_rect.height = screen_height;
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = screen_width << 16;
src_rect.height = screen_height << 16;
dispman_display = vc_dispmanx_display_open (0 /* LCD */);
dispman_update = vc_dispmanx_update_start (0);
dispman_element = vc_dispmanx_element_add (dispman_update,
dispman_display,
0 /*layer*/,
&dst_rect,
0 /*src*/,
&src_rect,
DISPMANX_PROTECTION_NONE,
0 /*alpha*/,
0 /*clamp*/,
DISPMANX_TRANSFORM_T (0) /*transform*/);
// Build an EGL_DISPMANX_WINDOW_T from the Dispmanx window
native_window.element = dispman_element;
native_window.width = screen_width;
native_window.height = screen_height;
vc_dispmanx_update_submit_sync (dispman_update);
cout << "Got a Dispmanx window" << endl;
}
GLboolean
GLES_utils::user_interrupt () {
return GL_FALSE;
}
#else
void
GLES_utils::init_display (EGL_STATE_T &state, const string &title) {
Window root;
XSetWindowAttributes swa;
XSetWindowAttributes xattr;
Atom wm_state;
XWMHints hints;
XEvent xev;
Window win;
state.width = 1024;
state.height = 768;
/*
* X11 native display initialization
*/
state.x_display = XOpenDisplay (NULL);
assert (state.x_display != NULL);
root = DefaultRootWindow (state.x_display);
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;
win = XCreateWindow (state.x_display,
root,
0,
0,
state.width,
state.height,
0,
CopyFromParent,
InputOutput,
CopyFromParent,
CWEventMask,
&swa);
xattr.override_redirect = false;
XChangeWindowAttributes (state.x_display, win, CWOverrideRedirect, &xattr);
hints.input = true;
hints.flags = InputHint;
XSetWMHints (state.x_display, win, &hints);
// make the window visible on the screen
XMapWindow (state.x_display, win);
XStoreName (state.x_display, win, title.c_str ());
// get identifiers for the provided atom name strings
wm_state = XInternAtom (state.x_display, "_NET_WM_STATE", false);
memset (&xev, 0, sizeof (xev));
xev.type = ClientMessage;
xev.xclient.window = win;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = 1;
xev.xclient.data.l[1] = false;
XSendEvent (state.x_display, DefaultRootWindow (state.x_display), false, SubstructureNotifyMask, &xev);
state.native_window = (EGLNativeWindowType) win;
}
GLboolean
GLES_utils::user_interrupt () {
XEvent xev;
KeySym key;
GLboolean user_interrupt = GL_FALSE;
char text;
// Pump all messages from X server. Keypresses are directed to keyfunc (if defined)
while (XPending (m_State.x_display)) {
XNextEvent (m_State.x_display, &xev);
if (xev.type == KeyPress) {
if (XLookupString (&xev.xkey, &text, 1, &key, 0) == 1) {
if (keyboard_func != NULL) {
keyboard_func (text, 0, 0);
}
}
}
if (xev.type == DestroyNotify) {
user_interrupt = GL_TRUE;
}
}
return user_interrupt;
}
#endif
void
GLES_utils::register_display_func (void (*display_func) ()) {
this->display_func = display_func;
}
void
GLES_utils::register_idle_func (void (*idle_func) ()) {
this->idle_func = idle_func;
}
void
GLES_utils::register_keyboard_func (void (*keyboard_func) (unsigned char, int, int)) {
this->keyboard_func = keyboard_func;
}
void
GLES_utils::register_reshape_func (void (*reshape_func) (int, int)) {
this->reshape_func = reshape_func;
}
void
GLES_utils::main_loop () {
struct timeval t1, t2;
struct timezone tz;
float delta_time;
float total_time = 0.0f;
unsigned int frames = 0;
gettimeofday (&t1 , &tz);
while (user_interrupt () == GL_FALSE) {
gettimeofday (&t2, &tz);
delta_time = (float) (t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6);
t1 = t2;
if (reshape_func != NULL) {
#ifdef _RPI
reshape_func (m_State.native_window.width, m_State.native_window.height);
#else
reshape_func (m_State.width, m_State.height);
#endif
}
if (idle_func != NULL) {
idle_func ();
}
if (display_func != NULL) {
display_func ();
}
eglSwapBuffers (m_State.display, m_State.surface);
total_time += delta_time;
++frames;
if (total_time > 2.0f) {
cout << frames << " frames rendered in " << total_time << " seconds -> FPS = " << (frames / total_time) << endl;
total_time -= 2.0f;
frames = 0;
}
}
}

View file

@ -0,0 +1,81 @@
//
// 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 GLES_UTILS_HXX
#define GLES_UTILS_HXX
#include <boost/utility.hpp>
#include <string>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
using namespace std;
class GLES_utils : private boost::noncopyable {
public:
static GLES_utils& instance ();
void init (const string &title);
void register_display_func (void (*display_func) ());
void register_idle_func (void (*idle_func) ());
void register_keyboard_func (void (*keyboard_func) (unsigned char, int, int));
void register_reshape_func (void (*reshape_func) (int, int));
void main_loop ();
private:
explicit GLES_utils ();
virtual ~GLES_utils ();
typedef struct {
#ifdef _RPI
EGL_DISPMANX_WINDOW_T native_window;
#else
EGLNativeWindowType native_window;
Display *x_display;
GLint width;
GLint height;
#endif
EGLint major_version;
EGLint minor_version;
EGLint num_configs;
EGLDisplay display;
EGLSurface surface;
EGLContext context;
EGLConfig config;
} EGL_STATE_T;
EGL_STATE_T m_State;
void (*display_func) ();
void (*idle_func) ();
void (*keyboard_func) (unsigned char, int, int);
void (*reshape_func) (int, int);
void print_config_info (const int n, const EGLDisplay &display, EGLConfig &config);
void init_egl (EGL_STATE_T &state, const GLuint flags);
#ifdef _RPI
void init_dispmanx (EGL_DISPMANX_WINDOW_T &native_window);
#else
void init_display (EGL_STATE_T &state, const string &title);
#endif
GLboolean user_interrupt ();
};
#endif

374
utils/fgpanel/GL_utils.cxx Normal file
View file

@ -0,0 +1,374 @@
//
// 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 <iostream>
#include <math.h>
#include <string.h>
#include "GL_utils.hxx"
const float PI (3.1415926535897932384626433832795);
GL_utils::GL_utils () {
Matrix Tmp;
memset (&Tmp, 0x0, sizeof (Matrix));
int i;
for (i = GL_UTILS_MODELVIEW; i < GL_UTILS_LAST; ++i) {
m_Current_Matrix_Mode = (GLenum_Mode) i;
m_Matrix[m_Current_Matrix_Mode].push (Tmp);
glLoadIdentity ();
}
m_Current_Matrix_Mode = GL_utils::GL_UTILS_UNSET;
}
GL_utils::~GL_utils () {}
GL_utils&
GL_utils::instance () {
static GL_utils* const The_Instance (new GL_utils);
return *The_Instance;
}
//
///
/// \brief Load a shader, check for compile errors, print error messages to std error
/// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER)
/// \param shader_src Shader source string
/// \return A new shader object on success, 0 on failure
//
GLuint
GL_utils::load_shader (GLenum type, const char *shader_src) {
GLint compiled;
// Create the shader object
GLuint shader (glCreateShader (type));
if (shader == 0) {
cerr << "Error creating shader" << endl;
return 0;
}
// Load the shader source
glShaderSource (shader, 1, &shader_src, NULL);
// Compile the shader
glCompileShader (shader);
// Check the compile status
glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint info_len (0);
glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &info_len);
if (info_len > 1) {
char* info_log ((char *) malloc (sizeof (char) * info_len));
glGetShaderInfoLog (shader, info_len, NULL, info_log);
cerr << "Error compiling shader:" << endl << info_log << endl;
free (info_log);
}
glDeleteShader (shader);
return 0;
}
return shader;
}
//
///
/// \brief Load a vertex and fragment shader, create a program object, link program.
// Errors output to std error.
/// \param vertShaderSrc Vertex shader source code
/// \param fragShaderSrc Fragment shader source code
/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure
//
GLuint
GL_utils::load_program (const char *vert_shader_src, const char *frag_shader_src) {
GLint linked;
// Load the vertex/fragment shaders
GLuint vertex_shader (load_shader (GL_VERTEX_SHADER, vert_shader_src));
if (vertex_shader == 0) {
cerr << "Error loading vertex shader" << endl;
return 0;
}
GLuint fragment_shader (load_shader (GL_FRAGMENT_SHADER, frag_shader_src));
if (fragment_shader == 0) {
cerr << "Error loading fragment shader" << endl;
glDeleteShader (vertex_shader);
return 0;
}
// Create the program object
GLuint program_object (glCreateProgram ());
if (program_object == 0) {
cerr << "Error creating program" << endl;
return 0;
}
glAttachShader (program_object, vertex_shader);
glAttachShader (program_object, fragment_shader);
// Link the program
glLinkProgram (program_object);
// Check the link status
glGetProgramiv (program_object, GL_LINK_STATUS, &linked);
if (!linked) {
GLint info_len (0);
glGetProgramiv (program_object, GL_INFO_LOG_LENGTH, &info_len);
if (info_len > 1) {
char* info_log ((char *) malloc (sizeof (char) * info_len));
glGetProgramInfoLog (program_object, info_len, NULL, info_log);
cerr << "Error linking program:" << endl << info_log << endl;
free (info_log);
}
glDeleteProgram (program_object);
return 0;
}
// Free up no longer needed shader resources
glDeleteShader (vertex_shader);
glDeleteShader (fragment_shader);
return program_object;
}
void
GL_utils::glMatrixMode (const GLenum_Mode mode) {
if (mode < GL_UTILS_LAST) {
m_Current_Matrix_Mode = mode;
}
}
void
GL_utils::glLoadIdentity () {
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
memset (&(m_Matrix[m_Current_Matrix_Mode].top ()), 0x0, sizeof (Matrix));
m_Matrix[m_Current_Matrix_Mode].top ().m[0][0] = 1.0f;
m_Matrix[m_Current_Matrix_Mode].top ().m[1][1] = 1.0f;
m_Matrix[m_Current_Matrix_Mode].top ().m[2][2] = 1.0f;
m_Matrix[m_Current_Matrix_Mode].top ().m[3][3] = 1.0f;
}
}
void
GL_utils::gluOrtho2D (const GLfloat left,
const GLfloat right,
const GLfloat bottom,
const GLfloat top) {
GL_utils::glOrtho (left, right, bottom, top, -1.0f, 1.0f);
}
void
GL_utils::glOrtho (const GLfloat left,
const GLfloat right,
const GLfloat bottom,
const GLfloat top,
const GLfloat nearVal,
const GLfloat farVal) {
const GLfloat Delta_X (right - left);
const GLfloat Delta_Y (top - bottom);
const GLfloat Delta_Z (farVal - nearVal);
Matrix Ortho;
if ((Delta_X == 0.0f) || (Delta_Y == 0.0f) || (Delta_Z == 0.0f) || (m_Current_Matrix_Mode < GL_UTILS_LAST)) {
return;
}
memset (&Ortho, 0x0, sizeof (Matrix));
Ortho.m[0][0] = 2.0f / Delta_X;
Ortho.m[3][0] = -(right + left) / Delta_X;
Ortho.m[1][1] = 2.0f / Delta_Y;
Ortho.m[3][1] = -(top + bottom) / Delta_Y;
Ortho.m[2][2] = -2.0f / Delta_Z;
Ortho.m[3][2] = -(nearVal + farVal) / Delta_Z;
Ortho.m[3][3] = 1.0f;
GL_utils::glMultMatrixf (Ortho.m);
}
void
GL_utils::glTranslatef (const GLfloat x, const GLfloat y, const GLfloat z) {
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
m_Matrix[m_Current_Matrix_Mode].top ().m[3][0] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][0] * x +
m_Matrix[m_Current_Matrix_Mode].top ().m[1][0] * y +
m_Matrix[m_Current_Matrix_Mode].top ().m[2][0] * z);
m_Matrix[m_Current_Matrix_Mode].top ().m[3][1] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][1] * x +
m_Matrix[m_Current_Matrix_Mode].top ().m[1][1] * y +
m_Matrix[m_Current_Matrix_Mode].top ().m[2][1] * z);
m_Matrix[m_Current_Matrix_Mode].top ().m[3][2] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][2] * x +
m_Matrix[m_Current_Matrix_Mode].top ().m[1][2] * y +
m_Matrix[m_Current_Matrix_Mode].top ().m[2][2] * z);
m_Matrix[m_Current_Matrix_Mode].top ().m[3][3] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][3] * x +
m_Matrix[m_Current_Matrix_Mode].top ().m[1][3] * y +
m_Matrix[m_Current_Matrix_Mode].top ().m[2][3] * z);
}
}
void
GL_utils::glRotatef (const GLfloat angle, const GLfloat x, const GLfloat y, const GLfloat z) {
const GLfloat xx (x * x);
const GLfloat yy (y * y);
const GLfloat zz (z * z);
const GLfloat Mag (sqrtf (xx + yy + zz));
if ((Mag > 0.0f) && (m_Current_Matrix_Mode < GL_UTILS_LAST)) {
const GLfloat Sin_Angle (sinf (-angle * PI / 180.0f));
const GLfloat Cos_Angle (cosf (angle * PI / 180.0f));
const GLfloat xy (x * y);
const GLfloat yz (y * z);
const GLfloat zx (z * x);
const GLfloat xs (x * Sin_Angle);
const GLfloat ys (y * Sin_Angle);
const GLfloat zs (z * Sin_Angle);
const GLfloat One_Minus_Cos (1.0f - Cos_Angle);
Matrix Rot;
// x /= mag;
// y /= mag;
// z /= mag;
Rot.m[0][0] = (One_Minus_Cos * xx) + Cos_Angle;
Rot.m[0][1] = (One_Minus_Cos * xy) - zs;
Rot.m[0][2] = (One_Minus_Cos * zx) + ys;
Rot.m[0][3] = 0.0f;
Rot.m[1][0] = (One_Minus_Cos * xy) + zs;
Rot.m[1][1] = (One_Minus_Cos * yy) + Cos_Angle;
Rot.m[1][2] = (One_Minus_Cos * yz) - xs;
Rot.m[1][3] = 0.0f;
Rot.m[2][0] = (One_Minus_Cos * zx) - ys;
Rot.m[2][1] = (One_Minus_Cos * yz) + xs;
Rot.m[2][2] = (One_Minus_Cos * zz) + Cos_Angle;
Rot.m[2][3] = 0.0f;
Rot.m[3][0] = 0.0f;
Rot.m[3][1] = 0.0f;
Rot.m[3][2] = 0.0f;
Rot.m[3][3] = 1.0f;
GL_utils::glMultMatrixf (Rot.m);
}
}
void
GL_utils::glScalef (GLfloat x, GLfloat y, GLfloat z) {
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
Matrix Scale;
Scale.m[0][0] = x;
Scale.m[0][1] = 0.0f;
Scale.m[0][2] = 0.0f;
Scale.m[0][3] = 0.0f;
Scale.m[1][0] = 0.0f;
Scale.m[1][1] = y;
Scale.m[1][2] = 0.0f;
Scale.m[1][3] = 0.0f;
Scale.m[2][0] = 0.0f;
Scale.m[2][1] = 0.0f;
Scale.m[2][2] = z;
Scale.m[2][3] = 0.0f;
Scale.m[3][0] = 0.0f;
Scale.m[3][1] = 0.0f;
Scale.m[3][2] = 0.0f;
Scale.m[3][3] = 1.0f;
GL_utils::glMultMatrixf (Scale.m);
}
}
void
GL_utils::glMultMatrixf (const GLfloat m[4][4]) {
Matrix Tmp;
for (int i = 0; i < 4; ++i) {
Tmp.m[i][0] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][0] +
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][0] +
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][0] +
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][0]);
Tmp.m[i][1] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][1] +
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][1] +
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][1] +
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][1]);
Tmp.m[i][2] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][2] +
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][2] +
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][2] +
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][2]);
Tmp.m[i][3] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][3] +
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][3] +
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][3] +
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][3]);
}
memcpy (&(m_Matrix[m_Current_Matrix_Mode].top ()), &Tmp, sizeof (Matrix));
}
void
GL_utils::glPushMatrix () {
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
m_Matrix[m_Current_Matrix_Mode].push (m_Matrix[m_Current_Matrix_Mode].top ());
}
}
void
GL_utils::glPopMatrix () {
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
m_Matrix[m_Current_Matrix_Mode].pop ();
}
}
GLfloat*
GL_utils::get_top_matrix (const GL_utils::GLenum_Mode mode) {
if (mode < GL_UTILS_LAST) {
return &(m_Matrix[mode].top ().m[0][0]);
} else {
return NULL;
}
}
void
GL_utils::Debug (const GL_utils::GLenum_Mode mode) const {
if (mode < GL_UTILS_LAST) {
for (int l = 0; l < 4; ++l) {
cout << " ";
for (int c = 0; c < 4; ++c) {
cout << m_Matrix[mode].top ().m[c][l] << " ";
}
cout << endl;
}
}
}

View file

@ -0,0 +1,85 @@
//
// 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 GL_UTILS_HXX
#define GL_UTILS_HXX
#include <boost/utility.hpp>
#include <stack>
#if defined (SG_MAC)
#include <OpenGL/gl.h>
#elif defined (_GLES2)
#include <GLES2/gl2.h>
#else
#include <GL/glew.h> // Must be included before <GL/gl.h>
#include <GL/gl.h>
#endif
using namespace std;
class GL_utils : private boost::noncopyable {
public:
static GL_utils& instance ();
enum GLenum_Mode {
GL_UTILS_MODELVIEW,
GL_UTILS_PROJECTION,
GL_UTILS_TEXTURE,
GL_UTILS_COLOR,
GL_UTILS_LAST,
GL_UTILS_UNSET
};
GLuint load_program (const char *vert_shader_src, const char *frag_shader_src);
void glMatrixMode (const GL_utils::GLenum_Mode mode);
void glLoadIdentity ();
void gluOrtho2D (const GLfloat left,
const GLfloat right,
const GLfloat bottom,
const GLfloat top);
void glOrtho (const GLfloat left,
const GLfloat right,
const GLfloat bottom,
const GLfloat top,
const GLfloat nearVal,
const GLfloat farVal);
void glTranslatef (const GLfloat x, const GLfloat y, const GLfloat z);
void glRotatef (const GLfloat angle, const GLfloat x, const GLfloat y, const GLfloat z);
void glScalef (const GLfloat x, const GLfloat y, const GLfloat z);
// C' = C X M
void glMultMatrixf (const GLfloat m[4][4]);
void glPushMatrix ();
void glPopMatrix ();
GLfloat* get_top_matrix (const GL_utils::GLenum_Mode mode);
void Debug (const GL_utils::GLenum_Mode mode) const;
private:
explicit GL_utils ();
virtual ~GL_utils ();
GLuint load_shader (GLenum type, const char *shader_src);
typedef struct {
GLfloat m[4][4];
} Matrix;
stack <Matrix> m_Matrix[GL_UTILS_LAST];
GLenum_Mode m_Current_Matrix_Mode;
};
#endif

44
utils/fgpanel/README.RPi Normal file
View file

@ -0,0 +1,44 @@
This is the FGPanel for the Raspberry Pi running Raspbian.
It should work with other Linux distributions but it has not been tested.
INSTALLATION
============
1. Build SimGear as usual.
OSG, Plib, GLUT,... will be required even they are not strictly needed to run FGPanel.
2. Configure FlightGear using CMake as usual.
CMakeLists.txt is used to compile FGPanel with OpenGL 2.0.
This should make FGPanel faster on modern graphics cards.
CMakeLists.txt is used to compile FGPanel with OpenGL ES 2.0 for the Raspberry Pi.
The source code of FGPanel can easily be adapted to other embedded devices supporting OpenGL ES 2.0.
3. Build FGPanel only (don't build all components on the Raspberry Pi as this will take ages!!!):
make -- fgpanel
USAGE
=====
1. Increase the amount of GPU memory by editing the /boot/config.txt file.
Add the following line (this is for Raspberry Pi model 1B with 512 Mb of memory):
gpu_mem_512=256
2. Reboot and check the amount of GPU memory:
vcgencmd get_mem gpu
3. Stop X server. FGPanel runs in the console (Linux framebuffer).
4. Start FGPanel as usual but as ROOT or use the 'sudo' command (see README):
sudo -- utils/fgpanel/fgpanel --fg-root=/path/to/fg/data --panel=Aircraft/MyAircraft/Panels/MyPanel.xml
ROOT privileges are required to access the GPU of the Raspberry Pi.
FEATURES
========
- Use OpenGL 2.0 instead of OpenGL 1.0 (fixed pipeline) using CMakeLists.txt.
- Use OpenGL ES 2.0 to run on the Raspberry Pi using CMakeLists.txt.
- Use VideoCore 4 graphics hardware acceleration (GPU) of the Raspberry Pi.
- Run at 30 frames per second.
- Don't use PLib anymore for the font rendering.

View file

@ -5,7 +5,7 @@
// 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
@ -17,14 +17,14 @@
//
#include "FGPanelApplication.hxx"
int main( int argc, char ** argv )
{
int
main (int argc, char ** argv) {
try {
FGPanelApplication app(argc,argv);
app.Run();
FGPanelApplication app (argc,argv);
app.Run ();
return 0;
}
catch( ... ) {
catch (...) {
cerr << "Sorry, your program terminated." << endl;
}
}

View file

@ -1,971 +0,0 @@
// 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>
#if defined (SG_MAC)
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#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.local8BitStr() );
SG_LOG( SG_COCKPIT, SG_DEBUG, "Texture " << tpath << " 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()));
if (!text_renderer.getFont())
{
SG_LOG( SG_COCKPIT, SG_ALERT, "Missing font file: " << _font_name );
return;
}
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

View file

@ -1,452 +0,0 @@
// 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/propsfwd.hxx>
#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;
using namespace std;
////////////////////////////////////////////////////////////////////////
// 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

View file

@ -6,7 +6,7 @@
// 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
@ -16,17 +16,17 @@
// 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 $
// $Id: panel_io.cxx,v 1.3 2016/08/25 23:41:34 allaert Exp $
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
# include <windows.h>
#include <windows.h>
#endif
#include <string.h> // for strcmp()
#include <string.h> // for strcmp()
#include <simgear/compiler.h>
#include <simgear/structure/exception.hxx>
@ -36,9 +36,13 @@
#include <simgear/props/condition.hxx>
#include <simgear/props/props_io.hxx>
#include "panel.hxx"
#include "panel_io.hxx"
#include "ApplicationProperties.hxx"
#include "FGGroupLayer.hxx"
#include "FGLayeredInstrument.hxx"
#include "FGSwitchLayer.hxx"
#include "FGTextLayer.hxx"
#include "FGTexturedLayer.hxx"
////////////////////////////////////////////////////////////////////////
@ -56,7 +60,7 @@
//
// A layer contains zero or more transformations.
//
// Some special types of layers also contain other objects, such as
// Some special types of layers also contain other objects, such as
// chunks of text or other layers.
//
// There are currently four types of layers:
@ -96,14 +100,13 @@
* 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());
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 ());
}
/**
@ -115,17 +118,15 @@ readTexture (const SGPropertyNode * node)
////////////////////////////////////////////////////////////////////////
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) );
;
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.
*
@ -152,91 +153,90 @@ readConditions (SGConditional *component, const SGPropertyNode *node)
* appear to be applied backwards.
*/
static FGPanelTransformation *
readTransformation (const SGPropertyNode * node, float w_scale, float h_scale)
{
FGPanelTransformation * t = new FGPanelTransformation;
readTransformation (const SGPropertyNode *node, const float w_scale, const 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;
const string name (node->getName ());
string type (node->getStringValue ("type"));
const 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\"" );
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);
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);
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");
// 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" );
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);
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" );
SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
<< " in interpolation");
}
}
} else {
t->table = 0;
}
// Move the layer horizontally.
// 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.
// 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.
// 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 );
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 );
SG_LOG(SG_COCKPIT, SG_DEBUG, "Read transformation " << name);
return t;
}
@ -258,56 +258,48 @@ readTransformation (const SGPropertyNode * node, float w_scale, float h_scale)
* 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");
readTextChunk (const SGPropertyNode *node) {
FGTextLayer::Chunk *chunk;
const string name (node->getStringValue ("name"));
string type (node->getStringValue ("type"));
const 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\"");
// 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.
// 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 );
const string text (node->getStringValue ("text"));
chunk = new FGTextLayer::Chunk (text, format);
} else if (type == "text-value") {
// The value of a string property.
const SGPropertyNode *target
(ApplicationProperties::Properties->getNode (node->getStringValue ("property"), true));
chunk = new FGTextLayer::Chunk (FGTextLayer::TEXT_VALUE, target, format);
} else if (type == "number-value") {
// The value of a float property.
const string propName (node->getStringValue ("property"));
const float scale (node->getFloatValue ("scale", 1.0));
const float offset (node->getFloatValue ("offset", 0.0));
const bool truncation (node->getBoolValue ("truncate", false));
const SGPropertyNode *target (ApplicationProperties::Properties->getNode (propName.c_str (), true));
chunk = new FGTextLayer::Chunk (FGTextLayer::DOUBLE_VALUE, target,
format, scale, offset, truncation);
} else {
// Unknown type.
SG_LOG(SG_COCKPIT, SG_ALERT, "Unrecognized type " << type
<< " for text chunk " << name);
return 0;
}
readConditions(chunk, node);
readConditions (chunk, node);
return chunk;
}
/**
* Read a single layer from an instrument's property list.
*
@ -330,254 +322,251 @@ readTextChunk (const SGPropertyNode * node)
* 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\"" );
readLayer (const SGPropertyNode *node, const float w_scale, const float h_scale) {
FGInstrumentLayer *layer (NULL);
const string name (node->getStringValue ("name"));
string type (node->getStringValue ("type"));
int w (node->getIntValue ("w", -1));
int h (node->getIntValue ("h", -1));
const 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.
// A textured instrument layer.
if (type == "texture") {
FGCroppedTexture_ptr texture = readTexture(node->getNode("texture"));
layer = new FGTexturedLayer(texture, w, h);
const FGCroppedTexture_ptr texture (readTexture (node->getNode ("texture")));
layer = new FGTexturedLayer (texture, w, h);
if (emissive) {
FGTexturedLayer *tl=(FGTexturedLayer*)layer;
tl->setEmissive(true);
FGTexturedLayer *tl = (FGTexturedLayer*) layer;
tl->setEmissive (true);
}
}
// A group of sublayers.
else if (type == "group") {
layer = new FGGroupLayer();
} else if (type == "group") {
// A group of sublayers.
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));
const SGPropertyNode *child = node->getChild (i);
if (!strcmp (child->getName (), "layer")) {
((FGGroupLayer *) layer)->addLayer (readLayer (child, w_scale, h_scale));
}
}
}
} else if (type == "text") {
// A textual instrument layer.
FGTextLayer *tlayer (new FGTextLayer (w, h)); // FIXME
// Set the text color.
const float red (node->getFloatValue ("color/red", 0.0));
const float green (node->getFloatValue ("color/green", 0.0));
const float blue (node->getFloatValue ("color/blue", 0.0));
tlayer->setColor (red, green, blue);
// A textual instrument layer.
else if (type == "text") {
FGTextLayer * tlayer = new FGTextLayer(w, h); // FIXME
// Set the point size.
const float pointSize (node->getFloatValue ("point-size", 10.0) * w_scale);
tlayer->setPointSize (pointSize);
// 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 font.
const string fontName (node->getStringValue ("font", "7-Segment"));
tlayer->setFontName (fontName);
// 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");
const SGPropertyNode *chunk_group (node->getNode ("chunks"));
if (chunk_group != 0) {
int nChunks = chunk_group->nChildren();
const 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" );
}
const SGPropertyNode *node (chunk_group->getChild (i));
if (!strcmp(node->getName (), "chunk")) {
FGTextLayer::Chunk * const 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));
} else if (type == "switch") {
// A switch instrument layer.
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 );
} else {
// An unknown type.
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");
const SGPropertyNode *trans_group (node->getNode ("transformations"));
if (trans_group != 0) {
int nTransformations = trans_group->nChildren();
const 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);
const SGPropertyNode *node (trans_group->getChild (i));
if (!strcmp(node->getName (), "transformation")) {
FGPanelTransformation * const 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" );
SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
<< " in transformations");
}
}
}
readConditions(layer, node);
SG_LOG( SG_COCKPIT, SG_DEBUG, "Read layer " << name );
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
* 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);
readInstrument (const SGPropertyNode *node) {
const string name (node->getStringValue ("name"));
const int x (node->getIntValue ("x", -1));
const int y (node->getIntValue ("y", -1));
const int real_w (node->getIntValue ("w", -1));
const 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" );
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;
float w_scale (1.0);
float h_scale (1.0);
if (real_w != -1) {
w_scale = float(real_w) / float(w);
w_scale = float (real_w) / float (w);
w = real_w;
}
if (real_h != -1) {
h_scale = float(real_h) / float(h);
h_scale = float (real_h) / float (h);
h = real_h;
}
SG_LOG( SG_COCKPIT, SG_DEBUG, "Reading instrument " << name );
SG_LOG(SG_COCKPIT, SG_DEBUG, "Reading instrument " << name);
FGLayeredInstrument * instrument =
new FGLayeredInstrument(x, y, w, h);
FGLayeredInstrument * const instrument
(new FGLayeredInstrument (x, y, w, h));
//
// Get the layers for the instrument.
//
const SGPropertyNode * layer_group = node->getNode("layers");
const SGPropertyNode *layer_group (node->getNode ("layers"));
if (layer_group != 0) {
int nLayers = layer_group->nChildren();
const 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);
const SGPropertyNode *node (layer_group->getChild (i));
if (!strcmp (node->getName (), "layer")) {
FGInstrumentLayer * const 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" );
SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName ()
<< " in layers");
}
}
}
readConditions(instrument, node);
SG_LOG( SG_COCKPIT, SG_DEBUG, "Done reading instrument " << name );
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]") );
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));
FGPanel * const 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() );
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 );
const 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 );
for (int i = 0; i < 8; i++) {
SGPropertyNode * const 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
if (mbgNode != NULL) {
mbgTexture = mbgNode->getStringValue ();
}
panel->setMultiBackground( new FGCroppedTexture(mbgTexture), i );
SG_LOG( SG_COCKPIT, SG_INFO, "Set multi-background texture" << i << " to " << mbgTexture );
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");
const SGPropertyNode *instrument_group (root->getChild ("instruments"));
if (instrument_group != 0) {
int nInstruments = instrument_group->nChildren();
const 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);
const SGPropertyNode *node = instrument_group->getChild (i);
if (!strcmp (node->getName (), "instrument")) {
FGPanelInstrument * const 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, "Skipping " << node->getName()
<< " in instruments section");
}
}
}
SG_LOG( SG_COCKPIT, SG_INFO, "Done reading panel instruments" );
SG_LOG(SG_COCKPIT, SG_INFO, "Done reading panel instruments");
//
@ -587,6 +576,3 @@ FGReadablePanel::read(SGPropertyNode_ptr root)
}
// end of panel_io.cxx

View file

@ -6,7 +6,7 @@
// 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
@ -16,25 +16,24 @@
// 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 $
// $Id: panel_io.hxx,v 1.2 2016/07/20 22:01:32 allaert Exp $
#ifndef __PANEL_IO_HXX
#define __PANEL_IO_HXX
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
# include <windows.h>
#include <windows.h>
#endif
#include "panel.hxx"
#include "FGPanel.hxx"
class FGReadablePanel : public FGPanel {
public:
static SGSharedPtr<FGPanel> read(SGPropertyNode_ptr root);
static SGSharedPtr<FGPanel> read (SGPropertyNode_ptr root);
};
#endif // __PANEL_IO_HXX