first commit

This commit is contained in:
Your Name
2022-10-20 20:29:11 +08:00
commit 4d531f8044
3238 changed files with 1387862 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
//
// 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.
//
#ifdef _WIN32
# include <direct.h> // for getcwd()
#else // !_WIN32
# include <unistd.h>
#endif
#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

@@ -0,0 +1,32 @@
//
// 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.
//
#pragma once
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
class ApplicationProperties {
public:
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;
};

View File

@@ -0,0 +1,143 @@
find_package(PNG QUIET)
find_package(OpenGL QUIET)
find_package(Freetype QUIET)
find_package(GLUT QUIET)
find_package(GLEW QUIET)
if(NOT ${GLUT_FOUND})
message(WARNING "GLUT NOT found, can't build FGPanel")
set(WITH_FGPANEL 0)
return()
endif()
if(NOT ${GLEW_FOUND})
message(WARNING "GLEW NOT found, can't build FGPanel")
set(WITH_FGPANEL 0)
return()
endif()
if((NOT PNG_FOUND) OR (NOT OPENGL_FOUND) OR (NOT FREETYPE_FOUND))
message(WARNING "FGPanel enabled, but some dependencies are missing")
message(STATUS "libPNG: ${PNG_FOUND}")
message(STATUS "OpenGL: ${OPENGL_FOUND}")
message(STATUS "Freetype: ${FREETYPE_FOUND}")
return()
endif()
find_path(BCMHOST_INCLUDE_DIR
NAMES bcm_host.h
PATHS /opt/vc/include
NO_DEFAULT_PATH
)
set(TARGET_SOURCES
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
)
add_executable(fgpanel ${TARGET_SOURCES})
target_link_libraries(fgpanel
SimGearCore
${PNG_LIBRARIES}
${FREETYPE_LIBRARIES}
OpenGL::GL
${GLUT_LIBRARIES}
${GLEW_LIBRARIES}
)
target_include_directories(fgpanel PUBLIC
${FREETYPE_INCLUDE_DIRS}
${PNG_INCLUDE_DIR}
${GLEW_INCLUDE_DIRS}
)
if(MSVC)
target_compile_definitions(fgpanel PUBLIC
-DFREEGLUT_LIB_PRAGMAS=0
)
endif(MSVC)
if(BCMHOST_INCLUDE_DIR)
message(STATUS "found Raspberry Pi")
add_executable(fgpanel-egl ${TARGET_SOURCES}
GLES_utils.cxx
GLES_utils.hxx
)
target_include_directories(fgpanel-egl PUBLIC
${FREETYPE_INCLUDE_DIRS}
${PNG_INCLUDE_DIR}
${BCMHOST_INCLUDE_DIR}
${BCMHOST_INCLUDE_DIR}/interface/vcos/pthreads
${BCMHOST_INCLUDE_DIR}/interface/vmcs_host/linux
)
target_link_libraries(fgpanel-egl
SimGearCore
${PNG_LIBRARIES}
${FREETYPE_LIBRARIES}
-lbrcmGLESv2 -lbrcmEGL -lm -lbcm_host -L/opt/vc/lib
)
target_compile_definitions(fgpanel-egl PUBLIC
-D_GLES2 -D_RPI
)
target_compile_definitions(fgpanel PUBLIC
-D_RPI
)
message(STATUS "FGPanel (Raspberry Pi) : ENABLED")
install(TARGETS fgpanel-egl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
else(BCMHOST_INCLUDE_DIR)
message(STATUS "FGPanel (Raspberry Pi) : DISABLED")
endif(BCMHOST_INCLUDE_DIR)
if(WITH_FGPANEL)
message(STATUS "FGPanel : ENABLED")
install(TARGETS fgpanel RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
else(WITH_FGPANEL)
message(WARNING "FGPanel : DISABLED")
endif(WITH_FGPANEL)

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,29 @@
//
// 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.
//
#pragma once
#include <string.h>
#include "FGTextureLoaderInterface.hxx"
class FGDummyTextureLoader : public FGTextureLoaderInterface {
public:
virtual GLuint loadTexture (const std::string& filename);
};

View File

@@ -0,0 +1,186 @@
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include <math.h>
#include "FGGLApplication.hxx"
#include "ApplicationProperties.hxx"
#include "FGFontCache.hxx"
////////////////////////////////////////////////////////////////////////
// FGFontCache class.
////////////////////////////////////////////////////////////////////////
const unsigned short FGFontCache::First_Printable_Char = 32;
const unsigned short FGFontCache::Last_Printable_Char = 127;
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::~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;
}
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 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;
}
} else {
return false;
}
}
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;
}
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);
}
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 ();
}

View File

@@ -0,0 +1,77 @@
//
// 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.
//
#pragma once
#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
/**
* A class to keep all fonts available for future use.
* This also assures a font isn't resident more than once.
*/
class FGFontCache {
public:
FGFontCache ();
~FGFontCache ();
bool Set_Font (const std::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 std::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 std::map <std::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 std::map <std::string, unsigned int> Pos_Map_Type;
Pos_Map_Type m_Pos_Map;
unsigned int m_Current_Pos;
GLuint m_Glyph_Texture;
};

View File

@@ -0,0 +1,156 @@
//
// 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.
//
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <iostream>
#include <exception>
#include <stdio.h>
#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
#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;
#ifdef _GLES2
GLES_utils::instance ().init ("FG Panel");
#else
glutInit (&argc, argv);
glutInitContextVersion (2, 1);
glutInitContextFlags (GLUT_CORE_PROFILE);
#endif
}
FGGLApplication::~FGGLApplication () {
#ifndef _GLES2
if (gameMode) {
glutLeaveGameMode ();
}
#endif
}
void
FGGLApplication::DisplayCallback () {
if (application) {
application->Display ();
}
}
void
FGGLApplication::IdleCallback () {
if (application) {
application->Idle ();
}
}
void
FGGLApplication::KeyCallback (const unsigned char key, const int x, const int y) {
if (application) {
application->Key (key, x, y);
}
}
void
FGGLApplication::ReshapeCallback (const int width, const int height) {
if (application) {
application->Reshape (width, 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 ();
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);
}
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

@@ -0,0 +1,52 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGGLAPPLICATION_HXX
#define __FGGLAPPLICATION_HXX
class FGGLApplication {
public:
FGGLApplication (const char *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 (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 () {}
int windowId;
bool gameMode;
const char *name;
static FGGLApplication *application;
private:
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);
};
#endif

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,57 @@
//
// 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.
//
#pragma once
#include <vector>
#include <simgear/props/condition.hxx>
#include "FGPanelTransformation.hxx"
/**
* 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 std::vector <FGPanelTransformation *> transformation_list;
transformation_list m_transformations;
};

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,50 @@
//
// 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.
//
#pragma once
#include "FGCroppedTexture.hxx"
#include "FGInstrumentLayer.hxx"
#include "FGPanelInstrument.hxx"
/**
* 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 std::vector <FGInstrumentLayer *> layer_list;
layer_list m_layers;
};

View File

@@ -0,0 +1,156 @@
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#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>
#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) {
//header for testing if it is a png
png_byte header[8];
//open file as binary
FILE * const fp (fopen (filename.c_str (), "rb"));
if (!fp) {
return NOTEXTURE;
}
//read the header
fread (header, 1, 8, fp);
//test if png
const int is_png (!png_sig_cmp (header, 0, 8));
if (!is_png) {
fclose (fp);
return NOTEXTURE;
}
//create png struct
png_structp png_ptr (png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL));
if (!png_ptr) {
fclose (fp);
return NOTEXTURE;
}
//create png info struct
png_infop info_ptr (png_create_info_struct (png_ptr));
if (!info_ptr) {
png_destroy_read_struct (&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
fclose (fp);
return NOTEXTURE;
}
//create png info struct
png_infop end_info (png_create_info_struct (png_ptr));
if (!end_info) {
png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL);
fclose (fp);
return NOTEXTURE;
}
//png error stuff, not sure libpng man suggests this.
if (setjmp (png_jmpbuf (png_ptr))) {
png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
fclose (fp);
return NOTEXTURE;
}
// init png reading
png_init_io (png_ptr, fp);
// let libpng know you already read the first 8 bytes
png_set_sig_bytes (png_ptr, 8);
// read all the info up to the image data
png_read_info (png_ptr, info_ptr);
// variables to pass to get info
int bit_depth, color_type;
png_uint_32 twidth, theight;
// get info about png
png_get_IHDR (png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, NULL, NULL, NULL);
// Update the png info struct.
png_read_update_info (png_ptr, info_ptr);
// Row size in bytes.
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]);
if (!image_data) {
//clean up memory and close stuff
png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
fclose (fp);
return NOTEXTURE;
}
// row_pointers is for pointing to image_data for reading the png with libpng
png_bytep *row_pointers (new png_bytep[theight]);
if (!row_pointers) {
//clean up memory and close stuff
png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
delete []image_data;
fclose (fp);
return NOTEXTURE;
}
// set the individual row_pointers to point at the correct offsets of image_data
for (png_uint_32 i = 0; i < theight; ++i) {
row_pointers[theight - 1 - i] = image_data + i * rowbytes;
}
//read the png into image_data through row_pointers
png_read_image (png_ptr, row_pointers);
//Now generate the OpenGL texture object
GLuint texture;
glGenTextures (1, &texture);
glBindTexture (GL_TEXTURE_2D, texture);
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);
return texture;
}

View File

@@ -0,0 +1,28 @@
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGPNGTEXTURELOADER_HXX
#define __FGPNGTEXTURELOADER_HXX
#include "FGTextureLoaderInterface.hxx"
class FGPNGTextureLoader : public FGTextureLoaderInterface {
public:
virtual GLuint loadTexture (const string &filename);
const static GLuint NOTEXTURE = 0;
};
#endif

441
utils/fgpanel/FGPanel.cxx Normal file
View File

@@ -0,0 +1,441 @@
// 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 _RPI
"#version 100 \n"
"attribute vec4 a_position; \n"
"attribute vec2 a_tex_coord; \n"
"varying vec2 v_tex_coord; \n"
#else
"#version 130 \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 _RPI
"#version 100 \n"
"precision mediump float; \n"
"varying vec2 v_tex_coord; \n"
#else
"#version 130 \n"
"in vec2 v_tex_coord; \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 (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
}
}
// Register the subsystem.
#if 0
SGSubsystemMgr::Registrant<FGPanel> registrantFGPanel;
#endif

102
utils/fgpanel/FGPanel.hxx Normal file
View File

@@ -0,0 +1,102 @@
// 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 $
#pragma once
#ifndef __cplusplus
# error This library requires C++
#endif
#include <simgear/props/propsfwd.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include "FGCroppedTexture.hxx"
#include "FGPanelInstrument.hxx"
////////////////////////////////////////////////////////////////////////
// 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 ();
// Subsystem API.
void init() override;
void bind() override;
void unbind() override;
void update(double dt) override;
// Subsystem identification.
static const char* staticSubsystemClassId() { return "panel"; }
// 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 std::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;
};

View File

@@ -0,0 +1,332 @@
//
// 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.
//
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
# include <windows.h>
# include <direct.h>
#else
# include <unistd.h>
#endif
#ifdef __APPLE__
# include <CoreFoundation/CoreFoundation.h>
#endif
#include <iostream>
#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 "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 "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++) {
const string arg (argv[i]);
if (arg.find (token) == 0) {
return arg.substr (token.length ());
}
}
return "";
}
// define default location of fgdata (use the same as for fgfs)
inline static SGPath
platformDefaultRoot () {
#if defined(__CYGWIN__)
return SGPath ("../data");
#elif defined(_WIN32)
return SGPath ("..\\data");
#elif defined(__APPLE__)
/*
The following code looks for the base package inside the application
bundle, in the standard Contents/Resources location.
*/
CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL (CFBundleGetMainBundle ());
// look for a 'data' subdir
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 ());
CFRelease (resourcesUrl);
CFRelease (dataDir);
CFRelease (path);
return SGPath (root);
#else
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);
ApplicationProperties::root = platformDefaultRoot ().local8BitStr ();
const string panelFilename (ParseArgs (argc, argv, "--panel="));
const string fgRoot (ParseArgs (argc, argv, "--fg-root="));
if (fgRoot.length () > 0) {
ApplicationProperties::root = fgRoot;
}
simgear::ResourceManager::instance ()->addBasePath (ApplicationProperties::root);
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 ();
}
try {
const SGPath tpath (ApplicationProperties::GetRootPath (panelFilename.c_str ()));
readProperties (tpath, ApplicationProperties::Properties);
}
catch (sg_io_exception & e) {
cerr << e.getFormattedMessage () << endl;
throw;
}
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 ());
}
}
}
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 () {
}
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) {
w = h / 0.75;
} else if (h == 0) {
h = w * 0.75;
}
const bool gameMode (ApplicationProperties::Properties->getNode ( "game-mode", true)->getBoolValue ());
FGGLApplication::Run (mode, gameMode, w, h);
}
void
FGPanelApplication::Init () {
#ifndef _GLES2
glutSetCursor (GLUT_CURSOR_NONE);
#endif
if (panel != NULL) {
panel->init ();
}
}
void
FGPanelApplication::Reshape (const int width, const int height) {
this->width = width;
this->height = height;
glViewport (0, 0, GLsizei (width), GLsizei (height));
}
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);
}
#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;
cnt++;
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 (const unsigned char key, const int x, const int y) {
switch (key) {
case 0x1b:
exit(0);
break;
}
}
double
FGPanelApplication::Sleep () {
SGTimeStamp current_time_stamp;
static SGTimeStamp last_time_stamp;
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);
// sleep based timing loop.
//
// Calling sleep, even usleep() on linux is less accurate than
// we like, but it does free up the cpu for other tasks during
// the sleep so it is desirable. Because of the way sleep()
// is implemented in consumer operating systems like windows
// and linux, you almost always sleep a little longer than the
// requested amount.
//
// To combat the problem of sleeping too long, we calculate the
// desired wait time and shorten it by 2000us (2ms) to avoid
// [hopefully] over-sleep'ing. The 2ms value was arrived at
// via experimentation. We follow this up at the end with a
// simple busy-wait loop to get the final pause timing exactly
// right.
//
// Assuming we don't oversleep by more than 2000us, this
// should be a reasonable compromise between sleep based
// waiting, and busy waiting.
// sleep() will always overshoot by a bit so undersleep by
// 2000us in the hopes of never oversleeping.
frame_us -= 2000.0;
if (frame_us < 0.0) {
frame_us = 0.0;
}
current_time_stamp.stamp ();
/* Convert to ms */
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));
#else
usleep (useconds_t (requested_us));
#endif
}
// busy wait timing loop.
//
// This yields the most accurate timing. If the previous
// usleep() call is omitted this will peg the cpu
// (which is just fine if FG is the only app you care about.)
current_time_stamp.stamp ();
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 ();
}
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.
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);
}

View File

@@ -0,0 +1,51 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGPANELAPPLICATION_HXX
#define __FGPANELAPPLICATION_HXX
#include <simgear/structure/subsystem_mgr.hxx>
#include "FGGLApplication.hxx"
#include "FGPanel.hxx"
#include "FGPanelProtocol.hxx"
class FGPanelApplication : public FGGLApplication {
public:
FGPanelApplication (int argc, char **argv);
~FGPanelApplication ();
void Run ();
protected:
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 ();
double Sleep ();
SGSharedPtr<FGPanel> panel;
SGSharedPtr<FGPanelProtocol> protocol;
int width;
int height;
};
#endif

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,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.
//
#pragma once
#include <simgear/props/condition.hxx>
/**
* 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;
};

View File

@@ -0,0 +1,185 @@
//
// 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.
//
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#ifdef WIN32
#define strtof strtod
#endif
#include <simgear/io/sg_socket.hxx>
#include <simgear/misc/strutils.hxx>
#include "ApplicationProperties.hxx"
#include "FGPanelProtocol.hxx"
class PropertySetter {
public:
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 );
}
};
class IntPropertySetter : public PropertySetter {
public:
IntPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {}
virtual void setValue (const char *value) {
_node->setIntValue (atol (value));
}
};
class FloatPropertySetter : public PropertySetter {
public:
FloatPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {}
virtual void setValue (const char *value) {
_node->setFloatValue (strtof (value, NULL));
}
};
class DoublePropertySetter : public PropertySetter {
public:
DoublePropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {}
virtual void setValue (const char *value) {
_node->setDoubleValue (strtod (value, NULL));
}
};
class StringPropertySetter : public PropertySetter {
public:
StringPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {}
virtual void setValue (const char *value) {
_node->setStringValue (value);
}
};
FGPanelProtocol::FGPanelProtocol (SGPropertyNode_ptr 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]);
const SGPropertyNode_ptr nodeNode (chunk->getNode ("node", false));
if (nodeNode == NULL) {
continue;
}
const SGPropertyNode_ptr node (ApplicationProperties::Properties->getNode (nodeNode->getStringValue (), true));
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));
}
}
}
}
FGPanelProtocol::~FGPanelProtocol()
{
for (PropertySetterVector::size_type i = 0; i < propertySetterVector.size(); i++) {
delete propertySetterVector[i];
}
}
void
FGPanelProtocol::update (double dt) {
char buf[2][8192];
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;
}
if (HaveData) {
// process most recent line of data
Page ^= 1;
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 () {
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 ());
if (io != NULL) {
delete io;
}
io = new SGSocket (hostname, port, style);
if (!io->open (SG_IO_IN)) {
cerr << "can't open socket " << style << ":" << hostname << ":" << port << endl;
}
}
void
FGPanelProtocol::reinit () {
init ();
}
// Register the subsystem.
#if 0
SGSubsystemMgr::Registrant<FGPanelProtocol> registrantFGPanelProtocol;
#endif

View File

@@ -0,0 +1,46 @@
//
// 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.
//
#pragma once
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
#include <simgear/io/iochannel.hxx>
class PropertySetter;
typedef std::vector<PropertySetter*> PropertySetterVector;
class FGPanelProtocol : public SGSubsystem {
public:
FGPanelProtocol (SGPropertyNode_ptr a_Root);
virtual ~FGPanelProtocol ();
// Subsystem API.
void init() override;
void reinit() override;
void update(double dt) override;
// Subsystem identification.
static const char* staticSubsystemClassId() { return "panel-protocol"; }
private:
SGPropertyNode_ptr root;
SGIOChannel *io;
PropertySetterVector propertySetterVector;
};

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

@@ -0,0 +1,477 @@
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// From the OpenSceneGraph distribution ReaderWriterRGB.cpp
// Reader for sgi's .rgb format.
// specification can be found at http://local.wasp.uwa.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#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>
#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 <iostream>
#include <fstream>
#include "FGRGBTextureLoader.hxx"
typedef struct _rawImageRec {
unsigned short imagic;
unsigned short type;
unsigned short dim;
unsigned short sizeX, sizeY, sizeZ;
unsigned long min, max;
unsigned long wasteBytes;
char name[80];
unsigned long colorMap;
istream *file;
unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
unsigned long rleEnd;
GLuint *rowStart;
GLint *rowSize;
GLenum swapFlag;
short bpc;
typedef unsigned char *BytePtr;
bool needsBytesSwapped () {
union {
int testWord;
char testByte[sizeof (int)];
} endianTest;
endianTest.testWord = 1;
if (endianTest.testByte[0] == 1) {
return true;
} else {
return false;
}
}
template <class T>
inline void swapBytes (T &s) {
if (sizeof (T) == 1) {
return;
}
T d = s;
BytePtr sptr ((BytePtr) &s);
BytePtr dptr = &(((BytePtr) &d)[sizeof (T) - 1]);
for (unsigned int i = 0; i < sizeof (T); i++) {
*(sptr++) = *(dptr--);
}
}
void swapBytes () {
swapBytes (imagic);
swapBytes (type);
swapBytes (dim);
swapBytes (sizeX);
swapBytes (sizeY);
swapBytes (sizeZ);
swapBytes (wasteBytes);
swapBytes (min);
swapBytes (max);
swapBytes (colorMap);
}
} rawImageRec;
static void
ConvertShort (unsigned short *array, long length) {
unsigned long b1, b2;
unsigned char *ptr ((unsigned char *) array);
while (length--) {
b1 = *ptr++;
b2 = *ptr++;
*array++ = (unsigned short) ((b1 << 8) | (b2));
}
}
static void
ConvertLong (GLuint *array, long length) {
unsigned long b1, b2, b3, b4;
unsigned char *ptr ((unsigned char *) array);
while (length--) {
b1 = *ptr++;
b2 = *ptr++;
b3 = *ptr++;
b4 = *ptr++;
*array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
}
}
static void
RawImageClose (rawImageRec *raw) {
if (raw) {
if (raw->tmp) {
delete []raw->tmp;
}
if (raw->tmpR) {
delete []raw->tmpR;
}
if (raw->tmpG) {
delete []raw->tmpG;
}
if (raw->tmpB) {
delete []raw->tmpB;
}
if (raw->tmpA) {
delete []raw->tmpA;
}
if (raw->rowStart) {
delete []raw->rowStart;
}
if (raw->rowSize) {
delete []raw->rowSize;
}
delete raw;
}
}
static rawImageRec *
RawImageOpen (istream& fin) {
union {
int testWord;
char testByte[4];
} endianTest;
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;
}
fin.read ((char*) raw, 12);
if (!fin.good ()) {
return NULL;
}
if (raw->swapFlag) {
ConvertShort (&raw->imagic, 6);
}
raw->tmp = raw->tmpR = raw->tmpG = raw->tmpB = raw->tmpA = 0L;
raw->rowStart = 0;
raw->rowSize = 0;
raw->bpc = (raw->type & 0x00FF);
raw->tmp = new unsigned char[raw->sizeX * 256 * raw->bpc];
if (raw->tmp == NULL ) {
// notify(FATAL)<< "Out of memory!"<< 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->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!"<< 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, const int y, const int z) {
unsigned short pixel;
int done = 0;
unsigned short *tempShort;
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]));
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);
}
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) {
// // 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<<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;
}
}
// supportsExtension("rgb","rgb image format");
// supportsExtension("rgba","rgba image format");
// supportsExtension("sgi","sgi image format");
// supportsExtension("int","int image format");
// supportsExtension("inta","inta image format");
// supportsExtension("bw","bw image format");
GLuint
readRGBStream (istream &fin) {
rawImageRec * const raw (RawImageOpen (fin));
if (raw == NULL) {
return 0;
}
const int s (raw->sizeX);
const int t (raw->sizeY);
// int r = 1;
#if 0
int internalFormat = raw->sizeZ == 3 ? GL_RGB5 :
raw->sizeZ == 4 ? GL_RGB5_A1 : GL_RGB;
#else
// int internalFormat = raw->sizeZ;
#endif
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);
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);
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 string &filename) {
GLuint texture = NOTEXTURE;
ifstream istream (filename.c_str (), ios::in | ios::binary);
texture = readRGBStream (istream);
istream.close ();
return texture;
}

View File

@@ -0,0 +1,28 @@
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGRGBTEXTURELOADER_HXX
#define __FGRGBTEXTURELOADER_HXX
#include "FGTextureLoaderInterface.hxx"
class FGRGBTextureLoader : public FGTextureLoaderInterface {
public:
virtual GLuint loadTexture (const 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,307 @@
//
// 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 _RPI
"#version 100 \n"
"attribute vec4 a_position; \n"
"attribute vec2 a_tex_coord; \n"
"varying vec2 v_tex_coord; \n"
#else
"#version 130 \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_Text_Layer_Shader_Str[] =
#ifdef _RPI
"#version 100 \n"
"precision mediump float; \n"
"varying vec2 v_tex_coord; \n"
#else
"#version 130 \n"
"in vec2 v_tex_coord; \n"
#endif
"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,107 @@
//
// 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.
//
#pragma once
#include <string>
#include <simgear/timing/timestamp.hxx>
#include "FGFontCache.hxx"
#include "FGInstrumentLayer.hxx"
/**
* 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 std::string &text,
const std::string &fmt = "%s");
Chunk (const ChunkType type,
const SGPropertyNode *node,
const std::string &fmt = "",
const float mult = 1.0,
const float offs = 0.0,
const bool truncation = false);
const char *getValue () const;
private:
ChunkType m_type;
std::string m_text;
SGConstPropertyNode_ptr m_node;
std::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 std::string &name);
private:
void recalc_value () const;
typedef std::vector<Chunk *> chunk_list;
chunk_list m_chunks;
float m_color[4];
float m_pointSize;
static SGPath The_Font_Path;
mutable std::string m_font_name;
mutable std::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;
};

View File

@@ -0,0 +1,38 @@
//
// 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.
//
#pragma once
#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 <simgear/compiler.h>
class FGTextureLoaderInterface {
public:
virtual GLuint loadTexture (const std::string &filename) = 0;
};

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,77 @@
//
// 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.
//
#pragma once
#include <boost/utility.hpp>
#include <string>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
class GLES_utils : private boost::noncopyable {
public:
static GLES_utils& instance ();
void init (const std::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 std::string &title);
#endif
GLboolean user_interrupt ();
};

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,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.
//
#pragma once
#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
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;
std::stack <Matrix> m_Matrix[GL_UTILS_LAST];
GLenum_Mode m_Current_Matrix_Mode;
};

148
utils/fgpanel/README Normal file
View File

@@ -0,0 +1,148 @@
=====================================================================
This is fgpanel - basically the stripped down 2D-Panel code from
FlightGear. It is designed as a standalone lightweight panel
rendering engine to draw 2d panels on a lowcost computer/graphic card
without 3d acceleration at reasonablel framerates.
=====================================================================
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
=====================================================================
Usage
start fgpanel with
fgpanel --fg-root=/path/to/fg/data --panel=Aircraft/MyAircraft/Panels/MyPanel.xml
with the command args set to
--fg-root shall point to the directory where your FGDATA lives
NOTE: you don't need a full copy of FGDATA, just the panel definition files for
your aircraft, e.g.
- Aircraft/MyAircraft/Panels/*
- Aircraft/Instruments/* (if referenced)
-panel shall point to a panel-configuration file, relative to FGDATA
start flightgear with
fgfs --generic=socket,out,10,239.24.10.64,5432,udp,../Aircraft/MyAircraft/Panels/SampleProtocol
=====================================================================
Sample:
Create the sample files within your aicraft directory, preferrable under Panels
MyPanel.xml
sample-2d-panel.xml
SampleProtocol.xml
=====================================================================
Sample panel configuration file (MyPanel.xml)
<PropertyList>
<!-- true: run full-screen, false; run in window -->
<game-mode type="bool">false</game-mode>
<!-- include the panel definitions (2d-panel syntax)-->
<panel include="sample-2d-panel.xml"/>
<!-- compose your property-tree here -->
<sim>
<panel>
<flip-x type="bool">false</flip-x>
</panel>
<instrument-options>
<omit-knobs type="bool">true</omit-knobs>
</instrument-options>
</sim>
<!-- network communication settings -->
<communication>
<listen>
<!-- interface to bind to,
leave empty for all interfaces -->
<host>239.24.10.64</host> <!-- multicast address! -->
<port>5432</port> <!-- tcp port to listen to -->
<style>udp</style> <!-- udp or tcp (forget about tcp!) -->
</listen>
<!-- the generic protocol definition
same as used for fgfs --generic=foobar option
-->
<protocol include="SampleProtocol.xml"/>
</communication>
</PropertyList>
=====================================================================
Sampe 2d-panel configuration file sample-2d-panel.xml
To be included from the panel configuration file
<?xml version="1.0"?>
<PropertyList>
<name>Sample Instrument Panel</name>
<w>375</w> <!-- screen width: 375mm -->
<h>305</h> <!-- screen height: 305mm -->
<instruments>
<!-- use FlightGear's c172 attitude indicator -->
<instrument include="../../Instruments/ati-c172s.xml">
<name>Attitude Gyro</name>
<x alias="../../../params/col-2"/>
<y alias="../../../params/row-1"/>
<w>80</w>
<h>80</h>
</instrument>
</instruments>
</PropertyList>
=====================================================================
Sample protocol configuration file to drive the AI (SampleProtocol.xml)
<?xml version="1.0"?>
<PropertyList>
<generic>
<output>
<line_separator>newline</line_separator>
<var_separator>,</var_separator>
<chunk>
<type>float</type>
<format>%.2f</format>
<node>/position/altitude-agl-ft</node>
</chunk>
<chunk>
<type>float</type>
<format>%.2f</format>
<node>/instrumentation/attitude-indicator/indicated-roll-deg</node>
</chunk>
<chunk>
<type>float</type>
<format>%.2f</format>
<node>/instrumentation/attitude-indicator/indicated-pitch-deg</node>
</chunk>
<chunk>
<type>float</type>
<format>%.2f</format>
<node>/instrumentation/attitude-indicator/horizon-offset-deg</node>
</chunk>
<chunk>
<type>float</type>
<format>%.4e</format>
<node>/instrumentation/attitude-indicator/spin</node>
</chunk>
</output>
</generic>
</PropertyList>
=====================================================================

55
utils/fgpanel/README.RPi Normal file
View File

@@ -0,0 +1,55 @@
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-egl fgpanel
USAGE (fgpanel-egl)
===================
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-egl --fg-root=/path/to/fg/data --panel=Aircraft/MyAircraft/Panels/MyPanel.xml
ROOT privileges are required to access the GPU of the Raspberry Pi.
USAGE (fgpanel)
===================
1. Activate the Full KMS driver on the Raspberry Pi using the raspi-config program:
Advanced Options -> GL Driver -> Full KMS
2. Reboot. The Full KMS driver should be activated.
3. When X server is running, start FGPanel as usual (see README):
utils/fgpanel/fgpanel --fg-root=/path/to/fg/data --panel=Aircraft/MyAircraft/Panels/MyPanel.xml
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.

30
utils/fgpanel/main.cxx Normal file
View File

@@ -0,0 +1,30 @@
//
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "FGPanelApplication.hxx"
int
main (int argc, char ** argv) {
try {
FGPanelApplication app (argc,argv);
app.Run ();
return 0;
}
catch (...) {
cerr << "Sorry, your program terminated." << endl;
}
}

579
utils/fgpanel/panel_io.cxx Normal file
View File

@@ -0,0 +1,579 @@
// panel_io.cxx - I/O for 2D panel.
//
// Written by David Megginson, started January 2000.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id: panel_io.cxx,v 1.3 2016/08/25 23:41:34 allaert Exp $
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include <string.h> // for strcmp()
#include <simgear/compiler.h>
#include <simgear/structure/exception.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/props/props_io.hxx>
#include "panel_io.hxx"
#include "ApplicationProperties.hxx"
#include "FGGroupLayer.hxx"
#include "FGLayeredInstrument.hxx"
#include "FGSwitchLayer.hxx"
#include "FGTextLayer.hxx"
#include "FGTexturedLayer.hxx"
////////////////////////////////////////////////////////////////////////
// Read and construct a panel.
//
// The panel is specified as a regular property list, and each of the
// instruments is its own, separate property list (and thus, a separate
// XML document). The functions in this section read in the files
// as property lists, then extract properties to set up the panel
// itself.
//
// A panel contains zero or more instruments.
//
// An instrument contains one or more layers and zero or more actions.
//
// A layer contains zero or more transformations.
//
// Some special types of layers also contain other objects, such as
// chunks of text or other layers.
//
// There are currently four types of layers:
//
// 1. Textured Layer (type="texture"), the default
// 2. Text Layer (type="text")
// 3. Switch Layer (type="switch")
// 4. Built-in Layer (type="built-in", must also specify class)
//
// The only built-in layer so far is the ribbon for the magnetic compass
// (class="compass-ribbon").
//
// There are three types of actions:
//
// 1. Adjust (type="adjust"), the default
// 2. Swap (type="swap")
// 3. Toggle (type="toggle")
//
// There are three types of transformations:
//
// 1. X shift (type="x-shift"), the default
// 2. Y shift (type="y-shift")
// 3. Rotation (type="rotation")
//
// Each of these may be associated with a property, so that a needle
// will rotate with the airspeed, for example, or may have a fixed
// floating-point value.
////////////////////////////////////////////////////////////////////////
/**
* Read a cropped texture from the instrument's property list.
*
* The x1 and y1 properties give the starting position of the texture
* (between 0.0 and 1.0), and the the x2 and y2 properties give the
* ending position. For example, to use the bottom-left quarter of a
* texture, x1=0.0, y1=0.0, x2=0.5, y2=0.5.
*/
static FGCroppedTexture_ptr
readTexture (const SGPropertyNode *node) {
SG_LOG(SG_COCKPIT, SG_DEBUG, "Read texture " << node->getName ());
return new FGCroppedTexture (node->getStringValue ("path"),
node->getFloatValue ("x1"),
node->getFloatValue ("y1"),
node->getFloatValue ("x2", 1.0),
node->getFloatValue ("y2", 1.0));
}
/**
* Test for a condition in the current node.
*/
////////////////////////////////////////////////////////////////////////
// Read a condition and use it if necessary.
////////////////////////////////////////////////////////////////////////
static void
readConditions (SGConditional *component, const SGPropertyNode *node) {
const SGPropertyNode * conditionNode (node->getChild ("condition"));
if (conditionNode != 0) {
// The top level is implicitly AND
component->setCondition (sgReadCondition (ApplicationProperties::Properties,
conditionNode));
}
}
/**
* Read a transformation from the instrument's property list.
*
* The panel module uses the transformations to slide or spin needles,
* knobs, and other indicators, and to place layers in the correct
* positions. Every layer starts centered exactly on the x,y co-ordinate,
* and many layers need to be moved or rotated simply to display the
* instrument correctly.
*
* There are three types of transformations:
*
* "x-shift" - move the layer horizontally.
*
* "y-shift" - move the layer vertically.
*
* "rotation" - rotate the layer.
*
* Each transformation may have a fixed offset, and may also have
* a floating-point property value to add to the offset. The
* floating-point property may be clamped to a minimum and/or
* maximum range and scaled (after clamping).
*
* Note that because of the way OpenGL works, transformations will
* appear to be applied backwards.
*/
static FGPanelTransformation *
readTransformation (const SGPropertyNode *node, const float w_scale, const float h_scale) {
FGPanelTransformation *t (new FGPanelTransformation);
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\"");
type = "rotation";
}
if (!propName.empty ()) {
target = ApplicationProperties::Properties->getNode (propName.c_str (), true);
}
t->node = target;
t->min = node->getFloatValue ("min", -9999999);
t->max = node->getFloatValue ("max", 99999999);
t->has_mod = node->hasChild ("modulator");
if (t->has_mod) {
t->mod = node->getFloatValue ("modulator");
}
t->factor = node->getFloatValue ("scale", 1.0);
t->offset = node->getFloatValue ("offset", 0.0);
// Check for an interpolation table
const SGPropertyNode *trans_table (node->getNode ("interpolation"));
if (trans_table != 0) {
SG_LOG(SG_COCKPIT, SG_INFO, "Found interpolation table with "
<< trans_table->nChildren() << " children");
t->table = new SGInterpTable();
for (int i = 0; i < trans_table->nChildren(); i++) {
const SGPropertyNode * node = trans_table->getChild(i);
if (!strcmp(node->getName(), "entry")) {
double ind = node->getDoubleValue("ind", 0.0);
double dep = node->getDoubleValue("dep", 0.0);
SG_LOG(SG_COCKPIT, SG_INFO, "Adding interpolation entry "
<< ind << "==>" << dep);
t->table->addEntry(ind, dep);
} else {
SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
<< " in interpolation");
}
}
} else {
t->table = 0;
}
// Move the layer horizontally.
if (type == "x-shift") {
t->type = FGPanelTransformation::XSHIFT;
// t->min *= w_scale; //removed by Martin Dressler
// t->max *= w_scale; //removed by Martin Dressler
t->offset *= w_scale;
t->factor *= w_scale; //Added by Martin Dressler
}
// Move the layer vertically.
else if (type == "y-shift") {
t->type = FGPanelTransformation::YSHIFT;
//t->min *= h_scale; //removed
//t->max *= h_scale; //removed
t->offset *= h_scale;
t->factor *= h_scale; //Added
}
// Rotate the layer. The rotation
// is in degrees, and does not need
// to scale with the instrument size.
else if (type == "rotation") {
t->type = FGPanelTransformation::ROTATION;
}
else {
SG_LOG(SG_COCKPIT, SG_ALERT, "Unrecognized transformation type " << type);
delete t;
return 0;
}
readConditions(t, node);
SG_LOG(SG_COCKPIT, SG_DEBUG, "Read transformation " << name);
return t;
}
/**
* Read a chunk of text from the instrument's property list.
*
* A text layer consists of one or more chunks of text. All chunks
* share the same font size and color (and eventually, font), but
* each can come from a different source. There are three types of
* text chunks:
*
* "literal" - a literal text string (the default)
*
* "text-value" - the current value of a string property
*
* "number-value" - the current value of a floating-point property.
*
* All three may also include a printf-style format string.
*/
FGTextLayer::Chunk *
readTextChunk (const SGPropertyNode *node) {
FGTextLayer::Chunk *chunk;
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\"");
type = "literal";
}
// A literal text string.
if (type == "literal") {
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);
return chunk;
}
/**
* Read a single layer from an instrument's property list.
*
* Each instrument consists of one or more layers stacked on top
* of each other; the lower layers show through only where the upper
* layers contain an alpha component. Each layer can be moved
* horizontally and vertically and rotated using transformations.
*
* This module currently recognizes four kinds of layers:
*
* "texture" - a layer containing a texture (the default)
*
* "text" - a layer containing text
*
* "switch" - a layer that switches between two other layers
* based on the current value of a boolean property.
*
* "built-in" - a hard-coded layer supported by C++ code in FlightGear.
*
* Currently, the only built-in layer class is "compass-ribbon".
*/
static FGInstrumentLayer *
readLayer (const SGPropertyNode *node, 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.
if (type == "texture") {
const FGCroppedTexture_ptr texture (readTexture (node->getNode ("texture")));
layer = new FGTexturedLayer (texture, w, h);
if (emissive) {
FGTexturedLayer *tl = (FGTexturedLayer*) layer;
tl->setEmissive (true);
}
} 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));
}
}
} 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);
// Set the point size.
const float pointSize (node->getFloatValue ("point-size", 10.0) * w_scale);
tlayer->setPointSize (pointSize);
// Set the font.
const string fontName (node->getStringValue ("font", "7-Segment"));
tlayer->setFontName (fontName);
const SGPropertyNode *chunk_group (node->getNode ("chunks"));
if (chunk_group != 0) {
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 * const chunk (readTextChunk (node));
if (chunk != 0) {
tlayer->addChunk (chunk);
}
} else {
SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
<< " in chunks");
}
}
layer = tlayer;
}
} 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));
}
}
} 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"));
if (trans_group != 0) {
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 * 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");
}
}
}
readConditions (layer, node);
SG_LOG(SG_COCKPIT, SG_DEBUG, "Read layer " << name);
return layer;
}
/**
* Read an instrument from a property list.
*
* The instrument consists of a preferred width and height
* (the panel may override these), together with a list of layers
* and a list of actions to be performed when the user clicks
* the mouse over the instrument. All co-ordinates are relative
* to the instrument's position, so instruments are fully relocatable;
* likewise, co-ordinates for actions and transformations will be
* scaled automatically if the instrument is not at its preferred size.
*/
static FGPanelInstrument *
readInstrument (const SGPropertyNode *node) {
const string name (node->getStringValue ("name"));
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");
return 0;
}
float w_scale (1.0);
float h_scale (1.0);
if (real_w != -1) {
w_scale = float (real_w) / float (w);
w = real_w;
}
if (real_h != -1) {
h_scale = float (real_h) / float (h);
h = real_h;
}
SG_LOG(SG_COCKPIT, SG_DEBUG, "Reading instrument " << name);
FGLayeredInstrument * const instrument
(new FGLayeredInstrument (x, y, w, h));
//
// Get the layers for the instrument.
//
const SGPropertyNode *layer_group (node->getNode ("layers"));
if (layer_group != 0) {
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 * 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");
}
}
}
readConditions (instrument, node);
SG_LOG(SG_COCKPIT, SG_DEBUG, "Done reading instrument " << name);
return instrument;
}
/**
* Construct the panel from a property tree.
*/
SGSharedPtr<FGPanel>
FGReadablePanel::read (SGPropertyNode_ptr root) {
SG_LOG(SG_COCKPIT, SG_INFO, "Reading properties for panel " <<
root->getStringValue ("name", "[Unnamed Panel]"));
FGPanel * 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 ());
// Assign the background texture, if any, or a bogus chequerboard.
//
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 * 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
}
}
panel->setMultiBackground (new FGCroppedTexture (mbgTexture), i);
SG_LOG(SG_COCKPIT, SG_INFO, "Set multi-background texture" << i << " to " << mbgTexture);
}
//
// Create each instrument.
//
SG_LOG( SG_COCKPIT, SG_INFO, "Reading panel instruments" );
const SGPropertyNode *instrument_group (root->getChild ("instruments"));
if (instrument_group != 0) {
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 * 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, "Done reading panel instruments");
//
// Return the new panel.
//
return panel;
}
// end of panel_io.cxx

View File

@@ -0,0 +1,42 @@
// panel_io.cxx - I/O for 2D panel.
//
// Written by David Megginson, started January 2000.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id: panel_io.hxx,v 1.2 2016/07/20 22:01:32 allaert Exp $
#ifndef __PANEL_IO_HXX
#define __PANEL_IO_HXX
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include "FGPanel.hxx"
class FGReadablePanel : public FGPanel {
public:
// Subsystem identification.
static const char* staticSubsystemClassId() { return "readable-panel"; }
static SGSharedPtr<FGPanel> read (SGPropertyNode_ptr root);
};
#endif // __PANEL_IO_HXX