From effca9da5eb608f58d1ff19a1261bb9f372eaba6 Mon Sep 17 00:00:00 2001 From: gallaert Date: Sun, 4 Dec 2016 18:36:53 +0000 Subject: [PATCH] Update FGPanel: - use OpenGL 2.0 instead of OpenGL 1.0; - port to Raspberry Pi; - remove PLib dependencies. --- utils/fgpanel/ApplicationProperties.cxx | 69 ++ utils/fgpanel/ApplicationProperties.hxx | 17 +- utils/fgpanel/CMakeLists.txt | 131 ++- utils/fgpanel/FGCroppedTexture.cxx | 127 +++ utils/fgpanel/FGCroppedTexture.hxx | 69 ++ utils/fgpanel/FGDummyTextureLoader.cxx | 41 + utils/fgpanel/FGDummyTextureLoader.hxx | 32 + utils/fgpanel/FGFontCache.cxx | 325 +++---- utils/fgpanel/FGFontCache.hxx | 118 ++- utils/fgpanel/FGGLApplication.cxx | 178 ++-- utils/fgpanel/FGGLApplication.hxx | 34 +- utils/fgpanel/FGGroupLayer.cxx | 43 + utils/fgpanel/FGGroupLayer.hxx | 43 + utils/fgpanel/FGInstrumentLayer.cxx | 100 +++ utils/fgpanel/FGInstrumentLayer.hxx | 61 ++ utils/fgpanel/FGLayeredInstrument.cxx | 70 ++ utils/fgpanel/FGLayeredInstrument.hxx | 54 ++ utils/fgpanel/FGPNGTextureLoader.cxx | 137 +-- utils/fgpanel/FGPNGTextureLoader.hxx | 6 +- utils/fgpanel/FGPanel.cxx | 434 +++++++++ utils/fgpanel/FGPanel.hxx | 109 +++ utils/fgpanel/FGPanelApplication.cxx | 368 ++++---- utils/fgpanel/FGPanelApplication.hxx | 30 +- utils/fgpanel/FGPanelInstrument.cxx | 65 ++ utils/fgpanel/FGPanelInstrument.hxx | 56 ++ utils/fgpanel/FGPanelProtocol.cxx | 160 ++-- utils/fgpanel/FGPanelProtocol.hxx | 22 +- utils/fgpanel/FGPanelTransformation.cxx | 28 + utils/fgpanel/FGPanelTransformation.hxx | 52 ++ utils/fgpanel/FGRGBTextureLoader.cxx | 704 +++++++-------- utils/fgpanel/FGRGBTextureLoader.hxx | 6 +- utils/fgpanel/FGSwitchLayer.cxx | 37 + utils/fgpanel/FGSwitchLayer.hxx | 38 + utils/fgpanel/FGTextLayer.cxx | 301 +++++++ utils/fgpanel/FGTextLayer.hxx | 111 +++ utils/fgpanel/FGTextureLoaderInterface.hxx | 18 +- utils/fgpanel/FGTexturedLayer.cxx | 124 +++ utils/fgpanel/FGTexturedLayer.hxx | 65 ++ utils/fgpanel/GLES_utils.cxx | 385 ++++++++ utils/fgpanel/GLES_utils.hxx | 81 ++ utils/fgpanel/GL_utils.cxx | 374 ++++++++ utils/fgpanel/GL_utils.hxx | 85 ++ utils/fgpanel/README.RPi | 44 + utils/fgpanel/main.cxx | 12 +- utils/fgpanel/panel.cxx | 971 --------------------- utils/fgpanel/panel.hxx | 452 ---------- utils/fgpanel/panel_io.cxx | 506 ++++++----- utils/fgpanel/panel_io.hxx | 13 +- 48 files changed, 4471 insertions(+), 2835 deletions(-) create mode 100644 utils/fgpanel/ApplicationProperties.cxx create mode 100644 utils/fgpanel/FGCroppedTexture.cxx create mode 100644 utils/fgpanel/FGCroppedTexture.hxx create mode 100644 utils/fgpanel/FGDummyTextureLoader.cxx create mode 100644 utils/fgpanel/FGDummyTextureLoader.hxx create mode 100644 utils/fgpanel/FGGroupLayer.cxx create mode 100644 utils/fgpanel/FGGroupLayer.hxx create mode 100644 utils/fgpanel/FGInstrumentLayer.cxx create mode 100644 utils/fgpanel/FGInstrumentLayer.hxx create mode 100644 utils/fgpanel/FGLayeredInstrument.cxx create mode 100644 utils/fgpanel/FGLayeredInstrument.hxx create mode 100644 utils/fgpanel/FGPanel.cxx create mode 100644 utils/fgpanel/FGPanel.hxx create mode 100644 utils/fgpanel/FGPanelInstrument.cxx create mode 100644 utils/fgpanel/FGPanelInstrument.hxx create mode 100644 utils/fgpanel/FGPanelTransformation.cxx create mode 100644 utils/fgpanel/FGPanelTransformation.hxx create mode 100644 utils/fgpanel/FGSwitchLayer.cxx create mode 100644 utils/fgpanel/FGSwitchLayer.hxx create mode 100644 utils/fgpanel/FGTextLayer.cxx create mode 100644 utils/fgpanel/FGTextLayer.hxx create mode 100644 utils/fgpanel/FGTexturedLayer.cxx create mode 100644 utils/fgpanel/FGTexturedLayer.hxx create mode 100644 utils/fgpanel/GLES_utils.cxx create mode 100644 utils/fgpanel/GLES_utils.hxx create mode 100644 utils/fgpanel/GL_utils.cxx create mode 100644 utils/fgpanel/GL_utils.hxx create mode 100644 utils/fgpanel/README.RPi delete mode 100644 utils/fgpanel/panel.cxx delete mode 100644 utils/fgpanel/panel.hxx diff --git a/utils/fgpanel/ApplicationProperties.cxx b/utils/fgpanel/ApplicationProperties.cxx new file mode 100644 index 000000000..2b1baad77 --- /dev/null +++ b/utils/fgpanel/ApplicationProperties.cxx @@ -0,0 +1,69 @@ +// +// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "ApplicationProperties.hxx" + +double +ApplicationProperties::getDouble (const char *name, const double def) { + const SGPropertyNode_ptr n (ApplicationProperties::Properties->getNode (name, false)); + if (n == NULL) { + return def; + } + return n->getDoubleValue (); +} + +SGPath +ApplicationProperties::GetCwd () { + SGPath path ("."); + char buf[512]; + char *cwd (getcwd (buf, 511)); + buf[511] = '\0'; + if (cwd) { + path = SGPath::fromLocal8Bit (cwd); + } + return path; +} + +SGPath +ApplicationProperties::GetRootPath (const char *sub) { + if (sub != NULL) { + const SGPath subpath (sub); + + // relative path to current working dir? + if (subpath.isRelative ()) { + SGPath path (GetCwd ()); + path.append (sub); + if (path.exists ()) { + return path; + } + } else if (subpath.exists ()) { + // absolute path + return subpath; + } + } + + // default: relative path to FGROOT + SGPath path (ApplicationProperties::root); + if (sub != NULL) { + path.append (sub); + } + return path; +} + +string ApplicationProperties::root = "."; +SGPropertyNode_ptr ApplicationProperties::Properties = new SGPropertyNode; diff --git a/utils/fgpanel/ApplicationProperties.hxx b/utils/fgpanel/ApplicationProperties.hxx index 69de27226..a0f38a99d 100644 --- a/utils/fgpanel/ApplicationProperties.hxx +++ b/utils/fgpanel/ApplicationProperties.hxx @@ -5,7 +5,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -17,16 +17,19 @@ // #ifndef __APPLICATION_PROPERTIES #define __APPLICATION_PROPERTIES + #include #include -#include "FGFontCache.hxx" + +using namespace std; + class ApplicationProperties { public: - static double getDouble( const char * name, double def = 0.0 ); - static SGPath GetRootPath( const char * subDir = NULL ); - static SGPath GetCwd(); + static double getDouble (const char *name, const double def = 0.0); + static SGPath GetRootPath (const char *subDir = NULL); + static SGPath GetCwd (); static SGPropertyNode_ptr Properties; - static std::string root; - static FGFontCache fontCache; + static string root; }; + #endif diff --git a/utils/fgpanel/CMakeLists.txt b/utils/fgpanel/CMakeLists.txt index fe2bc44af..83bc741ae 100644 --- a/utils/fgpanel/CMakeLists.txt +++ b/utils/fgpanel/CMakeLists.txt @@ -1,40 +1,103 @@ find_package(PNG REQUIRED) find_package(OpenGL REQUIRED) -find_package(GLUT REQUIRED) -if(GLUT_FOUND) - message(STATUS "found glut") +find_path(BCMHOST_INCLUDE_DIR + NAMES bcm_host.h + PATHS /opt/vc/include + NO_DEFAULT_PATH + ) - add_executable(fgpanel main.cxx - ApplicationProperties.hxx - FGGLApplication.cxx - FGGLApplication.hxx - FGPanelApplication.cxx - FGPanelApplication.hxx - FGPNGTextureLoader.cxx - FGPNGTextureLoader.hxx - FGRGBTextureLoader.cxx - FGRGBTextureLoader.hxx - FGPanelProtocol.cxx - FGPanelProtocol.hxx - FGFontCache.cxx - FGFontCache.hxx - panel.cxx - panel.hxx - panel_io.cxx - panel_io.hxx - ) +include_directories( + /usr/include/freetype2 + ${PNG_INCLUDE_DIR} + ) - target_link_libraries(fgpanel - ${PNG_LIBRARIES} - ${GLUT_LIBRARIES} - SimGearCore - ${OPENGL_LIBRARIES} - ${PLIB_LIBRARIES} - ) - - include_directories(${PNG_INCLUDE_DIR}) - - install(TARGETS fgpanel RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +if(${BCMHOST_INCLUDE_DIR} STREQUAL "BCMHOST_INCLUDE_DIR-NOTFOUND") else() - message(STATUS "glut NOT found, can't build fgpanel") + # CMAKE > 3.1 : target_sources(fgpanel + set(TARGET_SOURCES + GLES_utils.cxx + GLES_utils.hxx + ) endif() + +add_executable(fgpanel + main.cxx + ApplicationProperties.hxx + ApplicationProperties.cxx + FGCroppedTexture.hxx + FGCroppedTexture.cxx + FGDummyTextureLoader.hxx + FGDummyTextureLoader.cxx + FGFontCache.cxx + FGFontCache.hxx + FGGLApplication.cxx + FGGLApplication.hxx + FGGroupLayer.cxx + FGGroupLayer.hxx + FGInstrumentLayer.cxx + FGInstrumentLayer.hxx + FGLayeredInstrument.cxx + FGLayeredInstrument.hxx + FGPanel.cxx + FGPanel.hxx + FGPanelApplication.cxx + FGPanelApplication.hxx + FGPanelInstrument.cxx + FGPanelInstrument.hxx + FGPanelProtocol.cxx + FGPanelProtocol.hxx + FGPanelTransformation.cxx + FGPanelTransformation.hxx + FGPNGTextureLoader.cxx + FGPNGTextureLoader.hxx + FGRGBTextureLoader.cxx + FGRGBTextureLoader.hxx + FGSwitchLayer.cxx + FGSwitchLayer.hxx + FGTextLayer.cxx + FGTextLayer.hxx + FGTexturedLayer.cxx + FGTexturedLayer.hxx + panel_io.cxx + panel_io.hxx + GL_utils.cxx + GL_utils.hxx + ${TARGET_SOURCES} + ) + +target_link_libraries(fgpanel + ${PNG_LIBRARIES} + ${SIMGEAR_CORE_LIBRARIES} + ${SIMGEAR_CORE_LIBRARY_DEPENDENCIES} + -lfreetype + ) + +if(${BCMHOST_INCLUDE_DIR} STREQUAL "BCMHOST_INCLUDE_DIR-NOTFOUND") + find_package(GLUT REQUIRED) + if(GLUT_FOUND) + message(STATUS "found glut") + + target_link_libraries(fgpanel + ${GLUT_LIBRARIES} + -lGLEW ${OPENGL_LIBRARIES} + ) + else(GLUT_FOUND) + message(STATUS "glut NOT found, can't build fgpanel") + endif(GLUT_FOUND) +else() + message(STATUS "found Raspberry Pi") + + target_link_libraries(fgpanel + -lGLESv2 -lEGL -lm -lbcm_host -L/opt/vc/lib + ) + + include_directories( + ${BCMHOST_INCLUDE_DIR} + ${BCMHOST_INCLUDE_DIR}/interface/vcos/pthreads + ${BCMHOST_INCLUDE_DIR}/interface/vmcs_host/linux + ) + + add_definitions(-D_GLES2 -D_RPI) +endif() + +install(TARGETS fgpanel RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/utils/fgpanel/FGCroppedTexture.cxx b/utils/fgpanel/FGCroppedTexture.cxx new file mode 100644 index 000000000..588a99a20 --- /dev/null +++ b/utils/fgpanel/FGCroppedTexture.cxx @@ -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 +#include +#include "ApplicationProperties.hxx" +#include "FGCroppedTexture.hxx" + +GLuint FGCroppedTexture::s_current_bound_texture = 0; +map FGCroppedTexture::s_cache; +map 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; + } +} diff --git a/utils/fgpanel/FGCroppedTexture.hxx b/utils/fgpanel/FGCroppedTexture.hxx new file mode 100644 index 000000000..b08496799 --- /dev/null +++ b/utils/fgpanel/FGCroppedTexture.hxx @@ -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 +#include +#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 s_cache; + static map s_TextureLoader; + static FGDummyTextureLoader s_DummyTextureLoader; +}; + +typedef SGSharedPtr FGCroppedTexture_ptr; + +#endif diff --git a/utils/fgpanel/FGDummyTextureLoader.cxx b/utils/fgpanel/FGDummyTextureLoader.cxx new file mode 100644 index 000000000..67da2d0f8 --- /dev/null +++ b/utils/fgpanel/FGDummyTextureLoader.cxx @@ -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; +} diff --git a/utils/fgpanel/FGDummyTextureLoader.hxx b/utils/fgpanel/FGDummyTextureLoader.hxx new file mode 100644 index 000000000..42ee00c27 --- /dev/null +++ b/utils/fgpanel/FGDummyTextureLoader.hxx @@ -0,0 +1,32 @@ +// +// Written by David Megginson, started January 2000. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +#ifndef FGDUMMYTEXTURELOADER_HXX +#define FGDUMMYTEXTURELOADER_HXX + +#include + +#include "FGTextureLoaderInterface.hxx" + +using namespace std; + +class FGDummyTextureLoader : public FGTextureLoaderInterface { +public: + virtual GLuint loadTexture (const string& filename); +}; + +#endif diff --git a/utils/fgpanel/FGFontCache.cxx b/utils/fgpanel/FGFontCache.cxx index 53d007084..966dda09f 100644 --- a/utils/fgpanel/FGFontCache.cxx +++ b/utils/fgpanel/FGFontCache.cxx @@ -3,7 +3,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -17,213 +17,170 @@ # include #endif -#include "FGGLApplication.hxx" #ifdef HAVE_WINDOWS_H #include #endif -#include -#include - -#include -#include +#include +#include "FGGLApplication.hxx" #include "ApplicationProperties.hxx" #include "FGFontCache.hxx" - //////////////////////////////////////////////////////////////////////// // FGFontCache class. //////////////////////////////////////////////////////////////////////// -//extern puFont FONT_HELVETICA_14; -//extern puFont FONT_SANS_12B; +const unsigned short FGFontCache::First_Printable_Char = 32; +const unsigned short FGFontCache::Last_Printable_Char = 127; -namespace -{ -struct GuiFont -{ - const char *name; - puFont *font; - struct Predicate - : public std::unary_function - { - Predicate(const char* name_) : name(name_) {} - bool operator() (const GuiFont& f1) const - { - return ::strcmp(f1.name, name) == 0; - } - const char* name; - }; -}; - -const GuiFont guifonts[] = { - { "default", &PUFONT_HELVETICA_12 }, - { "FIXED_8x13", &PUFONT_8_BY_13 }, - { "FIXED_9x15", &PUFONT_9_BY_15 }, - { "TIMES_10", &PUFONT_TIMES_ROMAN_10 }, - { "TIMES_24", &PUFONT_TIMES_ROMAN_24 }, - { "HELVETICA_10", &PUFONT_HELVETICA_10 }, - { "HELVETICA_12", &PUFONT_HELVETICA_12 }, -// { "HELVETICA_14", &FONT_HELVETICA_14 }, - { "HELVETICA_18", &PUFONT_HELVETICA_18 }, -// { "SANS_12B", &FONT_SANS_12B }, - { 0 } -}; - -const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])-1]; +FGFontCache::FGFontCache () : + m_Face_Map (), + m_Current_Face_Ptr (NULL), + m_Pos_Map (), + m_Current_Pos (0) { + if (FT_Init_FreeType (&m_Ft)) { + SG_LOG (SG_COCKPIT, SG_ALERT, "Could not init freetype library"); + } + for (unsigned int Index = 0; Index < Texture_Size * Texture_Size; ++Index) { + m_Texture[Index] = char (0); + } + glGenTextures (1, &m_Glyph_Texture); } -FGFontCache::fnt::~fnt() -{ - if (texfont) { - delete pufont; - delete texfont; +FGFontCache::~FGFontCache () { + for (Face_Map_Type::iterator It = m_Face_Map.begin (); It != m_Face_Map.end (); ++It) { + delete (It->second); + } + m_Face_Map.clear (); + glDeleteTextures (1, &m_Glyph_Texture); +} + +bool +FGFontCache::Set_Font (const string& Font_Name, + const float Size, + GLuint &Glyph_Texture) { + if (m_Face_Map.find (Font_Name) != m_Face_Map.end ()) { + m_Current_Face_Ptr = m_Face_Map[Font_Name]; + } else { + FT_Face * const Face_Ptr (new FT_Face); + if (FT_New_Face (m_Ft, Font_Name.c_str (), 0, Face_Ptr)) { + SG_LOG (SG_COCKPIT, SG_ALERT, "Could not open font : " + Font_Name); + return false; } + m_Face_Map.insert (pair (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 (Key_Str, m_Current_Pos)); + } + Glyph_Texture = m_Glyph_Texture; + return true; } -FGFontCache::FGFontCache() : - _initialized(false) -{ -} - -FGFontCache::~FGFontCache() -{ - PuFontMap::iterator it, end = _puFonts.end(); - for (it = _puFonts.begin(); it != end; ++it) - delete it->second; -} - -inline bool FGFontCache::FntParamsLess::operator()(const FntParams& f1, - const FntParams& f2) const -{ - int comp = f1.name.compare(f2.name); - if (comp < 0) - return true; - else if (comp > 0) - return false; - if (f1.size < f2.size) - return true; - else if (f1.size > f2.size) - return false; - return f1.slant < f2.slant; -} - -struct FGFontCache::fnt * -FGFontCache::getfnt(const char *name, float size, float slant) -{ - std::string fontName(name); - FntParams fntParams(fontName, size, slant); - PuFontMap::iterator i = _puFonts.find(fntParams); - if (i != _puFonts.end()) - return i->second; - // fntTexFont s are all preloaded into the _texFonts map - TexFontMap::iterator texi = _texFonts.find(fontName); - fntTexFont* texfont = 0; - puFont* pufont = 0; - if (texi != _texFonts.end()) { - texfont = texi->second; +bool +FGFontCache::Get_Char (const char Char, + int &X, int &Y, + int &Left, int &Bottom, + int &W, int &H, + double &X1, double &Y1, + double &X2, double &Y2) const { + if (m_Current_Face_Ptr != NULL) { + if (FT_Load_Char (*m_Current_Face_Ptr, Char, FT_LOAD_RENDER)) { + SG_LOG (SG_COCKPIT, SG_ALERT, "Could not load character : " + Char); + return false; } else { - const GuiFont* guifont = std::find_if(&guifonts[0], guifontsEnd, - GuiFont::Predicate(name)); - if (guifont != guifontsEnd) { - pufont = guifont->font; - } + const FT_GlyphSlot Glyph ((*m_Current_Face_Ptr)->glyph); + Left = Glyph->bitmap_left; + W = Glyph->bitmap.width; + H = Glyph->bitmap.rows; + Bottom = Glyph->bitmap_top - H; + X += (Glyph->advance.x >> 6); + Y += (Glyph->advance.y >> 6); + Get_Relative_Pos (int (Char), 0, 0, X1, Y1); + Get_Relative_Pos (int (Char), Glyph->bitmap.rows, Glyph->bitmap.width, X2, Y2); + return true; } - fnt* f = new fnt; - if (pufont) { - f->pufont = pufont; - } else if (texfont) { - f->texfont = texfont; - f->pufont = new puFont; - f->pufont->initialize(static_cast(f->texfont), size, slant); - } else { - f->pufont = guifonts[0].font; - } - _puFonts[fntParams] = f; - return f; + } else { + return false; + } } -puFont * -FGFontCache::get(const char *name, float size, float slant) -{ - return getfnt(name, size, slant)->pufont; +void +FGFontCache::Get_Pos (const unsigned short ASCII_Code, + const unsigned short Row, + const unsigned short Width, + unsigned int &Line, + unsigned int &Column) const { + const unsigned short Font_Size (32); + Line = (((((ASCII_Code - First_Printable_Char) * Font_Size) / Texture_Size) + 3 * m_Current_Pos) * Font_Size) + Row; + Column = (((ASCII_Code - First_Printable_Char) * Font_Size) % Texture_Size) + Width; } -fntTexFont * -FGFontCache::getTexFont(const char *name, float size, float slant) -{ - init(); - return getfnt(name, size, slant)->texfont; +void +FGFontCache::Get_Relative_Pos (const unsigned short ASCII_Code, + const unsigned short Row, + const unsigned short Width, + double &X, + double &Y) const { + unsigned int Line; + unsigned int Column; + Get_Pos (ASCII_Code, Row, Width, Line, Column); + X = double (Column) / double (Texture_Size); + Y = double (Line) / double (Texture_Size); } -puFont * -FGFontCache::get(SGPropertyNode *node) -{ - if (!node) - return get("Helvetica.txf", 15.0, 0.0); - - const char *name = node->getStringValue("name", "Helvetica.txf"); - float size = node->getFloatValue("size", 15.0); - float slant = node->getFloatValue("slant", 0.0); - - return get(name, size, slant); +string +FGFontCache::Get_Size (const float Size) { + const int Half_Size (int (round (2.0 * Size))); + const int Int_Part (Half_Size / 2); + const int Dec_Part ((Half_Size % 2) ? 5 : 0); + stringstream Result_SS; + Result_SS << Int_Part << "." << Dec_Part; + return Result_SS.str (); } - -void FGFontCache::init() -{ - if (!_initialized) { - char *envp = ::getenv("FG_FONTS"); - if (envp != NULL) { - _path = SGPath::fromEnv("FG_FONTS"); - } else { - _path = ApplicationProperties::GetRootPath("Fonts"); - } - _initialized = true; - } -} - -SGPath -FGFontCache::getfntpath(const char *name) -{ - init(); - SGPath path(_path); - if (name && std::string(name) != "") { - path.append(name); - if (path.exists()) - return path; - } - - path = SGPath(_path); - path.append("Helvetica.txf"); - - return path; -} - -bool FGFontCache::initializeFonts() -{ - static std::string fontext("txf"); - init(); - std::string pdata = _path.local8BitStr(); - ulDir* fontdir = ulOpenDir(pdata.c_str()); - if (!fontdir) - return false; - const ulDirEnt *dirEntry; - while ((dirEntry = ulReadDir(fontdir)) != 0) { - SGPath path(_path); - path.append(dirEntry->d_name); - if (path.extension() == fontext) { - std::string fdata = path.local8BitStr(); - fntTexFont* f = new fntTexFont; - if (f->load((char *)fdata.c_str())) - _texFonts[std::string(dirEntry->d_name)] = f; - else - delete f; - } - } - ulCloseDir(fontdir); - return true; -} - -// end of new_gui.cxx - diff --git a/utils/fgpanel/FGFontCache.hxx b/utils/fgpanel/FGFontCache.hxx index f8c6e6fd4..e1f5e8fe4 100644 --- a/utils/fgpanel/FGFontCache.hxx +++ b/utils/fgpanel/FGFontCache.hxx @@ -1,8 +1,9 @@ +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -15,78 +16,65 @@ #ifndef __FGFONTCACHE_HXX #define __FGFONTCACHE_HXX -#include -#include +#include +#include +#include +#include FT_FREETYPE_H +#if defined (SG_MAC) +#include +#include +#elif defined (_GLES2) +#include +#else +#include // Must be included before +#include +#include +#endif -// forward declare only! -class puFont; -class fntTexFont; +using namespace std; /** * A class to keep all fonts available for future use. * This also assures a font isn't resident more than once. */ class FGFontCache { -private: - // The parameters of a request to the cache. - struct FntParams - { - const std::string name; - const float size; - const float slant; - FntParams() : size(0.0f), slant(0.0f) {} - FntParams(const FntParams& rhs) - : name(rhs.name), size(rhs.size), slant(rhs.slant) - { - } - FntParams(const std::string& name_, float size_, float slant_) - : name(name_), size(size_), slant(slant_) - { - } - }; - struct FntParamsLess - : public std::binary_function - { - bool operator() (const FntParams& f1, const FntParams& f2) const; - }; - struct fnt { - fnt(puFont *pu = 0) : pufont(pu), texfont(0) {} - ~fnt(); - // Font used by plib GUI code - puFont *pufont; - // TXF font - fntTexFont *texfont; - }; - // Path to the font directory - SGPath _path; - - typedef std::map TexFontMap; - typedef std::map PuFontMap; - TexFontMap _texFonts; - PuFontMap _puFonts; - - bool _initialized; - struct fnt *getfnt(const char *name, float size, float slant); - void init(); - public: - FGFontCache(); - ~FGFontCache(); - - puFont *get(const char *name, float size=15.0, float slant=0.0); - puFont *get(SGPropertyNode *node); - - fntTexFont *getTexFont(const char *name, float size=15.0, float slant=0.0); - - SGPath getfntpath(const char *name); - /** - * Preload all the fonts in the FlightGear font directory. It is - * important to load the font textures early, with the proper - * graphics context current, so that no plib (or our own) code - * tries to load a font from disk when there's no current graphics - * context. - */ - bool initializeFonts(); + FGFontCache (); + ~FGFontCache (); + bool Set_Font (const string& Font_Name, + const float Size, + GLuint &Glyph_Texture); + bool Get_Char (const char Char, + int &X, int &Y, + int &Left, int &Bottom, + int &W, int &H, + double &X1, double &Y1, // Top (Y1) left (X1) + double &X2, double &Y2) const; // Bottom (Y2) right (X2) +private: + void Get_Pos (const unsigned short ASCII_Code, + const unsigned short Row, + const unsigned short Width, + unsigned int &Line, + unsigned int &Column) const; + void Get_Relative_Pos (const unsigned short ASCII_Code, + const unsigned short Row, + const unsigned short Width, + double &X, + double &Y) const; + static string Get_Size (const float Size); + static const unsigned short First_Printable_Char; + static const unsigned short Last_Printable_Char; + static const unsigned int Texture_Size = 1024; + FT_Library m_Ft; + typedef map Face_Map_Type; + Face_Map_Type m_Face_Map; + FT_Face *m_Current_Face_Ptr; + char m_Texture[Texture_Size * Texture_Size]; + typedef map Pos_Map_Type; + Pos_Map_Type m_Pos_Map; + unsigned int m_Current_Pos; + GLuint m_Glyph_Texture; }; + #endif diff --git a/utils/fgpanel/FGGLApplication.cxx b/utils/fgpanel/FGGLApplication.cxx index 30bbba2f7..e947be11e 100644 --- a/utils/fgpanel/FGGLApplication.cxx +++ b/utils/fgpanel/FGGLApplication.cxx @@ -5,7 +5,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -20,93 +20,137 @@ # include #endif -#include "FGGLApplication.hxx" -#include - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#if defined (SG_MAC) -#include -#include -#else -#include -#include -#endif - #include #include #include -FGGLApplication * FGGLApplication::application = NULL; +#ifdef HAVE_WINDOWS_H +#include +#endif +#if defined (SG_MAC) +#include +#include +#elif defined (_GLES2) +#include +#include "GLES_utils.hxx" +#else +#include // Must be included before +#include +#include +#endif -FGGLApplication::FGGLApplication( const char * aName, int argc, char ** argv ) : - gameMode(false), - name( aName ) -{ - if( application != NULL ) { - std::cerr << "Only one instance of FGGLApplication allowed!" << std::endl; - throw std::exception(); +#include + +#include "FGGLApplication.hxx" + +using namespace std; + +FGGLApplication *FGGLApplication::application = NULL; + +FGGLApplication::FGGLApplication (const char * a_name, int argc, char **argv) : + gameMode (false), + name (a_name) { + if (application != NULL ) { + cerr << "Only one instance of FGGLApplication allowed!" << endl; + throw exception (); } - application = this; + application = this; - glutInit( &argc, argv ); +#ifdef _GLES2 + GLES_utils::instance ().init ("FG Panel"); +#else + glutInit (&argc, argv); + glutInitContextVersion (2, 1); + glutInitContextFlags (GLUT_CORE_PROFILE); +#endif } -FGGLApplication::~FGGLApplication() -{ - if (gameMode) - glutLeaveGameMode(); +FGGLApplication::~FGGLApplication () { +#ifndef _GLES2 + if (gameMode) { + glutLeaveGameMode (); + } +#endif } -void FGGLApplication::DisplayCallback() -{ - if( application ) application->Display(); +void +FGGLApplication::DisplayCallback () { + if (application) { + application->Display (); + } } -void FGGLApplication::IdleCallback() -{ - if( application ) application->Idle(); +void +FGGLApplication::IdleCallback () { + if (application) { + application->Idle (); + } } -void FGGLApplication::KeyCallback( unsigned char key, int x, int y ) -{ - if( application ) application->Key( key, x, y ); +void +FGGLApplication::KeyCallback (const unsigned char key, const int x, const int y) { + if (application) { + application->Key (key, x, y); + } } -void FGGLApplication::ReshapeCallback( int width, int height ) -{ - if( application ) application->Reshape( width, height ); +void +FGGLApplication::ReshapeCallback (const int width, const int height) { + if (application) { + application->Reshape (width, height); + } } -void FGGLApplication::Run( int glutMode, bool gameMode, int width, int height, int bpp ) -{ - glutInitDisplayMode(glutMode); - if( gameMode ) { - width = glutGet(GLUT_SCREEN_WIDTH); - height = glutGet(GLUT_SCREEN_HEIGHT); +void +FGGLApplication::Run (const int glutMode, + const bool gameMode, + int width, + int height, + const int bpp) { +#ifndef _GLES2 + glutInitDisplayMode (glutMode); + if (gameMode) { + width = glutGet (GLUT_SCREEN_WIDTH); + height = glutGet (GLUT_SCREEN_HEIGHT); char game_mode_str[20]; - snprintf(game_mode_str, 20, "%dx%d:%d", width, height, bpp ); - glutGameModeString( game_mode_str ); - glutEnterGameMode(); + snprintf (game_mode_str, 20, "%dx%d:%d", width, height, bpp); + glutGameModeString (game_mode_str); + glutEnterGameMode (); this->gameMode = gameMode; } else { - if( width == -1 ) - width = glutGet(GLUT_SCREEN_WIDTH); - - if( height == -1 ) - height = glutGet(GLUT_SCREEN_HEIGHT); - - glutInitDisplayMode(glutMode); -// glutInitWindowSize(width, height); - windowId = glutCreateWindow(name); + if (width == -1) { + width = glutGet (GLUT_SCREEN_WIDTH); + } + if (height == -1) { + height = glutGet (GLUT_SCREEN_HEIGHT); + } + glutInitDisplayMode (glutMode); + glutInitWindowSize(width, height); + windowId = glutCreateWindow (name); } - Init(); - - glutKeyboardFunc(FGGLApplication::KeyCallback); - glutIdleFunc(FGGLApplication::IdleCallback); - glutDisplayFunc(FGGLApplication::DisplayCallback); - glutReshapeFunc(FGGLApplication::ReshapeCallback); - glutMainLoop(); + const GLenum GLEW_err (glewInit ()); + if (GLEW_OK != GLEW_err) { + cerr << "Unable to initialize GLEW " << glewGetErrorString (GLEW_err) << endl; + exit (1); + } + if (!GLEW_VERSION_2_1) { // check that the machine supports the 2.1 API. + cerr << "GLEW version 2.1 not supported : " << glewGetString (GLEW_VERSION) << endl; + exit (1); + } + cout << "OpenGL version = " << glGetString (GL_VERSION) << endl; +#endif + Init (); +#ifdef _GLES2 + GLES_utils::instance ().register_keyboard_func (FGGLApplication::KeyCallback); + GLES_utils::instance ().register_idle_func (FGGLApplication::IdleCallback); + GLES_utils::instance ().register_display_func (FGGLApplication::DisplayCallback); + GLES_utils::instance ().register_reshape_func (FGGLApplication::ReshapeCallback); + GLES_utils::instance ().main_loop (); +#else + glutKeyboardFunc (FGGLApplication::KeyCallback); + glutIdleFunc (FGGLApplication::IdleCallback); + glutDisplayFunc (FGGLApplication::DisplayCallback); + glutReshapeFunc (FGGLApplication::ReshapeCallback); + glutMainLoop (); +#endif } diff --git a/utils/fgpanel/FGGLApplication.hxx b/utils/fgpanel/FGGLApplication.hxx index aba699fa8..89d264c94 100644 --- a/utils/fgpanel/FGGLApplication.hxx +++ b/utils/fgpanel/FGGLApplication.hxx @@ -5,7 +5,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -20,28 +20,32 @@ class FGGLApplication { public: - FGGLApplication( const char * name, int argc, char ** argv ); - virtual ~FGGLApplication(); - void Run( int glutMode, bool gameMode, int widht=-1, int height=-1, int bpp = 32 ); + FGGLApplication (const char *a_name, int argc, char **argv); + virtual ~FGGLApplication (); + void Run (const int glutMode, + const bool gameMode, + int widht = -1, + int height = -1, + const int bpp = 32); protected: - virtual void Key( unsigned char key, int x, int y ) {} - virtual void Idle() {} - virtual void Display() {} - virtual void Reshape( int width, int height ) {} + virtual void Key (const unsigned char key, const int x, const int y) {} + virtual void Idle () {} + virtual void Display () {} + virtual void Reshape (const int width, const int height) {} - virtual void Init() {} + virtual void Init () {} int windowId; bool gameMode; - const char * name; + const char *name; - static FGGLApplication * application; + static FGGLApplication *application; private: - static void KeyCallback( unsigned char key, int x, int y ); - static void IdleCallback(); - static void DisplayCallback(); - static void ReshapeCallback( int width, int height ); + static void KeyCallback (const unsigned char key, const int x, const int y); + static void IdleCallback (); + static void DisplayCallback (); + static void ReshapeCallback (const int width, const int height); }; diff --git a/utils/fgpanel/FGGroupLayer.cxx b/utils/fgpanel/FGGroupLayer.cxx new file mode 100644 index 000000000..06e8b8416 --- /dev/null +++ b/utils/fgpanel/FGGroupLayer.cxx @@ -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); +} diff --git a/utils/fgpanel/FGGroupLayer.hxx b/utils/fgpanel/FGGroupLayer.hxx new file mode 100644 index 000000000..c0fb3d473 --- /dev/null +++ b/utils/fgpanel/FGGroupLayer.hxx @@ -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 m_layers; +}; + +#endif diff --git a/utils/fgpanel/FGInstrumentLayer.cxx b/utils/fgpanel/FGInstrumentLayer.cxx new file mode 100644 index 000000000..821bb4933 --- /dev/null +++ b/utils/fgpanel/FGInstrumentLayer.cxx @@ -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 +#include + +#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); +} diff --git a/utils/fgpanel/FGInstrumentLayer.hxx b/utils/fgpanel/FGInstrumentLayer.hxx new file mode 100644 index 000000000..d5a0e4500 --- /dev/null +++ b/utils/fgpanel/FGInstrumentLayer.hxx @@ -0,0 +1,61 @@ +// +// Written by David Megginson, started January 2000. +// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef FGINSTRUMENTLAYER_HXX +#define FGINSTRUMENTLAYER_HXX + +#include +#include + +#include "FGPanelTransformation.hxx" + +using namespace std; + +/** + * A single layer of a multi-layered instrument. + * + * Each layer can be subject to a series of transformations based + * on current FGFS instrument readings: for example, a texture + * representing a needle can rotate to show the airspeed. + */ +class FGInstrumentLayer : public SGConditional { +public: + FGInstrumentLayer (const int w = -1, const int h = -1); + virtual ~FGInstrumentLayer (); + + virtual void draw () = 0; + virtual void transform () const; + + virtual int getWidth () const; + virtual int getHeight () const; + virtual void setWidth (const int w); + virtual void setHeight (const int h); + + // Transfer pointer ownership!! + // DEPRECATED + virtual void addTransformation (FGPanelTransformation * const transformation); + +protected: + int m_w, m_h; + + typedef vector transformation_list; + transformation_list m_transformations; +}; + +#endif diff --git a/utils/fgpanel/FGLayeredInstrument.cxx b/utils/fgpanel/FGLayeredInstrument.cxx new file mode 100644 index 000000000..55ad3c4fc --- /dev/null +++ b/utils/fgpanel/FGLayeredInstrument.cxx @@ -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); +} diff --git a/utils/fgpanel/FGLayeredInstrument.hxx b/utils/fgpanel/FGLayeredInstrument.hxx new file mode 100644 index 000000000..bace2e873 --- /dev/null +++ b/utils/fgpanel/FGLayeredInstrument.hxx @@ -0,0 +1,54 @@ +// +// Written by David Megginson, started January 2000. +// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef FGLAYEREDINSTRUMENT_HXX +#define FGLAYEREDINSTRUMENT_HXX + +#include "FGCroppedTexture.hxx" +#include "FGInstrumentLayer.hxx" +#include "FGPanelInstrument.hxx" + +using namespace std; + +/** + * An instrument constructed of multiple layers. + * + * Each individual layer can be rotated or shifted to correspond + * to internal FGFS instrument readings. + */ +class FGLayeredInstrument : public FGPanelInstrument { +public: + FGLayeredInstrument (const int x, const int y, const int w, const int h); + virtual ~FGLayeredInstrument (); + + virtual void draw (); + + // Transfer pointer ownership!! + virtual int addLayer (FGInstrumentLayer * const layer); + virtual int addLayer (const FGCroppedTexture_ptr texture, const int w = -1, const int h = -1); + + // Transfer pointer ownership!! + virtual void addTransformation (FGPanelTransformation * const transformation); + +private: + typedef vector layer_list; + layer_list m_layers; +}; + +#endif diff --git a/utils/fgpanel/FGPNGTextureLoader.cxx b/utils/fgpanel/FGPNGTextureLoader.cxx index a8a8baef4..ae21271e1 100644 --- a/utils/fgpanel/FGPNGTextureLoader.cxx +++ b/utils/fgpanel/FGPNGTextureLoader.cxx @@ -3,7 +3,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -20,134 +20,137 @@ #ifdef HAVE_WINDOWS_H #include #endif -#include "FGPNGTextureLoader.hxx" #if defined (SG_MAC) +#include #include +#elif defined (_GLES2) +#include #else +#include // Must be included before +#include #include #endif + #include #include #include - #include + +#include "FGPNGTextureLoader.hxx" + using namespace std; -GLuint FGPNGTextureLoader::loadTexture( const string & filename ) -{ + +GLuint +FGPNGTextureLoader::loadTexture (const string &filename) { //header for testing if it is a png png_byte header[8]; - + //open file as binary - FILE *fp = fopen(filename.c_str(), "rb"); + FILE * const fp (fopen (filename.c_str (), "rb")); if (!fp) { return NOTEXTURE; } - + //read the header - fread(header, 1, 8, fp); - + fread (header, 1, 8, fp); + //test if png - int is_png = !png_sig_cmp(header, 0, 8); + const int is_png (!png_sig_cmp (header, 0, 8)); if (!is_png) { - fclose(fp); + fclose (fp); return NOTEXTURE; } - + //create png struct - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, - NULL, NULL); + png_structp png_ptr (png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)); if (!png_ptr) { - fclose(fp); - return (NOTEXTURE); - } - - //create png info struct - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); - fclose(fp); - return (NOTEXTURE); + fclose (fp); + return NOTEXTURE; } //create png info struct - png_infop end_info = png_create_info_struct(png_ptr); + png_infop info_ptr (png_create_info_struct (png_ptr)); + if (!info_ptr) { + png_destroy_read_struct (&png_ptr, (png_infopp) NULL, (png_infopp) NULL); + fclose (fp); + return NOTEXTURE; + } + + //create png info struct + png_infop end_info (png_create_info_struct (png_ptr)); if (!end_info) { - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); - fclose(fp); - return (NOTEXTURE); + png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL); + fclose (fp); + return NOTEXTURE; } //png error stuff, not sure libpng man suggests this. - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - fclose(fp); - return (NOTEXTURE); + if (setjmp (png_jmpbuf (png_ptr))) { + png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); + fclose (fp); + return NOTEXTURE; } - //init png reading - png_init_io(png_ptr, fp); - - //let libpng know you already read the first 8 bytes - png_set_sig_bytes(png_ptr, 8); + // init png reading + png_init_io (png_ptr, fp); + + // let libpng know you already read the first 8 bytes + png_set_sig_bytes (png_ptr, 8); // read all the info up to the image data - png_read_info(png_ptr, info_ptr); + png_read_info (png_ptr, info_ptr); - //variables to pass to get info + // variables to pass to get info int bit_depth, color_type; png_uint_32 twidth, theight; // get info about png - png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, - NULL, NULL, NULL); + png_get_IHDR (png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, NULL, NULL, NULL); // Update the png info struct. - png_read_update_info(png_ptr, info_ptr); + png_read_update_info (png_ptr, info_ptr); // Row size in bytes. - int rowbytes = png_get_rowbytes(png_ptr, info_ptr); + const int rowbytes (png_get_rowbytes (png_ptr, info_ptr)); // Allocate the image_data as a big block, to be given to opengl - png_byte *image_data = new png_byte[rowbytes * theight]; + png_byte *image_data (new png_byte[rowbytes * theight]); if (!image_data) { //clean up memory and close stuff - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - fclose(fp); + png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); + fclose (fp); return NOTEXTURE; } - //row_pointers is for pointing to image_data for reading the png with libpng - png_bytep *row_pointers = new png_bytep[theight]; + // row_pointers is for pointing to image_data for reading the png with libpng + png_bytep *row_pointers (new png_bytep[theight]); if (!row_pointers) { //clean up memory and close stuff - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - delete[] image_data; - fclose(fp); + png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); + delete []image_data; + fclose (fp); return NOTEXTURE; } // set the individual row_pointers to point at the correct offsets of image_data - for (png_uint_32 i = 0; i < theight; ++i) + for (png_uint_32 i = 0; i < theight; ++i) { row_pointers[theight - 1 - i] = image_data + i * rowbytes; - + } //read the png into image_data through row_pointers - png_read_image(png_ptr, row_pointers); + png_read_image (png_ptr, row_pointers); //Now generate the OpenGL texture object GLuint texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - gluBuild2DMipmaps( GL_TEXTURE_2D, 4, twidth, theight, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)image_data ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR ); -// glTexImage2D(GL_TEXTURE_2D,0, GL_RGBA, twidth, theight, 0, -// GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) image_data); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glGenTextures (1, &texture); + glBindTexture (GL_TEXTURE_2D, texture); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, twidth, theight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) image_data); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //clean up memory and close stuff - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - delete[] image_data; - delete[] row_pointers; - fclose(fp); + png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); + delete []image_data; + delete []row_pointers; + fclose (fp); return texture; } diff --git a/utils/fgpanel/FGPNGTextureLoader.hxx b/utils/fgpanel/FGPNGTextureLoader.hxx index e8bbfa48c..be36adda7 100644 --- a/utils/fgpanel/FGPNGTextureLoader.hxx +++ b/utils/fgpanel/FGPNGTextureLoader.hxx @@ -1,8 +1,9 @@ +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -19,8 +20,9 @@ class FGPNGTextureLoader : public FGTextureLoaderInterface { public: - virtual GLuint loadTexture( const std::string & filename ); + virtual GLuint loadTexture (const string &filename); const static GLuint NOTEXTURE = 0; }; + #endif diff --git a/utils/fgpanel/FGPanel.cxx b/utils/fgpanel/FGPanel.cxx new file mode 100644 index 000000000..c5feb739a --- /dev/null +++ b/utils/fgpanel/FGPanel.cxx @@ -0,0 +1,434 @@ +// FGPanel.cxx - default, 2D single-engine prop instrument panel +// +// Written by David Megginson, started January 2000. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// $Id: FGPanel.cxx,v 1.1 2016/07/20 22:01:30 allaert Exp $ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_WINDOWS_H +# include +#endif + +#include // sprintf +#include + +#include +#include +#include + +#if defined (SG_MAC) +#include +#include +#elif defined (_GLES2) +#include +#else +#include // Must be included before +#include +#include +#endif + +#include "GL_utils.hxx" +#include "FGPanel.hxx" +#include "FGTextLayer.hxx" +#include "FGTexturedLayer.hxx" + +//////////////////////////////////////////////////////////////////////// +// Local functions. +//////////////////////////////////////////////////////////////////////// +GLuint FGPanel::Textured_Layer_Program_Object (0); +GLint FGPanel::Textured_Layer_Position_Loc (0); +GLint FGPanel::Textured_Layer_Tex_Coord_Loc (0); +GLint FGPanel::Textured_Layer_MVP_Loc (0); +GLint FGPanel::Textured_Layer_Sampler_Loc (0); + +//////////////////////////////////////////////////////////////////////// +// Implementation of FGPanel. +//////////////////////////////////////////////////////////////////////// + +/** + * Constructor. + */ +FGPanel::FGPanel (const SGPropertyNode_ptr root) : + m_flipx (root->getNode ("/sim/panel/flip-x", true)), + m_bg_width (1.0), m_bg_height (1.0) { +} + +/** + * Destructor. + */ +FGPanel::~FGPanel () { + for (instrument_list_type::iterator it = m_instruments.begin (); + it != m_instruments.end (); + ++it) { + delete *it; + *it = 0; + } +} + +/** + * Initialize the panel. + */ +void +FGPanel::init () { + // Textured Layer Shaders + const char V_Textured_Layer_Shader_Str[] = +#ifdef _GLES2 + "attribute vec4 a_position; \n" + "attribute vec2 a_tex_coord; \n" + "varying vec2 v_tex_coord; \n" +#else + "#version 330 \n" + "in vec4 a_position; \n" + "in vec2 a_tex_coord; \n" + "out vec2 v_tex_coord; \n" +#endif + "uniform mat4 u_mvp_matrix; \n" + "void main () { \n" + " gl_Position = u_mvp_matrix * a_position; \n" + " v_tex_coord = a_tex_coord; \n" + "} \n"; + + const char F_Textured_Layer_Shader_Str[] = +#ifdef _GLES2 + "precision mediump float; \n" + "varying vec2 v_tex_coord; \n" +#else + "#version 330 \n" + "in vec2 v_tex_coord; \n" + "out vec4 gl_FragColor; \n" +#endif + "uniform sampler2D u_texture; \n" + "void main () { \n" + " vec4 base_color = texture2D (u_texture, v_tex_coord); \n" + " if (base_color.a <= 0.1) { \n" + " discard; \n" + " } \n" + " gl_FragColor = base_color; \n" + "} \n"; + + Textured_Layer_Program_Object = GL_utils::instance ().load_program (V_Textured_Layer_Shader_Str, + F_Textured_Layer_Shader_Str); + if (Textured_Layer_Program_Object == 0) { + terminate (); + } + + // Get the attribute locations + Textured_Layer_Position_Loc = glGetAttribLocation (Textured_Layer_Program_Object, "a_position"); + Textured_Layer_Tex_Coord_Loc = glGetAttribLocation (Textured_Layer_Program_Object, "a_tex_coord"); + + // Get the uniform locations + Textured_Layer_MVP_Loc = glGetUniformLocation (Textured_Layer_Program_Object, "u_mvp_matrix"); + + // Get the sampler location + Textured_Layer_Sampler_Loc = glGetUniformLocation (Textured_Layer_Program_Object, "u_texture"); + + FGTexturedLayer::Init (Textured_Layer_Program_Object, + Textured_Layer_Position_Loc, + Textured_Layer_Tex_Coord_Loc, + Textured_Layer_MVP_Loc, + Textured_Layer_Sampler_Loc); + + // Text Layer Shaders + if (!FGTextLayer::Init ()) { + terminate (); + } + + glClearColor (0.0f, 0.0f, 0.0f, 1.0f); +} + +/** + * Bind panel properties. + */ +void +FGPanel::bind () { +} + +/** + * Unbind panel properties. + */ +void +FGPanel::unbind () { +} + +void +FGPanel::update (const double dt) { + getInitDisplayList (); + // Draw the instruments. + // Syd Adams: added instrument clipping + for (instrument_list_type::const_iterator current = m_instruments.begin (); + current != m_instruments.end (); + ++current) { + FGPanelInstrument *instr = *current; + GL_utils::instance ().glPushMatrix (); + GL_utils::instance ().glTranslatef (instr->getXPos (), instr->getYPos (), 0); + + instr->draw(); + + GL_utils::instance ().glPopMatrix (); + } +#ifndef _GLES2 + // restore some original state + //glPopAttrib (); +#endif +} + +/** + * Add an instrument to the panel. + */ +void +FGPanel::addInstrument (FGPanelInstrument * const instrument) { + m_instruments.push_back (instrument); +} + +/** + * Set the panel's background texture. + */ +void +FGPanel::setBackground (const FGCroppedTexture_ptr texture) { + m_bg = texture; +} + +void +FGPanel::setBackgroundWidth (const double d) { + m_bg_width = d; +} + +void +FGPanel::setBackgroundHeight (const double d) { + m_bg_height = d; +} + +/** + * Set the panel's multiple background textures. + */ +void +FGPanel::setMultiBackground (const FGCroppedTexture_ptr texture, const int idx) { + m_bg = 0; + m_mbg[idx] = texture; +} + +void +FGPanel::setWidth (const int width) { + m_width = width; +} + +int +FGPanel::getWidth () const { + return m_width; +} + +void +FGPanel::setHeight (const int height) { + m_height = height; +} + +int +FGPanel::getHeight () const { + return m_height; +} + +void +FGPanel::getInitDisplayList () { + glUseProgram (Textured_Layer_Program_Object); + GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION); + GL_utils::instance ().glLoadIdentity (); + if (m_flipx->getBoolValue ()) { + GL_utils::instance ().gluOrtho2D (m_width, 0, m_height, 0); + } else { + GL_utils::instance ().gluOrtho2D (0, m_width, 0, m_height); + } + GL_utils::instance ().glTranslatef (-1.0f, -1.0f, 0.0f); + GL_utils::instance ().glScalef (2.0f / GLfloat (m_width), 2.0f / GLfloat (m_height), 1.0f); + +#ifndef _GLES2 + glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); +#endif + + GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW); + GL_utils::instance ().glLoadIdentity (); + glClear (GL_COLOR_BUFFER_BIT); + + glUseProgram (Textured_Layer_Program_Object); +#ifndef _GLES2 + // save some state + //glPushAttrib (GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT | + // GL_TEXTURE_BIT | GL_PIXEL_MODE_BIT | GL_CULL_FACE | + // GL_DEPTH_BUFFER_BIT ); +#endif + // Draw the background + glEnable (GL_TEXTURE_2D); +#ifndef _GLES2 + glDisable (GL_LIGHTING); +#endif + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#ifndef _GLES2 + glEnable (GL_COLOR_MATERIAL); +#endif + glEnable (GL_CULL_FACE); + glCullFace (GL_BACK); + glDisable (GL_DEPTH_TEST); + + if (m_bg != NULL) { + m_bg->bind (Textured_Layer_Sampler_Loc); + const GLfloat v_Vertices[] = { + 0.0f, 0.0f, 0.0f, // Position 0 (bottom left corner) + 0.0f, 0.0f, // TexCoord 0 (bottom left corner) + float (m_width), 0.0f, 0.0f, // Position 1 (bottom right corner) + float (m_bg_width), 0.0f, // TexCoord 1 (bottom right corner) + float (m_width), float (m_height), 0.0f, // Position 2 (top right corner) + float (m_bg_width), float (m_bg_height), // TexCoord 2 (top right corner) + 0.0f, float (m_height), 0.0f, // Position 3 (top left corner) + 0.0f, float (m_bg_height) }; // TexCoord 3 (top left corner) + glVertexAttribPointer (Textured_Layer_Position_Loc, + 3, + GL_FLOAT, + GL_FALSE, + 5 * sizeof (GLfloat), + v_Vertices); + glVertexAttribPointer (Textured_Layer_Tex_Coord_Loc, + 2, + GL_FLOAT, + GL_FALSE, + 5 * sizeof (GLfloat), + &v_Vertices[3]); + + glEnableVertexAttribArray (Textured_Layer_Position_Loc); + glEnableVertexAttribArray (Textured_Layer_Tex_Coord_Loc); + + GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION); + GL_utils::instance ().glPushMatrix (); + GL_utils::instance ().glMultMatrixf + (*reinterpret_cast + (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 + (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 + (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 + } +} diff --git a/utils/fgpanel/FGPanel.hxx b/utils/fgpanel/FGPanel.hxx new file mode 100644 index 000000000..dc0003574 --- /dev/null +++ b/utils/fgpanel/FGPanel.hxx @@ -0,0 +1,109 @@ +// FGPanel.hxx - generic support classes for a 2D panel. +// +// Written by David Megginson, started January 2000. +// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// $Id: FGPanel.hxx,v 1.1 2016/07/20 22:01:30 allaert Exp $ + +#ifndef FGPANEL_HXX +#define FGPANEL_HXX + +#ifndef __cplusplus +# error This library requires C++ +#endif + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "FGCroppedTexture.hxx" +#include "FGPanelInstrument.hxx" + +using namespace std; + +//////////////////////////////////////////////////////////////////////// +// Top-level panel. +//////////////////////////////////////////////////////////////////////// + +/** + * Instrument panel class. + * + * The panel is a container that has a background texture and holds + * zero or more instruments. The panel will order the instruments to + * redraw themselves when necessary, and will pass mouse clicks on to + * the appropriate instruments for processing. + */ +class FGPanel : public SGSubsystem { +public: + FGPanel (const SGPropertyNode_ptr root); + virtual ~FGPanel (); + + // Update the panel (every frame). + virtual void init (); + virtual void bind (); + virtual void unbind (); + // virtual void draw (); + virtual void update (const double dt); + + // transfer pointer ownership!!! + virtual void addInstrument (FGPanelInstrument * const instrument); + + // Background texture. + virtual void setBackground (const FGCroppedTexture_ptr texture); + void setBackgroundWidth (const double d); + void setBackgroundHeight (const double d); + + // Background multiple textures. + virtual void setMultiBackground (const FGCroppedTexture_ptr texture , const int idx); + + // Full width of panel. + virtual void setWidth (const int width); + virtual int getWidth () const; + + // Full height of panel. + virtual void setHeight (const int height); + virtual int getHeight () const; + +private: + + typedef vector instrument_list_type; + int m_width; + int m_height; + + SGPropertyNode_ptr m_flipx; + + FGCroppedTexture_ptr m_bg; + double m_bg_width; + double m_bg_height; + FGCroppedTexture_ptr m_mbg[8]; + // List of instruments in panel. + instrument_list_type m_instruments; + + void getInitDisplayList (); + + static GLuint Textured_Layer_Program_Object; + static GLint Textured_Layer_Position_Loc; + static GLint Textured_Layer_Tex_Coord_Loc; + static GLint Textured_Layer_MVP_Loc; + static GLint Textured_Layer_Sampler_Loc; +}; + +#endif diff --git a/utils/fgpanel/FGPanelApplication.cxx b/utils/fgpanel/FGPanelApplication.cxx index a14cf267a..6073ebbbe 100644 --- a/utils/fgpanel/FGPanelApplication.cxx +++ b/utils/fgpanel/FGPanelApplication.cxx @@ -5,7 +5,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -29,245 +29,238 @@ # include #endif -#include "FGGLApplication.hxx" -#include "FGPanelApplication.hxx" +#include + #if defined (SG_MAC) #include #include +#elif defined (_GLES2) +#include +#include "GLES_utils.hxx" #else +#include // Must be included before #include #include #endif +#include "FGGLApplication.hxx" +#include "FGPanelApplication.hxx" + #include #include #include #include #include -#include - #include "panel_io.hxx" #include "ApplicationProperties.hxx" using namespace std; -inline static string ParseArgs( int argc, char ** argv, const string & token ) -{ - for( int i = 0; i < argc; i++ ) { - string arg = argv[i]; - if( arg.find( token ) == 0 ) - return arg.substr( token.length() ); +inline static string +ParseArgs (int argc, char **argv, const string &token) { + for (int i = 0; i < argc; i++) { + const string arg (argv[i]); + if (arg.find (token) == 0) { + return arg.substr (token.length ()); + } } return ""; } -inline static string ParseArgs( int argc, char ** argv, const char * token ) -{ - string s = token; - return ParseArgs( argc, argv, s ); -} - - // define default location of fgdata (use the same as for fgfs) +inline static SGPath +platformDefaultRoot () { #if defined(__CYGWIN__) -inline static SGPath platformDefaultRoot() -{ - return SGPath("../data"); -} - + return SGPath ("../data"); #elif defined(_WIN32) -inline static SGPath platformDefaultRoot() -{ - return SGPath("..\\data"); -} + return SGPath ("..\\data"); #elif defined(__APPLE__) -inline static SGPath platformDefaultRoot() -{ /* The following code looks for the base package inside the application bundle, in the standard Contents/Resources location. */ - CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL (CFBundleGetMainBundle ()); // look for a 'data' subdir - CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent(NULL, resourcesUrl, CFSTR("data"), true); + CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent (NULL, resourcesUrl, CFSTR ("data"), true); // now convert down to a path, and the a c-string - CFStringRef path = CFURLCopyFileSystemPath(dataDir, kCFURLPOSIXPathStyle); - string root = CFStringGetCStringPtr(path, CFStringGetSystemEncoding()); + CFStringRef path = CFURLCopyFileSystemPath (dataDir, kCFURLPOSIXPathStyle); + string root = CFStringGetCStringPtr (path, CFStringGetSystemEncoding ()); - CFRelease(resourcesUrl); - CFRelease(dataDir); - CFRelease(path); + CFRelease (resourcesUrl); + CFRelease (dataDir); + CFRelease (path); - return SGPath(root); -} + return SGPath (root); #else -inline static SGPath platformDefaultRoot() -{ - return SGPath(PKGLIBDIR); -} + return SGPath (PKGLIBDIR); #endif +} #include "FGPNGTextureLoader.hxx" #include "FGRGBTextureLoader.hxx" + static FGPNGTextureLoader pngTextureLoader; static FGRGBTextureLoader rgbTextureLoader; -FGPanelApplication::FGPanelApplication( int argc, char ** argv ) : - FGGLApplication( "FlightGear Panel", argc, argv ) -{ - sglog().setLogLevels( SG_ALL, SG_WARN ); - FGCroppedTexture::registerTextureLoader( "png", &pngTextureLoader ); - FGCroppedTexture::registerTextureLoader( "rgb", &rgbTextureLoader ); +FGPanelApplication::FGPanelApplication (int argc, char **argv) : + FGGLApplication ("FlightGear Panel", argc, argv) { + sglog().setLogLevels (SG_ALL, SG_WARN); + FGCroppedTexture::registerTextureLoader ("png", &pngTextureLoader); + FGCroppedTexture::registerTextureLoader ("rgb", &rgbTextureLoader); - ApplicationProperties::root = platformDefaultRoot().local8BitStr(); + ApplicationProperties::root = platformDefaultRoot ().local8BitStr (); - string panelFilename; - string fgRoot; + const string panelFilename (ParseArgs (argc, argv, "--panel=")); + const string fgRoot (ParseArgs (argc, argv, "--fg-root=")); - for( int i = 1; i < argc; i++ ) { - panelFilename = ParseArgs( argc, argv, "--panel=" ); - fgRoot = ParseArgs( argc, argv, "--fg-root=" ); - } - - if( fgRoot.length() > 0 ) + if (fgRoot.length () > 0) { ApplicationProperties::root = fgRoot; + } + simgear::ResourceManager::instance ()->addBasePath (ApplicationProperties::root); - simgear::ResourceManager::instance()->addBasePath(ApplicationProperties::root); - - if( panelFilename.length() == 0 ) { - cerr << "Need a panel filename. Use --panel=path_to_filename" << endl; - throw exception(); + if (panelFilename.length () == 0 ) { + cerr << "Need a panel filename. Use --panel=path_to_filename" << endl; + throw exception (); } // see if we got a valid fgdata path - SGPath BaseCheck(ApplicationProperties::root); - BaseCheck.append("version"); - if (!BaseCheck.exists()) - { - cerr << "Missing base package. Use --fg-root=path_to_fgdata" << endl; - throw exception(); + SGPath BaseCheck (ApplicationProperties::root); + BaseCheck.append ("version"); + if (!BaseCheck.exists ()) { + cerr << "Missing base package. Use --fg-root=path_to_fgdata" << endl; + throw exception (); } try { - SGPath tpath = ApplicationProperties::GetRootPath( panelFilename.c_str() ); - readProperties( tpath, ApplicationProperties::Properties ); + const SGPath tpath (ApplicationProperties::GetRootPath (panelFilename.c_str ())); + readProperties (tpath, ApplicationProperties::Properties); } - catch( sg_io_exception & e ) { - cerr << e.getFormattedMessage() << endl; + catch (sg_io_exception & e) { + cerr << e.getFormattedMessage () << endl; throw; } - for( int i = 1; i < argc; i++ ) { - string arg = argv[i]; - if( arg.find( "--prop:" ) == 0 ) { - string s2 = arg.substr( 7 ); - string::size_type p = s2.find( "=" ); - if( p != string::npos ) { - string propertyName = s2.substr( 0, p ); - string propertyValue = s2.substr( p+1 ); - ApplicationProperties::Properties->getNode( propertyName.c_str(), true )->setValue( propertyValue.c_str() ); + for (int i = 1; i < argc; i++) { + const string arg (argv[i]); + if (arg.find ("--prop:") == 0 ) { + const string s2 (arg.substr (7)); + string::size_type p (s2.find ("=")); + if (p != string::npos) { + const string propertyName (s2.substr (0, p)); + const string propertyValue (s2.substr (p + 1)); + ApplicationProperties::Properties->getNode (propertyName.c_str (), true )->setValue (propertyValue.c_str ()); } } } - SGPropertyNode_ptr n; - if( (n = ApplicationProperties::Properties->getNode( "panel" )) != NULL ) - panel = FGReadablePanel::read( n ); - - protocol = new FGPanelProtocol( ApplicationProperties::Properties->getNode( "communication", true ) ); - protocol->init(); + const SGPropertyNode_ptr n (ApplicationProperties::Properties->getNode ("panel")); + if (n != NULL) { + panel = FGReadablePanel::read (n); + } + protocol = new FGPanelProtocol (ApplicationProperties::Properties->getNode ("communication", true)); + protocol->init (); } -FGPanelApplication::~FGPanelApplication() -{ +FGPanelApplication::~FGPanelApplication () { } -void FGPanelApplication::Run() -{ - int mode = GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE; - int w = panel == NULL ? 0 : panel->getWidth(); - int h = panel == NULL ? 0 : panel->getHeight(); - if( w == 0 && h == 0 ) { +void +FGPanelApplication::Run () { +#ifdef _GLES2 + const int mode (0); +#else + const int mode (GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); +#endif + int w (panel == NULL ? 0 : panel->getWidth ()); + int h (panel == NULL ? 0 : panel->getHeight ()); + if (w == 0 && h == 0) { w = 1024; h = 768; - } else if( w == 0 ) { + } else if (w == 0) { w = h / 0.75; - } else if( h == 0 ) { + } else if (h == 0) { h = w * 0.75; } - - bool gameMode = ApplicationProperties::Properties->getNode( "game-mode", true )->getBoolValue(); - FGGLApplication::Run( mode, gameMode, w, h ); + + const bool gameMode (ApplicationProperties::Properties->getNode ( "game-mode", true)->getBoolValue ()); + FGGLApplication::Run (mode, gameMode, w, h); } -void FGPanelApplication::Init() -{ - glAlphaFunc(GL_GREATER, 0.1); - glutSetCursor( GLUT_CURSOR_NONE ); - ApplicationProperties::fontCache.initializeFonts(); +void +FGPanelApplication::Init () { +#ifndef _GLES2 + glutSetCursor (GLUT_CURSOR_NONE); +#endif + if (panel != NULL) { + panel->init (); + } } -void FGPanelApplication::Reshape( int width, int height ) -{ +void +FGPanelApplication::Reshape (const int width, const int height) { this->width = width; this->height = height; - glViewport(0, 0, (GLsizei) width, (GLsizei) height); + glViewport (0, 0, GLsizei (width), GLsizei (height)); } -void FGPanelApplication::Idle() -{ - double d = glutGet(GLUT_ELAPSED_TIME); - - double dt = Sleep(); - if( dt == 0 ) +void +FGPanelApplication::Idle () { +#ifndef _GLES2 + const double d (glutGet (GLUT_ELAPSED_TIME)); +#endif + const double dt (Sleep ()); + if (dt == 0) { return; - - if( panel != NULL ) - panel->update( dt ); - - glutSwapBuffers(); - - if( protocol != NULL ) - protocol->update( dt ); - + } + if (panel != NULL) { + panel->update (dt); + } +#ifndef _GLES2 + glutSwapBuffers (); +#endif + if (protocol != NULL) { + protocol->update (dt); + } +#ifndef _GLES2 static double dsum = 0.0; static unsigned cnt = 0; - dsum += glutGet(GLUT_ELAPSED_TIME)-d; + dsum += glutGet (GLUT_ELAPSED_TIME) - d; cnt++; - if( dsum > 1000.0 ) { - ApplicationProperties::Properties->getNode( "/sim/frame-rate", true )->setDoubleValue(cnt*1000.0/dsum ); + if (dsum > 1000.0) { + ApplicationProperties::Properties->getNode ("/sim/frame-rate", true)->setDoubleValue (cnt * 1000.0 / dsum); dsum = 0.0; cnt = 0; } +#endif } -void FGPanelApplication::Key( unsigned char key, int x, int y ) -{ - switch( key ) { - case 0x1b: - exit(0); - break; +void +FGPanelApplication::Key (const unsigned char key, const int x, const int y) { + switch (key) { + case 0x1b: + exit(0); + break; } } -double FGPanelApplication::Sleep() -{ +double +FGPanelApplication::Sleep () { SGTimeStamp current_time_stamp; static SGTimeStamp last_time_stamp; - if ( last_time_stamp.get_seconds() == 0 ) - last_time_stamp.stamp(); - - double model_hz = 60; - double throttle_hz = ApplicationProperties::getDouble("/sim/frame-rate-throttle-hz", 0.0); - if ( throttle_hz > 0.0 ) { + if (last_time_stamp.get_seconds () == 0) { + last_time_stamp.stamp (); + } + const double model_hz (60); + const double throttle_hz (ApplicationProperties::getDouble ("/sim/frame-rate-throttle-hz", 0.0)); + if (throttle_hz > 0.0) { // optionally throttle the frame rate (to get consistent frame // rates or reduce cpu usage. - double frame_us = 1.0e6 / throttle_hz; + double frame_us (1.0e6 / throttle_hz); // sleep based timing loop. // @@ -292,19 +285,19 @@ double FGPanelApplication::Sleep() // sleep() will always overshoot by a bit so undersleep by // 2000us in the hopes of never oversleeping. frame_us -= 2000.0; - if ( frame_us < 0.0 ) { + if (frame_us < 0.0) { frame_us = 0.0; } - current_time_stamp.stamp(); + current_time_stamp.stamp (); /* Convert to ms */ - double elapsed_us = (current_time_stamp - last_time_stamp).toUSecs(); - if ( elapsed_us < frame_us ) { - double requested_us = frame_us - elapsed_us; + const double elapsed_us ((current_time_stamp - last_time_stamp).toUSecs ()); + if (elapsed_us < frame_us) { + const double requested_us (frame_us - elapsed_us); #ifdef _WIN32 - ::Sleep ((int)(requested_us / 1000.0)) ; + ::Sleep (int (requested_us / 1000.0)); #else - usleep ( (useconds_t)(requested_us ) ) ; + usleep (useconds_t (requested_us)); #endif } // busy wait timing loop. @@ -312,82 +305,27 @@ double FGPanelApplication::Sleep() // This yields the most accurate timing. If the previous // usleep() call is omitted this will peg the cpu // (which is just fine if FG is the only app you care about.) - current_time_stamp.stamp(); - SGTimeStamp next_time_stamp = last_time_stamp; - next_time_stamp += SGTimeStamp::fromSec(1e-6*frame_us); - while ( current_time_stamp < next_time_stamp ) { - current_time_stamp.stamp(); + current_time_stamp.stamp (); + const SGTimeStamp next_time_stamp (last_time_stamp + SGTimeStamp::fromSec (1e-6*frame_us)); + while (current_time_stamp < next_time_stamp) { + current_time_stamp.stamp (); } } else { - current_time_stamp.stamp(); + current_time_stamp.stamp (); } - double real_delta_time_sec = double(current_time_stamp.toUSecs() - last_time_stamp.toUSecs()) / 1000000.0; + static double reminder = 0.0; + static long global_multi_loop = 0; + const double real_delta_time_sec ((double (current_time_stamp.toUSecs () - last_time_stamp.toUSecs ()) / 1000000.0) + reminder); last_time_stamp = current_time_stamp; //fprintf(stdout,"\r%4.1lf ", 1/real_delta_time_sec ); //fflush(stdout); // round the real time down to a multiple of 1/model-hz. // this way all systems are updated the _same_ amount of dt. - static double reminder = 0.0; - static long global_multi_loop = 0; - real_delta_time_sec += reminder; - global_multi_loop = long(floor(real_delta_time_sec*model_hz)); - global_multi_loop = SGMisc::max(0, global_multi_loop); - reminder = real_delta_time_sec - double(global_multi_loop)/double(model_hz); - return double(global_multi_loop)/double(model_hz); + global_multi_loop = long (floor (real_delta_time_sec * model_hz)); + global_multi_loop = SGMisc::max (0, global_multi_loop); + reminder = real_delta_time_sec - double (global_multi_loop) / double (model_hz); + return double (global_multi_loop) / double (model_hz); } - -double ApplicationProperties::getDouble( const char * name, double def ) -{ - SGPropertyNode_ptr n = ApplicationProperties::Properties->getNode( name, false ); - if( n == NULL ) return def; - return n->getDoubleValue(); -} - -SGPath ApplicationProperties::GetCwd() -{ - SGPath path("."); - char buf[512], *cwd = getcwd(buf, 511); - buf[511] = '\0'; - if (cwd) - { - path = SGPath::fromLocal8Bit(cwd); - } - return path; -} - -SGPath ApplicationProperties::GetRootPath( const char * sub ) -{ - if( sub != NULL ) - { - SGPath subpath( sub ); - - // relative path to current working dir? - if (subpath.isRelative()) - { - SGPath path = GetCwd(); - path.append( sub ); - if (path.exists()) - return path; - } - else - if ( subpath.exists() ) - { - // absolute path - return subpath; - } - } - - // default: relative path to FGROOT - SGPath path( ApplicationProperties::root ); - if( sub != NULL ) - path.append( sub ); - - return path; -} - -std::string ApplicationProperties::root = "."; -SGPropertyNode_ptr ApplicationProperties::Properties = new SGPropertyNode; -FGFontCache ApplicationProperties::fontCache; diff --git a/utils/fgpanel/FGPanelApplication.hxx b/utils/fgpanel/FGPanelApplication.hxx index f2652ee3a..f7540aa61 100644 --- a/utils/fgpanel/FGPanelApplication.hxx +++ b/utils/fgpanel/FGPanelApplication.hxx @@ -5,7 +5,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -18,32 +18,28 @@ #ifndef __FGPANELAPPLICATION_HXX #define __FGPANELAPPLICATION_HXX -#include "FGGLApplication.hxx" -#include "FGPanelProtocol.hxx" - #include -#include -#include - -#include "panel.hxx" +#include "FGGLApplication.hxx" +#include "FGPanel.hxx" +#include "FGPanelProtocol.hxx" class FGPanelApplication : public FGGLApplication { public: - FGPanelApplication( int argc, char ** argv ); - ~FGPanelApplication(); + FGPanelApplication (int argc, char **argv); + ~FGPanelApplication (); - void Run(); + void Run (); protected: - virtual void Key( unsigned char key, int x, int y ); - virtual void Idle(); -// virtual void Display(); - virtual void Reshape( int width, int height ); + virtual void Key (const unsigned char key, const int x, const int y); + virtual void Idle (); + // !!! virtual void Display (); + virtual void Reshape (const int width, const int height); - virtual void Init(); + virtual void Init (); - double Sleep(); + double Sleep (); SGSharedPtr panel; SGSharedPtr protocol; diff --git a/utils/fgpanel/FGPanelInstrument.cxx b/utils/fgpanel/FGPanelInstrument.cxx new file mode 100644 index 000000000..3b924bb56 --- /dev/null +++ b/utils/fgpanel/FGPanelInstrument.cxx @@ -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; +} diff --git a/utils/fgpanel/FGPanelInstrument.hxx b/utils/fgpanel/FGPanelInstrument.hxx new file mode 100644 index 000000000..c2a43adf1 --- /dev/null +++ b/utils/fgpanel/FGPanelInstrument.hxx @@ -0,0 +1,56 @@ +// +// Written by David Megginson, started January 2000. +// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef FGPANELINSTRUMENT_HXX +#define FGPANELINSTRUMENT_HXX + +#include + +using namespace std; + +/** + * Abstract base class for a panel instrument. + * + * A panel instrument consists of zero or more actions, associated + * with mouse clicks in rectangular areas. Currently, the only + * concrete class derived from this is FGLayeredInstrument, but others + * may show up in the future (some complex instruments could be + * entirely hand-coded, for example). + */ +class FGPanelInstrument : public SGConditional { +public: + FGPanelInstrument (); + FGPanelInstrument (const int x, const int y, const int w, const int h); + virtual ~FGPanelInstrument (); + + virtual void draw () = 0; + + virtual void setPosition (const int x, const int y); + virtual void setSize (const int w, const int h); + + virtual int getXPos () const; + virtual int getYPos () const; + virtual int getWidth () const; + virtual int getHeight () const; + +private: + int m_x, m_y, m_w, m_h; +}; + +#endif diff --git a/utils/fgpanel/FGPanelProtocol.cxx b/utils/fgpanel/FGPanelProtocol.cxx index d11c1c615..9c4f970f3 100644 --- a/utils/fgpanel/FGPanelProtocol.cxx +++ b/utils/fgpanel/FGPanelProtocol.cxx @@ -5,7 +5,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -27,92 +27,92 @@ #define strtof strtod #endif -#include "FGPanelProtocol.hxx" -#include "ApplicationProperties.hxx" #include #include -using namespace std; +#include "ApplicationProperties.hxx" +#include "FGPanelProtocol.hxx" class PropertySetter { public: - PropertySetter( SGPropertyNode_ptr node ) : _node(node) {} - virtual void setValue( const char * value ) = 0; - virtual ~PropertySetter() {}; + PropertySetter (SGPropertyNode_ptr node) : _node (node) {} + virtual void setValue (const char *value) = 0; + virtual ~PropertySetter () {}; protected: SGPropertyNode_ptr _node; }; class BoolPropertySetter : public PropertySetter { public: - BoolPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {} - virtual void setValue( const char * value ) { - _node->setBoolValue( atoi( value ) != 0 ); + BoolPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {} + virtual void setValue (const char *value) { + _node->setBoolValue (atoi (value) != 0 ); } }; class IntPropertySetter : public PropertySetter { public: - IntPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {} - virtual void setValue( const char * value ) { - _node->setIntValue( atol( value ) ); + IntPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {} + virtual void setValue (const char *value) { + _node->setIntValue (atol (value)); } }; class FloatPropertySetter : public PropertySetter { public: - FloatPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {} - virtual void setValue( const char * value ) { - _node->setFloatValue( strtof( value, NULL ) ); + FloatPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {} + virtual void setValue (const char *value) { + _node->setFloatValue (strtof (value, NULL)); } }; class DoublePropertySetter : public PropertySetter { public: - DoublePropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {} - virtual void setValue( const char * value ) { - _node->setDoubleValue( strtod( value, NULL ) ); + DoublePropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {} + virtual void setValue (const char *value) { + _node->setDoubleValue (strtod (value, NULL)); } }; class StringPropertySetter : public PropertySetter { public: - StringPropertySetter( SGPropertyNode_ptr node ) : PropertySetter(node) {} - virtual void setValue( const char * value ) { - _node->setStringValue( value ); + StringPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {} + virtual void setValue (const char *value) { + _node->setStringValue (value); } }; -FGPanelProtocol::FGPanelProtocol( SGPropertyNode_ptr aRoot ) - : SGSubsystem(), - root(aRoot), - io(NULL) -{ - SGPropertyNode_ptr outputNode = root->getNode( "protocol/generic/output" ); - if( outputNode ) { - vector chunks = outputNode->getChildren( "chunk" ); - for( vector::size_type i = 0; i < chunks.size(); i++ ) { - SGPropertyNode_ptr chunk = chunks[i]; +FGPanelProtocol::FGPanelProtocol (SGPropertyNode_ptr a_Root) : + SGSubsystem (), + root (a_Root), + io (NULL) { + const SGPropertyNode_ptr outputNode (root->getNode ("protocol/generic/output")); + if (outputNode) { + const vector chunks (outputNode->getChildren ("chunk")); + for (vector::size_type i = 0; i < chunks.size (); i++) { + const SGPropertyNode_ptr chunk (chunks[i]); - SGPropertyNode_ptr nodeNode = chunk->getNode("node", false ); - if( nodeNode == NULL ) + const SGPropertyNode_ptr nodeNode (chunk->getNode ("node", false)); + if (nodeNode == NULL) { continue; + } + const SGPropertyNode_ptr node (ApplicationProperties::Properties->getNode (nodeNode->getStringValue (), true)); - SGPropertyNode_ptr node = ApplicationProperties::Properties->getNode( nodeNode->getStringValue(), true ); - - string type = ""; - SGPropertyNode_ptr typeNode = chunk->getNode( "type", false ); - if( typeNode != NULL ) type = typeNode->getStringValue(); - if( type == "float" ) { - propertySetterVector.push_back( new FloatPropertySetter( node ) ); - } else if( type == "double" || type == "fixed" ) { - propertySetterVector.push_back( new DoublePropertySetter( node ) ); - } else if( type == "bool" || type == "boolean" ) { - propertySetterVector.push_back( new BoolPropertySetter( node ) ); - } else if( type == "string" ) { - propertySetterVector.push_back( new StringPropertySetter( node ) ); + string type; + const SGPropertyNode_ptr typeNode (chunk->getNode ("type", false)); + if (typeNode != NULL) { + type = typeNode->getStringValue (); + } + if (type == "float") { + propertySetterVector.push_back (new FloatPropertySetter (node)); + } else if (type == "double" || type == "fixed") { + propertySetterVector.push_back (new DoublePropertySetter (node)); + } else if (type == "bool" || type == "boolean") { + propertySetterVector.push_back (new BoolPropertySetter (node)); + } else if (type == "string") { + propertySetterVector.push_back (new StringPropertySetter (node)); } else { - propertySetterVector.push_back( new IntPropertySetter( node ) ); + propertySetterVector.push_back (new IntPropertySetter (node)); } } } @@ -120,60 +120,60 @@ FGPanelProtocol::FGPanelProtocol( SGPropertyNode_ptr aRoot ) FGPanelProtocol::~FGPanelProtocol() { - for( PropertySetterVector::size_type i = 0; i < propertySetterVector.size(); i++ ) + for (PropertySetterVector::size_type i = 0; i < propertySetterVector.size(); i++) { delete propertySetterVector[i]; + } } -void FGPanelProtocol::update( double dt ) -{ +void +FGPanelProtocol::update (double dt) { char buf[2][8192]; - if( io == NULL ) + if (io == NULL) { return; - + } // read all available lines, keep last one - int Page = 0; - bool HaveData = false; - while ( io->readline( buf[Page], sizeof(buf[Page])-1 ) > 0 ) - { - HaveData = true; - Page ^= 1; + int Page (0); + bool HaveData (false); + while (io->readline (buf[Page], sizeof (buf[Page]) - 1) > 0) { + HaveData = true; + Page ^= 1; } - if ( HaveData ) { + if (HaveData) { // process most recent line of data Page ^= 1; - buf[Page][sizeof(buf[Page])-1] = 0; - vector tokens = simgear::strutils::split( buf[Page], "," ); - for( vector::size_type i = 0; i < tokens.size(); i++ ) { - if( i < propertySetterVector.size() ) - propertySetterVector[i]->setValue( tokens[i].c_str() ); + buf[Page][sizeof (buf[Page]) - 1] = 0; + const vector tokens (simgear::strutils::split (buf[Page], ",")); + for (vector::size_type i = 0; i < tokens.size (); i++) { + if (i < propertySetterVector.size ()) { + propertySetterVector[i]->setValue (tokens[i].c_str ()); + } } } } -void FGPanelProtocol::init() -{ - SGPropertyNode_ptr listenNode = root->getNode( "listen" ); - if( listenNode == NULL ) { +void +FGPanelProtocol::init () { + const SGPropertyNode_ptr listenNode (root->getNode ("listen")); + if (listenNode == NULL) { return; } + const string hostname (listenNode->getNode ("host", true)->getStringValue ()); + const string port (listenNode->getNode ("port", true)->getStringValue ()); + const string style (listenNode->getNode ("style", true)->getStringValue ()); - string hostname = listenNode->getNode( "host", true )->getStringValue(); - string port = listenNode->getNode( "port", true )->getStringValue(); - string style = listenNode->getNode( "style", true )->getStringValue(); - - if( io != NULL ) + if (io != NULL) { delete io; + } + io = new SGSocket (hostname, port, style); - io = new SGSocket( hostname, port, style ); - - if( !io->open( SG_IO_IN ) ) { + if (!io->open (SG_IO_IN)) { cerr << "can't open socket " << style << ":" << hostname << ":" << port << endl; } } -void FGPanelProtocol::reinit() -{ - init(); +void +FGPanelProtocol::reinit () { + init (); } diff --git a/utils/fgpanel/FGPanelProtocol.hxx b/utils/fgpanel/FGPanelProtocol.hxx index 69cb672f3..c58e2f1d3 100644 --- a/utils/fgpanel/FGPanelProtocol.hxx +++ b/utils/fgpanel/FGPanelProtocol.hxx @@ -5,7 +5,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -17,25 +17,31 @@ // #ifndef __FGPANELPROTOCOL_HXX #define __FGPANELPROTOCOL_HXX + #include #include #include + +using namespace std; + class PropertySetter; -typedef std::vector PropertySetterVector; +typedef vector PropertySetterVector; + class FGPanelProtocol : public SGSubsystem { public: - FGPanelProtocol( SGPropertyNode_ptr root ); - virtual ~FGPanelProtocol(); - virtual void init(); - virtual void reinit(); - virtual void update( double dt ); + FGPanelProtocol (SGPropertyNode_ptr a_Root); + virtual ~FGPanelProtocol (); + virtual void init (); + virtual void reinit (); + virtual void update (double dt); protected: private: SGPropertyNode_ptr root; - SGIOChannel * io; + SGIOChannel *io; PropertySetterVector propertySetterVector; }; + #endif diff --git a/utils/fgpanel/FGPanelTransformation.cxx b/utils/fgpanel/FGPanelTransformation.cxx new file mode 100644 index 000000000..2bc9ec527 --- /dev/null +++ b/utils/fgpanel/FGPanelTransformation.cxx @@ -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; +} diff --git a/utils/fgpanel/FGPanelTransformation.hxx b/utils/fgpanel/FGPanelTransformation.hxx new file mode 100644 index 000000000..ebf8e1951 --- /dev/null +++ b/utils/fgpanel/FGPanelTransformation.hxx @@ -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 +#include +#include + +/** + * 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 diff --git a/utils/fgpanel/FGRGBTextureLoader.cxx b/utils/fgpanel/FGRGBTextureLoader.cxx index e5dbe6e03..27b6337fd 100644 --- a/utils/fgpanel/FGRGBTextureLoader.cxx +++ b/utils/fgpanel/FGRGBTextureLoader.cxx @@ -3,7 +3,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -25,23 +25,25 @@ #include #endif -#include "FGRGBTextureLoader.hxx" #if defined (SG_MAC) #include #include +#elif defined (_GLES2) +#include #else +#include // Must be included before #include #include #endif #include #include -#include #include #include -typedef struct _rawImageRec -{ +#include "FGRGBTextureLoader.hxx" + +typedef struct _rawImageRec { unsigned short imagic; unsigned short type; unsigned short dim; @@ -50,145 +52,138 @@ typedef struct _rawImageRec unsigned long wasteBytes; char name[80]; unsigned long colorMap; - std::istream *file; + istream *file; unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA; unsigned long rleEnd; GLuint *rowStart; GLint *rowSize; GLenum swapFlag; short bpc; - - typedef unsigned char * BytePtr; - bool needsBytesSwapped() - { + typedef unsigned char *BytePtr; + + bool needsBytesSwapped () { union { int testWord; - char testByte[sizeof(int)]; - }endianTest; + char testByte[sizeof (int)]; + } endianTest; endianTest.testWord = 1; - if( endianTest.testByte[0] == 1 ) + if (endianTest.testByte[0] == 1) { return true; - else + } else { return false; + } } template - inline void swapBytes( T &s ) - { - if( sizeof( T ) == 1 ) - return; + inline void swapBytes (T &s) { + if (sizeof (T) == 1) { + return; + } + T d = s; + BytePtr sptr ((BytePtr) &s); + BytePtr dptr = &(((BytePtr) &d)[sizeof (T) - 1]); - T d = s; - BytePtr sptr = (BytePtr)&s; - BytePtr dptr = &(((BytePtr)&d)[sizeof(T)-1]); - - for( unsigned int i = 0; i < sizeof(T); i++ ) - *(sptr++) = *(dptr--); + for (unsigned int i = 0; i < sizeof (T); i++) { + *(sptr++) = *(dptr--); + } } - void swapBytes() - { - swapBytes( imagic ); - swapBytes( type ); - swapBytes( dim ); - swapBytes( sizeX ); - swapBytes( sizeY ); - swapBytes( sizeZ ); - swapBytes( wasteBytes ); - swapBytes( min ); - swapBytes( max ); - swapBytes( colorMap ); + void swapBytes () { + swapBytes (imagic); + swapBytes (type); + swapBytes (dim); + swapBytes (sizeX); + swapBytes (sizeY); + swapBytes (sizeZ); + swapBytes (wasteBytes); + swapBytes (min); + swapBytes (max); + swapBytes (colorMap); } } rawImageRec; -static void ConvertShort(unsigned short *array, long length) -{ +static void +ConvertShort (unsigned short *array, long length) { unsigned long b1, b2; - unsigned char *ptr; - - ptr = (unsigned char *)array; - while (length--) - { - b1 = *ptr++; - b2 = *ptr++; - *array++ = (unsigned short) ((b1 << 8) | (b2)); + unsigned char *ptr ((unsigned char *) array); + while (length--) { + b1 = *ptr++; + b2 = *ptr++; + *array++ = (unsigned short) ((b1 << 8) | (b2)); } } -static void ConvertLong(GLuint *array, long length) -{ +static void +ConvertLong (GLuint *array, long length) { unsigned long b1, b2, b3, b4; - unsigned char *ptr; - - ptr = (unsigned char *)array; - while (length--) - { - b1 = *ptr++; - b2 = *ptr++; - b3 = *ptr++; - b4 = *ptr++; - *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4); + unsigned char *ptr ((unsigned char *) array); + while (length--) { + b1 = *ptr++; + b2 = *ptr++; + b3 = *ptr++; + b4 = *ptr++; + *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4); } } - -static void RawImageClose(rawImageRec *raw) -{ - if (raw) - { - - if (raw->tmp) delete [] raw->tmp; - if (raw->tmpR) delete [] raw->tmpR; - if (raw->tmpG) delete [] raw->tmpG; - if (raw->tmpB) delete [] raw->tmpB; - if (raw->tmpA) delete [] raw->tmpA; - - if (raw->rowStart) delete [] raw->rowStart; - if (raw->rowSize) delete [] raw->rowSize; - - delete raw; +static void +RawImageClose (rawImageRec *raw) { + if (raw) { + if (raw->tmp) { + delete []raw->tmp; + } + if (raw->tmpR) { + delete []raw->tmpR; + } + if (raw->tmpG) { + delete []raw->tmpG; + } + if (raw->tmpB) { + delete []raw->tmpB; + } + if (raw->tmpA) { + delete []raw->tmpA; + } + if (raw->rowStart) { + delete []raw->rowStart; + } + if (raw->rowSize) { + delete []raw->rowSize; + } + delete raw; } } - -static rawImageRec *RawImageOpen(std::istream& fin) -{ - union - { - int testWord; - char testByte[4]; +static rawImageRec * +RawImageOpen (istream& fin) { + union { + int testWord; + char testByte[4]; } endianTest; - rawImageRec *raw; - int x; - raw = new rawImageRec; - if (raw == NULL) - { -// notify(WARN)<< "Out of memory!"<< std::endl; - return NULL; + rawImageRec *raw = new rawImageRec; + if (raw == NULL) { +// notify(WARN)<< "Out of memory!"<< endl; + return NULL; } //Set istream pointer raw->file = &fin; endianTest.testWord = 1; - if (endianTest.testByte[0] == 1) - { - raw->swapFlag = GL_TRUE; - } - else - { - raw->swapFlag = GL_FALSE; + if (endianTest.testByte[0] == 1) { + raw->swapFlag = GL_TRUE; + } else { + raw->swapFlag = GL_FALSE; } - fin.read((char*)raw,12); - if (!fin.good()) - return NULL; - - if (raw->swapFlag) - { - ConvertShort(&raw->imagic, 6); + fin.read ((char*) raw, 12); + if (!fin.good ()) { + return NULL; + } + if (raw->swapFlag) { + ConvertShort (&raw->imagic, 6); } raw->tmp = raw->tmpR = raw->tmpG = raw->tmpB = raw->tmpA = 0L; @@ -196,259 +191,228 @@ static rawImageRec *RawImageOpen(std::istream& fin) raw->rowSize = 0; raw->bpc = (raw->type & 0x00FF); - raw->tmp = new unsigned char [raw->sizeX*256*raw->bpc]; - if (raw->tmp == NULL ) - { -// notify(FATAL)<< "Out of memory!"<< std::endl; - RawImageClose(raw); + raw->tmp = new unsigned char[raw->sizeX * 256 * raw->bpc]; + if (raw->tmp == NULL ) { +// notify(FATAL)<< "Out of memory!"<< endl; + RawImageClose (raw); + return NULL; + } + + if (raw->sizeZ >= 1) { + if ((raw->tmpR = new unsigned char[raw->sizeX * raw->bpc]) == NULL) { +// notify(FATAL)<< "Out of memory!"<< endl; + RawImageClose (raw); return NULL; + } + } + if (raw->sizeZ >= 2) { + if ((raw->tmpG = new unsigned char[raw->sizeX * raw->bpc]) == NULL) { +// notify(FATAL)<< "Out of memory!"<< endl; + RawImageClose (raw); + return NULL; + } + } + if (raw->sizeZ >= 3) { + if ((raw->tmpB = new unsigned char[raw->sizeX*raw->bpc]) == NULL) { +// notify(FATAL)<< "Out of memory!"<< endl; + RawImageClose (raw); + return NULL; + } + } + if (raw->sizeZ >= 4) { + if ((raw->tmpA = new unsigned char[raw->sizeX * raw->bpc]) == NULL) { +// notify(FATAL)<< "Out of memory!"<< endl; + RawImageClose (raw); + return NULL; + } } - if( raw->sizeZ >= 1 ) - { - if( (raw->tmpR = new unsigned char [raw->sizeX*raw->bpc]) == NULL ) - { -// notify(FATAL)<< "Out of memory!"<< std::endl; - RawImageClose(raw); - return NULL; - } - } - if( raw->sizeZ >= 2 ) - { - if( (raw->tmpG = new unsigned char [raw->sizeX*raw->bpc]) == NULL ) - { -// notify(FATAL)<< "Out of memory!"<< std::endl; - RawImageClose(raw); - return NULL; - } - } - if( raw->sizeZ >= 3 ) - { - if( (raw->tmpB = new unsigned char [raw->sizeX*raw->bpc]) == NULL ) - { -// notify(FATAL)<< "Out of memory!"<< std::endl; - RawImageClose(raw); - return NULL; - } - } - if (raw->sizeZ >= 4) - { - if( (raw->tmpA = new unsigned char [raw->sizeX*raw->bpc]) == NULL ) - { -// notify(FATAL)<< "Out of memory!"<< std::endl; - RawImageClose(raw); - return NULL; - } - } - - if ((raw->type & 0xFF00) == 0x0100) - { - unsigned int ybyz = raw->sizeY * raw->sizeZ; - if ( (raw->rowStart = new GLuint [ybyz]) == NULL ) - { -// notify(FATAL)<< "Out of memory!"<< std::endl; - RawImageClose(raw); - return NULL; - } + if ((raw->type & 0xFF00) == 0x0100) { + unsigned int ybyz (raw->sizeY * raw->sizeZ); + if ((raw->rowStart = new GLuint[ybyz]) == NULL) { +// notify(FATAL)<< "Out of memory!"<< endl; + RawImageClose (raw); + return NULL; + } - if ( (raw->rowSize = new GLint [ybyz]) == NULL ) - { -// notify(FATAL)<< "Out of memory!"<< std::endl; - RawImageClose(raw); - return NULL; - } - x = ybyz * sizeof(GLuint); - raw->rleEnd = 512 + (2 * x); - fin.seekg(512,std::ios::beg); - fin.read((char*)raw->rowStart,x); - fin.read((char*)raw->rowSize,x); - if (raw->swapFlag) - { - ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint))); - ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint))); - } + if ((raw->rowSize = new GLint[ybyz]) == NULL) { +// notify(FATAL)<< "Out of memory!"<< endl; + RawImageClose (raw); + return NULL; + } + int x (ybyz * sizeof (GLuint)); + raw->rleEnd = 512 + (2 * x); + fin.seekg (512, ios::beg); + fin.read ((char*) raw->rowStart, x); + fin.read ((char*) raw->rowSize, x); + if (raw->swapFlag) { + ConvertLong (raw->rowStart, long (x / sizeof (GLuint))); + ConvertLong ((GLuint *) raw->rowSize, long (x /sizeof (GLint))); + } } return raw; } - -static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z) -{ - unsigned char *iPtr, *oPtr; +static void +RawImageGetRow (rawImageRec *raw, unsigned char *buf, const int y, const int z) { unsigned short pixel; - int count, done = 0; + int done = 0; unsigned short *tempShort; - if ((raw->type & 0xFF00) == 0x0100) - { - raw->file->seekg((long) raw->rowStart[y+z*raw->sizeY], std::ios::beg); - raw->file->read((char*)raw->tmp, (unsigned int)raw->rowSize[y+z*raw->sizeY]); + if ((raw->type & 0xFF00) == 0x0100) { + raw->file->seekg (long (raw->rowStart[y + z * raw->sizeY]), ios::beg); + raw->file->read ((char*) raw->tmp, (unsigned int) (raw->rowSize[y + z * raw->sizeY])); - iPtr = raw->tmp; - oPtr = buf; - while (!done) - { - if (raw->bpc == 1) - pixel = *iPtr++; - else - { - tempShort = reinterpret_cast(iPtr); - pixel = *tempShort; - tempShort++; - iPtr = reinterpret_cast(tempShort); - } - - if(raw->bpc != 1) - ConvertShort(&pixel, 1); - - count = (int)(pixel & 0x7F); - - // limit the count value to the remiaing row size - if (oPtr + count*raw->bpc > buf + raw->sizeX*raw->bpc) - { - count = ( (buf + raw->sizeX*raw->bpc) - oPtr ) / raw->bpc; - } - - if (count<=0) - { - done = 1; - return; - } - - if (pixel & 0x80) - { - while (count--) - { - if(raw->bpc == 1) - *oPtr++ = *iPtr++; - else{ - tempShort = reinterpret_cast(iPtr); - pixel = *tempShort; - tempShort++; - iPtr = reinterpret_cast(tempShort); - - ConvertShort(&pixel, 1); - - tempShort = reinterpret_cast(oPtr); - *tempShort = pixel; - tempShort++; - oPtr = reinterpret_cast(tempShort); - } - } - } - else - { - if (raw->bpc == 1) - { - pixel = *iPtr++; - } - else - { - tempShort = reinterpret_cast(iPtr); - pixel = *tempShort; - tempShort++; - iPtr = reinterpret_cast(tempShort); - } - if(raw->bpc != 1) - ConvertShort(&pixel, 1); - while (count--) - { - if(raw->bpc == 1) - *oPtr++ = pixel; - else - { - tempShort = reinterpret_cast(oPtr); - *tempShort = pixel; - tempShort++; - oPtr = reinterpret_cast(tempShort); - } - } - } + unsigned char *iPtr = raw->tmp; + unsigned char *oPtr = buf; + while (!done) { + if (raw->bpc == 1) { + pixel = *iPtr++; + } else { + tempShort = reinterpret_cast (iPtr); + pixel = *tempShort; + tempShort++; + iPtr = reinterpret_cast (tempShort); } - } - else - { - raw->file->seekg(512+(y*raw->sizeX*raw->bpc)+(z*raw->sizeX*raw->sizeY*raw->bpc),std::ios::beg); - raw->file->read((char*)buf, raw->sizeX*raw->bpc); - if(raw->swapFlag && raw->bpc != 1){ - ConvertShort(reinterpret_cast(buf), raw->sizeX); + + if (raw->bpc != 1) { + ConvertShort (&pixel, 1); } + int count (int (pixel & 0x7F)); + + // limit the count value to the remiaing row size + if (oPtr + count * raw->bpc > buf + raw->sizeX * raw->bpc) { + count = ((buf + raw->sizeX * raw->bpc) - oPtr) / raw->bpc; + } + + if (count <= 0) { + done = 1; + return; + } + + if (pixel & 0x80) { + while (count--) { + if (raw->bpc == 1) { + *oPtr++ = *iPtr++; + } else { + tempShort = reinterpret_cast (iPtr); + pixel = *tempShort; + tempShort++; + iPtr = reinterpret_cast (tempShort); + + ConvertShort (&pixel, 1); + + tempShort = reinterpret_cast (oPtr); + *tempShort = pixel; + tempShort++; + oPtr = reinterpret_cast (tempShort); + } + } + } else { + if (raw->bpc == 1) { + pixel = *iPtr++; + } else { + tempShort = reinterpret_cast (iPtr); + pixel = *tempShort; + tempShort++; + iPtr = reinterpret_cast (tempShort); + } + if (raw->bpc != 1) { + ConvertShort (&pixel, 1); + } + while (count--) { + if (raw->bpc == 1) { + *oPtr++ = pixel; + } else { + tempShort = reinterpret_cast (oPtr); + *tempShort = pixel; + tempShort++; + oPtr = reinterpret_cast (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 (buf), raw->sizeX); + } } } - -static void RawImageGetData(rawImageRec *raw, unsigned char **data ) -{ - unsigned char *ptr; - int i, j; - unsigned short *tempShort; +static void +RawImageGetData (rawImageRec *raw, unsigned char **data) { // // round the width to a factor 4 // int width = (int)(floorf((float)raw->sizeX/4.0f)*4.0f); // if (width!=raw->sizeX) width += 4; // byte aligned. - -// osg::notify(osg::INFO)<<"raw->sizeX = "<sizeX<sizeY = "<sizeY<sizeZ = "<sizeZ<bpc = "<bpc<sizeX)*(raw->sizeY)*(raw->sizeZ)*(raw->bpc)]; - ptr = *data; - for (i = 0; i < (int)(raw->sizeY); i++) - { - if( raw->sizeZ >= 1 ) - RawImageGetRow(raw, raw->tmpR, i, 0); - if( raw->sizeZ >= 2 ) - RawImageGetRow(raw, raw->tmpG, i, 1); - if( raw->sizeZ >= 3 ) - RawImageGetRow(raw, raw->tmpB, i, 2); - if( raw->sizeZ >= 4 ) - RawImageGetRow(raw, raw->tmpA, i, 3); - for (j = 0; j < (int)(raw->sizeX); j++) - { - if(raw->bpc == 1){ - if( raw->sizeZ >= 1 ) - *ptr++ = *(raw->tmpR + j); - if( raw->sizeZ >= 2 ) - *ptr++ = *(raw->tmpG + j); - if( raw->sizeZ >= 3 ) - *ptr++ = *(raw->tmpB + j); - if( raw->sizeZ >= 4 ) - *ptr++ = *(raw->tmpA + j); - }else{ - if( raw->sizeZ >= 1 ) - { - tempShort = reinterpret_cast(ptr); - *tempShort = *(reinterpret_cast(raw->tmpR) + j); - tempShort++; - ptr = reinterpret_cast(tempShort); - } - if( raw->sizeZ >= 2 ) - { - tempShort = reinterpret_cast(ptr); - *tempShort = *(reinterpret_cast(raw->tmpG) + j); - tempShort++; - ptr = reinterpret_cast(tempShort); - } - if( raw->sizeZ >= 3 ) - { - tempShort = reinterpret_cast(ptr); - *tempShort = *(reinterpret_cast(raw->tmpB) + j); - tempShort++; - ptr = reinterpret_cast(tempShort); - } - if( raw->sizeZ >= 4 ) - { - tempShort = reinterpret_cast(ptr); - *tempShort = *(reinterpret_cast(raw->tmpA) + j); - tempShort++; - ptr = reinterpret_cast(tempShort); - } +// osg::notify(osg::INFO)<<"raw->sizeX = "<sizeX<sizeY = "<sizeY<sizeZ = "<sizeZ<bpc = "<bpc<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 (ptr); + *tempShort = *(reinterpret_cast (raw->tmpR) + j); + tempShort++; + ptr = reinterpret_cast (tempShort); + } + if (raw->sizeZ >= 2) { + tempShort = reinterpret_cast (ptr); + *tempShort = *(reinterpret_cast (raw->tmpG) + j); + tempShort++; + ptr = reinterpret_cast (tempShort); + } + if (raw->sizeZ >= 3) { + tempShort = reinterpret_cast (ptr); + *tempShort = *(reinterpret_cast (raw->tmpB) + j); + tempShort++; + ptr = reinterpret_cast (tempShort); + } + if (raw->sizeZ >= 4) { + tempShort = reinterpret_cast (ptr); + *tempShort = *(reinterpret_cast (raw->tmpA) + j); + tempShort++; + ptr = reinterpret_cast (tempShort); + } } + } // // pad the image width with blanks to bring it up to the rounded width. // for(;jsizeX; - int t = raw->sizeY; -// int r = 1; + if (raw == NULL) { + return 0; + } - #if 0 - int internalFormat = raw->sizeZ == 3 ? GL_RGB5 : - raw->sizeZ == 4 ? GL_RGB5_A1 : GL_RGB; - #else -// int internalFormat = raw->sizeZ; - #endif - unsigned int pixelFormat = - raw->sizeZ == 1 ? GL_LUMINANCE : - raw->sizeZ == 2 ? GL_LUMINANCE_ALPHA : - raw->sizeZ == 3 ? GL_RGB : - raw->sizeZ == 4 ? GL_RGBA : (GLenum)-1; - GLint component = raw->sizeZ; + const int s (raw->sizeX); + const int t (raw->sizeY); + // int r = 1; - unsigned int dataType = raw->bpc == 1 ? GL_UNSIGNED_BYTE : - GL_UNSIGNED_SHORT; +#if 0 + int internalFormat = raw->sizeZ == 3 ? GL_RGB5 : + raw->sizeZ == 4 ? GL_RGB5_A1 : GL_RGB; +#else + // int internalFormat = raw->sizeZ; +#endif + const unsigned int pixelFormat + (raw->sizeZ == 1 ? GL_LUMINANCE : + raw->sizeZ == 2 ? GL_LUMINANCE_ALPHA : + raw->sizeZ == 3 ? GL_RGB : + raw->sizeZ == 4 ? GL_RGBA : (GLenum) - 1); - unsigned char *data; - RawImageGetData(raw, &data); - RawImageClose(raw); + const unsigned int dataType (raw->bpc == 1 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT); + + unsigned char *data; + RawImageGetData (raw, &data); + RawImageClose (raw); GLuint texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - gluBuild2DMipmaps( GL_TEXTURE_2D, component, s, t, pixelFormat, dataType, (GLvoid*)data ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + glGenTextures (1, &texture); + glBindTexture (GL_TEXTURE_2D, texture); + glTexImage2D (GL_TEXTURE_2D, 0, pixelFormat, s, t, 0, pixelFormat, dataType, (GLvoid*) data); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - delete []data; - return texture; - } - -GLuint FGRGBTextureLoader::loadTexture( const std::string & filename ) -{ - GLuint texture = NOTEXTURE; - std::ifstream istream(filename.c_str(), std::ios::in | std::ios::binary ); - texture = readRGBStream(istream); - istream.close(); + delete []data; return texture; } +GLuint +FGRGBTextureLoader::loadTexture (const string &filename) { + GLuint texture = NOTEXTURE; + ifstream istream (filename.c_str (), ios::in | ios::binary); + texture = readRGBStream (istream); + istream.close (); + return texture; +} diff --git a/utils/fgpanel/FGRGBTextureLoader.hxx b/utils/fgpanel/FGRGBTextureLoader.hxx index e3c27664b..84a4b56a4 100644 --- a/utils/fgpanel/FGRGBTextureLoader.hxx +++ b/utils/fgpanel/FGRGBTextureLoader.hxx @@ -1,8 +1,9 @@ +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -19,8 +20,9 @@ class FGRGBTextureLoader : public FGTextureLoaderInterface { public: - virtual GLuint loadTexture( const std::string & filename ); + virtual GLuint loadTexture (const string &filename); const static GLuint NOTEXTURE = 0; }; + #endif diff --git a/utils/fgpanel/FGSwitchLayer.cxx b/utils/fgpanel/FGSwitchLayer.cxx new file mode 100644 index 000000000..eb4d57566 --- /dev/null +++ b/utils/fgpanel/FGSwitchLayer.cxx @@ -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; + } + } + } +} diff --git a/utils/fgpanel/FGSwitchLayer.hxx b/utils/fgpanel/FGSwitchLayer.hxx new file mode 100644 index 000000000..31f069777 --- /dev/null +++ b/utils/fgpanel/FGSwitchLayer.hxx @@ -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 diff --git a/utils/fgpanel/FGTextLayer.cxx b/utils/fgpanel/FGTextLayer.cxx new file mode 100644 index 000000000..8ca9de1fe --- /dev/null +++ b/utils/fgpanel/FGTextLayer.cxx @@ -0,0 +1,301 @@ +// +// Written by David Megginson, started January 2000. +// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "ApplicationProperties.hxx" +#include "GL_utils.hxx" +#include "FGTextLayer.hxx" + +SGPath FGTextLayer::The_Font_Path; + +FGFontCache FGTextLayer::The_Font_Cache; + +GLuint FGTextLayer::Text_Layer_Program_Object (0); +GLint FGTextLayer::Text_Layer_Position_Loc (0); +GLint FGTextLayer::Text_Layer_Tex_Coord_Loc (0); +GLint FGTextLayer::Text_Layer_MVP_Loc (0); +GLint FGTextLayer::Text_Layer_Sampler_Loc (0); +GLint FGTextLayer::Text_Layer_Color_Loc (0); + +bool +FGTextLayer::Init () { + const char V_Text_Layer_Shader_Str[] = +#ifdef _GLES2 + "attribute vec4 a_position; \n" + "attribute vec2 a_tex_coord; \n" +#else + "#version 330 \n" + "in vec4 a_position; \n" + "in vec2 a_tex_coord; \n" +#endif + "uniform mat4 u_mvp_matrix; \n" + "varying vec2 v_tex_coord; \n" + "void main () { \n" + " gl_Position = u_mvp_matrix * a_position; \n" + " v_tex_coord = a_tex_coord; \n" + "} \n"; + + const char F_Text_Layer_Shader_Str[] = +#ifdef _GLES2 + "precision mediump float; \n" +#endif + "varying vec2 v_tex_coord; \n" + "uniform sampler2D u_texture; \n" + "uniform vec4 u_color; \n" + "void main () { \n" + " gl_FragColor = vec4 (1, 1, 1, \n" + " texture2D (u_texture, v_tex_coord).a) * \n" + " u_color; \n" + "} \n"; + + Text_Layer_Program_Object = GL_utils::instance ().load_program (V_Text_Layer_Shader_Str, + F_Text_Layer_Shader_Str); + if (Text_Layer_Program_Object == 0) { + return false; + } + + // Get the attribute locations + Text_Layer_Position_Loc = glGetAttribLocation (Text_Layer_Program_Object, "a_position"); + Text_Layer_Tex_Coord_Loc = glGetAttribLocation (Text_Layer_Program_Object, "a_tex_coord"); + + // Get the uniform locations + Text_Layer_MVP_Loc = glGetUniformLocation (Text_Layer_Program_Object, "u_mvp_matrix"); + + // Get the sampler location + Text_Layer_Sampler_Loc = glGetUniformLocation (Text_Layer_Program_Object, "u_texture"); + + // Get the color location + Text_Layer_Color_Loc = glGetUniformLocation (Text_Layer_Program_Object, "u_color"); + + return true; +} + +FGTextLayer::FGTextLayer (const int w, const int h) : + FGInstrumentLayer (w, h), + m_pointSize (0.0), + m_font_name () { + m_then.stamp (); + m_color[0] = m_color[1] = m_color[2] = 0.0; + m_color[3] = 1.0; +} + +FGTextLayer::~FGTextLayer () { + for (chunk_list::iterator It = m_chunks.begin (); + It != m_chunks.end (); + ++It) { + delete *It; + } +} + +void +FGTextLayer::draw () { + if (test ()) { + glUseProgram (Text_Layer_Program_Object); + glUniform4fv (Text_Layer_Color_Loc, 1, m_color); + + transform (); + + GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION); + GL_utils::instance ().glPushMatrix (); + GL_utils::instance ().glMultMatrixf + (*reinterpret_cast + (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 ""; + } +} diff --git a/utils/fgpanel/FGTextLayer.hxx b/utils/fgpanel/FGTextLayer.hxx new file mode 100644 index 000000000..e61930720 --- /dev/null +++ b/utils/fgpanel/FGTextLayer.hxx @@ -0,0 +1,111 @@ +// +// Written by David Megginson, started January 2000. +// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef FGTEXTLAYER_HXX +#define FGTEXTLAYER_HXX + +#include +#include + +#include "FGFontCache.hxx" +#include "FGInstrumentLayer.hxx" + +using namespace std; + +/** + * A text layer of an instrument. + * + * This is a layer holding a string of static and/or generated text. + * It is useful for instruments that have text displays, such as + * a chronometer, GPS, or NavCom radio. + */ + +class FGTextLayer : public FGInstrumentLayer { +public: + enum ChunkType { + TEXT, + TEXT_VALUE, + DOUBLE_VALUE + }; + + class Chunk : public SGConditional { + public: + Chunk (const string &text, + const string &fmt = "%s"); + Chunk (const ChunkType type, + const SGPropertyNode *node, + const string &fmt = "", + const float mult = 1.0, + const float offs = 0.0, + const bool truncation = false); + + const char *getValue () const; + private: + ChunkType m_type; + string m_text; + SGConstPropertyNode_ptr m_node; + string m_fmt; + float m_mult; + float m_offs; + bool m_trunc; + mutable char m_buf[1024]; + + }; + + static bool Init (); + + FGTextLayer (const int w = -1, const int h = -1); + virtual ~FGTextLayer (); + + virtual void draw (); + + // Transfer pointer!! + virtual void addChunk (Chunk * const chunk); + virtual void setColor (const float r, + const float g, + const float b); + virtual void setPointSize (const float size); + virtual void setFontName (const string &name); + +private: + + void recalc_value () const; + + typedef vector chunk_list; + chunk_list m_chunks; + float m_color[4]; + + float m_pointSize; + static SGPath The_Font_Path; + mutable string m_font_name; + mutable string m_value; + mutable SGTimeStamp m_then; + mutable SGTimeStamp m_now; + + static FGFontCache The_Font_Cache; + + static GLuint Text_Layer_Program_Object; + static GLint Text_Layer_Position_Loc; + static GLint Text_Layer_Tex_Coord_Loc; + static GLint Text_Layer_MVP_Loc; + static GLint Text_Layer_Sampler_Loc; + static GLint Text_Layer_Color_Loc; +}; + +#endif diff --git a/utils/fgpanel/FGTextureLoaderInterface.hxx b/utils/fgpanel/FGTextureLoaderInterface.hxx index 09009309c..4e36ae07e 100644 --- a/utils/fgpanel/FGTextureLoaderInterface.hxx +++ b/utils/fgpanel/FGTextureLoaderInterface.hxx @@ -5,7 +5,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -17,15 +17,25 @@ // #ifndef __FGTEXTURELOADERINTERFACE_HXX #define __FGTEXTURELOADERINTERFACE_HXX -#include + +#include + #if defined (SG_MAC) #include +#elif defined (_GLES2) +#include #else +#include // Must be included before #include #endif -#include + +#include + +using namespace std; + class FGTextureLoaderInterface { public: - virtual GLuint loadTexture( const std::string & filename ) = 0; + virtual GLuint loadTexture (const string &filename) = 0; }; + #endif diff --git a/utils/fgpanel/FGTexturedLayer.cxx b/utils/fgpanel/FGTexturedLayer.cxx new file mode 100644 index 000000000..0e19601ac --- /dev/null +++ b/utils/fgpanel/FGTexturedLayer.cxx @@ -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 + (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); +} diff --git a/utils/fgpanel/FGTexturedLayer.hxx b/utils/fgpanel/FGTexturedLayer.hxx new file mode 100644 index 000000000..2b86b757b --- /dev/null +++ b/utils/fgpanel/FGTexturedLayer.hxx @@ -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 diff --git a/utils/fgpanel/GLES_utils.cxx b/utils/fgpanel/GLES_utils.cxx new file mode 100644 index 000000000..c436a8c55 --- /dev/null +++ b/utils/fgpanel/GLES_utils.cxx @@ -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 +#include +#include +#include + +#ifdef _RPI +#include +#else +#include +#include +#include +#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; + } + } +} diff --git a/utils/fgpanel/GLES_utils.hxx b/utils/fgpanel/GLES_utils.hxx new file mode 100644 index 000000000..563ced020 --- /dev/null +++ b/utils/fgpanel/GLES_utils.hxx @@ -0,0 +1,81 @@ +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef GLES_UTILS_HXX +#define GLES_UTILS_HXX + +#include +#include + +#include +#include +#include + +using namespace std; + +class GLES_utils : private boost::noncopyable { +public: + static GLES_utils& instance (); + + void init (const string &title); + + void register_display_func (void (*display_func) ()); + void register_idle_func (void (*idle_func) ()); + void register_keyboard_func (void (*keyboard_func) (unsigned char, int, int)); + void register_reshape_func (void (*reshape_func) (int, int)); + + void main_loop (); + +private: + explicit GLES_utils (); + virtual ~GLES_utils (); + + typedef struct { +#ifdef _RPI + EGL_DISPMANX_WINDOW_T native_window; +#else + EGLNativeWindowType native_window; + Display *x_display; + GLint width; + GLint height; +#endif + EGLint major_version; + EGLint minor_version; + EGLint num_configs; + EGLDisplay display; + EGLSurface surface; + EGLContext context; + EGLConfig config; + } EGL_STATE_T; + + EGL_STATE_T m_State; + + void (*display_func) (); + void (*idle_func) (); + void (*keyboard_func) (unsigned char, int, int); + void (*reshape_func) (int, int); + + void print_config_info (const int n, const EGLDisplay &display, EGLConfig &config); + void init_egl (EGL_STATE_T &state, const GLuint flags); +#ifdef _RPI + void init_dispmanx (EGL_DISPMANX_WINDOW_T &native_window); +#else + void init_display (EGL_STATE_T &state, const string &title); +#endif + GLboolean user_interrupt (); +}; + +#endif diff --git a/utils/fgpanel/GL_utils.cxx b/utils/fgpanel/GL_utils.cxx new file mode 100644 index 000000000..c1d2a40b2 --- /dev/null +++ b/utils/fgpanel/GL_utils.cxx @@ -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 +#include +#include + +#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; + } + } +} diff --git a/utils/fgpanel/GL_utils.hxx b/utils/fgpanel/GL_utils.hxx new file mode 100644 index 000000000..b6bbaca55 --- /dev/null +++ b/utils/fgpanel/GL_utils.hxx @@ -0,0 +1,85 @@ +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef GL_UTILS_HXX +#define GL_UTILS_HXX + +#include +#include + +#if defined (SG_MAC) +#include +#elif defined (_GLES2) +#include +#else +#include // Must be included before +#include +#endif + +using namespace std; + +class GL_utils : private boost::noncopyable { +public: + static GL_utils& instance (); + + enum GLenum_Mode { + GL_UTILS_MODELVIEW, + GL_UTILS_PROJECTION, + GL_UTILS_TEXTURE, + GL_UTILS_COLOR, + GL_UTILS_LAST, + GL_UTILS_UNSET + }; + + GLuint load_program (const char *vert_shader_src, const char *frag_shader_src); + + void glMatrixMode (const GL_utils::GLenum_Mode mode); + void glLoadIdentity (); + void gluOrtho2D (const GLfloat left, + const GLfloat right, + const GLfloat bottom, + const GLfloat top); + void glOrtho (const GLfloat left, + const GLfloat right, + const GLfloat bottom, + const GLfloat top, + const GLfloat nearVal, + const GLfloat farVal); + void glTranslatef (const GLfloat x, const GLfloat y, const GLfloat z); + void glRotatef (const GLfloat angle, const GLfloat x, const GLfloat y, const GLfloat z); + void glScalef (const GLfloat x, const GLfloat y, const GLfloat z); + // C' = C X M + void glMultMatrixf (const GLfloat m[4][4]); + void glPushMatrix (); + void glPopMatrix (); + GLfloat* get_top_matrix (const GL_utils::GLenum_Mode mode); + void Debug (const GL_utils::GLenum_Mode mode) const; + +private: + explicit GL_utils (); + virtual ~GL_utils (); + + GLuint load_shader (GLenum type, const char *shader_src); + + typedef struct { + GLfloat m[4][4]; + } Matrix; + + stack m_Matrix[GL_UTILS_LAST]; + GLenum_Mode m_Current_Matrix_Mode; +}; + +#endif diff --git a/utils/fgpanel/README.RPi b/utils/fgpanel/README.RPi new file mode 100644 index 000000000..ac56fc14b --- /dev/null +++ b/utils/fgpanel/README.RPi @@ -0,0 +1,44 @@ +This is the FGPanel for the Raspberry Pi running Raspbian. +It should work with other Linux distributions but it has not been tested. + +INSTALLATION +============ + +1. Build SimGear as usual. + OSG, Plib, GLUT,... will be required even they are not strictly needed to run FGPanel. + +2. Configure FlightGear using CMake as usual. + CMakeLists.txt is used to compile FGPanel with OpenGL 2.0. + This should make FGPanel faster on modern graphics cards. + + CMakeLists.txt is used to compile FGPanel with OpenGL ES 2.0 for the Raspberry Pi. + The source code of FGPanel can easily be adapted to other embedded devices supporting OpenGL ES 2.0. + +3. Build FGPanel only (don't build all components on the Raspberry Pi as this will take ages!!!): + make -- fgpanel + +USAGE +===== + +1. Increase the amount of GPU memory by editing the /boot/config.txt file. + Add the following line (this is for Raspberry Pi model 1B with 512 Mb of memory): + gpu_mem_512=256 + +2. Reboot and check the amount of GPU memory: + vcgencmd get_mem gpu + +3. Stop X server. FGPanel runs in the console (Linux framebuffer). + +4. Start FGPanel as usual but as ROOT or use the 'sudo' command (see README): + sudo -- utils/fgpanel/fgpanel --fg-root=/path/to/fg/data --panel=Aircraft/MyAircraft/Panels/MyPanel.xml + + ROOT privileges are required to access the GPU of the Raspberry Pi. + +FEATURES +======== + +- Use OpenGL 2.0 instead of OpenGL 1.0 (fixed pipeline) using CMakeLists.txt. +- Use OpenGL ES 2.0 to run on the Raspberry Pi using CMakeLists.txt. +- Use VideoCore 4 graphics hardware acceleration (GPU) of the Raspberry Pi. +- Run at 30 frames per second. +- Don't use PLib anymore for the font rendering. diff --git a/utils/fgpanel/main.cxx b/utils/fgpanel/main.cxx index 80215e94a..d911bd2ea 100644 --- a/utils/fgpanel/main.cxx +++ b/utils/fgpanel/main.cxx @@ -5,7 +5,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -17,14 +17,14 @@ // #include "FGPanelApplication.hxx" -int main( int argc, char ** argv ) -{ +int +main (int argc, char ** argv) { try { - FGPanelApplication app(argc,argv); - app.Run(); + FGPanelApplication app (argc,argv); + app.Run (); return 0; } - catch( ... ) { + catch (...) { cerr << "Sorry, your program terminated." << endl; } } diff --git a/utils/fgpanel/panel.cxx b/utils/fgpanel/panel.cxx deleted file mode 100644 index 22d225038..000000000 --- a/utils/fgpanel/panel.cxx +++ /dev/null @@ -1,971 +0,0 @@ -// panel.cxx - default, 2D single-engine prop instrument panel -// -// Written by David Megginson, started January 2000. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id: panel.cxx,v 1.44 2006/09/05 20:28:48 curt Exp $ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef HAVE_WINDOWS_H -# include -#endif - -#include // sprintf -#include - -#include - -#if defined (SG_MAC) -#include -#else -#include -#endif - -#include - -#include -#include - -#include "panel.hxx" -#include "ApplicationProperties.hxx" -//////////////////////////////////////////////////////////////////////// -// Local functions. -//////////////////////////////////////////////////////////////////////// - -class FGDummyTextureLoader : public FGTextureLoaderInterface { -public: - virtual GLuint loadTexture( const string & filename ); -}; - -GLuint FGDummyTextureLoader::loadTexture( const string & filename ) -{ - GLuint _texture = 0; - glGenTextures( 1, &_texture ); - glBindTexture( GL_TEXTURE_2D, _texture ); - -// glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ; -// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) ; -// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ) ; -// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ) ; -// glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ) ; - - GLubyte image[ 2 * 2 * 3 ] ; - - /* Red and white chequerboard */ - image [ 0 ] = 255 ; image [ 1 ] = 0 ; image [ 2 ] = 0 ; - image [ 3 ] = 255 ; image [ 4 ] = 255 ; image [ 5 ] = 255 ; - image [ 6 ] = 255 ; image [ 7 ] = 255 ; image [ 8 ] = 255 ; - image [ 9 ] = 255 ; image [ 10] = 0 ; image [ 11] = 0 ; - - glTexImage2D(GL_TEXTURE_2D,0, GL_RGB, 2, 2, 0, - GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) image); - - return _texture; -} - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGCropped Texture. -//////////////////////////////////////////////////////////////////////// - -GLuint FGCroppedTexture::current_bound_texture = 0; -map FGCroppedTexture::cache; -map FGCroppedTexture::textureLoader; -static FGDummyTextureLoader dummyTextureLoader; - -FGCroppedTexture::FGCroppedTexture (const string &path, - float minX, float minY, - float maxX, float maxY) - : _path(path), - _minX(minX), _minY(minY), _maxX(maxX), _maxY(maxY), _texture(0) -{ -} - -FGCroppedTexture::~FGCroppedTexture () -{ -} - -void FGCroppedTexture::bind( bool doGLBind ) -{ - if( _texture == 0 ) { - SG_LOG( SG_COCKPIT, SG_DEBUG, "First bind of texture " << _path ); - if( cache.count(_path) > 0 ) { - _texture = cache[_path]; - SG_LOG( SG_COCKPIT, SG_DEBUG, "Using texture " << _path << " from cache (#" << _texture << ")" ); - } else { - SGPath tpath = ApplicationProperties::GetRootPath(_path.c_str()); - string extension = tpath.extension(); - FGTextureLoaderInterface * loader = &dummyTextureLoader; - if( textureLoader.count( extension ) == 0 ) { - SG_LOG( SG_COCKPIT, SG_ALERT, "Can't handle textures of type " << extension ); - } else { - loader = textureLoader[extension]; - } - - _texture = loader->loadTexture( tpath.local8BitStr() ); - SG_LOG( SG_COCKPIT, SG_DEBUG, "Texture " << tpath << " loaded from file as #" << _texture ); - - cache[_path] = _texture; - } - } - - if( !doGLBind || current_bound_texture == _texture ) - return; - - glBindTexture( GL_TEXTURE_2D, _texture ); - current_bound_texture = _texture; -} - - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGPanel. -//////////////////////////////////////////////////////////////////////// - -/** - * Constructor. - */ -FGPanel::FGPanel ( SGPropertyNode_ptr root) - : _root(root), - _flipx(root->getNode("/sim/panel/flip-x", true)), - _rotate(root->getNode("/sim/panel/rotate-deg", true)), - _bg_width(1.0), _bg_height(1.0), - initDisplayList(0) -{ -} - - -/** - * Destructor. - */ -FGPanel::~FGPanel () -{ - for (instrument_list_type::iterator it = _instruments.begin(); - it != _instruments.end(); - it++) { - delete *it; - *it = 0; - } -} - - -/** - * Add an instrument to the panel. - */ -void -FGPanel::addInstrument (FGPanelInstrument * instrument) -{ - _instruments.push_back(instrument); -} - - -/** - * Initialize the panel. - */ -void -FGPanel::init () -{ -} - - -/** - * Bind panel properties. - */ -void -FGPanel::bind () -{ -} - - -/** - * Unbind panel properties. - */ -void -FGPanel::unbind () -{ -} - -GLuint FGPanel::getInitDisplayList() -{ - if( initDisplayList != 0 ) return initDisplayList; - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if ( _flipx->getBoolValue() ) { - gluOrtho2D( _width, 0, _height, 0 ); /* up side down */ - } else { - gluOrtho2D( 0, _width, 0, _height ); /* right side up */ - } - - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glClear( GL_COLOR_BUFFER_BIT); - - // save some state - glPushAttrib( GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT - | GL_TEXTURE_BIT | GL_PIXEL_MODE_BIT | GL_CULL_FACE - | GL_DEPTH_BUFFER_BIT ); - - // Draw the background - glEnable(GL_TEXTURE_2D); - - glDisable(GL_LIGHTING); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_ALPHA_TEST); - glEnable(GL_COLOR_MATERIAL); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glDisable(GL_DEPTH_TEST); - - if (_bg != NULL) { - _bg->bind(); -// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); glVertex2f(0, 0); - glTexCoord2f(_bg_width, 0.0); glVertex2f(_width, 0); - glTexCoord2f(_bg_width, _bg_height); glVertex2f(_width, _height); - glTexCoord2f(0.0, _bg_height); glVertex2f(0, _height); - glEnd(); - } else if( _mbg[0] != NULL ) { - for (int i = 0; i < 4; i ++) { - // top row of textures...(1,3,5,7) - _mbg[i*2]->bind(); -// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); glVertex2f(i*_width/4, _height/2); - glTexCoord2f(1.0, 0.0); glVertex2f((i+1)*_width/4, _height/2); - glTexCoord2f(1.0, 1.0); glVertex2f((i+1)*_width/4, _height); - glTexCoord2f(0.0, 1.0); glVertex2f(i*_width/4, _height); - glEnd(); - // bottom row of textures...(2,4,6,8) - _mbg[i*2+1]->bind(); -// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); glVertex2f( i*_width/4, 0); - glTexCoord2f(1.0, 0.0); glVertex2f( (i+1)*_width/4, 0); - glTexCoord2f(1.0, 1.0); glVertex2f( (i+1)*_width/4, _height/2); - glTexCoord2f(0.0, 1.0); glVertex2f( i*_width/4, _height/2); - glEnd(); - } - } else { - float c[4]; - glGetFloatv( GL_CURRENT_COLOR, c ); - glColor4f( 0.0, 0.0, 0.0, 1.0 ); - glBegin(GL_QUADS); - glVertex2f(0, 0); - glVertex2f(_width, 0); - glVertex2f(_width, _height); - glVertex2f(0, _height); - glEnd(); - glColor4fv( c ); - } - - - return initDisplayList; -} - -void -FGPanel::update (double dt) -{ - /*glCallList*/(getInitDisplayList()); - - // Draw the instruments. - // Syd Adams: added instrument clipping - instrument_list_type::const_iterator current = _instruments.begin(); - instrument_list_type::const_iterator end = _instruments.end(); - - GLdouble blx[4]={1.0,0.0,0.0,0.0}; - GLdouble bly[4]={0.0,1.0,0.0,0.0}; - GLdouble urx[4]={-1.0,0.0,0.0,0.0}; - GLdouble ury[4]={0.0,-1.0,0.0,0.0}; - - for ( ; current != end; current++) { - FGPanelInstrument * instr = *current; - glPushMatrix(); - glTranslated(instr->getXPos(), instr->getYPos(), 0); - - int ix= instr->getWidth(); - int iy= instr->getHeight(); - glPushMatrix(); - glTranslated(-ix/2,-iy/2,0); - glClipPlane(GL_CLIP_PLANE0,blx); - glClipPlane(GL_CLIP_PLANE1,bly); - glEnable(GL_CLIP_PLANE0); - glEnable(GL_CLIP_PLANE1); - - glTranslated(ix,iy,0); - glClipPlane(GL_CLIP_PLANE2,urx); - glClipPlane(GL_CLIP_PLANE3,ury); - glEnable(GL_CLIP_PLANE2); - glEnable(GL_CLIP_PLANE3); - glPopMatrix(); - instr->draw(); - - glPopMatrix(); - } - - glDisable(GL_CLIP_PLANE0); - glDisable(GL_CLIP_PLANE1); - glDisable(GL_CLIP_PLANE2); - glDisable(GL_CLIP_PLANE3); - - // restore some original state - glPopAttrib(); -} - -#if 0 -/** - * Update the panel. - */ -void -FGPanel::update (double dt) -{ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if ( _flipx->getBoolValue() ) { - gluOrtho2D( _width, 0, _height, 0 ); /* up side down */ - } else { - gluOrtho2D( 0, _width, 0, _height ); /* right side up */ - } - - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - draw(); -} - -void FGPanel::draw() -{ - glClear( GL_COLOR_BUFFER_BIT); - - // save some state - glPushAttrib( GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT - | GL_TEXTURE_BIT | GL_PIXEL_MODE_BIT | GL_CULL_FACE - | GL_DEPTH_BUFFER_BIT ); - - // Draw the background - glEnable(GL_TEXTURE_2D); - - glDisable(GL_LIGHTING); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_ALPHA_TEST); - glEnable(GL_COLOR_MATERIAL); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glDisable(GL_DEPTH_TEST); - - if (_bg != NULL) { - _bg->bind(); -// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); glVertex2f(0, 0); - glTexCoord2f(_bg_width, 0.0); glVertex2f(_width, 0); - glTexCoord2f(_bg_width, _bg_height); glVertex2f(_width, _height); - glTexCoord2f(0.0, _bg_height); glVertex2f(0, _height); - glEnd(); - } else if( _mbg[0] != NULL ) { - for (int i = 0; i < 4; i ++) { - // top row of textures...(1,3,5,7) - _mbg[i*2]->bind(); -// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); glVertex2f(i*_width/4, _height/2); - glTexCoord2f(1.0, 0.0); glVertex2f((i+1)*_width/4, _height/2); - glTexCoord2f(1.0, 1.0); glVertex2f((i+1)*_width/4, _height); - glTexCoord2f(0.0, 1.0); glVertex2f(i*_width/4, _height); - glEnd(); - // bottom row of textures...(2,4,6,8) - _mbg[i*2+1]->bind(); -// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); glVertex2f( i*_width/4, 0); - glTexCoord2f(1.0, 0.0); glVertex2f( (i+1)*_width/4, 0); - glTexCoord2f(1.0, 1.0); glVertex2f( (i+1)*_width/4, _height/2); - glTexCoord2f(0.0, 1.0); glVertex2f( i*_width/4, _height/2); - glEnd(); - } - } else { - float c[4]; - glGetFloatv( GL_CURRENT_COLOR, c ); - glColor4f( 0.0, 0.0, 0.0, 1.0 ); - glBegin(GL_QUADS); - glVertex2f(0, 0); - glVertex2f(_width, 0); - glVertex2f(_width, _height); - glVertex2f(0, _height); - glEnd(); - glColor4fv( c ); - } - - // Draw the instruments. - // Syd Adams: added instrument clipping - instrument_list_type::const_iterator current = _instruments.begin(); - instrument_list_type::const_iterator end = _instruments.end(); - - GLdouble blx[4]={1.0,0.0,0.0,0.0}; - GLdouble bly[4]={0.0,1.0,0.0,0.0}; - GLdouble urx[4]={-1.0,0.0,0.0,0.0}; - GLdouble ury[4]={0.0,-1.0,0.0,0.0}; - - for ( ; current != end; current++) { - FGPanelInstrument * instr = *current; - glPushMatrix(); - glTranslated(instr->getXPos(), instr->getYPos(), 0); - - int ix= instr->getWidth(); - int iy= instr->getHeight(); - glPushMatrix(); - glTranslated(-ix/2,-iy/2,0); - glClipPlane(GL_CLIP_PLANE0,blx); - glClipPlane(GL_CLIP_PLANE1,bly); - glEnable(GL_CLIP_PLANE0); - glEnable(GL_CLIP_PLANE1); - - glTranslated(ix,iy,0); - glClipPlane(GL_CLIP_PLANE2,urx); - glClipPlane(GL_CLIP_PLANE3,ury); - glEnable(GL_CLIP_PLANE2); - glEnable(GL_CLIP_PLANE3); - glPopMatrix(); - instr->draw(); - - glPopMatrix(); - } - - glDisable(GL_CLIP_PLANE0); - glDisable(GL_CLIP_PLANE1); - glDisable(GL_CLIP_PLANE2); - glDisable(GL_CLIP_PLANE3); - - // restore some original state - glPopAttrib(); -} -#endif - -/** - * Set the panel's background texture. - */ -void -FGPanel::setBackground (FGCroppedTexture_ptr texture) -{ - _bg = texture; -} - -/** - * Set the panel's multiple background textures. - */ -void -FGPanel::setMultiBackground (FGCroppedTexture_ptr texture, int idx) -{ - _bg = 0; - _mbg[idx] = texture; -} - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGPanelTransformation. -//////////////////////////////////////////////////////////////////////// - -FGPanelTransformation::FGPanelTransformation () - : table(0) -{ -} - -FGPanelTransformation::~FGPanelTransformation () -{ - delete table; -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGPanelInstrument. -//////////////////////////////////////////////////////////////////////// - - -FGPanelInstrument::FGPanelInstrument () -{ - setPosition(0, 0); - setSize(0, 0); -} - -FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h) -{ - setPosition(x, y); - setSize(w, h); -} - -FGPanelInstrument::~FGPanelInstrument () -{ -} - -void -FGPanelInstrument::setPosition (int x, int y) -{ - _x = x; - _y = y; -} - -void -FGPanelInstrument::setSize (int w, int h) -{ - _w = w; - _h = h; -} - -int -FGPanelInstrument::getXPos () const -{ - return _x; -} - -int -FGPanelInstrument::getYPos () const -{ - return _y; -} - -int -FGPanelInstrument::getWidth () const -{ - return _w; -} - -int -FGPanelInstrument::getHeight () const -{ - return _h; -} - - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGLayeredInstrument. -//////////////////////////////////////////////////////////////////////// - -FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h) - : FGPanelInstrument(x, y, w, h) -{ -} - -FGLayeredInstrument::~FGLayeredInstrument () -{ - for (layer_list::iterator it = _layers.begin(); it != _layers.end(); it++) { - delete *it; - *it = 0; - } -} - -void -FGLayeredInstrument::draw () -{ - if (!test()) - return; - - for (int i = 0; i < (int)_layers.size(); i++) { - glPushMatrix(); - _layers[i]->draw(); - glPopMatrix(); - } -} - -int -FGLayeredInstrument::addLayer (FGInstrumentLayer *layer) -{ - int n = _layers.size(); - if (layer->getWidth() == -1) { - layer->setWidth(getWidth()); - } - if (layer->getHeight() == -1) { - layer->setHeight(getHeight()); - } - _layers.push_back(layer); - return n; -} - -int -FGLayeredInstrument::addLayer (FGCroppedTexture_ptr texture, int w, int h) -{ - return addLayer(new FGTexturedLayer(texture, w, h)); -} - -void -FGLayeredInstrument::addTransformation (FGPanelTransformation * transformation) -{ - int layer = _layers.size() - 1; - _layers[layer]->addTransformation(transformation); -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGInstrumentLayer. -//////////////////////////////////////////////////////////////////////// - -FGInstrumentLayer::FGInstrumentLayer (int w, int h) - : _w(w), - _h(h) -{ -} - -FGInstrumentLayer::~FGInstrumentLayer () -{ - for (transformation_list::iterator it = _transformations.begin(); - it != _transformations.end(); - it++) { - delete *it; - *it = 0; - } -} - -void -FGInstrumentLayer::transform () const -{ - transformation_list::const_iterator it = _transformations.begin(); - transformation_list::const_iterator last = _transformations.end(); - while (it != last) { - FGPanelTransformation *t = *it; - if (t->test()) { - float val = (t->node == 0 ? 0.0 : t->node->getFloatValue()); - - if (t->has_mod) - val = fmod(val, t->mod); - if (val < t->min) { - val = t->min; - } else if (val > t->max) { - val = t->max; - } - - if (t->table==0) { - val = val * t->factor + t->offset; - } else { - val = t->table->interpolate(val) * t->factor + t->offset; - } - - switch (t->type) { - case FGPanelTransformation::XSHIFT: - glTranslatef(val, 0.0, 0.0); - break; - case FGPanelTransformation::YSHIFT: - glTranslatef(0.0, val, 0.0); - break; - case FGPanelTransformation::ROTATION: - glRotatef(-val, 0.0, 0.0, 1.0); - break; - } - } - it++; - } -} - -void -FGInstrumentLayer::addTransformation (FGPanelTransformation * transformation) -{ - _transformations.push_back(transformation); -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGGroupLayer. -//////////////////////////////////////////////////////////////////////// - -FGGroupLayer::FGGroupLayer () -{ -} - -FGGroupLayer::~FGGroupLayer () -{ - for (unsigned int i = 0; i < _layers.size(); i++) - delete _layers[i]; -} - -void -FGGroupLayer::draw () -{ - if (test()) { - transform(); - int nLayers = _layers.size(); - for (int i = 0; i < nLayers; i++) - _layers[i]->draw( ); - } -} - -void -FGGroupLayer::addLayer (FGInstrumentLayer * layer) -{ - _layers.push_back(layer); -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGTexturedLayer. -//////////////////////////////////////////////////////////////////////// - - -FGTexturedLayer::FGTexturedLayer (FGCroppedTexture_ptr texture, int w, int h) - : FGInstrumentLayer(w, h), - _emissive(false), - displayList(0) -{ - setTexture(texture); -} - - -FGTexturedLayer::~FGTexturedLayer () -{ -} - -GLuint -FGTexturedLayer::getDisplayList() -{ - if( displayList != 0 ) - return displayList; - - int w2 = _w / 2; - int h2 = _h / 2; - - _texture->bind( false ); - displayList = glGenLists(1); - glNewList(displayList,GL_COMPILE_AND_EXECUTE); - glBindTexture( GL_TEXTURE_2D, _texture->getTexture() ); - glBegin(GL_QUADS); - glTexCoord2f(_texture->getMinX(), _texture->getMinY()); glVertex2f(-w2, -h2); - glTexCoord2f(_texture->getMaxX(), _texture->getMinY()); glVertex2f(w2, -h2); - glTexCoord2f(_texture->getMaxX(), _texture->getMaxY()); glVertex2f(w2, h2); - glTexCoord2f(_texture->getMinX(), _texture->getMaxY()); glVertex2f(-w2, h2); - glEnd(); - glEndList(); - - return displayList; -} - -void -FGTexturedLayer::draw ( ) -{ - if (test()) { - transform(); - glCallList(getDisplayList()); - } -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGTextLayer. -//////////////////////////////////////////////////////////////////////// - -fntRenderer FGTextLayer::text_renderer; - -FGTextLayer::FGTextLayer (int w, int h) - : FGInstrumentLayer(w, h), _pointSize(14.0), _font_name("Helvetica.txf") -{ - _then.stamp(); - _color[0] = _color[1] = _color[2] = 0.0; - _color[3] = 1.0; -} - -FGTextLayer::~FGTextLayer () -{ - chunk_list::iterator it = _chunks.begin(); - chunk_list::iterator last = _chunks.end(); - for ( ; it != last; it++) { - delete *it; - } -} - -void -FGTextLayer::draw () -{ - if (test()) { - float c[4]; - glGetFloatv( GL_CURRENT_COLOR, c ); - glColor4fv(_color); - transform(); - - text_renderer.setFont(ApplicationProperties::fontCache.getTexFont(_font_name.c_str())); - if (!text_renderer.getFont()) - { - SG_LOG( SG_COCKPIT, SG_ALERT, "Missing font file: " << _font_name ); - return; - } - - text_renderer.setPointSize(_pointSize); - text_renderer.begin(); - text_renderer.start3f(0, 0, 0); - - _now.stamp(); - long diff = (_now - _then).toUSecs(); - - if (diff > 100000 || diff < 0 ) { - // ( diff < 0 ) is a sanity check and indicates our time stamp - // difference math probably overflowed. We can handle a max - // difference of 35.8 minutes since the returned value is in - // usec. So if the panel is left off longer than that we can - // over flow the math with it is turned back on. This (diff < - // 0) catches that situation, get's us out of trouble, and - // back on track. - recalc_value(); - _then = _now; - } - - // Something is goofy. The code in this file renders only CCW - // polygons, and I have verified that the font code in plib - // renders only CCW trianbles. Yet they come out backwards. - // Something around here or in plib is either changing the winding - // order or (more likely) pushing a left-handed matrix onto the - // stack. But I can't find it; get out the chainsaw... - glFrontFace(GL_CW); - text_renderer.puts((char *)(_value.c_str())); - glFrontFace(GL_CCW); - - text_renderer.end(); - glColor4fv( c ); - } -} - -void -FGTextLayer::addChunk (FGTextLayer::Chunk * chunk) -{ - _chunks.push_back(chunk); -} - -void -FGTextLayer::setColor (float r, float g, float b) -{ - _color[0] = r; - _color[1] = g; - _color[2] = b; - _color[3] = 1.0; -} - -void -FGTextLayer::setPointSize (float size) -{ - _pointSize = size; -} - -void -FGTextLayer::setFontName(const string &name) -{ - _font_name = name + ".txf"; -} - - -void -FGTextLayer::setFont(fntFont * font) -{ - FGTextLayer::text_renderer.setFont(font); -} - - -void -FGTextLayer::recalc_value () const -{ - _value = ""; - chunk_list::const_iterator it = _chunks.begin(); - chunk_list::const_iterator last = _chunks.end(); - for ( ; it != last; it++) { - _value += (*it)->getValue(); - } -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGTextLayer::Chunk. -//////////////////////////////////////////////////////////////////////// - -FGTextLayer::Chunk::Chunk (const string &text, const string &fmt) - : _type(FGTextLayer::TEXT), _fmt(fmt) -{ - _text = text; - if (_fmt.empty()) - _fmt = "%s"; -} - -FGTextLayer::Chunk::Chunk (ChunkType type, const SGPropertyNode * node, - const string &fmt, float mult, float offs, - bool truncation) - : _type(type), _fmt(fmt), _mult(mult), _offs(offs), _trunc(truncation) -{ - if (_fmt.empty()) { - if (type == TEXT_VALUE) - _fmt = "%s"; - else - _fmt = "%.2f"; - } - _node = node; -} - -const char * -FGTextLayer::Chunk::getValue () const -{ - if (test()) { - _buf[0] = '\0'; - switch (_type) { - case TEXT: - sprintf(_buf, _fmt.c_str(), _text.c_str()); - return _buf; - case TEXT_VALUE: - sprintf(_buf, _fmt.c_str(), _node->getStringValue()); - break; - case DOUBLE_VALUE: - double d = _offs + _node->getFloatValue() * _mult; - if (_trunc) d = (d < 0) ? -floor(-d) : floor(d); - sprintf(_buf, _fmt.c_str(), d); - break; - } - return _buf; - } else { - return ""; - } -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGSwitchLayer. -//////////////////////////////////////////////////////////////////////// - -FGSwitchLayer::FGSwitchLayer () - : FGGroupLayer() -{ -} - -void -FGSwitchLayer::draw () -{ - if (test()) { - transform(); - int nLayers = _layers.size(); - for (int i = 0; i < nLayers; i++) { - if (_layers[i]->test()) { - _layers[i]->draw(); - return; - } - } - } -} - - -// end of panel.cxx diff --git a/utils/fgpanel/panel.hxx b/utils/fgpanel/panel.hxx deleted file mode 100644 index 5a3c5fa67..000000000 --- a/utils/fgpanel/panel.hxx +++ /dev/null @@ -1,452 +0,0 @@ -// panel.hxx - generic support classes for a 2D panel. -// -// Written by David Megginson, started January 2000. -// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009 -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id$ - -#ifndef __PANEL_HXX -#define __PANEL_HXX - -#ifndef __cplusplus -# error This library requires C++ -#endif - - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include -#include -#include -#include -#include -#include "FGTextureLoaderInterface.hxx" - -class FGPanelInstrument; -using namespace std; - -//////////////////////////////////////////////////////////////////////// -// Texture management. -//////////////////////////////////////////////////////////////////////// - -class FGCroppedTexture; -typedef SGSharedPtr FGCroppedTexture_ptr; -/** - * Cropped texture (should migrate out into FGFS). - * - * This structure wraps an SSG texture with cropping information. - */ -class FGCroppedTexture : public SGReferenced -{ -public: - FGCroppedTexture (const string &path, - float _minX = 0.0, float _minY = 0.0, - float _maxX = 1.0, float _maxY = 1.0); - - virtual ~FGCroppedTexture (); - - virtual void setPath (const string &path) { _path = path; } - - virtual const string &getPath () const { return _path; } - - virtual void setCrop (float minX, float minY, float maxX, float maxY) { - _minX = minX; _minY = minY; _maxX = maxX; _maxY = maxY; - } - - static void registerTextureLoader( const string & extension, FGTextureLoaderInterface * loader ) { - if( textureLoader.count( extension ) == 0 ) - textureLoader[extension] = loader; - } - - virtual float getMinX () const { return _minX; } - virtual float getMinY () const { return _minY; } - virtual float getMaxX () const { return _maxX; } - virtual float getMaxY () const { return _maxY; } - GLuint getTexture() const { return _texture; } - - virtual void bind( bool doGLBind = true ); - -private: - string _path; - float _minX, _minY, _maxX, _maxY; - - GLuint _texture; - static GLuint current_bound_texture; - static map cache; - static map textureLoader; -}; - - - -//////////////////////////////////////////////////////////////////////// -// Top-level panel. -//////////////////////////////////////////////////////////////////////// - - -/** - * Instrument panel class. - * - * The panel is a container that has a background texture and holds - * zero or more instruments. The panel will order the instruments to - * redraw themselves when necessary, and will pass mouse clicks on to - * the appropriate instruments for processing. - */ -class FGPanel : public SGSubsystem -{ -public: - - FGPanel ( SGPropertyNode_ptr root ); - virtual ~FGPanel (); - - // Update the panel (every frame). - virtual void init (); - virtual void bind (); - virtual void unbind (); -// virtual void draw (); - virtual void update (double dt); - - // transfer pointer ownership!!! - virtual void addInstrument (FGPanelInstrument * instrument); - - // Background texture. - virtual void setBackground (FGCroppedTexture_ptr texture); - inline void setBackgroundWidth( double d ) { - _bg_width = d; - } - - inline void setBackgroundHeight( double d ) { - _bg_height = d; - } - - // Background multiple textures. - virtual void setMultiBackground (FGCroppedTexture_ptr texture , int idx); - - // Full width of panel. - virtual void setWidth (int width) { _width = width; } - virtual int getWidth () const { return _width; } - - // Full height of panel. - virtual void setHeight (int height) { _height = height; } - virtual int getHeight () const { return _height; } - -private: - - typedef vector instrument_list_type; - int _width; - int _height; - - SGPropertyNode_ptr _root; - SGPropertyNode_ptr _flipx; - SGPropertyNode_ptr _rotate; - - FGCroppedTexture_ptr _bg; - double _bg_width; - double _bg_height; - FGCroppedTexture_ptr _mbg[8]; - // List of instruments in panel. - instrument_list_type _instruments; - - GLuint initDisplayList; - - GLuint getInitDisplayList(); -}; - - - -//////////////////////////////////////////////////////////////////////// -// Transformations. -//////////////////////////////////////////////////////////////////////// - - -/** - * A transformation for a layer. - */ -class FGPanelTransformation : public SGConditional -{ -public: - - enum Type { - XSHIFT, - YSHIFT, - ROTATION - }; - - FGPanelTransformation (); - virtual ~FGPanelTransformation (); - - Type type; - SGConstPropertyNode_ptr node; - float min; - float max; - bool has_mod; - float mod; - float factor; - float offset; - SGInterpTable * table; -}; - - - - -//////////////////////////////////////////////////////////////////////// -// Layers -//////////////////////////////////////////////////////////////////////// - - -/** - * A single layer of a multi-layered instrument. - * - * Each layer can be subject to a series of transformations based - * on current FGFS instrument readings: for example, a texture - * representing a needle can rotate to show the airspeed. - */ -class FGInstrumentLayer : public SGConditional -{ -public: - - FGInstrumentLayer (int w = -1, int h = -1); - virtual ~FGInstrumentLayer (); - - virtual void draw () = 0; - virtual void transform () const; - - virtual int getWidth () const { return _w; } - virtual int getHeight () const { return _h; } - virtual void setWidth (int w) { _w = w; } - virtual void setHeight (int h) { _h = h; } - - // Transfer pointer ownership!! - // DEPRECATED - virtual void addTransformation (FGPanelTransformation * transformation); - -protected: - int _w, _h; - - typedef vector transformation_list; - transformation_list _transformations; -}; - - - -//////////////////////////////////////////////////////////////////////// -// Instruments. -//////////////////////////////////////////////////////////////////////// - - -/** - * Abstract base class for a panel instrument. - * - * A panel instrument consists of zero or more actions, associated - * with mouse clicks in rectangular areas. Currently, the only - * concrete class derived from this is FGLayeredInstrument, but others - * may show up in the future (some complex instruments could be - * entirely hand-coded, for example). - */ -class FGPanelInstrument : public SGConditional -{ -public: - FGPanelInstrument (); - FGPanelInstrument (int x, int y, int w, int h); - virtual ~FGPanelInstrument (); - - virtual void draw () = 0; - - virtual void setPosition(int x, int y); - virtual void setSize(int w, int h); - - virtual int getXPos () const; - virtual int getYPos () const; - virtual int getWidth () const; - virtual int getHeight () const; - -protected: - int _x, _y, _w, _h; -}; - - -/** - * An instrument constructed of multiple layers. - * - * Each individual layer can be rotated or shifted to correspond - * to internal FGFS instrument readings. - */ -class FGLayeredInstrument : public FGPanelInstrument -{ -public: - FGLayeredInstrument (int x, int y, int w, int h); - virtual ~FGLayeredInstrument (); - - virtual void draw (); - - // Transfer pointer ownership!! - virtual int addLayer (FGInstrumentLayer *layer); - virtual int addLayer (FGCroppedTexture_ptr texture, int w = -1, int h = -1); - - // Transfer pointer ownership!! - virtual void addTransformation (FGPanelTransformation * transformation); - -protected: - typedef vector layer_list; - layer_list _layers; -}; - - -/** - * An instrument layer containing a group of sublayers. - * - * This class is useful for gathering together a group of related - * layers, either to hold in an external file or to work under - * the same condition. - */ -class FGGroupLayer : public FGInstrumentLayer -{ -public: - FGGroupLayer (); - virtual ~FGGroupLayer (); - virtual void draw (); - // transfer pointer ownership - virtual void addLayer (FGInstrumentLayer * layer); -protected: - vector _layers; -}; - - -/** - * A textured layer of an instrument. - * - * This is a layer holding a single texture. Normally, the texture's - * backgound should be transparent so that lower layers and the panel - * background can show through. - */ -class FGTexturedLayer : public FGInstrumentLayer -{ -public: - FGTexturedLayer (int w = -1, int h = -1) : FGInstrumentLayer(w, h) {} - FGTexturedLayer (FGCroppedTexture_ptr texture, int w = -1, int h = -1); - virtual ~FGTexturedLayer (); - - virtual void draw (); - - virtual void setTexture (FGCroppedTexture_ptr texture) { - _texture = texture; - } - FGCroppedTexture_ptr getTexture() { return _texture; } - - void setEmissive(bool e) { _emissive = e; } - -private: - GLuint getDisplayList(); - - FGCroppedTexture_ptr _texture; - bool _emissive; - GLuint displayList; -}; - - -/** - * A text layer of an instrument. - * - * This is a layer holding a string of static and/or generated text. - * It is useful for instruments that have text displays, such as - * a chronometer, GPS, or NavCom radio. - */ -class FGTextLayer : public FGInstrumentLayer -{ -public: - enum ChunkType { - TEXT, - TEXT_VALUE, - DOUBLE_VALUE - }; - - class Chunk : public SGConditional - { - public: - Chunk (const string &text, const string &fmt = "%s"); - Chunk (ChunkType type, const SGPropertyNode * node, - const string &fmt = "", float mult = 1.0, float offs = 0.0, - bool truncation = false); - - const char * getValue () const; - private: - ChunkType _type; - string _text; - SGConstPropertyNode_ptr _node; - string _fmt; - float _mult; - float _offs; - bool _trunc; - mutable char _buf[1024]; - - }; - - FGTextLayer (int w = -1, int h = -1); - virtual ~FGTextLayer (); - - virtual void draw (); - - // Transfer pointer!! - virtual void addChunk (Chunk * chunk); - virtual void setColor (float r, float g, float b); - virtual void setPointSize (float size); - virtual void setFontName ( const string &name ); - virtual void setFont (fntFont * font); - -private: - - void recalc_value () const; - - typedef vector chunk_list; - chunk_list _chunks; - float _color[4]; - - float _pointSize; - mutable string _font_name; - mutable string _value; - mutable SGTimeStamp _then; - mutable SGTimeStamp _now; - - static fntRenderer text_renderer; -}; - - -/** - * A group layer that switches among its children. - * - * The first layer that passes its condition will be drawn, and - * any following layers will be ignored. - */ -class FGSwitchLayer : public FGGroupLayer -{ -public: - // Transfer pointers!! - FGSwitchLayer (); - virtual void draw (); - -}; - - -#endif // __PANEL_HXX - -// end of panel.hxx - - - diff --git a/utils/fgpanel/panel_io.cxx b/utils/fgpanel/panel_io.cxx index cd243f69f..bfcb0e631 100644 --- a/utils/fgpanel/panel_io.cxx +++ b/utils/fgpanel/panel_io.cxx @@ -6,7 +6,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -16,17 +16,17 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // -// $Id: panel_io.cxx,v 1.26 2006/08/10 11:12:39 mfranz Exp $ +// $Id: panel_io.cxx,v 1.3 2016/08/25 23:41:34 allaert Exp $ #ifdef HAVE_CONFIG_H -# include +#include #endif #ifdef HAVE_WINDOWS_H -# include +#include #endif -#include // for strcmp() +#include // for strcmp() #include #include @@ -36,9 +36,13 @@ #include #include -#include "panel.hxx" #include "panel_io.hxx" #include "ApplicationProperties.hxx" +#include "FGGroupLayer.hxx" +#include "FGLayeredInstrument.hxx" +#include "FGSwitchLayer.hxx" +#include "FGTextLayer.hxx" +#include "FGTexturedLayer.hxx" //////////////////////////////////////////////////////////////////////// @@ -56,7 +60,7 @@ // // A layer contains zero or more transformations. // -// Some special types of layers also contain other objects, such as +// Some special types of layers also contain other objects, such as // chunks of text or other layers. // // There are currently four types of layers: @@ -96,14 +100,13 @@ * texture, x1=0.0, y1=0.0, x2=0.5, y2=0.5. */ static FGCroppedTexture_ptr -readTexture (const SGPropertyNode * node) -{ - return new FGCroppedTexture(node->getStringValue("path"), - node->getFloatValue("x1"), - node->getFloatValue("y1"), - node->getFloatValue("x2", 1.0), - node->getFloatValue("y2", 1.0)); - SG_LOG(SG_COCKPIT, SG_DEBUG, "Read texture " << node->getName()); +readTexture (const SGPropertyNode *node) { + return new FGCroppedTexture (node->getStringValue ("path"), + node->getFloatValue ("x1"), + node->getFloatValue ("y1"), + node->getFloatValue ("x2", 1.0), + node->getFloatValue ("y2", 1.0)); + SG_LOG(SG_COCKPIT, SG_DEBUG, "Read texture " << node->getName ()); } /** @@ -115,17 +118,15 @@ readTexture (const SGPropertyNode * node) //////////////////////////////////////////////////////////////////////// static void -readConditions (SGConditional *component, const SGPropertyNode *node) -{ - const SGPropertyNode * conditionNode = node->getChild("condition"); - if (conditionNode != 0) - // The top level is implicitly AND - component->setCondition(sgReadCondition(ApplicationProperties::Properties, - conditionNode) ); - ; +readConditions (SGConditional *component, const SGPropertyNode *node) { + const SGPropertyNode * conditionNode (node->getChild ("condition")); + if (conditionNode != 0) { + // The top level is implicitly AND + component->setCondition (sgReadCondition (ApplicationProperties::Properties, + conditionNode)); + } } - /** * Read a transformation from the instrument's property list. * @@ -152,91 +153,90 @@ readConditions (SGConditional *component, const SGPropertyNode *node) * appear to be applied backwards. */ static FGPanelTransformation * -readTransformation (const SGPropertyNode * node, float w_scale, float h_scale) -{ - FGPanelTransformation * t = new FGPanelTransformation; +readTransformation (const SGPropertyNode *node, const float w_scale, const float h_scale) { + FGPanelTransformation *t (new FGPanelTransformation); - string name = node->getName(); - string type = node->getStringValue("type"); - string propName = node->getStringValue("property", ""); - const SGPropertyNode * target = 0; + const string name (node->getName ()); + string type (node->getStringValue ("type")); + const string propName (node->getStringValue ("property", "")); + const SGPropertyNode *target (0); - if (type.empty()) { - SG_LOG( SG_COCKPIT, SG_INFO, - "No type supplied for transformation " << name - << " assuming \"rotation\"" ); + if (type.empty ()) { + SG_LOG(SG_COCKPIT, SG_INFO, + "No type supplied for transformation " << name + << " assuming \"rotation\""); type = "rotation"; } - if (!propName.empty()) - target = ApplicationProperties::Properties->getNode(propName.c_str(), true); - + if (!propName.empty ()) { + target = ApplicationProperties::Properties->getNode (propName.c_str (), true); + } t->node = target; - t->min = node->getFloatValue("min", -9999999); - t->max = node->getFloatValue("max", 99999999); - t->has_mod = node->hasChild("modulator"); - if (t->has_mod) - t->mod = node->getFloatValue("modulator"); - t->factor = node->getFloatValue("scale", 1.0); - t->offset = node->getFloatValue("offset", 0.0); + t->min = node->getFloatValue ("min", -9999999); + t->max = node->getFloatValue ("max", 99999999); + t->has_mod = node->hasChild ("modulator"); + if (t->has_mod) { + t->mod = node->getFloatValue ("modulator"); + } + t->factor = node->getFloatValue ("scale", 1.0); + t->offset = node->getFloatValue ("offset", 0.0); - - // Check for an interpolation table - const SGPropertyNode * trans_table = node->getNode("interpolation"); + // Check for an interpolation table + const SGPropertyNode *trans_table (node->getNode ("interpolation")); if (trans_table != 0) { - SG_LOG( SG_COCKPIT, SG_INFO, "Found interpolation table with " - << trans_table->nChildren() << " children" ); + SG_LOG(SG_COCKPIT, SG_INFO, "Found interpolation table with " + << trans_table->nChildren() << " children"); t->table = new SGInterpTable(); for (int i = 0; i < trans_table->nChildren(); i++) { const SGPropertyNode * node = trans_table->getChild(i); if (!strcmp(node->getName(), "entry")) { - double ind = node->getDoubleValue("ind", 0.0); - double dep = node->getDoubleValue("dep", 0.0); - SG_LOG( SG_COCKPIT, SG_INFO, "Adding interpolation entry " - << ind << "==>" << dep ); - t->table->addEntry(ind, dep); + double ind = node->getDoubleValue("ind", 0.0); + double dep = node->getDoubleValue("dep", 0.0); + SG_LOG(SG_COCKPIT, SG_INFO, "Adding interpolation entry " + << ind << "==>" << dep); + t->table->addEntry(ind, dep); } else { - SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName() - << " in interpolation" ); + SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName() + << " in interpolation"); } } } else { t->table = 0; } - - // Move the layer horizontally. + + // Move the layer horizontally. if (type == "x-shift") { t->type = FGPanelTransformation::XSHIFT; // t->min *= w_scale; //removed by Martin Dressler // t->max *= w_scale; //removed by Martin Dressler t->offset *= w_scale; t->factor *= w_scale; //Added by Martin Dressler - } + } - // Move the layer vertically. + // Move the layer vertically. else if (type == "y-shift") { t->type = FGPanelTransformation::YSHIFT; //t->min *= h_scale; //removed //t->max *= h_scale; //removed t->offset *= h_scale; t->factor *= h_scale; //Added - } + } - // Rotate the layer. The rotation - // is in degrees, and does not need - // to scale with the instrument size. + // Rotate the layer. The rotation + // is in degrees, and does not need + // to scale with the instrument size. else if (type == "rotation") { t->type = FGPanelTransformation::ROTATION; - } + } else { - SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized transformation type " << type ); + SG_LOG(SG_COCKPIT, SG_ALERT, "Unrecognized transformation type " << type); delete t; return 0; } readConditions(t, node); - SG_LOG( SG_COCKPIT, SG_DEBUG, "Read transformation " << name ); + SG_LOG(SG_COCKPIT, SG_DEBUG, "Read transformation " << name); return t; } @@ -258,56 +258,48 @@ readTransformation (const SGPropertyNode * node, float w_scale, float h_scale) * All three may also include a printf-style format string. */ FGTextLayer::Chunk * -readTextChunk (const SGPropertyNode * node) -{ - FGTextLayer::Chunk * chunk; - string name = node->getStringValue("name"); - string type = node->getStringValue("type"); - string format = node->getStringValue("format"); +readTextChunk (const SGPropertyNode *node) { + FGTextLayer::Chunk *chunk; + const string name (node->getStringValue ("name")); + string type (node->getStringValue ("type")); + const string format (node->getStringValue ("format")); - // Default to literal text. - if (type.empty()) { - SG_LOG( SG_COCKPIT, SG_INFO, "No type provided for text chunk " << name - << " assuming \"literal\""); + // Default to literal text. + if (type.empty ()) { + SG_LOG(SG_COCKPIT, SG_INFO, "No type provided for text chunk " << name + << " assuming \"literal\""); type = "literal"; } - // A literal text string. + // A literal text string. if (type == "literal") { - string text = node->getStringValue("text"); - chunk = new FGTextLayer::Chunk(text, format); - } - - // The value of a string property. - else if (type == "text-value") { - SGPropertyNode * target = - ApplicationProperties::Properties->getNode( node->getStringValue("property"), true); - chunk = new FGTextLayer::Chunk(FGTextLayer::TEXT_VALUE, target, format); - } - - // The value of a float property. - else if (type == "number-value") { - string propName = node->getStringValue("property"); - float scale = node->getFloatValue("scale", 1.0); - float offset = node->getFloatValue("offset", 0.0); - bool truncation = node->getBoolValue("truncate", false); - SGPropertyNode * target = ApplicationProperties::Properties->getNode(propName.c_str(), true); - chunk = new FGTextLayer::Chunk(FGTextLayer::DOUBLE_VALUE, target, - format, scale, offset, truncation); - } - - // Unknown type. - else { - SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized type " << type - << " for text chunk " << name ); + const string text (node->getStringValue ("text")); + chunk = new FGTextLayer::Chunk (text, format); + } else if (type == "text-value") { + // The value of a string property. + const SGPropertyNode *target + (ApplicationProperties::Properties->getNode (node->getStringValue ("property"), true)); + chunk = new FGTextLayer::Chunk (FGTextLayer::TEXT_VALUE, target, format); + } else if (type == "number-value") { + // The value of a float property. + const string propName (node->getStringValue ("property")); + const float scale (node->getFloatValue ("scale", 1.0)); + const float offset (node->getFloatValue ("offset", 0.0)); + const bool truncation (node->getBoolValue ("truncate", false)); + const SGPropertyNode *target (ApplicationProperties::Properties->getNode (propName.c_str (), true)); + chunk = new FGTextLayer::Chunk (FGTextLayer::DOUBLE_VALUE, target, + format, scale, offset, truncation); + } else { + // Unknown type. + SG_LOG(SG_COCKPIT, SG_ALERT, "Unrecognized type " << type + << " for text chunk " << name); return 0; } - readConditions(chunk, node); + readConditions (chunk, node); return chunk; } - /** * Read a single layer from an instrument's property list. * @@ -330,254 +322,251 @@ readTextChunk (const SGPropertyNode * node) * Currently, the only built-in layer class is "compass-ribbon". */ static FGInstrumentLayer * -readLayer (const SGPropertyNode * node, float w_scale, float h_scale) -{ - FGInstrumentLayer * layer = NULL; - string name = node->getStringValue("name"); - string type = node->getStringValue("type"); - int w = node->getIntValue("w", -1); - int h = node->getIntValue("h", -1); - bool emissive = node->getBoolValue("emissive", false); - if (w != -1) - w = int(w * w_scale); - if (h != -1) - h = int(h * h_scale); - - - if (type.empty()) { - SG_LOG( SG_COCKPIT, SG_INFO, - "No type supplied for layer " << name - << " assuming \"texture\"" ); +readLayer (const SGPropertyNode *node, const float w_scale, const float h_scale) { + FGInstrumentLayer *layer (NULL); + const string name (node->getStringValue ("name")); + string type (node->getStringValue ("type")); + int w (node->getIntValue ("w", -1)); + int h (node->getIntValue ("h", -1)); + const bool emissive (node->getBoolValue ("emissive", false)); + if (w != -1) { + w = int (w * w_scale); + } + if (h != -1) { + h = int (h * h_scale); + } + if (type.empty ()) { + SG_LOG(SG_COCKPIT, SG_INFO, + "No type supplied for layer " << name + << " assuming \"texture\""); type = "texture"; } - - // A textured instrument layer. + // A textured instrument layer. if (type == "texture") { - FGCroppedTexture_ptr texture = readTexture(node->getNode("texture")); - layer = new FGTexturedLayer(texture, w, h); + const FGCroppedTexture_ptr texture (readTexture (node->getNode ("texture"))); + layer = new FGTexturedLayer (texture, w, h); if (emissive) { - FGTexturedLayer *tl=(FGTexturedLayer*)layer; - tl->setEmissive(true); + FGTexturedLayer *tl = (FGTexturedLayer*) layer; + tl->setEmissive (true); } - - } - // A group of sublayers. - else if (type == "group") { - layer = new FGGroupLayer(); + } else if (type == "group") { + // A group of sublayers. + layer = new FGGroupLayer (); for (int i = 0; i < node->nChildren(); i++) { - const SGPropertyNode * child = node->getChild(i); - if (!strcmp(child->getName(), "layer")) - ((FGGroupLayer *)layer)->addLayer(readLayer(child, w_scale, h_scale)); + const SGPropertyNode *child = node->getChild (i); + if (!strcmp (child->getName (), "layer")) { + ((FGGroupLayer *) layer)->addLayer (readLayer (child, w_scale, h_scale)); + } } - } + } else if (type == "text") { + // A textual instrument layer. + FGTextLayer *tlayer (new FGTextLayer (w, h)); // FIXME + // Set the text color. + const float red (node->getFloatValue ("color/red", 0.0)); + const float green (node->getFloatValue ("color/green", 0.0)); + const float blue (node->getFloatValue ("color/blue", 0.0)); + tlayer->setColor (red, green, blue); - // A textual instrument layer. - else if (type == "text") { - FGTextLayer * tlayer = new FGTextLayer(w, h); // FIXME + // Set the point size. + const float pointSize (node->getFloatValue ("point-size", 10.0) * w_scale); + tlayer->setPointSize (pointSize); - // Set the text color. - float red = node->getFloatValue("color/red", 0.0); - float green = node->getFloatValue("color/green", 0.0); - float blue = node->getFloatValue("color/blue", 0.0); - tlayer->setColor(red, green, blue); + // Set the font. + const string fontName (node->getStringValue ("font", "7-Segment")); + tlayer->setFontName (fontName); - // Set the point size. - float pointSize = node->getFloatValue("point-size", 10.0) * w_scale; - tlayer->setPointSize(pointSize); - - // Set the font. - string fontName = node->getStringValue("font", "Helvetica"); - tlayer->setFontName(fontName); - - const SGPropertyNode * chunk_group = node->getNode("chunks"); + const SGPropertyNode *chunk_group (node->getNode ("chunks")); if (chunk_group != 0) { - int nChunks = chunk_group->nChildren(); + const int nChunks (chunk_group->nChildren ()); for (int i = 0; i < nChunks; i++) { - const SGPropertyNode * node = chunk_group->getChild(i); - if (!strcmp(node->getName(), "chunk")) { - FGTextLayer::Chunk * chunk = readTextChunk(node); - if (chunk != 0) - tlayer->addChunk(chunk); - } else { - SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName() - << " in chunks" ); - } + const SGPropertyNode *node (chunk_group->getChild (i)); + if (!strcmp(node->getName (), "chunk")) { + FGTextLayer::Chunk * const chunk (readTextChunk (node)); + if (chunk != 0) { + tlayer->addChunk (chunk); + } + } else { + SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName() + << " in chunks"); + } } layer = tlayer; } - } - - // A switch instrument layer. - else if (type == "switch") { - layer = new FGSwitchLayer(); - for (int i = 0; i < node->nChildren(); i++) { - const SGPropertyNode * child = node->getChild(i); - if (!strcmp(child->getName(), "layer")) - ((FGGroupLayer *)layer)->addLayer(readLayer(child, w_scale, h_scale)); + } else if (type == "switch") { + // A switch instrument layer. + layer = new FGSwitchLayer (); + for (int i = 0; i < node->nChildren (); i++) { + const SGPropertyNode *child (node->getChild (i)); + if (!strcmp (child->getName (), "layer")) { + ((FGGroupLayer *) layer)->addLayer (readLayer (child, w_scale, h_scale)); + } } - } - - // An unknown type. - else { - SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized layer type " << type ); + } else { + // An unknown type. + SG_LOG(SG_COCKPIT, SG_ALERT, "Unrecognized layer type " << type); delete layer; return 0; } - + // // Get the transformations for each layer. // - const SGPropertyNode * trans_group = node->getNode("transformations"); + const SGPropertyNode *trans_group (node->getNode ("transformations")); if (trans_group != 0) { - int nTransformations = trans_group->nChildren(); + const int nTransformations (trans_group->nChildren ()); for (int i = 0; i < nTransformations; i++) { - const SGPropertyNode * node = trans_group->getChild(i); - if (!strcmp(node->getName(), "transformation")) { - FGPanelTransformation * t = readTransformation(node, w_scale, h_scale); - if (t != 0) - layer->addTransformation(t); + const SGPropertyNode *node (trans_group->getChild (i)); + if (!strcmp(node->getName (), "transformation")) { + FGPanelTransformation * const t (readTransformation (node, w_scale, h_scale)); + if (t != 0) { + layer->addTransformation (t); + } } else { - SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName() - << " in transformations" ); + SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName() + << " in transformations"); } } } - readConditions(layer, node); - SG_LOG( SG_COCKPIT, SG_DEBUG, "Read layer " << name ); + readConditions (layer, node); + SG_LOG(SG_COCKPIT, SG_DEBUG, "Read layer " << name); return layer; } - /** * Read an instrument from a property list. * * The instrument consists of a preferred width and height * (the panel may override these), together with a list of layers - * and a list of actions to be performed when the user clicks + * and a list of actions to be performed when the user clicks * the mouse over the instrument. All co-ordinates are relative * to the instrument's position, so instruments are fully relocatable; * likewise, co-ordinates for actions and transformations will be * scaled automatically if the instrument is not at its preferred size. */ static FGPanelInstrument * -readInstrument (const SGPropertyNode * node) -{ - const string name = node->getStringValue("name"); - int x = node->getIntValue("x", -1); - int y = node->getIntValue("y", -1); - int real_w = node->getIntValue("w", -1); - int real_h = node->getIntValue("h", -1); - int w = node->getIntValue("w-base", -1); - int h = node->getIntValue("h-base", -1); +readInstrument (const SGPropertyNode *node) { + const string name (node->getStringValue ("name")); + const int x (node->getIntValue ("x", -1)); + const int y (node->getIntValue ("y", -1)); + const int real_w (node->getIntValue ("w", -1)); + const int real_h (node->getIntValue ("h", -1)); + int w (node->getIntValue ("w-base", -1)); + int h (node->getIntValue ("h-base", -1)); if (x == -1 || y == -1) { - SG_LOG( SG_COCKPIT, SG_ALERT, - "x and y positions must be specified and > 0" ); + SG_LOG(SG_COCKPIT, SG_ALERT, + "x and y positions must be specified and > 0"); return 0; } - float w_scale = 1.0; - float h_scale = 1.0; + float w_scale (1.0); + float h_scale (1.0); if (real_w != -1) { - w_scale = float(real_w) / float(w); + w_scale = float (real_w) / float (w); w = real_w; } if (real_h != -1) { - h_scale = float(real_h) / float(h); + h_scale = float (real_h) / float (h); h = real_h; } - SG_LOG( SG_COCKPIT, SG_DEBUG, "Reading instrument " << name ); + SG_LOG(SG_COCKPIT, SG_DEBUG, "Reading instrument " << name); - FGLayeredInstrument * instrument = - new FGLayeredInstrument(x, y, w, h); + FGLayeredInstrument * const instrument + (new FGLayeredInstrument (x, y, w, h)); // // Get the layers for the instrument. // - const SGPropertyNode * layer_group = node->getNode("layers"); + const SGPropertyNode *layer_group (node->getNode ("layers")); if (layer_group != 0) { - int nLayers = layer_group->nChildren(); + const int nLayers (layer_group->nChildren ()); for (int i = 0; i < nLayers; i++) { - const SGPropertyNode * node = layer_group->getChild(i); - if (!strcmp(node->getName(), "layer")) { - FGInstrumentLayer * layer = readLayer(node, w_scale, h_scale); - if (layer != 0) - instrument->addLayer(layer); + const SGPropertyNode *node (layer_group->getChild (i)); + if (!strcmp (node->getName (), "layer")) { + FGInstrumentLayer * const layer (readLayer (node, w_scale, h_scale)); + if (layer != 0) { + instrument->addLayer (layer); + } } else { - SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName() - << " in layers" ); + SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName () + << " in layers"); } } } - readConditions(instrument, node); - SG_LOG( SG_COCKPIT, SG_DEBUG, "Done reading instrument " << name ); + readConditions (instrument, node); + SG_LOG(SG_COCKPIT, SG_DEBUG, "Done reading instrument " << name); return instrument; } - /** * Construct the panel from a property tree. */ SGSharedPtr -FGReadablePanel::read(SGPropertyNode_ptr root) -{ - SG_LOG( SG_COCKPIT, SG_INFO, "Reading properties for panel " << - root->getStringValue("name", "[Unnamed Panel]") ); +FGReadablePanel::read (SGPropertyNode_ptr root) { + SG_LOG(SG_COCKPIT, SG_INFO, "Reading properties for panel " << + root->getStringValue ("name", "[Unnamed Panel]")); - FGPanel * panel = new FGPanel(root); - panel->setWidth(root->getIntValue("w", 1024)); - panel->setHeight(root->getIntValue("h", 443)); + FGPanel * const panel (new FGPanel (root)); + panel->setWidth (root->getIntValue ("w", 1024)); + panel->setHeight (root->getIntValue ("h", 443)); - SG_LOG( SG_COCKPIT, SG_INFO, "Size=" << panel->getWidth() << "x" << panel->getHeight() ); + SG_LOG(SG_COCKPIT, SG_INFO, "Size=" << panel->getWidth () << "x" << panel->getHeight ()); // Assign the background texture, if any, or a bogus chequerboard. // - string bgTexture = root->getStringValue("background"); - if( !bgTexture.empty() ) - panel->setBackground( new FGCroppedTexture( bgTexture ) ); - panel->setBackgroundWidth( root->getDoubleValue( "background-width", 1.0 ) ); - panel->setBackgroundHeight( root->getDoubleValue( "background-height", 1.0 ) ); - SG_LOG( SG_COCKPIT, SG_INFO, "Set background texture to " << bgTexture ); + const string bgTexture (root->getStringValue ("background")); + if (!bgTexture.empty ()) { + panel->setBackground (new FGCroppedTexture (bgTexture)); + } + panel->setBackgroundWidth (root->getDoubleValue( "background-width", 1.0)); + panel->setBackgroundHeight (root->getDoubleValue( "background-height", 1.0)); + SG_LOG(SG_COCKPIT, SG_INFO, "Set background texture to " << bgTexture); // // Get multibackground if any... // - for( int i = 0; i < 8; i++ ) { - SGPropertyNode * mbgNode = root->getChild( "multibackground", i ); + for (int i = 0; i < 8; i++) { + SGPropertyNode * const mbgNode (root->getChild ("multibackground", i)); string mbgTexture; - if( mbgNode != NULL ) mbgTexture = mbgNode->getStringValue(); - if( mbgTexture.empty() ) { - if( i == 0 ) break; // if first texture is missing, ignore the rest - else mbgTexture = "FOO"; // if others are missing - set default texture + if (mbgNode != NULL) { + mbgTexture = mbgNode->getStringValue (); } - panel->setMultiBackground( new FGCroppedTexture(mbgTexture), i ); - SG_LOG( SG_COCKPIT, SG_INFO, "Set multi-background texture" << i << " to " << mbgTexture ); + if (mbgTexture.empty ()) { + if (i == 0) { + break; // if first texture is missing, ignore the rest + } else { + mbgTexture = "FOO"; // if others are missing - set default texture + } + } + panel->setMultiBackground (new FGCroppedTexture (mbgTexture), i); + SG_LOG(SG_COCKPIT, SG_INFO, "Set multi-background texture" << i << " to " << mbgTexture); } // // Create each instrument. // SG_LOG( SG_COCKPIT, SG_INFO, "Reading panel instruments" ); - const SGPropertyNode * instrument_group = root->getChild("instruments"); + const SGPropertyNode *instrument_group (root->getChild ("instruments")); if (instrument_group != 0) { - int nInstruments = instrument_group->nChildren(); + const int nInstruments (instrument_group->nChildren ()); for (int i = 0; i < nInstruments; i++) { - const SGPropertyNode * node = instrument_group->getChild(i); - if (!strcmp(node->getName(), "instrument")) { - FGPanelInstrument * instrument = readInstrument(node); - if (instrument != 0) - panel->addInstrument(instrument); + const SGPropertyNode *node = instrument_group->getChild (i); + if (!strcmp (node->getName (), "instrument")) { + FGPanelInstrument * const instrument (readInstrument (node)); + if (instrument != 0) { + panel->addInstrument (instrument); + } } else { - SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName() - << " in instruments section" ); + SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName() + << " in instruments section"); } } } - SG_LOG( SG_COCKPIT, SG_INFO, "Done reading panel instruments" ); + SG_LOG(SG_COCKPIT, SG_INFO, "Done reading panel instruments"); // @@ -587,6 +576,3 @@ FGReadablePanel::read(SGPropertyNode_ptr root) } // end of panel_io.cxx - - - diff --git a/utils/fgpanel/panel_io.hxx b/utils/fgpanel/panel_io.hxx index e353ce04e..bc502b09a 100644 --- a/utils/fgpanel/panel_io.hxx +++ b/utils/fgpanel/panel_io.hxx @@ -6,7 +6,7 @@ // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -16,25 +16,24 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // -// $Id: panel_io.hxx,v 1.6 2006/04/17 13:03:43 mfranz Exp $ +// $Id: panel_io.hxx,v 1.2 2016/07/20 22:01:32 allaert Exp $ #ifndef __PANEL_IO_HXX #define __PANEL_IO_HXX #ifdef HAVE_CONFIG_H -# include +#include #endif #ifdef HAVE_WINDOWS_H -# include +#include #endif -#include "panel.hxx" +#include "FGPanel.hxx" class FGReadablePanel : public FGPanel { public: - static SGSharedPtr read(SGPropertyNode_ptr root); + static SGSharedPtr read (SGPropertyNode_ptr root); }; - #endif // __PANEL_IO_HXX