first commit
This commit is contained in:
75
utils/fgpanel/ApplicationProperties.cxx
Normal file
75
utils/fgpanel/ApplicationProperties.cxx
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <direct.h> // for getcwd()
|
||||
#else // !_WIN32
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ApplicationProperties.hxx"
|
||||
|
||||
double
|
||||
ApplicationProperties::getDouble (const char *name, const double def) {
|
||||
const SGPropertyNode_ptr n (ApplicationProperties::Properties->getNode (name, false));
|
||||
if (n == NULL) {
|
||||
return def;
|
||||
}
|
||||
return n->getDoubleValue ();
|
||||
}
|
||||
|
||||
SGPath
|
||||
ApplicationProperties::GetCwd () {
|
||||
SGPath path (".");
|
||||
char buf[512];
|
||||
char *cwd (getcwd (buf, 511));
|
||||
buf[511] = '\0';
|
||||
if (cwd) {
|
||||
path = SGPath::fromLocal8Bit (cwd);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
SGPath
|
||||
ApplicationProperties::GetRootPath (const char *sub) {
|
||||
if (sub != NULL) {
|
||||
const SGPath subpath (sub);
|
||||
|
||||
// relative path to current working dir?
|
||||
if (subpath.isRelative ()) {
|
||||
SGPath path (GetCwd ());
|
||||
path.append (sub);
|
||||
if (path.exists ()) {
|
||||
return path;
|
||||
}
|
||||
} else if (subpath.exists ()) {
|
||||
// absolute path
|
||||
return subpath;
|
||||
}
|
||||
}
|
||||
|
||||
// default: relative path to FGROOT
|
||||
SGPath path (ApplicationProperties::root);
|
||||
if (sub != NULL) {
|
||||
path.append (sub);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
string ApplicationProperties::root = ".";
|
||||
SGPropertyNode_ptr ApplicationProperties::Properties = new SGPropertyNode;
|
||||
32
utils/fgpanel/ApplicationProperties.hxx
Normal file
32
utils/fgpanel/ApplicationProperties.hxx
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
|
||||
class ApplicationProperties {
|
||||
public:
|
||||
static double getDouble (const char *name, const double def = 0.0);
|
||||
static SGPath GetRootPath (const char *subDir = NULL);
|
||||
static SGPath GetCwd ();
|
||||
static SGPropertyNode_ptr Properties;
|
||||
static std::string root;
|
||||
};
|
||||
143
utils/fgpanel/CMakeLists.txt
Normal file
143
utils/fgpanel/CMakeLists.txt
Normal file
@@ -0,0 +1,143 @@
|
||||
find_package(PNG QUIET)
|
||||
find_package(OpenGL QUIET)
|
||||
find_package(Freetype QUIET)
|
||||
|
||||
find_package(GLUT QUIET)
|
||||
find_package(GLEW QUIET)
|
||||
|
||||
if(NOT ${GLUT_FOUND})
|
||||
message(WARNING "GLUT NOT found, can't build FGPanel")
|
||||
set(WITH_FGPANEL 0)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT ${GLEW_FOUND})
|
||||
message(WARNING "GLEW NOT found, can't build FGPanel")
|
||||
set(WITH_FGPANEL 0)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if((NOT PNG_FOUND) OR (NOT OPENGL_FOUND) OR (NOT FREETYPE_FOUND))
|
||||
message(WARNING "FGPanel enabled, but some dependencies are missing")
|
||||
message(STATUS "libPNG: ${PNG_FOUND}")
|
||||
message(STATUS "OpenGL: ${OPENGL_FOUND}")
|
||||
message(STATUS "Freetype: ${FREETYPE_FOUND}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_path(BCMHOST_INCLUDE_DIR
|
||||
NAMES bcm_host.h
|
||||
PATHS /opt/vc/include
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
set(TARGET_SOURCES
|
||||
main.cxx
|
||||
ApplicationProperties.hxx
|
||||
ApplicationProperties.cxx
|
||||
FGCroppedTexture.hxx
|
||||
FGCroppedTexture.cxx
|
||||
FGDummyTextureLoader.hxx
|
||||
FGDummyTextureLoader.cxx
|
||||
FGFontCache.cxx
|
||||
FGFontCache.hxx
|
||||
FGGLApplication.cxx
|
||||
FGGLApplication.hxx
|
||||
FGGroupLayer.cxx
|
||||
FGGroupLayer.hxx
|
||||
FGInstrumentLayer.cxx
|
||||
FGInstrumentLayer.hxx
|
||||
FGLayeredInstrument.cxx
|
||||
FGLayeredInstrument.hxx
|
||||
FGPanel.cxx
|
||||
FGPanel.hxx
|
||||
FGPanelApplication.cxx
|
||||
FGPanelApplication.hxx
|
||||
FGPanelInstrument.cxx
|
||||
FGPanelInstrument.hxx
|
||||
FGPanelProtocol.cxx
|
||||
FGPanelProtocol.hxx
|
||||
FGPanelTransformation.cxx
|
||||
FGPanelTransformation.hxx
|
||||
FGPNGTextureLoader.cxx
|
||||
FGPNGTextureLoader.hxx
|
||||
FGRGBTextureLoader.cxx
|
||||
FGRGBTextureLoader.hxx
|
||||
FGSwitchLayer.cxx
|
||||
FGSwitchLayer.hxx
|
||||
FGTextLayer.cxx
|
||||
FGTextLayer.hxx
|
||||
FGTexturedLayer.cxx
|
||||
FGTexturedLayer.hxx
|
||||
panel_io.cxx
|
||||
panel_io.hxx
|
||||
GL_utils.cxx
|
||||
GL_utils.hxx
|
||||
)
|
||||
|
||||
add_executable(fgpanel ${TARGET_SOURCES})
|
||||
|
||||
target_link_libraries(fgpanel
|
||||
SimGearCore
|
||||
${PNG_LIBRARIES}
|
||||
${FREETYPE_LIBRARIES}
|
||||
OpenGL::GL
|
||||
${GLUT_LIBRARIES}
|
||||
${GLEW_LIBRARIES}
|
||||
)
|
||||
|
||||
target_include_directories(fgpanel PUBLIC
|
||||
${FREETYPE_INCLUDE_DIRS}
|
||||
${PNG_INCLUDE_DIR}
|
||||
${GLEW_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_definitions(fgpanel PUBLIC
|
||||
-DFREEGLUT_LIB_PRAGMAS=0
|
||||
)
|
||||
endif(MSVC)
|
||||
|
||||
if(BCMHOST_INCLUDE_DIR)
|
||||
message(STATUS "found Raspberry Pi")
|
||||
|
||||
add_executable(fgpanel-egl ${TARGET_SOURCES}
|
||||
GLES_utils.cxx
|
||||
GLES_utils.hxx
|
||||
)
|
||||
target_include_directories(fgpanel-egl PUBLIC
|
||||
${FREETYPE_INCLUDE_DIRS}
|
||||
${PNG_INCLUDE_DIR}
|
||||
${BCMHOST_INCLUDE_DIR}
|
||||
${BCMHOST_INCLUDE_DIR}/interface/vcos/pthreads
|
||||
${BCMHOST_INCLUDE_DIR}/interface/vmcs_host/linux
|
||||
)
|
||||
|
||||
target_link_libraries(fgpanel-egl
|
||||
SimGearCore
|
||||
${PNG_LIBRARIES}
|
||||
${FREETYPE_LIBRARIES}
|
||||
-lbrcmGLESv2 -lbrcmEGL -lm -lbcm_host -L/opt/vc/lib
|
||||
)
|
||||
|
||||
target_compile_definitions(fgpanel-egl PUBLIC
|
||||
-D_GLES2 -D_RPI
|
||||
)
|
||||
target_compile_definitions(fgpanel PUBLIC
|
||||
-D_RPI
|
||||
)
|
||||
message(STATUS "FGPanel (Raspberry Pi) : ENABLED")
|
||||
install(TARGETS fgpanel-egl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
else(BCMHOST_INCLUDE_DIR)
|
||||
message(STATUS "FGPanel (Raspberry Pi) : DISABLED")
|
||||
endif(BCMHOST_INCLUDE_DIR)
|
||||
|
||||
|
||||
|
||||
|
||||
if(WITH_FGPANEL)
|
||||
message(STATUS "FGPanel : ENABLED")
|
||||
install(TARGETS fgpanel RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
else(WITH_FGPANEL)
|
||||
message(WARNING "FGPanel : DISABLED")
|
||||
endif(WITH_FGPANEL)
|
||||
127
utils/fgpanel/FGCroppedTexture.cxx
Normal file
127
utils/fgpanel/FGCroppedTexture.cxx
Normal file
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include "ApplicationProperties.hxx"
|
||||
#include "FGCroppedTexture.hxx"
|
||||
|
||||
GLuint FGCroppedTexture::s_current_bound_texture = 0;
|
||||
map <string, GLuint> FGCroppedTexture::s_cache;
|
||||
map <string, FGTextureLoaderInterface*> FGCroppedTexture::s_TextureLoader;
|
||||
FGDummyTextureLoader FGCroppedTexture::s_DummyTextureLoader;
|
||||
|
||||
FGCroppedTexture::FGCroppedTexture (const string &path,
|
||||
const float minX, const float minY,
|
||||
const float maxX, const float maxY) :
|
||||
m_path (path),
|
||||
m_minX (minX), m_minY (minY),
|
||||
m_maxX (maxX), m_maxY (maxY),
|
||||
m_texture(0) {
|
||||
}
|
||||
|
||||
FGCroppedTexture::~FGCroppedTexture () {
|
||||
}
|
||||
|
||||
void
|
||||
FGCroppedTexture::setPath (const string &path) {
|
||||
m_path = path;
|
||||
}
|
||||
|
||||
const string &
|
||||
FGCroppedTexture::getPath () const {
|
||||
return m_path;
|
||||
}
|
||||
|
||||
void
|
||||
FGCroppedTexture::setCrop (const float minX, const float minY, const float maxX, const float maxY) {
|
||||
m_minX = minX; m_minY = minY; m_maxX = maxX; m_maxY = maxY;
|
||||
}
|
||||
|
||||
void
|
||||
FGCroppedTexture::registerTextureLoader (const string &extension,
|
||||
FGTextureLoaderInterface * const loader) {
|
||||
if (s_TextureLoader.count (extension) == 0) {
|
||||
s_TextureLoader[extension] = loader;
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
FGCroppedTexture::getMinX () const {
|
||||
return m_minX;
|
||||
}
|
||||
|
||||
float
|
||||
FGCroppedTexture::getMinY () const {
|
||||
return m_minY;
|
||||
}
|
||||
|
||||
float
|
||||
FGCroppedTexture::getMaxX () const {
|
||||
return m_maxX;
|
||||
}
|
||||
|
||||
float
|
||||
FGCroppedTexture::getMaxY () const {
|
||||
return m_maxY;
|
||||
}
|
||||
|
||||
GLuint
|
||||
FGCroppedTexture::getTexture () const {
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
void
|
||||
FGCroppedTexture::bind (const GLint Textured_Layer_Sampler_Loc) {
|
||||
if (m_texture == 0) {
|
||||
SG_LOG (SG_COCKPIT,
|
||||
SG_DEBUG,
|
||||
"First bind of texture " << m_path);
|
||||
if (s_cache.count (m_path) > 0 ) {
|
||||
m_texture = s_cache[m_path];
|
||||
SG_LOG (SG_COCKPIT,
|
||||
SG_DEBUG,
|
||||
"Using texture " << m_path << " from cache (#" << m_texture << ")");
|
||||
} else {
|
||||
const SGPath path (ApplicationProperties::GetRootPath (m_path.c_str ()));
|
||||
const string extension (path.extension ());
|
||||
FGTextureLoaderInterface *loader (&s_DummyTextureLoader);
|
||||
if (s_TextureLoader.count (extension) == 0) {
|
||||
SG_LOG (SG_COCKPIT,
|
||||
SG_ALERT,
|
||||
"Can't handle textures of type " << extension);
|
||||
} else {
|
||||
loader = s_TextureLoader[extension];
|
||||
}
|
||||
|
||||
m_texture = loader->loadTexture (path.local8BitStr ());
|
||||
SG_LOG (SG_COCKPIT,
|
||||
SG_DEBUG,
|
||||
"Texture " << path << " loaded from file as #" << m_texture);
|
||||
s_cache[m_path] = m_texture;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_current_bound_texture != m_texture) {
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, m_texture);
|
||||
glUniform1i (Textured_Layer_Sampler_Loc, 0);
|
||||
s_current_bound_texture = m_texture;
|
||||
}
|
||||
}
|
||||
69
utils/fgpanel/FGCroppedTexture.hxx
Normal file
69
utils/fgpanel/FGCroppedTexture.hxx
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef FGCROPPEDTEXTURE_HXX
|
||||
#define FGCROPPEDTEXTURE_HXX
|
||||
|
||||
#include <map>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include "FGDummyTextureLoader.hxx"
|
||||
|
||||
/**
|
||||
* Cropped texture (should migrate out into FGFS).
|
||||
*
|
||||
* This structure wraps an SSG texture with cropping information.
|
||||
*/
|
||||
class FGCroppedTexture : public SGReferenced {
|
||||
public:
|
||||
FGCroppedTexture (const string &path,
|
||||
const float minX = 0.0, const float minY = 0.0,
|
||||
const float maxX = 1.0, const float maxY = 1.0);
|
||||
|
||||
virtual ~FGCroppedTexture ();
|
||||
|
||||
virtual void setPath (const string &path);
|
||||
|
||||
virtual const string &getPath () const;
|
||||
|
||||
virtual void setCrop (const float minX, const float minY, const float maxX, const float maxY);
|
||||
|
||||
static void registerTextureLoader (const string &extension,
|
||||
FGTextureLoaderInterface * const loader);
|
||||
|
||||
virtual float getMinX () const;
|
||||
virtual float getMinY () const;
|
||||
virtual float getMaxX () const;
|
||||
virtual float getMaxY () const;
|
||||
GLuint getTexture () const;
|
||||
|
||||
virtual void bind (const GLint Textured_Layer_Sampler_Loc);
|
||||
|
||||
private:
|
||||
string m_path;
|
||||
float m_minX, m_minY, m_maxX, m_maxY;
|
||||
|
||||
GLuint m_texture;
|
||||
static GLuint s_current_bound_texture;
|
||||
static map <string, GLuint> s_cache;
|
||||
static map <string, FGTextureLoaderInterface*> s_TextureLoader;
|
||||
static FGDummyTextureLoader s_DummyTextureLoader;
|
||||
};
|
||||
|
||||
typedef SGSharedPtr <FGCroppedTexture> FGCroppedTexture_ptr;
|
||||
|
||||
#endif
|
||||
41
utils/fgpanel/FGDummyTextureLoader.cxx
Normal file
41
utils/fgpanel/FGDummyTextureLoader.cxx
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "FGDummyTextureLoader.hxx"
|
||||
|
||||
GLuint
|
||||
FGDummyTextureLoader::loadTexture (const string& filename) {
|
||||
GLuint texture;
|
||||
glGenTextures (1, &texture);
|
||||
glBindTexture (GL_TEXTURE_2D, texture);
|
||||
|
||||
GLubyte image[ 2 * 2 * 3 ];
|
||||
|
||||
/* Red and white chequerboard */
|
||||
image [ 0] = 255; image [ 1] = 0; image [ 2] = 0;
|
||||
image [ 3] = 255; image [ 4] = 255; image [ 5] = 255;
|
||||
image [ 6] = 255; image [ 7] = 255; image [ 8] = 255;
|
||||
image [ 9] = 255; image [10] = 0; image [11] = 0;
|
||||
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
|
||||
GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) image);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
return texture;
|
||||
}
|
||||
29
utils/fgpanel/FGDummyTextureLoader.hxx
Normal file
29
utils/fgpanel/FGDummyTextureLoader.hxx
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "FGTextureLoaderInterface.hxx"
|
||||
|
||||
|
||||
class FGDummyTextureLoader : public FGTextureLoaderInterface {
|
||||
public:
|
||||
virtual GLuint loadTexture (const std::string& filename);
|
||||
};
|
||||
186
utils/fgpanel/FGFontCache.cxx
Normal file
186
utils/fgpanel/FGFontCache.cxx
Normal file
@@ -0,0 +1,186 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "FGGLApplication.hxx"
|
||||
#include "ApplicationProperties.hxx"
|
||||
#include "FGFontCache.hxx"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// FGFontCache class.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const unsigned short FGFontCache::First_Printable_Char = 32;
|
||||
const unsigned short FGFontCache::Last_Printable_Char = 127;
|
||||
|
||||
FGFontCache::FGFontCache () :
|
||||
m_Face_Map (),
|
||||
m_Current_Face_Ptr (NULL),
|
||||
m_Pos_Map (),
|
||||
m_Current_Pos (0) {
|
||||
if (FT_Init_FreeType (&m_Ft)) {
|
||||
SG_LOG (SG_COCKPIT, SG_ALERT, "Could not init freetype library");
|
||||
}
|
||||
for (unsigned int Index = 0; Index < Texture_Size * Texture_Size; ++Index) {
|
||||
m_Texture[Index] = char (0);
|
||||
}
|
||||
glGenTextures (1, &m_Glyph_Texture);
|
||||
}
|
||||
|
||||
FGFontCache::~FGFontCache () {
|
||||
for (Face_Map_Type::iterator It = m_Face_Map.begin (); It != m_Face_Map.end (); ++It) {
|
||||
delete (It->second);
|
||||
}
|
||||
m_Face_Map.clear ();
|
||||
glDeleteTextures (1, &m_Glyph_Texture);
|
||||
}
|
||||
|
||||
bool
|
||||
FGFontCache::Set_Font (const string& Font_Name,
|
||||
const float Size,
|
||||
GLuint &Glyph_Texture) {
|
||||
if (m_Face_Map.find (Font_Name) != m_Face_Map.end ()) {
|
||||
m_Current_Face_Ptr = m_Face_Map[Font_Name];
|
||||
} else {
|
||||
FT_Face * const Face_Ptr (new FT_Face);
|
||||
if (FT_New_Face (m_Ft, Font_Name.c_str (), 0, Face_Ptr)) {
|
||||
SG_LOG (SG_COCKPIT, SG_ALERT, "Could not open font : " + Font_Name);
|
||||
return false;
|
||||
}
|
||||
m_Face_Map.insert (pair <string, FT_Face *> (Font_Name, Face_Ptr));
|
||||
m_Current_Face_Ptr = Face_Ptr;
|
||||
}
|
||||
if (m_Current_Face_Ptr != NULL) {
|
||||
FT_Set_Pixel_Sizes (*m_Current_Face_Ptr, 0, Size);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const string Key_Str (Font_Name + "_" + Get_Size (Size));
|
||||
if (m_Pos_Map.find (Key_Str) != m_Pos_Map.end ()) {
|
||||
m_Current_Pos = m_Pos_Map[Key_Str];
|
||||
} else {
|
||||
m_Current_Pos = m_Pos_Map.size ();
|
||||
for (unsigned short ASCII_Code = First_Printable_Char;
|
||||
ASCII_Code < Last_Printable_Char;
|
||||
++ASCII_Code) {
|
||||
if (FT_Load_Char (*m_Current_Face_Ptr, char (ASCII_Code), FT_LOAD_RENDER)) {
|
||||
SG_LOG (SG_COCKPIT, SG_ALERT, "Could not load character : " << char (ASCII_Code));
|
||||
} else {
|
||||
unsigned int Line;
|
||||
unsigned int Column;
|
||||
const FT_GlyphSlot Glyph ((*m_Current_Face_Ptr)->glyph);
|
||||
for (unsigned int Row = 0; Row < Glyph->bitmap.rows; ++Row) {
|
||||
for (unsigned int Width = 0; Width < Glyph->bitmap.width; ++Width) {
|
||||
Get_Pos (ASCII_Code, Row, Width, Line, Column);
|
||||
m_Texture[Line * Texture_Size + Column] =
|
||||
Glyph->bitmap.buffer[Row * Glyph->bitmap.width + Width];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
glBindTexture (GL_TEXTURE_2D, m_Glyph_Texture);
|
||||
/* We require 1 byte alignment when uploading texture data */
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
|
||||
/* Clamping to edges is important to prevent artifacts when scaling */
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
/* Linear filtering usually looks best for text */
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D (GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_ALPHA,
|
||||
Texture_Size,
|
||||
Texture_Size,
|
||||
0,
|
||||
GL_ALPHA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
m_Texture);
|
||||
m_Pos_Map.insert (pair <string, unsigned int> (Key_Str, m_Current_Pos));
|
||||
}
|
||||
Glyph_Texture = m_Glyph_Texture;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FGFontCache::Get_Char (const char Char,
|
||||
int &X, int &Y,
|
||||
int &Left, int &Bottom,
|
||||
int &W, int &H,
|
||||
double &X1, double &Y1,
|
||||
double &X2, double &Y2) const {
|
||||
if (m_Current_Face_Ptr != NULL) {
|
||||
if (FT_Load_Char (*m_Current_Face_Ptr, Char, FT_LOAD_RENDER)) {
|
||||
SG_LOG (SG_COCKPIT, SG_ALERT, "Could not load character : " + Char);
|
||||
return false;
|
||||
} else {
|
||||
const FT_GlyphSlot Glyph ((*m_Current_Face_Ptr)->glyph);
|
||||
Left = Glyph->bitmap_left;
|
||||
W = Glyph->bitmap.width;
|
||||
H = Glyph->bitmap.rows;
|
||||
Bottom = Glyph->bitmap_top - H;
|
||||
X += (Glyph->advance.x >> 6);
|
||||
Y += (Glyph->advance.y >> 6);
|
||||
Get_Relative_Pos (int (Char), 0, 0, X1, Y1);
|
||||
Get_Relative_Pos (int (Char), Glyph->bitmap.rows, Glyph->bitmap.width, X2, Y2);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGFontCache::Get_Pos (const unsigned short ASCII_Code,
|
||||
const unsigned short Row,
|
||||
const unsigned short Width,
|
||||
unsigned int &Line,
|
||||
unsigned int &Column) const {
|
||||
const unsigned short Font_Size (32);
|
||||
Line = (((((ASCII_Code - First_Printable_Char) * Font_Size) / Texture_Size) + 3 * m_Current_Pos) * Font_Size) + Row;
|
||||
Column = (((ASCII_Code - First_Printable_Char) * Font_Size) % Texture_Size) + Width;
|
||||
}
|
||||
|
||||
void
|
||||
FGFontCache::Get_Relative_Pos (const unsigned short ASCII_Code,
|
||||
const unsigned short Row,
|
||||
const unsigned short Width,
|
||||
double &X,
|
||||
double &Y) const {
|
||||
unsigned int Line;
|
||||
unsigned int Column;
|
||||
Get_Pos (ASCII_Code, Row, Width, Line, Column);
|
||||
X = double (Column) / double (Texture_Size);
|
||||
Y = double (Line) / double (Texture_Size);
|
||||
}
|
||||
|
||||
string
|
||||
FGFontCache::Get_Size (const float Size) {
|
||||
const int Half_Size (int (round (2.0 * Size)));
|
||||
const int Int_Part (Half_Size / 2);
|
||||
const int Dec_Part ((Half_Size % 2) ? 5 : 0);
|
||||
stringstream Result_SS;
|
||||
Result_SS << Int_Part << "." << Dec_Part;
|
||||
return Result_SS.str ();
|
||||
}
|
||||
77
utils/fgpanel/FGFontCache.hxx
Normal file
77
utils/fgpanel/FGFontCache.hxx
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <GLUT/glut.h>
|
||||
#elif defined (_GLES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#else
|
||||
#include <GL/glew.h> // Must be included before <GL/gl.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* A class to keep all fonts available for future use.
|
||||
* This also assures a font isn't resident more than once.
|
||||
*/
|
||||
class FGFontCache {
|
||||
public:
|
||||
FGFontCache ();
|
||||
~FGFontCache ();
|
||||
bool Set_Font (const std::string& Font_Name,
|
||||
const float Size,
|
||||
GLuint &Glyph_Texture);
|
||||
bool Get_Char (const char Char,
|
||||
int &X, int &Y,
|
||||
int &Left, int &Bottom,
|
||||
int &W, int &H,
|
||||
double &X1, double &Y1, // Top (Y1) left (X1)
|
||||
double &X2, double &Y2) const; // Bottom (Y2) right (X2)
|
||||
private:
|
||||
void Get_Pos (const unsigned short ASCII_Code,
|
||||
const unsigned short Row,
|
||||
const unsigned short Width,
|
||||
unsigned int &Line,
|
||||
unsigned int &Column) const;
|
||||
void Get_Relative_Pos (const unsigned short ASCII_Code,
|
||||
const unsigned short Row,
|
||||
const unsigned short Width,
|
||||
double &X,
|
||||
double &Y) const;
|
||||
static std::string Get_Size (const float Size);
|
||||
static const unsigned short First_Printable_Char;
|
||||
static const unsigned short Last_Printable_Char;
|
||||
static const unsigned int Texture_Size = 1024;
|
||||
FT_Library m_Ft;
|
||||
typedef std::map <std::string, FT_Face *> Face_Map_Type;
|
||||
Face_Map_Type m_Face_Map;
|
||||
FT_Face *m_Current_Face_Ptr;
|
||||
char m_Texture[Texture_Size * Texture_Size];
|
||||
typedef std::map <std::string, unsigned int> Pos_Map_Type;
|
||||
Pos_Map_Type m_Pos_Map;
|
||||
unsigned int m_Current_Pos;
|
||||
GLuint m_Glyph_Texture;
|
||||
};
|
||||
156
utils/fgpanel/FGGLApplication.cxx
Normal file
156
utils/fgpanel/FGGLApplication.cxx
Normal file
@@ -0,0 +1,156 @@
|
||||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <GLUT/glut.h>
|
||||
#elif defined (_GLES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#include "GLES_utils.hxx"
|
||||
#else
|
||||
#include <GL/glew.h> // Must be included before <GL/gl.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/freeglut.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "FGGLApplication.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
FGGLApplication *FGGLApplication::application = NULL;
|
||||
|
||||
FGGLApplication::FGGLApplication (const char * a_name, int argc, char **argv) :
|
||||
gameMode (false),
|
||||
name (a_name) {
|
||||
if (application != NULL ) {
|
||||
cerr << "Only one instance of FGGLApplication allowed!" << endl;
|
||||
throw exception ();
|
||||
}
|
||||
application = this;
|
||||
|
||||
#ifdef _GLES2
|
||||
GLES_utils::instance ().init ("FG Panel");
|
||||
#else
|
||||
glutInit (&argc, argv);
|
||||
glutInitContextVersion (2, 1);
|
||||
glutInitContextFlags (GLUT_CORE_PROFILE);
|
||||
#endif
|
||||
}
|
||||
|
||||
FGGLApplication::~FGGLApplication () {
|
||||
#ifndef _GLES2
|
||||
if (gameMode) {
|
||||
glutLeaveGameMode ();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
FGGLApplication::DisplayCallback () {
|
||||
if (application) {
|
||||
application->Display ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGGLApplication::IdleCallback () {
|
||||
if (application) {
|
||||
application->Idle ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGGLApplication::KeyCallback (const unsigned char key, const int x, const int y) {
|
||||
if (application) {
|
||||
application->Key (key, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGGLApplication::ReshapeCallback (const int width, const int height) {
|
||||
if (application) {
|
||||
application->Reshape (width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGGLApplication::Run (const int glutMode,
|
||||
const bool gameMode,
|
||||
int width,
|
||||
int height,
|
||||
const int bpp) {
|
||||
#ifndef _GLES2
|
||||
glutInitDisplayMode (glutMode);
|
||||
if (gameMode) {
|
||||
width = glutGet (GLUT_SCREEN_WIDTH);
|
||||
height = glutGet (GLUT_SCREEN_HEIGHT);
|
||||
char game_mode_str[20];
|
||||
snprintf (game_mode_str, 20, "%dx%d:%d", width, height, bpp);
|
||||
glutGameModeString (game_mode_str);
|
||||
glutEnterGameMode ();
|
||||
this->gameMode = gameMode;
|
||||
} else {
|
||||
if (width == -1) {
|
||||
width = glutGet (GLUT_SCREEN_WIDTH);
|
||||
}
|
||||
if (height == -1) {
|
||||
height = glutGet (GLUT_SCREEN_HEIGHT);
|
||||
}
|
||||
glutInitDisplayMode (glutMode);
|
||||
glutInitWindowSize(width, height);
|
||||
windowId = glutCreateWindow (name);
|
||||
}
|
||||
const GLenum GLEW_err (glewInit ());
|
||||
if (GLEW_OK != GLEW_err) {
|
||||
cerr << "Unable to initialize GLEW " << glewGetErrorString (GLEW_err) << endl;
|
||||
exit (1);
|
||||
}
|
||||
if (!GLEW_VERSION_2_1) { // check that the machine supports the 2.1 API.
|
||||
cerr << "GLEW version 2.1 not supported : " << glewGetString (GLEW_VERSION) << endl;
|
||||
exit (1);
|
||||
}
|
||||
cout << "OpenGL version = " << glGetString (GL_VERSION) << endl;
|
||||
#endif
|
||||
Init ();
|
||||
#ifdef _GLES2
|
||||
GLES_utils::instance ().register_keyboard_func (FGGLApplication::KeyCallback);
|
||||
GLES_utils::instance ().register_idle_func (FGGLApplication::IdleCallback);
|
||||
GLES_utils::instance ().register_display_func (FGGLApplication::DisplayCallback);
|
||||
GLES_utils::instance ().register_reshape_func (FGGLApplication::ReshapeCallback);
|
||||
GLES_utils::instance ().main_loop ();
|
||||
#else
|
||||
glutKeyboardFunc (FGGLApplication::KeyCallback);
|
||||
glutIdleFunc (FGGLApplication::IdleCallback);
|
||||
glutDisplayFunc (FGGLApplication::DisplayCallback);
|
||||
glutReshapeFunc (FGGLApplication::ReshapeCallback);
|
||||
glutMainLoop ();
|
||||
#endif
|
||||
}
|
||||
52
utils/fgpanel/FGGLApplication.hxx
Normal file
52
utils/fgpanel/FGGLApplication.hxx
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGGLAPPLICATION_HXX
|
||||
#define __FGGLAPPLICATION_HXX
|
||||
|
||||
class FGGLApplication {
|
||||
public:
|
||||
FGGLApplication (const char *a_name, int argc, char **argv);
|
||||
virtual ~FGGLApplication ();
|
||||
void Run (const int glutMode,
|
||||
const bool gameMode,
|
||||
int widht = -1,
|
||||
int height = -1,
|
||||
const int bpp = 32);
|
||||
protected:
|
||||
virtual void Key (const unsigned char key, const int x, const int y) {}
|
||||
virtual void Idle () {}
|
||||
virtual void Display () {}
|
||||
virtual void Reshape (const int width, const int height) {}
|
||||
|
||||
virtual void Init () {}
|
||||
|
||||
int windowId;
|
||||
bool gameMode;
|
||||
|
||||
const char *name;
|
||||
|
||||
static FGGLApplication *application;
|
||||
private:
|
||||
static void KeyCallback (const unsigned char key, const int x, const int y);
|
||||
static void IdleCallback ();
|
||||
static void DisplayCallback ();
|
||||
static void ReshapeCallback (const int width, const int height);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
43
utils/fgpanel/FGGroupLayer.cxx
Normal file
43
utils/fgpanel/FGGroupLayer.cxx
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "FGGroupLayer.hxx"
|
||||
|
||||
FGGroupLayer::FGGroupLayer () {
|
||||
}
|
||||
|
||||
FGGroupLayer::~FGGroupLayer () {
|
||||
for (unsigned int i = 0; i < m_layers.size (); ++i)
|
||||
delete m_layers[i];
|
||||
}
|
||||
|
||||
void
|
||||
FGGroupLayer::draw () {
|
||||
if (test ()) {
|
||||
transform ();
|
||||
for (unsigned int i = 0; i < m_layers.size (); ++i) {
|
||||
m_layers[i]->draw ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGGroupLayer::addLayer (FGInstrumentLayer * const layer) {
|
||||
m_layers.push_back (layer);
|
||||
}
|
||||
43
utils/fgpanel/FGGroupLayer.hxx
Normal file
43
utils/fgpanel/FGGroupLayer.hxx
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef FGGROUPLAYER_HXX
|
||||
#define FGGROUPLAYER_HXX
|
||||
|
||||
#include "FGInstrumentLayer.hxx"
|
||||
|
||||
/**
|
||||
* An instrument layer containing a group of sublayers.
|
||||
*
|
||||
* This class is useful for gathering together a group of related
|
||||
* layers, either to hold in an external file or to work under
|
||||
* the same condition.
|
||||
*/
|
||||
class FGGroupLayer : public FGInstrumentLayer {
|
||||
public:
|
||||
FGGroupLayer ();
|
||||
virtual ~FGGroupLayer ();
|
||||
virtual void draw ();
|
||||
// transfer pointer ownership
|
||||
virtual void addLayer (FGInstrumentLayer * const layer);
|
||||
protected:
|
||||
vector <FGInstrumentLayer *> m_layers;
|
||||
};
|
||||
|
||||
#endif
|
||||
100
utils/fgpanel/FGInstrumentLayer.cxx
Normal file
100
utils/fgpanel/FGInstrumentLayer.cxx
Normal file
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include <math.h>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include "GL_utils.hxx"
|
||||
#include "FGInstrumentLayer.hxx"
|
||||
|
||||
FGInstrumentLayer::FGInstrumentLayer (const int w, const int h) :
|
||||
m_w (w), m_h (h) {
|
||||
}
|
||||
|
||||
FGInstrumentLayer::~FGInstrumentLayer () {
|
||||
for (transformation_list::iterator it = m_transformations.begin ();
|
||||
it != m_transformations.end ();
|
||||
++it) {
|
||||
delete *it;
|
||||
*it = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGInstrumentLayer::transform () const {
|
||||
for (transformation_list::const_iterator it = m_transformations.begin ();
|
||||
it != m_transformations.end ();
|
||||
++it) {
|
||||
FGPanelTransformation *t = *it;
|
||||
if (t->test ()) {
|
||||
float val (t->node == 0 ? 0.0 : t->node->getFloatValue ());
|
||||
if (t->has_mod) {
|
||||
val = fmod (val, t->mod);
|
||||
}
|
||||
if (val < t->min) {
|
||||
val = t->min;
|
||||
} else if (val > t->max) {
|
||||
val = t->max;
|
||||
}
|
||||
|
||||
if (t->table == 0) {
|
||||
val = val * t->factor + t->offset;
|
||||
} else {
|
||||
val = t->table->interpolate (val) * t->factor + t->offset;
|
||||
}
|
||||
|
||||
switch (t->type) {
|
||||
case FGPanelTransformation::XSHIFT:
|
||||
GL_utils::instance ().glTranslatef (val, 0.0, 0.0);
|
||||
break;
|
||||
case FGPanelTransformation::YSHIFT:
|
||||
GL_utils::instance ().glTranslatef (0.0, val, 0.0);
|
||||
break;
|
||||
case FGPanelTransformation::ROTATION:
|
||||
GL_utils::instance ().glRotatef (-val, 0.0, 0.0, 1.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
FGInstrumentLayer::getWidth () const {
|
||||
return m_w;
|
||||
}
|
||||
|
||||
int
|
||||
FGInstrumentLayer::getHeight () const {
|
||||
return m_h;
|
||||
}
|
||||
|
||||
void
|
||||
FGInstrumentLayer::setWidth (const int w) {
|
||||
m_w = w;
|
||||
}
|
||||
|
||||
void
|
||||
FGInstrumentLayer::setHeight (const int h) {
|
||||
m_h = h;
|
||||
}
|
||||
|
||||
void
|
||||
FGInstrumentLayer::addTransformation (FGPanelTransformation * const transformation) {
|
||||
m_transformations.push_back (transformation);
|
||||
}
|
||||
57
utils/fgpanel/FGInstrumentLayer.hxx
Normal file
57
utils/fgpanel/FGInstrumentLayer.hxx
Normal file
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <simgear/props/condition.hxx>
|
||||
|
||||
#include "FGPanelTransformation.hxx"
|
||||
|
||||
|
||||
/**
|
||||
* A single layer of a multi-layered instrument.
|
||||
*
|
||||
* Each layer can be subject to a series of transformations based
|
||||
* on current FGFS instrument readings: for example, a texture
|
||||
* representing a needle can rotate to show the airspeed.
|
||||
*/
|
||||
class FGInstrumentLayer : public SGConditional {
|
||||
public:
|
||||
FGInstrumentLayer (const int w = -1, const int h = -1);
|
||||
virtual ~FGInstrumentLayer ();
|
||||
|
||||
virtual void draw () = 0;
|
||||
virtual void transform () const;
|
||||
|
||||
virtual int getWidth () const;
|
||||
virtual int getHeight () const;
|
||||
virtual void setWidth (const int w);
|
||||
virtual void setHeight (const int h);
|
||||
|
||||
// Transfer pointer ownership!!
|
||||
// DEPRECATED
|
||||
virtual void addTransformation (FGPanelTransformation * const transformation);
|
||||
|
||||
protected:
|
||||
int m_w, m_h;
|
||||
|
||||
typedef std::vector <FGPanelTransformation *> transformation_list;
|
||||
transformation_list m_transformations;
|
||||
};
|
||||
70
utils/fgpanel/FGLayeredInstrument.cxx
Normal file
70
utils/fgpanel/FGLayeredInstrument.cxx
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "GL_utils.hxx"
|
||||
#include "FGLayeredInstrument.hxx"
|
||||
#include "FGTexturedLayer.hxx"
|
||||
|
||||
FGLayeredInstrument::FGLayeredInstrument (const int x, const int y, const int w, const int h) :
|
||||
FGPanelInstrument (x, y, w, h) {
|
||||
}
|
||||
|
||||
FGLayeredInstrument::~FGLayeredInstrument () {
|
||||
for (layer_list::iterator it = m_layers.begin();
|
||||
it != m_layers.end();
|
||||
++it) {
|
||||
delete *it;
|
||||
*it = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGLayeredInstrument::draw () {
|
||||
if (test ()) {
|
||||
for (unsigned int i = 0; i < m_layers.size (); ++i) {
|
||||
GL_utils::instance ().glPushMatrix ();
|
||||
m_layers[i]->draw ();
|
||||
GL_utils::instance ().glPopMatrix ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
FGLayeredInstrument::addLayer (FGInstrumentLayer * const layer) {
|
||||
const int n (m_layers.size ());
|
||||
if (layer->getWidth () == -1) {
|
||||
layer->setWidth (getWidth ());
|
||||
}
|
||||
if (layer->getHeight () == -1) {
|
||||
layer->setHeight (getHeight ());
|
||||
}
|
||||
m_layers.push_back (layer);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
FGLayeredInstrument::addLayer (const FGCroppedTexture_ptr texture, const int w, const int h) {
|
||||
return addLayer (new FGTexturedLayer (texture, w, h));
|
||||
}
|
||||
|
||||
void
|
||||
FGLayeredInstrument::addTransformation (FGPanelTransformation * const transformation) {
|
||||
const int layer (m_layers.size () - 1);
|
||||
m_layers[layer]->addTransformation (transformation);
|
||||
}
|
||||
50
utils/fgpanel/FGLayeredInstrument.hxx
Normal file
50
utils/fgpanel/FGLayeredInstrument.hxx
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FGCroppedTexture.hxx"
|
||||
#include "FGInstrumentLayer.hxx"
|
||||
#include "FGPanelInstrument.hxx"
|
||||
|
||||
|
||||
/**
|
||||
* An instrument constructed of multiple layers.
|
||||
*
|
||||
* Each individual layer can be rotated or shifted to correspond
|
||||
* to internal FGFS instrument readings.
|
||||
*/
|
||||
class FGLayeredInstrument : public FGPanelInstrument {
|
||||
public:
|
||||
FGLayeredInstrument (const int x, const int y, const int w, const int h);
|
||||
virtual ~FGLayeredInstrument ();
|
||||
|
||||
virtual void draw ();
|
||||
|
||||
// Transfer pointer ownership!!
|
||||
virtual int addLayer (FGInstrumentLayer * const layer);
|
||||
virtual int addLayer (const FGCroppedTexture_ptr texture, const int w = -1, const int h = -1);
|
||||
|
||||
// Transfer pointer ownership!!
|
||||
virtual void addTransformation (FGPanelTransformation * const transformation);
|
||||
|
||||
private:
|
||||
typedef std::vector <FGInstrumentLayer *> layer_list;
|
||||
layer_list m_layers;
|
||||
};
|
||||
156
utils/fgpanel/FGPNGTextureLoader.cxx
Normal file
156
utils/fgpanel/FGPNGTextureLoader.cxx
Normal file
@@ -0,0 +1,156 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <GLUT/glut.h>
|
||||
#elif defined (_GLES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#else
|
||||
#include <GL/glew.h> // Must be included before <GL/gl.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
#include <png.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "FGPNGTextureLoader.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
GLuint
|
||||
FGPNGTextureLoader::loadTexture (const string &filename) {
|
||||
//header for testing if it is a png
|
||||
png_byte header[8];
|
||||
|
||||
//open file as binary
|
||||
FILE * const fp (fopen (filename.c_str (), "rb"));
|
||||
if (!fp) {
|
||||
return NOTEXTURE;
|
||||
}
|
||||
|
||||
//read the header
|
||||
fread (header, 1, 8, fp);
|
||||
|
||||
//test if png
|
||||
const int is_png (!png_sig_cmp (header, 0, 8));
|
||||
if (!is_png) {
|
||||
fclose (fp);
|
||||
return NOTEXTURE;
|
||||
}
|
||||
|
||||
//create png struct
|
||||
png_structp png_ptr (png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL));
|
||||
if (!png_ptr) {
|
||||
fclose (fp);
|
||||
return NOTEXTURE;
|
||||
}
|
||||
|
||||
//create png info struct
|
||||
png_infop info_ptr (png_create_info_struct (png_ptr));
|
||||
if (!info_ptr) {
|
||||
png_destroy_read_struct (&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
|
||||
fclose (fp);
|
||||
return NOTEXTURE;
|
||||
}
|
||||
|
||||
//create png info struct
|
||||
png_infop end_info (png_create_info_struct (png_ptr));
|
||||
if (!end_info) {
|
||||
png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL);
|
||||
fclose (fp);
|
||||
return NOTEXTURE;
|
||||
}
|
||||
|
||||
//png error stuff, not sure libpng man suggests this.
|
||||
if (setjmp (png_jmpbuf (png_ptr))) {
|
||||
png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
|
||||
fclose (fp);
|
||||
return NOTEXTURE;
|
||||
}
|
||||
|
||||
// init png reading
|
||||
png_init_io (png_ptr, fp);
|
||||
|
||||
// let libpng know you already read the first 8 bytes
|
||||
png_set_sig_bytes (png_ptr, 8);
|
||||
|
||||
// read all the info up to the image data
|
||||
png_read_info (png_ptr, info_ptr);
|
||||
|
||||
// variables to pass to get info
|
||||
int bit_depth, color_type;
|
||||
png_uint_32 twidth, theight;
|
||||
|
||||
// get info about png
|
||||
png_get_IHDR (png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, NULL, NULL, NULL);
|
||||
|
||||
// Update the png info struct.
|
||||
png_read_update_info (png_ptr, info_ptr);
|
||||
|
||||
// Row size in bytes.
|
||||
const int rowbytes (png_get_rowbytes (png_ptr, info_ptr));
|
||||
|
||||
// Allocate the image_data as a big block, to be given to opengl
|
||||
png_byte *image_data (new png_byte[rowbytes * theight]);
|
||||
if (!image_data) {
|
||||
//clean up memory and close stuff
|
||||
png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
|
||||
fclose (fp);
|
||||
return NOTEXTURE;
|
||||
}
|
||||
|
||||
// row_pointers is for pointing to image_data for reading the png with libpng
|
||||
png_bytep *row_pointers (new png_bytep[theight]);
|
||||
if (!row_pointers) {
|
||||
//clean up memory and close stuff
|
||||
png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
|
||||
delete []image_data;
|
||||
fclose (fp);
|
||||
return NOTEXTURE;
|
||||
}
|
||||
// set the individual row_pointers to point at the correct offsets of image_data
|
||||
for (png_uint_32 i = 0; i < theight; ++i) {
|
||||
row_pointers[theight - 1 - i] = image_data + i * rowbytes;
|
||||
}
|
||||
//read the png into image_data through row_pointers
|
||||
png_read_image (png_ptr, row_pointers);
|
||||
|
||||
//Now generate the OpenGL texture object
|
||||
GLuint texture;
|
||||
glGenTextures (1, &texture);
|
||||
glBindTexture (GL_TEXTURE_2D, texture);
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, twidth, theight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) image_data);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
//clean up memory and close stuff
|
||||
png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
|
||||
delete []image_data;
|
||||
delete []row_pointers;
|
||||
fclose (fp);
|
||||
return texture;
|
||||
}
|
||||
28
utils/fgpanel/FGPNGTextureLoader.hxx
Normal file
28
utils/fgpanel/FGPNGTextureLoader.hxx
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGPNGTEXTURELOADER_HXX
|
||||
#define __FGPNGTEXTURELOADER_HXX
|
||||
|
||||
#include "FGTextureLoaderInterface.hxx"
|
||||
|
||||
class FGPNGTextureLoader : public FGTextureLoaderInterface {
|
||||
public:
|
||||
virtual GLuint loadTexture (const string &filename);
|
||||
|
||||
const static GLuint NOTEXTURE = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
441
utils/fgpanel/FGPanel.cxx
Normal file
441
utils/fgpanel/FGPanel.cxx
Normal file
@@ -0,0 +1,441 @@
|
||||
// FGPanel.cxx - default, 2D single-engine prop instrument panel
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id: FGPanel.cxx,v 1.1 2016/07/20 22:01:30 allaert Exp $
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h> // sprintf
|
||||
#include <string.h>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <GLUT/glut.h>
|
||||
#elif defined (_GLES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#else
|
||||
#include <GL/glew.h> // Must be included before <GL/gl.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
#include "GL_utils.hxx"
|
||||
#include "FGPanel.hxx"
|
||||
#include "FGTextLayer.hxx"
|
||||
#include "FGTexturedLayer.hxx"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Local functions.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
GLuint FGPanel::Textured_Layer_Program_Object (0);
|
||||
GLint FGPanel::Textured_Layer_Position_Loc (0);
|
||||
GLint FGPanel::Textured_Layer_Tex_Coord_Loc (0);
|
||||
GLint FGPanel::Textured_Layer_MVP_Loc (0);
|
||||
GLint FGPanel::Textured_Layer_Sampler_Loc (0);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGPanel.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
FGPanel::FGPanel (const SGPropertyNode_ptr root) :
|
||||
m_flipx (root->getNode ("/sim/panel/flip-x", true)),
|
||||
m_bg_width (1.0), m_bg_height (1.0) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
FGPanel::~FGPanel () {
|
||||
for (instrument_list_type::iterator it = m_instruments.begin ();
|
||||
it != m_instruments.end ();
|
||||
++it) {
|
||||
delete *it;
|
||||
*it = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the panel.
|
||||
*/
|
||||
void
|
||||
FGPanel::init () {
|
||||
// Textured Layer Shaders
|
||||
const char V_Textured_Layer_Shader_Str[] =
|
||||
#ifdef _RPI
|
||||
"#version 100 \n"
|
||||
"attribute vec4 a_position; \n"
|
||||
"attribute vec2 a_tex_coord; \n"
|
||||
"varying vec2 v_tex_coord; \n"
|
||||
#else
|
||||
"#version 130 \n"
|
||||
"in vec4 a_position; \n"
|
||||
"in vec2 a_tex_coord; \n"
|
||||
"out vec2 v_tex_coord; \n"
|
||||
#endif
|
||||
"uniform mat4 u_mvp_matrix; \n"
|
||||
"void main () { \n"
|
||||
" gl_Position = u_mvp_matrix * a_position; \n"
|
||||
" v_tex_coord = a_tex_coord; \n"
|
||||
"} \n";
|
||||
|
||||
const char F_Textured_Layer_Shader_Str[] =
|
||||
#ifdef _RPI
|
||||
"#version 100 \n"
|
||||
"precision mediump float; \n"
|
||||
"varying vec2 v_tex_coord; \n"
|
||||
#else
|
||||
"#version 130 \n"
|
||||
"in vec2 v_tex_coord; \n"
|
||||
#endif
|
||||
"uniform sampler2D u_texture; \n"
|
||||
"void main () { \n"
|
||||
" vec4 base_color = texture2D (u_texture, v_tex_coord); \n"
|
||||
" if (base_color.a <= 0.1) { \n"
|
||||
" discard; \n"
|
||||
" } \n"
|
||||
" gl_FragColor = base_color; \n"
|
||||
"} \n";
|
||||
|
||||
Textured_Layer_Program_Object = GL_utils::instance ().load_program (V_Textured_Layer_Shader_Str,
|
||||
F_Textured_Layer_Shader_Str);
|
||||
if (Textured_Layer_Program_Object == 0) {
|
||||
terminate ();
|
||||
}
|
||||
|
||||
// Get the attribute locations
|
||||
Textured_Layer_Position_Loc = glGetAttribLocation (Textured_Layer_Program_Object, "a_position");
|
||||
Textured_Layer_Tex_Coord_Loc = glGetAttribLocation (Textured_Layer_Program_Object, "a_tex_coord");
|
||||
|
||||
// Get the uniform locations
|
||||
Textured_Layer_MVP_Loc = glGetUniformLocation (Textured_Layer_Program_Object, "u_mvp_matrix");
|
||||
|
||||
// Get the sampler location
|
||||
Textured_Layer_Sampler_Loc = glGetUniformLocation (Textured_Layer_Program_Object, "u_texture");
|
||||
|
||||
FGTexturedLayer::Init (Textured_Layer_Program_Object,
|
||||
Textured_Layer_Position_Loc,
|
||||
Textured_Layer_Tex_Coord_Loc,
|
||||
Textured_Layer_MVP_Loc,
|
||||
Textured_Layer_Sampler_Loc);
|
||||
|
||||
// Text Layer Shaders
|
||||
if (!FGTextLayer::Init ()) {
|
||||
terminate ();
|
||||
}
|
||||
|
||||
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind panel properties.
|
||||
*/
|
||||
void
|
||||
FGPanel::bind () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind panel properties.
|
||||
*/
|
||||
void
|
||||
FGPanel::unbind () {
|
||||
}
|
||||
|
||||
void
|
||||
FGPanel::update (double dt) {
|
||||
getInitDisplayList ();
|
||||
// Draw the instruments.
|
||||
// Syd Adams: added instrument clipping
|
||||
for (instrument_list_type::const_iterator current = m_instruments.begin ();
|
||||
current != m_instruments.end ();
|
||||
++current) {
|
||||
FGPanelInstrument *instr = *current;
|
||||
GL_utils::instance ().glPushMatrix ();
|
||||
GL_utils::instance ().glTranslatef (instr->getXPos (), instr->getYPos (), 0);
|
||||
|
||||
instr->draw();
|
||||
|
||||
GL_utils::instance ().glPopMatrix ();
|
||||
}
|
||||
#ifndef _GLES2
|
||||
// restore some original state
|
||||
//glPopAttrib ();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an instrument to the panel.
|
||||
*/
|
||||
void
|
||||
FGPanel::addInstrument (FGPanelInstrument * const instrument) {
|
||||
m_instruments.push_back (instrument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the panel's background texture.
|
||||
*/
|
||||
void
|
||||
FGPanel::setBackground (const FGCroppedTexture_ptr texture) {
|
||||
m_bg = texture;
|
||||
}
|
||||
|
||||
void
|
||||
FGPanel::setBackgroundWidth (const double d) {
|
||||
m_bg_width = d;
|
||||
}
|
||||
|
||||
void
|
||||
FGPanel::setBackgroundHeight (const double d) {
|
||||
m_bg_height = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the panel's multiple background textures.
|
||||
*/
|
||||
void
|
||||
FGPanel::setMultiBackground (const FGCroppedTexture_ptr texture, const int idx) {
|
||||
m_bg = 0;
|
||||
m_mbg[idx] = texture;
|
||||
}
|
||||
|
||||
void
|
||||
FGPanel::setWidth (const int width) {
|
||||
m_width = width;
|
||||
}
|
||||
|
||||
int
|
||||
FGPanel::getWidth () const {
|
||||
return m_width;
|
||||
}
|
||||
|
||||
void
|
||||
FGPanel::setHeight (const int height) {
|
||||
m_height = height;
|
||||
}
|
||||
|
||||
int
|
||||
FGPanel::getHeight () const {
|
||||
return m_height;
|
||||
}
|
||||
|
||||
void
|
||||
FGPanel::getInitDisplayList () {
|
||||
glUseProgram (Textured_Layer_Program_Object);
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
|
||||
GL_utils::instance ().glLoadIdentity ();
|
||||
if (m_flipx->getBoolValue ()) {
|
||||
GL_utils::instance ().gluOrtho2D (m_width, 0, m_height, 0);
|
||||
} else {
|
||||
GL_utils::instance ().gluOrtho2D (0, m_width, 0, m_height);
|
||||
}
|
||||
GL_utils::instance ().glTranslatef (-1.0f, -1.0f, 0.0f);
|
||||
GL_utils::instance ().glScalef (2.0f / GLfloat (m_width), 2.0f / GLfloat (m_height), 1.0f);
|
||||
|
||||
#ifndef _GLES2
|
||||
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
||||
#endif
|
||||
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
|
||||
GL_utils::instance ().glLoadIdentity ();
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glUseProgram (Textured_Layer_Program_Object);
|
||||
#ifndef _GLES2
|
||||
// save some state
|
||||
//glPushAttrib (GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT |
|
||||
// GL_TEXTURE_BIT | GL_PIXEL_MODE_BIT | GL_CULL_FACE |
|
||||
// GL_DEPTH_BUFFER_BIT );
|
||||
#endif
|
||||
// Draw the background
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
#ifndef _GLES2
|
||||
glDisable (GL_LIGHTING);
|
||||
#endif
|
||||
glEnable (GL_BLEND);
|
||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
#ifndef _GLES2
|
||||
glEnable (GL_COLOR_MATERIAL);
|
||||
#endif
|
||||
glEnable (GL_CULL_FACE);
|
||||
glCullFace (GL_BACK);
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
|
||||
if (m_bg != NULL) {
|
||||
m_bg->bind (Textured_Layer_Sampler_Loc);
|
||||
const GLfloat v_Vertices[] = {
|
||||
0.0f, 0.0f, 0.0f, // Position 0 (bottom left corner)
|
||||
0.0f, 0.0f, // TexCoord 0 (bottom left corner)
|
||||
float (m_width), 0.0f, 0.0f, // Position 1 (bottom right corner)
|
||||
float (m_bg_width), 0.0f, // TexCoord 1 (bottom right corner)
|
||||
float (m_width), float (m_height), 0.0f, // Position 2 (top right corner)
|
||||
float (m_bg_width), float (m_bg_height), // TexCoord 2 (top right corner)
|
||||
0.0f, float (m_height), 0.0f, // Position 3 (top left corner)
|
||||
0.0f, float (m_bg_height) }; // TexCoord 3 (top left corner)
|
||||
glVertexAttribPointer (Textured_Layer_Position_Loc,
|
||||
3,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
5 * sizeof (GLfloat),
|
||||
v_Vertices);
|
||||
glVertexAttribPointer (Textured_Layer_Tex_Coord_Loc,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
5 * sizeof (GLfloat),
|
||||
&v_Vertices[3]);
|
||||
|
||||
glEnableVertexAttribArray (Textured_Layer_Position_Loc);
|
||||
glEnableVertexAttribArray (Textured_Layer_Tex_Coord_Loc);
|
||||
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
|
||||
GL_utils::instance ().glPushMatrix ();
|
||||
GL_utils::instance ().glMultMatrixf
|
||||
(*reinterpret_cast <GLfloat (*)[4][4]>
|
||||
(GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_MODELVIEW)));
|
||||
glUniformMatrix4fv (Textured_Layer_MVP_Loc,
|
||||
1,
|
||||
GL_FALSE,
|
||||
GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_PROJECTION));
|
||||
|
||||
const GLushort indices[] = {0, 1, 2, 0, 2, 3};
|
||||
glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
|
||||
|
||||
GL_utils::instance ().glPopMatrix ();
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
|
||||
} else if (m_mbg[0] != NULL) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// top row of textures...(1,3,5,7)
|
||||
m_mbg[i*2]->bind (Textured_Layer_Sampler_Loc);
|
||||
const GLfloat v_Vertices_Top[] = {
|
||||
float (i * m_width / 4), float (m_height / 2), 0.0f, // Position 0 (bottom left corner)
|
||||
0.0f, 0.0f, // TexCoord 0 (bottom left corner)
|
||||
float ((i + 1) * m_width / 4), float (m_height / 2), 0.0f, // Position 1 (bottom right corner)
|
||||
1.0f, 0.0f, // TexCoord 1 (bottom right corner)
|
||||
float ((i + 1) * m_width / 4), float (m_height), 0.0f, // Position 2 (top right corner)
|
||||
1.0f, 1.0f, // TexCoord 2 (top right corner)
|
||||
float (i * m_width / 4), float (m_height), 0.0f, // Position 3 (top left corner)
|
||||
0.0f, 1.0f }; // TexCoord 3 (top left corner)
|
||||
glVertexAttribPointer (Textured_Layer_Position_Loc,
|
||||
3,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
5 * sizeof (GLfloat),
|
||||
v_Vertices_Top);
|
||||
glVertexAttribPointer (Textured_Layer_Tex_Coord_Loc,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
5 * sizeof (GLfloat),
|
||||
&v_Vertices_Top[3]);
|
||||
|
||||
glEnableVertexAttribArray (Textured_Layer_Position_Loc);
|
||||
glEnableVertexAttribArray (Textured_Layer_Tex_Coord_Loc);
|
||||
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
|
||||
GL_utils::instance ().glPushMatrix ();
|
||||
GL_utils::instance ().glMultMatrixf
|
||||
(*reinterpret_cast <GLfloat (*)[4][4]>
|
||||
(GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_MODELVIEW)));
|
||||
glUniformMatrix4fv (Textured_Layer_MVP_Loc,
|
||||
1,
|
||||
GL_FALSE,
|
||||
GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_PROJECTION));
|
||||
|
||||
const GLushort indices[] = {0, 1, 2, 0, 2, 3};
|
||||
glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
|
||||
|
||||
GL_utils::instance ().glPopMatrix ();
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
|
||||
|
||||
// bottom row of textures...(2,4,6,8)
|
||||
m_mbg[i*2+1]->bind (Textured_Layer_Sampler_Loc);
|
||||
const GLfloat v_Vertices_Bot[] = {
|
||||
float (i * m_width / 4), 0.0f, 0.0f, // Position 0 (bottom left corner)
|
||||
0.0f, 0.0f, // TexCoord 0 (bottom left corner)
|
||||
float ((i + 1) * m_width / 4), 0.0f, 0.0f, // Position 1 (bottom right corner)
|
||||
1.0f, 0.0f, // TexCoord 1 (bottom right corner)
|
||||
float ((i + 1) * m_width / 4), float (m_height / 2), 0.0f, // Position 2 (top right corner)
|
||||
1.0f, 1.0f, // TexCoord 2 (top right corner)
|
||||
float (i * m_width / 4), float (m_height / 2), 0.0f, // Position 3 (top left corner)
|
||||
0.0f, 1.0f }; // TexCoord 3 (top left corner)
|
||||
glVertexAttribPointer (Textured_Layer_Position_Loc,
|
||||
3,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
5 * sizeof (GLfloat),
|
||||
v_Vertices_Bot);
|
||||
glVertexAttribPointer (Textured_Layer_Tex_Coord_Loc,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
5 * sizeof (GLfloat),
|
||||
&v_Vertices_Bot[3]);
|
||||
|
||||
glEnableVertexAttribArray (Textured_Layer_Position_Loc);
|
||||
glEnableVertexAttribArray (Textured_Layer_Tex_Coord_Loc);
|
||||
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
|
||||
GL_utils::instance ().glPushMatrix ();
|
||||
GL_utils::instance ().glMultMatrixf
|
||||
(*reinterpret_cast <GLfloat (*)[4][4]>
|
||||
(GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_MODELVIEW)));
|
||||
glUniformMatrix4fv (Textured_Layer_MVP_Loc,
|
||||
1,
|
||||
GL_FALSE,
|
||||
GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_PROJECTION));
|
||||
|
||||
glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
|
||||
|
||||
GL_utils::instance ().glPopMatrix ();
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
|
||||
}
|
||||
} else {
|
||||
#ifndef _GLES2
|
||||
glUseProgram (0);
|
||||
float c[4];
|
||||
glGetFloatv (GL_CURRENT_COLOR, c);
|
||||
glColor4f (1.0, 0.0, 0.0, 1.0);
|
||||
glBegin (GL_QUADS);
|
||||
glVertex2f (0, 0);
|
||||
glVertex2f (m_width, 0);
|
||||
glVertex2f (m_width, m_height);
|
||||
glVertex2f (0, m_height);
|
||||
glEnd ();
|
||||
glColor4fv (c);
|
||||
glUseProgram (Textured_Layer_Program_Object);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Register the subsystem.
|
||||
#if 0
|
||||
SGSubsystemMgr::Registrant<FGPanel> registrantFGPanel;
|
||||
#endif
|
||||
102
utils/fgpanel/FGPanel.hxx
Normal file
102
utils/fgpanel/FGPanel.hxx
Normal file
@@ -0,0 +1,102 @@
|
||||
// FGPanel.hxx - generic support classes for a 2D panel.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id: FGPanel.hxx,v 1.1 2016/07/20 22:01:30 allaert Exp $
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
|
||||
#include <simgear/props/propsfwd.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
#include "FGCroppedTexture.hxx"
|
||||
#include "FGPanelInstrument.hxx"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Top-level panel.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Instrument panel class.
|
||||
*
|
||||
* The panel is a container that has a background texture and holds
|
||||
* zero or more instruments. The panel will order the instruments to
|
||||
* redraw themselves when necessary, and will pass mouse clicks on to
|
||||
* the appropriate instruments for processing.
|
||||
*/
|
||||
class FGPanel : public SGSubsystem {
|
||||
public:
|
||||
FGPanel (const SGPropertyNode_ptr root);
|
||||
virtual ~FGPanel ();
|
||||
|
||||
// Subsystem API.
|
||||
void init() override;
|
||||
void bind() override;
|
||||
void unbind() override;
|
||||
void update(double dt) override;
|
||||
|
||||
// Subsystem identification.
|
||||
static const char* staticSubsystemClassId() { return "panel"; }
|
||||
|
||||
// transfer pointer ownership!!!
|
||||
virtual void addInstrument (FGPanelInstrument * const instrument);
|
||||
|
||||
// Background texture.
|
||||
virtual void setBackground (const FGCroppedTexture_ptr texture);
|
||||
void setBackgroundWidth (const double d);
|
||||
void setBackgroundHeight (const double d);
|
||||
|
||||
// Background multiple textures.
|
||||
virtual void setMultiBackground (const FGCroppedTexture_ptr texture , const int idx);
|
||||
|
||||
// Full width of panel.
|
||||
virtual void setWidth (const int width);
|
||||
virtual int getWidth () const;
|
||||
|
||||
// Full height of panel.
|
||||
virtual void setHeight (const int height);
|
||||
virtual int getHeight () const;
|
||||
|
||||
private:
|
||||
typedef std::vector <FGPanelInstrument *> instrument_list_type;
|
||||
int m_width;
|
||||
int m_height;
|
||||
|
||||
SGPropertyNode_ptr m_flipx;
|
||||
|
||||
FGCroppedTexture_ptr m_bg;
|
||||
double m_bg_width;
|
||||
double m_bg_height;
|
||||
FGCroppedTexture_ptr m_mbg[8];
|
||||
// List of instruments in panel.
|
||||
instrument_list_type m_instruments;
|
||||
|
||||
void getInitDisplayList ();
|
||||
|
||||
static GLuint Textured_Layer_Program_Object;
|
||||
static GLint Textured_Layer_Position_Loc;
|
||||
static GLint Textured_Layer_Tex_Coord_Loc;
|
||||
static GLint Textured_Layer_MVP_Loc;
|
||||
static GLint Textured_Layer_Sampler_Loc;
|
||||
};
|
||||
332
utils/fgpanel/FGPanelApplication.cxx
Normal file
332
utils/fgpanel/FGPanelApplication.cxx
Normal file
@@ -0,0 +1,332 @@
|
||||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
# include <windows.h>
|
||||
# include <direct.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <GLUT/glut.h>
|
||||
#elif defined (_GLES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#else
|
||||
#include <GL/glew.h> // Must be included before <GL/gl.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
#include "FGGLApplication.hxx"
|
||||
#include "FGPanelApplication.hxx"
|
||||
|
||||
#include <simgear/math/SGMisc.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/misc/ResourceManager.hxx>
|
||||
|
||||
#include "panel_io.hxx"
|
||||
#include "ApplicationProperties.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
inline static string
|
||||
ParseArgs (int argc, char **argv, const string &token) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
const string arg (argv[i]);
|
||||
if (arg.find (token) == 0) {
|
||||
return arg.substr (token.length ());
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// define default location of fgdata (use the same as for fgfs)
|
||||
inline static SGPath
|
||||
platformDefaultRoot () {
|
||||
#if defined(__CYGWIN__)
|
||||
return SGPath ("../data");
|
||||
#elif defined(_WIN32)
|
||||
return SGPath ("..\\data");
|
||||
#elif defined(__APPLE__)
|
||||
/*
|
||||
The following code looks for the base package inside the application
|
||||
bundle, in the standard Contents/Resources location.
|
||||
*/
|
||||
CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL (CFBundleGetMainBundle ());
|
||||
|
||||
// look for a 'data' subdir
|
||||
CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent (NULL, resourcesUrl, CFSTR ("data"), true);
|
||||
|
||||
// now convert down to a path, and the a c-string
|
||||
CFStringRef path = CFURLCopyFileSystemPath (dataDir, kCFURLPOSIXPathStyle);
|
||||
string root = CFStringGetCStringPtr (path, CFStringGetSystemEncoding ());
|
||||
|
||||
CFRelease (resourcesUrl);
|
||||
CFRelease (dataDir);
|
||||
CFRelease (path);
|
||||
|
||||
return SGPath (root);
|
||||
#else
|
||||
return SGPath (PKGLIBDIR);
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "FGPNGTextureLoader.hxx"
|
||||
#include "FGRGBTextureLoader.hxx"
|
||||
|
||||
static FGPNGTextureLoader pngTextureLoader;
|
||||
static FGRGBTextureLoader rgbTextureLoader;
|
||||
|
||||
FGPanelApplication::FGPanelApplication (int argc, char **argv) :
|
||||
FGGLApplication ("FlightGear Panel", argc, argv) {
|
||||
sglog().setLogLevels (SG_ALL, SG_WARN);
|
||||
FGCroppedTexture::registerTextureLoader ("png", &pngTextureLoader);
|
||||
FGCroppedTexture::registerTextureLoader ("rgb", &rgbTextureLoader);
|
||||
|
||||
ApplicationProperties::root = platformDefaultRoot ().local8BitStr ();
|
||||
|
||||
const string panelFilename (ParseArgs (argc, argv, "--panel="));
|
||||
const string fgRoot (ParseArgs (argc, argv, "--fg-root="));
|
||||
|
||||
if (fgRoot.length () > 0) {
|
||||
ApplicationProperties::root = fgRoot;
|
||||
}
|
||||
simgear::ResourceManager::instance ()->addBasePath (ApplicationProperties::root);
|
||||
|
||||
if (panelFilename.length () == 0 ) {
|
||||
cerr << "Need a panel filename. Use --panel=path_to_filename" << endl;
|
||||
throw exception ();
|
||||
}
|
||||
|
||||
// see if we got a valid fgdata path
|
||||
SGPath BaseCheck (ApplicationProperties::root);
|
||||
BaseCheck.append ("version");
|
||||
if (!BaseCheck.exists ()) {
|
||||
cerr << "Missing base package. Use --fg-root=path_to_fgdata" << endl;
|
||||
throw exception ();
|
||||
}
|
||||
|
||||
try {
|
||||
const SGPath tpath (ApplicationProperties::GetRootPath (panelFilename.c_str ()));
|
||||
readProperties (tpath, ApplicationProperties::Properties);
|
||||
}
|
||||
catch (sg_io_exception & e) {
|
||||
cerr << e.getFormattedMessage () << endl;
|
||||
throw;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const string arg (argv[i]);
|
||||
if (arg.find ("--prop:") == 0 ) {
|
||||
const string s2 (arg.substr (7));
|
||||
string::size_type p (s2.find ("="));
|
||||
if (p != string::npos) {
|
||||
const string propertyName (s2.substr (0, p));
|
||||
const string propertyValue (s2.substr (p + 1));
|
||||
ApplicationProperties::Properties->getNode (propertyName.c_str (), true )->setValue (propertyValue.c_str ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SGPropertyNode_ptr n (ApplicationProperties::Properties->getNode ("panel"));
|
||||
if (n != NULL) {
|
||||
panel = FGReadablePanel::read (n);
|
||||
}
|
||||
protocol = new FGPanelProtocol (ApplicationProperties::Properties->getNode ("communication", true));
|
||||
protocol->init ();
|
||||
}
|
||||
|
||||
FGPanelApplication::~FGPanelApplication () {
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelApplication::Run () {
|
||||
#ifdef _GLES2
|
||||
const int mode (0);
|
||||
#else
|
||||
const int mode (GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
|
||||
#endif
|
||||
int w (panel == NULL ? 0 : panel->getWidth ());
|
||||
int h (panel == NULL ? 0 : panel->getHeight ());
|
||||
if (w == 0 && h == 0) {
|
||||
w = 1024;
|
||||
h = 768;
|
||||
} else if (w == 0) {
|
||||
w = h / 0.75;
|
||||
} else if (h == 0) {
|
||||
h = w * 0.75;
|
||||
}
|
||||
|
||||
const bool gameMode (ApplicationProperties::Properties->getNode ( "game-mode", true)->getBoolValue ());
|
||||
FGGLApplication::Run (mode, gameMode, w, h);
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelApplication::Init () {
|
||||
#ifndef _GLES2
|
||||
glutSetCursor (GLUT_CURSOR_NONE);
|
||||
#endif
|
||||
if (panel != NULL) {
|
||||
panel->init ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelApplication::Reshape (const int width, const int height) {
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
glViewport (0, 0, GLsizei (width), GLsizei (height));
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelApplication::Idle () {
|
||||
#ifndef _GLES2
|
||||
const double d (glutGet (GLUT_ELAPSED_TIME));
|
||||
#endif
|
||||
const double dt (Sleep ());
|
||||
if (dt == 0) {
|
||||
return;
|
||||
}
|
||||
if (panel != NULL) {
|
||||
panel->update (dt);
|
||||
}
|
||||
#ifndef _GLES2
|
||||
glutSwapBuffers ();
|
||||
#endif
|
||||
if (protocol != NULL) {
|
||||
protocol->update (dt);
|
||||
}
|
||||
#ifndef _GLES2
|
||||
static double dsum = 0.0;
|
||||
static unsigned cnt = 0;
|
||||
dsum += glutGet (GLUT_ELAPSED_TIME) - d;
|
||||
cnt++;
|
||||
if (dsum > 1000.0) {
|
||||
ApplicationProperties::Properties->getNode ("/sim/frame-rate", true)->setDoubleValue (cnt * 1000.0 / dsum);
|
||||
dsum = 0.0;
|
||||
cnt = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelApplication::Key (const unsigned char key, const int x, const int y) {
|
||||
switch (key) {
|
||||
case 0x1b:
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
FGPanelApplication::Sleep () {
|
||||
SGTimeStamp current_time_stamp;
|
||||
static SGTimeStamp last_time_stamp;
|
||||
|
||||
if (last_time_stamp.get_seconds () == 0) {
|
||||
last_time_stamp.stamp ();
|
||||
}
|
||||
const double model_hz (60);
|
||||
const double throttle_hz (ApplicationProperties::getDouble ("/sim/frame-rate-throttle-hz", 0.0));
|
||||
if (throttle_hz > 0.0) {
|
||||
// optionally throttle the frame rate (to get consistent frame
|
||||
// rates or reduce cpu usage.
|
||||
|
||||
double frame_us (1.0e6 / throttle_hz);
|
||||
|
||||
// sleep based timing loop.
|
||||
//
|
||||
// Calling sleep, even usleep() on linux is less accurate than
|
||||
// we like, but it does free up the cpu for other tasks during
|
||||
// the sleep so it is desirable. Because of the way sleep()
|
||||
// is implemented in consumer operating systems like windows
|
||||
// and linux, you almost always sleep a little longer than the
|
||||
// requested amount.
|
||||
//
|
||||
// To combat the problem of sleeping too long, we calculate the
|
||||
// desired wait time and shorten it by 2000us (2ms) to avoid
|
||||
// [hopefully] over-sleep'ing. The 2ms value was arrived at
|
||||
// via experimentation. We follow this up at the end with a
|
||||
// simple busy-wait loop to get the final pause timing exactly
|
||||
// right.
|
||||
//
|
||||
// Assuming we don't oversleep by more than 2000us, this
|
||||
// should be a reasonable compromise between sleep based
|
||||
// waiting, and busy waiting.
|
||||
|
||||
// sleep() will always overshoot by a bit so undersleep by
|
||||
// 2000us in the hopes of never oversleeping.
|
||||
frame_us -= 2000.0;
|
||||
if (frame_us < 0.0) {
|
||||
frame_us = 0.0;
|
||||
}
|
||||
current_time_stamp.stamp ();
|
||||
|
||||
/* Convert to ms */
|
||||
const double elapsed_us ((current_time_stamp - last_time_stamp).toUSecs ());
|
||||
if (elapsed_us < frame_us) {
|
||||
const double requested_us (frame_us - elapsed_us);
|
||||
#ifdef _WIN32
|
||||
::Sleep (int (requested_us / 1000.0));
|
||||
#else
|
||||
usleep (useconds_t (requested_us));
|
||||
#endif
|
||||
}
|
||||
// busy wait timing loop.
|
||||
//
|
||||
// This yields the most accurate timing. If the previous
|
||||
// usleep() call is omitted this will peg the cpu
|
||||
// (which is just fine if FG is the only app you care about.)
|
||||
current_time_stamp.stamp ();
|
||||
const SGTimeStamp next_time_stamp (last_time_stamp + SGTimeStamp::fromSec (1e-6*frame_us));
|
||||
while (current_time_stamp < next_time_stamp) {
|
||||
current_time_stamp.stamp ();
|
||||
}
|
||||
|
||||
} else {
|
||||
current_time_stamp.stamp ();
|
||||
}
|
||||
|
||||
static double reminder = 0.0;
|
||||
static long global_multi_loop = 0;
|
||||
const double real_delta_time_sec ((double (current_time_stamp.toUSecs () - last_time_stamp.toUSecs ()) / 1000000.0) + reminder);
|
||||
last_time_stamp = current_time_stamp;
|
||||
//fprintf(stdout,"\r%4.1lf ", 1/real_delta_time_sec );
|
||||
//fflush(stdout);
|
||||
|
||||
// round the real time down to a multiple of 1/model-hz.
|
||||
// this way all systems are updated the _same_ amount of dt.
|
||||
global_multi_loop = long (floor (real_delta_time_sec * model_hz));
|
||||
global_multi_loop = SGMisc<long>::max (0, global_multi_loop);
|
||||
reminder = real_delta_time_sec - double (global_multi_loop) / double (model_hz);
|
||||
return double (global_multi_loop) / double (model_hz);
|
||||
}
|
||||
51
utils/fgpanel/FGPanelApplication.hxx
Normal file
51
utils/fgpanel/FGPanelApplication.hxx
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGPANELAPPLICATION_HXX
|
||||
#define __FGPANELAPPLICATION_HXX
|
||||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
#include "FGGLApplication.hxx"
|
||||
#include "FGPanel.hxx"
|
||||
#include "FGPanelProtocol.hxx"
|
||||
|
||||
class FGPanelApplication : public FGGLApplication {
|
||||
public:
|
||||
FGPanelApplication (int argc, char **argv);
|
||||
~FGPanelApplication ();
|
||||
|
||||
void Run ();
|
||||
|
||||
protected:
|
||||
virtual void Key (const unsigned char key, const int x, const int y);
|
||||
virtual void Idle ();
|
||||
// !!! virtual void Display ();
|
||||
virtual void Reshape (const int width, const int height);
|
||||
|
||||
virtual void Init ();
|
||||
|
||||
double Sleep ();
|
||||
|
||||
SGSharedPtr<FGPanel> panel;
|
||||
SGSharedPtr<FGPanelProtocol> protocol;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
#endif
|
||||
65
utils/fgpanel/FGPanelInstrument.cxx
Normal file
65
utils/fgpanel/FGPanelInstrument.cxx
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "FGPanelInstrument.hxx"
|
||||
|
||||
FGPanelInstrument::FGPanelInstrument () {
|
||||
setPosition (0, 0);
|
||||
setSize (0, 0);
|
||||
}
|
||||
|
||||
FGPanelInstrument::FGPanelInstrument (const int x, const int y, const int w, const int h) {
|
||||
setPosition (x, y);
|
||||
setSize (w, h);
|
||||
}
|
||||
|
||||
FGPanelInstrument::~FGPanelInstrument () {
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelInstrument::setPosition (const int x, const int y) {
|
||||
m_x = x;
|
||||
m_y = y;
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelInstrument::setSize (const int w, const int h) {
|
||||
m_w = w;
|
||||
m_h = h;
|
||||
}
|
||||
|
||||
int
|
||||
FGPanelInstrument::getXPos () const {
|
||||
return m_x;
|
||||
}
|
||||
|
||||
int
|
||||
FGPanelInstrument::getYPos () const {
|
||||
return m_y;
|
||||
}
|
||||
|
||||
int
|
||||
FGPanelInstrument::getWidth () const {
|
||||
return m_w;
|
||||
}
|
||||
|
||||
int
|
||||
FGPanelInstrument::getHeight () const {
|
||||
return m_h;
|
||||
}
|
||||
52
utils/fgpanel/FGPanelInstrument.hxx
Normal file
52
utils/fgpanel/FGPanelInstrument.hxx
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <simgear/props/condition.hxx>
|
||||
|
||||
|
||||
/**
|
||||
* Abstract base class for a panel instrument.
|
||||
*
|
||||
* A panel instrument consists of zero or more actions, associated
|
||||
* with mouse clicks in rectangular areas. Currently, the only
|
||||
* concrete class derived from this is FGLayeredInstrument, but others
|
||||
* may show up in the future (some complex instruments could be
|
||||
* entirely hand-coded, for example).
|
||||
*/
|
||||
class FGPanelInstrument : public SGConditional {
|
||||
public:
|
||||
FGPanelInstrument ();
|
||||
FGPanelInstrument (const int x, const int y, const int w, const int h);
|
||||
virtual ~FGPanelInstrument ();
|
||||
|
||||
virtual void draw () = 0;
|
||||
|
||||
virtual void setPosition (const int x, const int y);
|
||||
virtual void setSize (const int w, const int h);
|
||||
|
||||
virtual int getXPos () const;
|
||||
virtual int getYPos () const;
|
||||
virtual int getWidth () const;
|
||||
virtual int getHeight () const;
|
||||
|
||||
private:
|
||||
int m_x, m_y, m_w, m_h;
|
||||
};
|
||||
185
utils/fgpanel/FGPanelProtocol.cxx
Normal file
185
utils/fgpanel/FGPanelProtocol.cxx
Normal file
@@ -0,0 +1,185 @@
|
||||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define strtof strtod
|
||||
#endif
|
||||
|
||||
#include <simgear/io/sg_socket.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
|
||||
#include "ApplicationProperties.hxx"
|
||||
#include "FGPanelProtocol.hxx"
|
||||
|
||||
class PropertySetter {
|
||||
public:
|
||||
PropertySetter (SGPropertyNode_ptr node) : _node (node) {}
|
||||
virtual void setValue (const char *value) = 0;
|
||||
virtual ~PropertySetter () {};
|
||||
protected:
|
||||
SGPropertyNode_ptr _node;
|
||||
};
|
||||
|
||||
class BoolPropertySetter : public PropertySetter {
|
||||
public:
|
||||
BoolPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {}
|
||||
virtual void setValue (const char *value) {
|
||||
_node->setBoolValue (atoi (value) != 0 );
|
||||
}
|
||||
};
|
||||
|
||||
class IntPropertySetter : public PropertySetter {
|
||||
public:
|
||||
IntPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {}
|
||||
virtual void setValue (const char *value) {
|
||||
_node->setIntValue (atol (value));
|
||||
}
|
||||
};
|
||||
|
||||
class FloatPropertySetter : public PropertySetter {
|
||||
public:
|
||||
FloatPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {}
|
||||
virtual void setValue (const char *value) {
|
||||
_node->setFloatValue (strtof (value, NULL));
|
||||
}
|
||||
};
|
||||
|
||||
class DoublePropertySetter : public PropertySetter {
|
||||
public:
|
||||
DoublePropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {}
|
||||
virtual void setValue (const char *value) {
|
||||
_node->setDoubleValue (strtod (value, NULL));
|
||||
}
|
||||
};
|
||||
|
||||
class StringPropertySetter : public PropertySetter {
|
||||
public:
|
||||
StringPropertySetter (SGPropertyNode_ptr node) : PropertySetter (node) {}
|
||||
virtual void setValue (const char *value) {
|
||||
_node->setStringValue (value);
|
||||
}
|
||||
};
|
||||
|
||||
FGPanelProtocol::FGPanelProtocol (SGPropertyNode_ptr a_Root) :
|
||||
SGSubsystem (),
|
||||
root (a_Root),
|
||||
io (NULL) {
|
||||
const SGPropertyNode_ptr outputNode (root->getNode ("protocol/generic/output"));
|
||||
if (outputNode) {
|
||||
const vector<SGPropertyNode_ptr> chunks (outputNode->getChildren ("chunk"));
|
||||
for (vector<SGPropertyNode_ptr>::size_type i = 0; i < chunks.size (); i++) {
|
||||
const SGPropertyNode_ptr chunk (chunks[i]);
|
||||
|
||||
const SGPropertyNode_ptr nodeNode (chunk->getNode ("node", false));
|
||||
if (nodeNode == NULL) {
|
||||
continue;
|
||||
}
|
||||
const SGPropertyNode_ptr node (ApplicationProperties::Properties->getNode (nodeNode->getStringValue (), true));
|
||||
|
||||
string type;
|
||||
const SGPropertyNode_ptr typeNode (chunk->getNode ("type", false));
|
||||
if (typeNode != NULL) {
|
||||
type = typeNode->getStringValue ();
|
||||
}
|
||||
if (type == "float") {
|
||||
propertySetterVector.push_back (new FloatPropertySetter (node));
|
||||
} else if (type == "double" || type == "fixed") {
|
||||
propertySetterVector.push_back (new DoublePropertySetter (node));
|
||||
} else if (type == "bool" || type == "boolean") {
|
||||
propertySetterVector.push_back (new BoolPropertySetter (node));
|
||||
} else if (type == "string") {
|
||||
propertySetterVector.push_back (new StringPropertySetter (node));
|
||||
} else {
|
||||
propertySetterVector.push_back (new IntPropertySetter (node));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FGPanelProtocol::~FGPanelProtocol()
|
||||
{
|
||||
for (PropertySetterVector::size_type i = 0; i < propertySetterVector.size(); i++) {
|
||||
delete propertySetterVector[i];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelProtocol::update (double dt) {
|
||||
char buf[2][8192];
|
||||
|
||||
if (io == NULL) {
|
||||
return;
|
||||
}
|
||||
// read all available lines, keep last one
|
||||
int Page (0);
|
||||
bool HaveData (false);
|
||||
while (io->readline (buf[Page], sizeof (buf[Page]) - 1) > 0) {
|
||||
HaveData = true;
|
||||
Page ^= 1;
|
||||
}
|
||||
|
||||
if (HaveData) {
|
||||
// process most recent line of data
|
||||
Page ^= 1;
|
||||
buf[Page][sizeof (buf[Page]) - 1] = 0;
|
||||
const vector<string> tokens (simgear::strutils::split (buf[Page], ","));
|
||||
for (vector<string>::size_type i = 0; i < tokens.size (); i++) {
|
||||
if (i < propertySetterVector.size ()) {
|
||||
propertySetterVector[i]->setValue (tokens[i].c_str ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelProtocol::init () {
|
||||
const SGPropertyNode_ptr listenNode (root->getNode ("listen"));
|
||||
if (listenNode == NULL) {
|
||||
return;
|
||||
}
|
||||
const string hostname (listenNode->getNode ("host", true)->getStringValue ());
|
||||
const string port (listenNode->getNode ("port", true)->getStringValue ());
|
||||
const string style (listenNode->getNode ("style", true)->getStringValue ());
|
||||
|
||||
if (io != NULL) {
|
||||
delete io;
|
||||
}
|
||||
io = new SGSocket (hostname, port, style);
|
||||
|
||||
if (!io->open (SG_IO_IN)) {
|
||||
cerr << "can't open socket " << style << ":" << hostname << ":" << port << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGPanelProtocol::reinit () {
|
||||
init ();
|
||||
}
|
||||
|
||||
|
||||
// Register the subsystem.
|
||||
#if 0
|
||||
SGSubsystemMgr::Registrant<FGPanelProtocol> registrantFGPanelProtocol;
|
||||
#endif
|
||||
46
utils/fgpanel/FGPanelProtocol.hxx
Normal file
46
utils/fgpanel/FGPanelProtocol.hxx
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/io/iochannel.hxx>
|
||||
|
||||
class PropertySetter;
|
||||
|
||||
typedef std::vector<PropertySetter*> PropertySetterVector;
|
||||
|
||||
class FGPanelProtocol : public SGSubsystem {
|
||||
public:
|
||||
FGPanelProtocol (SGPropertyNode_ptr a_Root);
|
||||
virtual ~FGPanelProtocol ();
|
||||
|
||||
// Subsystem API.
|
||||
void init() override;
|
||||
void reinit() override;
|
||||
void update(double dt) override;
|
||||
|
||||
// Subsystem identification.
|
||||
static const char* staticSubsystemClassId() { return "panel-protocol"; }
|
||||
|
||||
private:
|
||||
SGPropertyNode_ptr root;
|
||||
SGIOChannel *io;
|
||||
PropertySetterVector propertySetterVector;
|
||||
};
|
||||
28
utils/fgpanel/FGPanelTransformation.cxx
Normal file
28
utils/fgpanel/FGPanelTransformation.cxx
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "FGPanelTransformation.hxx"
|
||||
|
||||
FGPanelTransformation::FGPanelTransformation () :
|
||||
table (0) {
|
||||
}
|
||||
|
||||
FGPanelTransformation::~FGPanelTransformation () {
|
||||
delete table;
|
||||
}
|
||||
52
utils/fgpanel/FGPanelTransformation.hxx
Normal file
52
utils/fgpanel/FGPanelTransformation.hxx
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef FGPANELTRANSFORMATION_HXX
|
||||
#define FGPANELTRANSFORMATION_HXX
|
||||
|
||||
#include <simgear/math/interpolater.hxx>
|
||||
#include <simgear/props/condition.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
/**
|
||||
* A transformation for a layer.
|
||||
*/
|
||||
class FGPanelTransformation : public SGConditional {
|
||||
public:
|
||||
enum Type {
|
||||
XSHIFT,
|
||||
YSHIFT,
|
||||
ROTATION
|
||||
};
|
||||
|
||||
FGPanelTransformation ();
|
||||
virtual ~FGPanelTransformation ();
|
||||
|
||||
Type type;
|
||||
SGConstPropertyNode_ptr node;
|
||||
float min;
|
||||
float max;
|
||||
bool has_mod;
|
||||
float mod;
|
||||
float factor;
|
||||
float offset;
|
||||
SGInterpTable *table;
|
||||
};
|
||||
|
||||
#endif
|
||||
477
utils/fgpanel/FGRGBTextureLoader.cxx
Normal file
477
utils/fgpanel/FGRGBTextureLoader.cxx
Normal file
@@ -0,0 +1,477 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// From the OpenSceneGraph distribution ReaderWriterRGB.cpp
|
||||
// Reader for sgi's .rgb format.
|
||||
// specification can be found at http://local.wasp.uwa.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <GLUT/glut.h>
|
||||
#elif defined (_GLES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#else
|
||||
#include <GL/glew.h> // Must be included before <GL/gl.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glut.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "FGRGBTextureLoader.hxx"
|
||||
|
||||
typedef struct _rawImageRec {
|
||||
unsigned short imagic;
|
||||
unsigned short type;
|
||||
unsigned short dim;
|
||||
unsigned short sizeX, sizeY, sizeZ;
|
||||
unsigned long min, max;
|
||||
unsigned long wasteBytes;
|
||||
char name[80];
|
||||
unsigned long colorMap;
|
||||
istream *file;
|
||||
unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
|
||||
unsigned long rleEnd;
|
||||
GLuint *rowStart;
|
||||
GLint *rowSize;
|
||||
GLenum swapFlag;
|
||||
short bpc;
|
||||
|
||||
typedef unsigned char *BytePtr;
|
||||
|
||||
bool needsBytesSwapped () {
|
||||
union {
|
||||
int testWord;
|
||||
char testByte[sizeof (int)];
|
||||
} endianTest;
|
||||
endianTest.testWord = 1;
|
||||
if (endianTest.testByte[0] == 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void swapBytes (T &s) {
|
||||
if (sizeof (T) == 1) {
|
||||
return;
|
||||
}
|
||||
T d = s;
|
||||
BytePtr sptr ((BytePtr) &s);
|
||||
BytePtr dptr = &(((BytePtr) &d)[sizeof (T) - 1]);
|
||||
|
||||
for (unsigned int i = 0; i < sizeof (T); i++) {
|
||||
*(sptr++) = *(dptr--);
|
||||
}
|
||||
}
|
||||
|
||||
void swapBytes () {
|
||||
swapBytes (imagic);
|
||||
swapBytes (type);
|
||||
swapBytes (dim);
|
||||
swapBytes (sizeX);
|
||||
swapBytes (sizeY);
|
||||
swapBytes (sizeZ);
|
||||
swapBytes (wasteBytes);
|
||||
swapBytes (min);
|
||||
swapBytes (max);
|
||||
swapBytes (colorMap);
|
||||
}
|
||||
} rawImageRec;
|
||||
|
||||
static void
|
||||
ConvertShort (unsigned short *array, long length) {
|
||||
unsigned long b1, b2;
|
||||
unsigned char *ptr ((unsigned char *) array);
|
||||
while (length--) {
|
||||
b1 = *ptr++;
|
||||
b2 = *ptr++;
|
||||
*array++ = (unsigned short) ((b1 << 8) | (b2));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ConvertLong (GLuint *array, long length) {
|
||||
unsigned long b1, b2, b3, b4;
|
||||
unsigned char *ptr ((unsigned char *) array);
|
||||
while (length--) {
|
||||
b1 = *ptr++;
|
||||
b2 = *ptr++;
|
||||
b3 = *ptr++;
|
||||
b4 = *ptr++;
|
||||
*array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
RawImageClose (rawImageRec *raw) {
|
||||
if (raw) {
|
||||
if (raw->tmp) {
|
||||
delete []raw->tmp;
|
||||
}
|
||||
if (raw->tmpR) {
|
||||
delete []raw->tmpR;
|
||||
}
|
||||
if (raw->tmpG) {
|
||||
delete []raw->tmpG;
|
||||
}
|
||||
if (raw->tmpB) {
|
||||
delete []raw->tmpB;
|
||||
}
|
||||
if (raw->tmpA) {
|
||||
delete []raw->tmpA;
|
||||
}
|
||||
if (raw->rowStart) {
|
||||
delete []raw->rowStart;
|
||||
}
|
||||
if (raw->rowSize) {
|
||||
delete []raw->rowSize;
|
||||
}
|
||||
delete raw;
|
||||
}
|
||||
}
|
||||
|
||||
static rawImageRec *
|
||||
RawImageOpen (istream& fin) {
|
||||
union {
|
||||
int testWord;
|
||||
char testByte[4];
|
||||
} endianTest;
|
||||
|
||||
rawImageRec *raw = new rawImageRec;
|
||||
if (raw == NULL) {
|
||||
// notify(WARN)<< "Out of memory!"<< endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Set istream pointer
|
||||
raw->file = &fin;
|
||||
|
||||
endianTest.testWord = 1;
|
||||
if (endianTest.testByte[0] == 1) {
|
||||
raw->swapFlag = GL_TRUE;
|
||||
} else {
|
||||
raw->swapFlag = GL_FALSE;
|
||||
}
|
||||
|
||||
fin.read ((char*) raw, 12);
|
||||
if (!fin.good ()) {
|
||||
return NULL;
|
||||
}
|
||||
if (raw->swapFlag) {
|
||||
ConvertShort (&raw->imagic, 6);
|
||||
}
|
||||
|
||||
raw->tmp = raw->tmpR = raw->tmpG = raw->tmpB = raw->tmpA = 0L;
|
||||
raw->rowStart = 0;
|
||||
raw->rowSize = 0;
|
||||
raw->bpc = (raw->type & 0x00FF);
|
||||
|
||||
raw->tmp = new unsigned char[raw->sizeX * 256 * raw->bpc];
|
||||
if (raw->tmp == NULL ) {
|
||||
// notify(FATAL)<< "Out of memory!"<< endl;
|
||||
RawImageClose (raw);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (raw->sizeZ >= 1) {
|
||||
if ((raw->tmpR = new unsigned char[raw->sizeX * raw->bpc]) == NULL) {
|
||||
// notify(FATAL)<< "Out of memory!"<< endl;
|
||||
RawImageClose (raw);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (raw->sizeZ >= 2) {
|
||||
if ((raw->tmpG = new unsigned char[raw->sizeX * raw->bpc]) == NULL) {
|
||||
// notify(FATAL)<< "Out of memory!"<< endl;
|
||||
RawImageClose (raw);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (raw->sizeZ >= 3) {
|
||||
if ((raw->tmpB = new unsigned char[raw->sizeX*raw->bpc]) == NULL) {
|
||||
// notify(FATAL)<< "Out of memory!"<< endl;
|
||||
RawImageClose (raw);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (raw->sizeZ >= 4) {
|
||||
if ((raw->tmpA = new unsigned char[raw->sizeX * raw->bpc]) == NULL) {
|
||||
// notify(FATAL)<< "Out of memory!"<< endl;
|
||||
RawImageClose (raw);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((raw->type & 0xFF00) == 0x0100) {
|
||||
unsigned int ybyz (raw->sizeY * raw->sizeZ);
|
||||
if ((raw->rowStart = new GLuint[ybyz]) == NULL) {
|
||||
// notify(FATAL)<< "Out of memory!"<< endl;
|
||||
RawImageClose (raw);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((raw->rowSize = new GLint[ybyz]) == NULL) {
|
||||
// notify(FATAL)<< "Out of memory!"<< endl;
|
||||
RawImageClose (raw);
|
||||
return NULL;
|
||||
}
|
||||
int x (ybyz * sizeof (GLuint));
|
||||
raw->rleEnd = 512 + (2 * x);
|
||||
fin.seekg (512, ios::beg);
|
||||
fin.read ((char*) raw->rowStart, x);
|
||||
fin.read ((char*) raw->rowSize, x);
|
||||
if (raw->swapFlag) {
|
||||
ConvertLong (raw->rowStart, long (x / sizeof (GLuint)));
|
||||
ConvertLong ((GLuint *) raw->rowSize, long (x /sizeof (GLint)));
|
||||
}
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
static void
|
||||
RawImageGetRow (rawImageRec *raw, unsigned char *buf, const int y, const int z) {
|
||||
unsigned short pixel;
|
||||
int done = 0;
|
||||
unsigned short *tempShort;
|
||||
|
||||
if ((raw->type & 0xFF00) == 0x0100) {
|
||||
raw->file->seekg (long (raw->rowStart[y + z * raw->sizeY]), ios::beg);
|
||||
raw->file->read ((char*) raw->tmp, (unsigned int) (raw->rowSize[y + z * raw->sizeY]));
|
||||
|
||||
unsigned char *iPtr = raw->tmp;
|
||||
unsigned char *oPtr = buf;
|
||||
while (!done) {
|
||||
if (raw->bpc == 1) {
|
||||
pixel = *iPtr++;
|
||||
} else {
|
||||
tempShort = reinterpret_cast<unsigned short*> (iPtr);
|
||||
pixel = *tempShort;
|
||||
tempShort++;
|
||||
iPtr = reinterpret_cast<unsigned char *> (tempShort);
|
||||
}
|
||||
|
||||
if (raw->bpc != 1) {
|
||||
ConvertShort (&pixel, 1);
|
||||
}
|
||||
int count (int (pixel & 0x7F));
|
||||
|
||||
// limit the count value to the remiaing row size
|
||||
if (oPtr + count * raw->bpc > buf + raw->sizeX * raw->bpc) {
|
||||
count = ((buf + raw->sizeX * raw->bpc) - oPtr) / raw->bpc;
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
done = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pixel & 0x80) {
|
||||
while (count--) {
|
||||
if (raw->bpc == 1) {
|
||||
*oPtr++ = *iPtr++;
|
||||
} else {
|
||||
tempShort = reinterpret_cast<unsigned short*> (iPtr);
|
||||
pixel = *tempShort;
|
||||
tempShort++;
|
||||
iPtr = reinterpret_cast<unsigned char *> (tempShort);
|
||||
|
||||
ConvertShort (&pixel, 1);
|
||||
|
||||
tempShort = reinterpret_cast<unsigned short*> (oPtr);
|
||||
*tempShort = pixel;
|
||||
tempShort++;
|
||||
oPtr = reinterpret_cast<unsigned char *> (tempShort);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (raw->bpc == 1) {
|
||||
pixel = *iPtr++;
|
||||
} else {
|
||||
tempShort = reinterpret_cast<unsigned short*> (iPtr);
|
||||
pixel = *tempShort;
|
||||
tempShort++;
|
||||
iPtr = reinterpret_cast<unsigned char *> (tempShort);
|
||||
}
|
||||
if (raw->bpc != 1) {
|
||||
ConvertShort (&pixel, 1);
|
||||
}
|
||||
while (count--) {
|
||||
if (raw->bpc == 1) {
|
||||
*oPtr++ = pixel;
|
||||
} else {
|
||||
tempShort = reinterpret_cast<unsigned short*> (oPtr);
|
||||
*tempShort = pixel;
|
||||
tempShort++;
|
||||
oPtr = reinterpret_cast<unsigned char *> (tempShort);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
raw->file->seekg (512 + (y * raw->sizeX * raw->bpc) + (z * raw->sizeX * raw->sizeY * raw->bpc), ios::beg);
|
||||
raw->file->read ((char*) buf, raw->sizeX * raw->bpc);
|
||||
if (raw->swapFlag && raw->bpc != 1) {
|
||||
ConvertShort (reinterpret_cast<unsigned short*> (buf), raw->sizeX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
RawImageGetData (rawImageRec *raw, unsigned char **data) {
|
||||
|
||||
// // round the width to a factor 4
|
||||
// int width = (int)(floorf((float)raw->sizeX/4.0f)*4.0f);
|
||||
// if (width!=raw->sizeX) width += 4;
|
||||
|
||||
// byte aligned.
|
||||
|
||||
// osg::notify(osg::INFO)<<"raw->sizeX = "<<raw->sizeX<<endl;
|
||||
// osg::notify(osg::INFO)<<"raw->sizeY = "<<raw->sizeY<<endl;
|
||||
// osg::notify(osg::INFO)<<"raw->sizeZ = "<<raw->sizeZ<<endl;
|
||||
// osg::notify(osg::INFO)<<"raw->bpc = "<<raw->bpc<<endl;
|
||||
|
||||
*data = new unsigned char [(raw->sizeX) * (raw->sizeY) * (raw->sizeZ) * (raw->bpc)];
|
||||
|
||||
unsigned char *ptr (*data);
|
||||
for (int i = 0; i < int (raw->sizeY); i++) {
|
||||
if (raw->sizeZ >= 1) {
|
||||
RawImageGetRow (raw, raw->tmpR, i, 0);
|
||||
}
|
||||
if (raw->sizeZ >= 2) {
|
||||
RawImageGetRow (raw, raw->tmpG, i, 1);
|
||||
}
|
||||
if (raw->sizeZ >= 3) {
|
||||
RawImageGetRow (raw, raw->tmpB, i, 2);
|
||||
}
|
||||
if (raw->sizeZ >= 4) {
|
||||
RawImageGetRow (raw, raw->tmpA, i, 3);
|
||||
}
|
||||
for (int j = 0; j < int (raw->sizeX); j++) {
|
||||
if (raw->bpc == 1) {
|
||||
if (raw->sizeZ >= 1) {
|
||||
*ptr++ = *(raw->tmpR + j);
|
||||
}
|
||||
if (raw->sizeZ >= 2) {
|
||||
*ptr++ = *(raw->tmpG + j);
|
||||
}
|
||||
if (raw->sizeZ >= 3) {
|
||||
*ptr++ = *(raw->tmpB + j);
|
||||
}
|
||||
if (raw->sizeZ >= 4) {
|
||||
*ptr++ = *(raw->tmpA + j);
|
||||
}
|
||||
} else {
|
||||
unsigned short *tempShort;
|
||||
if (raw->sizeZ >= 1) {
|
||||
tempShort = reinterpret_cast<unsigned short*> (ptr);
|
||||
*tempShort = *(reinterpret_cast<unsigned short*> (raw->tmpR) + j);
|
||||
tempShort++;
|
||||
ptr = reinterpret_cast<unsigned char *> (tempShort);
|
||||
}
|
||||
if (raw->sizeZ >= 2) {
|
||||
tempShort = reinterpret_cast<unsigned short*> (ptr);
|
||||
*tempShort = *(reinterpret_cast<unsigned short*> (raw->tmpG) + j);
|
||||
tempShort++;
|
||||
ptr = reinterpret_cast<unsigned char *> (tempShort);
|
||||
}
|
||||
if (raw->sizeZ >= 3) {
|
||||
tempShort = reinterpret_cast<unsigned short*> (ptr);
|
||||
*tempShort = *(reinterpret_cast<unsigned short*> (raw->tmpB) + j);
|
||||
tempShort++;
|
||||
ptr = reinterpret_cast<unsigned char *> (tempShort);
|
||||
}
|
||||
if (raw->sizeZ >= 4) {
|
||||
tempShort = reinterpret_cast<unsigned short*> (ptr);
|
||||
*tempShort = *(reinterpret_cast<unsigned short*> (raw->tmpA) + j);
|
||||
tempShort++;
|
||||
ptr = reinterpret_cast<unsigned char *> (tempShort);
|
||||
}
|
||||
}
|
||||
}
|
||||
// // pad the image width with blanks to bring it up to the rounded width.
|
||||
// for(;j<width;++j) *ptr++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// supportsExtension("rgb","rgb image format");
|
||||
// supportsExtension("rgba","rgba image format");
|
||||
// supportsExtension("sgi","sgi image format");
|
||||
// supportsExtension("int","int image format");
|
||||
// supportsExtension("inta","inta image format");
|
||||
// supportsExtension("bw","bw image format");
|
||||
|
||||
GLuint
|
||||
readRGBStream (istream &fin) {
|
||||
rawImageRec * const raw (RawImageOpen (fin));
|
||||
|
||||
if (raw == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int s (raw->sizeX);
|
||||
const int t (raw->sizeY);
|
||||
// int r = 1;
|
||||
|
||||
#if 0
|
||||
int internalFormat = raw->sizeZ == 3 ? GL_RGB5 :
|
||||
raw->sizeZ == 4 ? GL_RGB5_A1 : GL_RGB;
|
||||
#else
|
||||
// int internalFormat = raw->sizeZ;
|
||||
#endif
|
||||
const unsigned int pixelFormat
|
||||
(raw->sizeZ == 1 ? GL_LUMINANCE :
|
||||
raw->sizeZ == 2 ? GL_LUMINANCE_ALPHA :
|
||||
raw->sizeZ == 3 ? GL_RGB :
|
||||
raw->sizeZ == 4 ? GL_RGBA : (GLenum) - 1);
|
||||
|
||||
const unsigned int dataType (raw->bpc == 1 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT);
|
||||
|
||||
unsigned char *data;
|
||||
RawImageGetData (raw, &data);
|
||||
RawImageClose (raw);
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures (1, &texture);
|
||||
glBindTexture (GL_TEXTURE_2D, texture);
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, pixelFormat, s, t, 0, pixelFormat, dataType, (GLvoid*) data);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
delete []data;
|
||||
return texture;
|
||||
}
|
||||
|
||||
GLuint
|
||||
FGRGBTextureLoader::loadTexture (const string &filename) {
|
||||
GLuint texture = NOTEXTURE;
|
||||
ifstream istream (filename.c_str (), ios::in | ios::binary);
|
||||
texture = readRGBStream (istream);
|
||||
istream.close ();
|
||||
return texture;
|
||||
}
|
||||
28
utils/fgpanel/FGRGBTextureLoader.hxx
Normal file
28
utils/fgpanel/FGRGBTextureLoader.hxx
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#ifndef __FGRGBTEXTURELOADER_HXX
|
||||
#define __FGRGBTEXTURELOADER_HXX
|
||||
|
||||
#include "FGTextureLoaderInterface.hxx"
|
||||
|
||||
class FGRGBTextureLoader : public FGTextureLoaderInterface {
|
||||
public:
|
||||
virtual GLuint loadTexture (const string &filename);
|
||||
|
||||
const static GLuint NOTEXTURE = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
37
utils/fgpanel/FGSwitchLayer.cxx
Normal file
37
utils/fgpanel/FGSwitchLayer.cxx
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "FGSwitchLayer.hxx"
|
||||
|
||||
FGSwitchLayer::FGSwitchLayer () :
|
||||
FGGroupLayer () {
|
||||
}
|
||||
|
||||
void
|
||||
FGSwitchLayer::draw () {
|
||||
if (test ()) {
|
||||
transform ();
|
||||
for (unsigned int i = 0; i < m_layers.size (); ++i) {
|
||||
if (m_layers[i]->test ()) {
|
||||
m_layers[i]->draw ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
utils/fgpanel/FGSwitchLayer.hxx
Normal file
38
utils/fgpanel/FGSwitchLayer.hxx
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef FGSWITCHLAYER_HXX
|
||||
#define FGSWITCHLAYER_HXX
|
||||
|
||||
#include "FGGroupLayer.hxx"
|
||||
|
||||
/**
|
||||
* A group layer that switches among its children.
|
||||
*
|
||||
* The first layer that passes its condition will be drawn, and
|
||||
* any following layers will be ignored.
|
||||
*/
|
||||
class FGSwitchLayer : public FGGroupLayer {
|
||||
public:
|
||||
// Transfer pointers!!
|
||||
FGSwitchLayer ();
|
||||
virtual void draw ();
|
||||
};
|
||||
|
||||
#endif
|
||||
307
utils/fgpanel/FGTextLayer.cxx
Normal file
307
utils/fgpanel/FGTextLayer.cxx
Normal file
@@ -0,0 +1,307 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "ApplicationProperties.hxx"
|
||||
#include "GL_utils.hxx"
|
||||
#include "FGTextLayer.hxx"
|
||||
|
||||
SGPath FGTextLayer::The_Font_Path;
|
||||
|
||||
FGFontCache FGTextLayer::The_Font_Cache;
|
||||
|
||||
GLuint FGTextLayer::Text_Layer_Program_Object (0);
|
||||
GLint FGTextLayer::Text_Layer_Position_Loc (0);
|
||||
GLint FGTextLayer::Text_Layer_Tex_Coord_Loc (0);
|
||||
GLint FGTextLayer::Text_Layer_MVP_Loc (0);
|
||||
GLint FGTextLayer::Text_Layer_Sampler_Loc (0);
|
||||
GLint FGTextLayer::Text_Layer_Color_Loc (0);
|
||||
|
||||
bool
|
||||
FGTextLayer::Init () {
|
||||
const char V_Text_Layer_Shader_Str[] =
|
||||
#ifdef _RPI
|
||||
"#version 100 \n"
|
||||
"attribute vec4 a_position; \n"
|
||||
"attribute vec2 a_tex_coord; \n"
|
||||
"varying vec2 v_tex_coord; \n"
|
||||
#else
|
||||
"#version 130 \n"
|
||||
"in vec4 a_position; \n"
|
||||
"in vec2 a_tex_coord; \n"
|
||||
"out vec2 v_tex_coord; \n"
|
||||
#endif
|
||||
"uniform mat4 u_mvp_matrix; \n"
|
||||
"void main () { \n"
|
||||
" gl_Position = u_mvp_matrix * a_position; \n"
|
||||
" v_tex_coord = a_tex_coord; \n"
|
||||
"} \n";
|
||||
|
||||
const char F_Text_Layer_Shader_Str[] =
|
||||
#ifdef _RPI
|
||||
"#version 100 \n"
|
||||
"precision mediump float; \n"
|
||||
"varying vec2 v_tex_coord; \n"
|
||||
#else
|
||||
"#version 130 \n"
|
||||
"in vec2 v_tex_coord; \n"
|
||||
#endif
|
||||
"uniform sampler2D u_texture; \n"
|
||||
"uniform vec4 u_color; \n"
|
||||
"void main () { \n"
|
||||
" gl_FragColor = vec4 (1, 1, 1, \n"
|
||||
" texture2D (u_texture, v_tex_coord).a) * \n"
|
||||
" u_color; \n"
|
||||
"} \n";
|
||||
|
||||
Text_Layer_Program_Object = GL_utils::instance ().load_program (V_Text_Layer_Shader_Str,
|
||||
F_Text_Layer_Shader_Str);
|
||||
if (Text_Layer_Program_Object == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the attribute locations
|
||||
Text_Layer_Position_Loc = glGetAttribLocation (Text_Layer_Program_Object, "a_position");
|
||||
Text_Layer_Tex_Coord_Loc = glGetAttribLocation (Text_Layer_Program_Object, "a_tex_coord");
|
||||
|
||||
// Get the uniform locations
|
||||
Text_Layer_MVP_Loc = glGetUniformLocation (Text_Layer_Program_Object, "u_mvp_matrix");
|
||||
|
||||
// Get the sampler location
|
||||
Text_Layer_Sampler_Loc = glGetUniformLocation (Text_Layer_Program_Object, "u_texture");
|
||||
|
||||
// Get the color location
|
||||
Text_Layer_Color_Loc = glGetUniformLocation (Text_Layer_Program_Object, "u_color");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FGTextLayer::FGTextLayer (const int w, const int h) :
|
||||
FGInstrumentLayer (w, h),
|
||||
m_pointSize (0.0),
|
||||
m_font_name () {
|
||||
m_then.stamp ();
|
||||
m_color[0] = m_color[1] = m_color[2] = 0.0;
|
||||
m_color[3] = 1.0;
|
||||
}
|
||||
|
||||
FGTextLayer::~FGTextLayer () {
|
||||
for (chunk_list::iterator It = m_chunks.begin ();
|
||||
It != m_chunks.end ();
|
||||
++It) {
|
||||
delete *It;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::draw () {
|
||||
if (test ()) {
|
||||
glUseProgram (Text_Layer_Program_Object);
|
||||
glUniform4fv (Text_Layer_Color_Loc, 1, m_color);
|
||||
|
||||
transform ();
|
||||
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
|
||||
GL_utils::instance ().glPushMatrix ();
|
||||
GL_utils::instance ().glMultMatrixf
|
||||
(*reinterpret_cast <GLfloat (*)[4][4]>
|
||||
(GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_MODELVIEW)));
|
||||
glUniformMatrix4fv (Text_Layer_MVP_Loc,
|
||||
1,
|
||||
GL_FALSE,
|
||||
GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_PROJECTION));
|
||||
GLuint Glyph_Texture;
|
||||
if (!The_Font_Cache.Set_Font (m_font_name, m_pointSize, Glyph_Texture)) {
|
||||
SG_LOG (SG_COCKPIT, SG_ALERT, "Missing font : " << m_font_name << " " << m_pointSize);
|
||||
}
|
||||
|
||||
m_now.stamp ();
|
||||
const long diff ((m_now - m_then).toUSecs ());
|
||||
|
||||
if (diff > 100000 || diff < 0 ) {
|
||||
// ( diff < 0 ) is a sanity check and indicates our time stamp
|
||||
// difference math probably overflowed. We can handle a max
|
||||
// difference of 35.8 minutes since the returned value is in
|
||||
// usec. So if the panel is left off longer than that we can
|
||||
// over flow the math with it is turned back on. This (diff <
|
||||
// 0) catches that situation, get's us out of trouble, and
|
||||
// back on track.
|
||||
recalc_value ();
|
||||
m_then = m_now;
|
||||
}
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, Glyph_Texture);
|
||||
glUniform1i (Text_Layer_Sampler_Loc, 0);
|
||||
|
||||
int X (0);
|
||||
int Y (0);
|
||||
int Previous_X (0);
|
||||
int Previous_Y (0);
|
||||
int Left, Bottom, W, H;
|
||||
double X1, Y1, X2, Y2;
|
||||
|
||||
for (string::iterator It = m_value.begin (); It != m_value.end (); ++It) {
|
||||
if (The_Font_Cache.Get_Char (*It,
|
||||
X, Y,
|
||||
Left, Bottom,
|
||||
W, H,
|
||||
X1, Y1,
|
||||
X2, Y2)) {
|
||||
const GLfloat v_Vertices[] = {
|
||||
float (Previous_X + Left), float (Previous_Y + Bottom), 0.0f, // Position 0 (bottom left corner)
|
||||
float (X1), float (Y2), // TexCoord 0 (bottom left corner)
|
||||
float (Previous_X + Left + W), float (Previous_Y + Bottom), 0.0f, // Position 1 (bottom right corner)
|
||||
float (X2), float (Y2), // TexCoord 1 (bottom right corner)
|
||||
float (Previous_X + Left + W), float (Previous_Y + Bottom + H), 0.0f, // Position 2 (top right corner)
|
||||
float (X2), float (Y1), // TexCoord 2 (top right corner)
|
||||
float (Previous_X + Left), float (Previous_Y + Bottom + H), 0.0f, // Position 3 (top left corner)
|
||||
float (X1), float (Y1) }; // TexCoord 3 (top left corner)
|
||||
glVertexAttribPointer (Text_Layer_Position_Loc,
|
||||
3,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
5 * sizeof (GLfloat),
|
||||
v_Vertices);
|
||||
glVertexAttribPointer (Text_Layer_Tex_Coord_Loc,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
5 * sizeof (GLfloat),
|
||||
&v_Vertices[3]);
|
||||
|
||||
glEnableVertexAttribArray (Text_Layer_Position_Loc);
|
||||
glEnableVertexAttribArray (Text_Layer_Tex_Coord_Loc);
|
||||
|
||||
const GLushort indices[] = {0, 1, 2, 0, 2, 3};
|
||||
glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
|
||||
Previous_X = X;
|
||||
Previous_Y = Y;
|
||||
}
|
||||
}
|
||||
|
||||
GL_utils::instance ().glPopMatrix ();
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::addChunk (FGTextLayer::Chunk * const chunk) {
|
||||
m_chunks.push_back (chunk);
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::setColor (const float r,
|
||||
const float g,
|
||||
const float b) {
|
||||
m_color[0] = r;
|
||||
m_color[1] = g;
|
||||
m_color[2] = b;
|
||||
m_color[3] = 1.0;
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::setPointSize (const float size) {
|
||||
m_pointSize = size;
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::setFontName (const string &name) {
|
||||
if (The_Font_Path.isNull ()) {
|
||||
char *Env_Path = ::getenv ("FG_FONTS");
|
||||
if (Env_Path != NULL) {
|
||||
The_Font_Path = SGPath::fromEnv (Env_Path);
|
||||
} else {
|
||||
The_Font_Path = ApplicationProperties::GetRootPath ("Fonts");
|
||||
}
|
||||
}
|
||||
m_font_name = The_Font_Path.local8BitStr () + "/" + name + ".ttf";
|
||||
}
|
||||
|
||||
void
|
||||
FGTextLayer::recalc_value () const {
|
||||
m_value = "";
|
||||
for (chunk_list::const_iterator It = m_chunks.begin ();
|
||||
It != m_chunks.end ();
|
||||
++It) {
|
||||
m_value += (*It)->getValue ();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGTextLayer::Chunk.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGTextLayer::Chunk::Chunk (const string &text,
|
||||
const string &fmt) :
|
||||
m_type (FGTextLayer::TEXT),
|
||||
m_text (text),
|
||||
m_fmt (fmt),
|
||||
m_mult (1.0),
|
||||
m_offs (0.0),
|
||||
m_trunc (false) {
|
||||
if (m_fmt.empty ()) {
|
||||
m_fmt = "%s";
|
||||
}
|
||||
}
|
||||
|
||||
FGTextLayer::Chunk::Chunk (const ChunkType type,
|
||||
const SGPropertyNode *node,
|
||||
const string &fmt,
|
||||
const float mult,
|
||||
const float offs,
|
||||
const bool truncation) :
|
||||
m_type (type),
|
||||
m_node (node),
|
||||
m_fmt (fmt),
|
||||
m_mult (mult),
|
||||
m_offs (offs),
|
||||
m_trunc (truncation) {
|
||||
if (m_fmt.empty ()) {
|
||||
if (type == TEXT_VALUE) {
|
||||
m_fmt = "%s";
|
||||
} else {
|
||||
m_fmt = "%.2f";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
FGTextLayer::Chunk::getValue () const {
|
||||
if (test ()) {
|
||||
m_buf[0] = '\0';
|
||||
switch (m_type) {
|
||||
case TEXT:
|
||||
sprintf (m_buf, m_fmt.c_str (), m_text.c_str ());
|
||||
break;
|
||||
case TEXT_VALUE:
|
||||
sprintf (m_buf, m_fmt.c_str (), m_node->getStringValue ());
|
||||
break;
|
||||
case DOUBLE_VALUE:
|
||||
double d (m_offs + m_node->getFloatValue() * m_mult);
|
||||
if (m_trunc) {
|
||||
d = (d < 0) ? -floor (-d) : floor (d);
|
||||
}
|
||||
sprintf (m_buf, m_fmt.c_str(), d);
|
||||
break;
|
||||
}
|
||||
return m_buf;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
107
utils/fgpanel/FGTextLayer.hxx
Normal file
107
utils/fgpanel/FGTextLayer.hxx
Normal file
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
|
||||
#include "FGFontCache.hxx"
|
||||
#include "FGInstrumentLayer.hxx"
|
||||
|
||||
|
||||
/**
|
||||
* A text layer of an instrument.
|
||||
*
|
||||
* This is a layer holding a string of static and/or generated text.
|
||||
* It is useful for instruments that have text displays, such as
|
||||
* a chronometer, GPS, or NavCom radio.
|
||||
*/
|
||||
|
||||
class FGTextLayer : public FGInstrumentLayer {
|
||||
public:
|
||||
enum ChunkType {
|
||||
TEXT,
|
||||
TEXT_VALUE,
|
||||
DOUBLE_VALUE
|
||||
};
|
||||
|
||||
class Chunk : public SGConditional {
|
||||
public:
|
||||
Chunk (const std::string &text,
|
||||
const std::string &fmt = "%s");
|
||||
Chunk (const ChunkType type,
|
||||
const SGPropertyNode *node,
|
||||
const std::string &fmt = "",
|
||||
const float mult = 1.0,
|
||||
const float offs = 0.0,
|
||||
const bool truncation = false);
|
||||
|
||||
const char *getValue () const;
|
||||
private:
|
||||
ChunkType m_type;
|
||||
std::string m_text;
|
||||
SGConstPropertyNode_ptr m_node;
|
||||
std::string m_fmt;
|
||||
float m_mult;
|
||||
float m_offs;
|
||||
bool m_trunc;
|
||||
mutable char m_buf[1024];
|
||||
|
||||
};
|
||||
|
||||
static bool Init ();
|
||||
|
||||
FGTextLayer (const int w = -1, const int h = -1);
|
||||
virtual ~FGTextLayer ();
|
||||
|
||||
virtual void draw ();
|
||||
|
||||
// Transfer pointer!!
|
||||
virtual void addChunk (Chunk * const chunk);
|
||||
virtual void setColor (const float r,
|
||||
const float g,
|
||||
const float b);
|
||||
virtual void setPointSize (const float size);
|
||||
virtual void setFontName (const std::string &name);
|
||||
|
||||
private:
|
||||
|
||||
void recalc_value () const;
|
||||
|
||||
typedef std::vector<Chunk *> chunk_list;
|
||||
chunk_list m_chunks;
|
||||
float m_color[4];
|
||||
|
||||
float m_pointSize;
|
||||
static SGPath The_Font_Path;
|
||||
mutable std::string m_font_name;
|
||||
mutable std::string m_value;
|
||||
mutable SGTimeStamp m_then;
|
||||
mutable SGTimeStamp m_now;
|
||||
|
||||
static FGFontCache The_Font_Cache;
|
||||
|
||||
static GLuint Text_Layer_Program_Object;
|
||||
static GLint Text_Layer_Position_Loc;
|
||||
static GLint Text_Layer_Tex_Coord_Loc;
|
||||
static GLint Text_Layer_MVP_Loc;
|
||||
static GLint Text_Layer_Sampler_Loc;
|
||||
static GLint Text_Layer_Color_Loc;
|
||||
};
|
||||
38
utils/fgpanel/FGTextureLoaderInterface.hxx
Normal file
38
utils/fgpanel/FGTextureLoaderInterface.hxx
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#elif defined (_GLES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#else
|
||||
#include <GL/glew.h> // Must be included before <GL/gl.h>
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
|
||||
class FGTextureLoaderInterface {
|
||||
public:
|
||||
virtual GLuint loadTexture (const std::string &filename) = 0;
|
||||
};
|
||||
124
utils/fgpanel/FGTexturedLayer.cxx
Normal file
124
utils/fgpanel/FGTexturedLayer.cxx
Normal file
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "GL_utils.hxx"
|
||||
#include "FGTexturedLayer.hxx"
|
||||
|
||||
GLuint FGTexturedLayer::Textured_Layer_Program_Object (0);
|
||||
GLint FGTexturedLayer::Textured_Layer_Position_Loc (0);
|
||||
GLint FGTexturedLayer::Textured_Layer_Tex_Coord_Loc (0);
|
||||
GLint FGTexturedLayer::Textured_Layer_MVP_Loc (0);
|
||||
GLint FGTexturedLayer::Textured_Layer_Sampler_Loc (0);
|
||||
|
||||
void
|
||||
FGTexturedLayer::Init (const GLuint Program_Object,
|
||||
const GLint Position_Loc,
|
||||
const GLint Tex_Coord_Loc,
|
||||
const GLint MVP_Loc,
|
||||
const GLint Sampler_Loc) {
|
||||
Textured_Layer_Program_Object = Program_Object;
|
||||
Textured_Layer_Position_Loc = Position_Loc;
|
||||
Textured_Layer_Tex_Coord_Loc = Tex_Coord_Loc;
|
||||
Textured_Layer_MVP_Loc = MVP_Loc;
|
||||
Textured_Layer_Sampler_Loc = Sampler_Loc;
|
||||
}
|
||||
|
||||
FGTexturedLayer::FGTexturedLayer (const int w, const int h) :
|
||||
FGInstrumentLayer (w, h) {
|
||||
}
|
||||
|
||||
FGTexturedLayer::FGTexturedLayer (const FGCroppedTexture_ptr texture, const int w, const int h) :
|
||||
FGInstrumentLayer (w, h),
|
||||
m_texture (texture),
|
||||
m_emissive (false) {
|
||||
}
|
||||
|
||||
FGTexturedLayer::~FGTexturedLayer () {
|
||||
}
|
||||
|
||||
void
|
||||
FGTexturedLayer::draw () {
|
||||
if (test ()) {
|
||||
transform ();
|
||||
getDisplayList ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGTexturedLayer::setTexture (const FGCroppedTexture_ptr texture) {
|
||||
m_texture = texture;
|
||||
}
|
||||
|
||||
FGCroppedTexture_ptr
|
||||
FGTexturedLayer::getTexture () const {
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
void
|
||||
FGTexturedLayer::setEmissive (const bool emissive) {
|
||||
m_emissive = emissive;
|
||||
}
|
||||
|
||||
void
|
||||
FGTexturedLayer::getDisplayList () {
|
||||
int w2 = m_w / 2;
|
||||
int h2 = m_h / 2;
|
||||
|
||||
glUseProgram (Textured_Layer_Program_Object);
|
||||
m_texture->bind (Textured_Layer_Sampler_Loc);
|
||||
const GLfloat v_Vertices[] = {
|
||||
float (-w2), float (-h2), 0.0f, // Position 0 (bottom left corner)
|
||||
m_texture->getMinX (), m_texture->getMinY (), // TexCoord 0 (bottom left corner)
|
||||
float ( w2), float (-h2), 0.0f, // Position 1 (bottom right corner)
|
||||
m_texture->getMaxX (), m_texture->getMinY (), // TexCoord 1 (bottom right corner)
|
||||
float ( w2), float ( h2), 0.0f, // Position 2 (top right corner)
|
||||
m_texture->getMaxX (), m_texture->getMaxY (), // TexCoord 2 (top right corner)
|
||||
float (-w2), float ( h2), 0.0f, // Position 3 (top left corner)
|
||||
m_texture->getMinX (), m_texture->getMaxY () }; // TexCoord 3 (top left corner)
|
||||
glVertexAttribPointer (Textured_Layer_Position_Loc,
|
||||
3,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
5 * sizeof (GLfloat),
|
||||
v_Vertices);
|
||||
glVertexAttribPointer (Textured_Layer_Tex_Coord_Loc,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
5 * sizeof (GLfloat),
|
||||
&v_Vertices[3]);
|
||||
|
||||
glEnableVertexAttribArray (Textured_Layer_Position_Loc);
|
||||
glEnableVertexAttribArray (Textured_Layer_Tex_Coord_Loc);
|
||||
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_PROJECTION);
|
||||
GL_utils::instance ().glPushMatrix ();
|
||||
GL_utils::instance ().glMultMatrixf
|
||||
(*reinterpret_cast <GLfloat (*)[4][4]>
|
||||
(GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_MODELVIEW)));
|
||||
glUniformMatrix4fv (Textured_Layer_MVP_Loc,
|
||||
1,
|
||||
GL_FALSE,
|
||||
GL_utils::instance ().get_top_matrix (GL_utils::GL_UTILS_PROJECTION));
|
||||
|
||||
const GLushort indices[] = {0, 1, 2, 0, 2, 3};
|
||||
glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
|
||||
GL_utils::instance ().glPopMatrix ();
|
||||
GL_utils::instance ().glMatrixMode (GL_utils::GL_UTILS_MODELVIEW);
|
||||
}
|
||||
65
utils/fgpanel/FGTexturedLayer.hxx
Normal file
65
utils/fgpanel/FGTexturedLayer.hxx
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
// Adopted for standalone fgpanel application by Torsten Dreyer, August 2009
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef FGTEXTUREDLAYER_HXX
|
||||
#define FGTEXTUREDLAYER_HXX
|
||||
|
||||
#include "FGCroppedTexture.hxx"
|
||||
#include "FGInstrumentLayer.hxx"
|
||||
|
||||
/**
|
||||
* A textured layer of an instrument.
|
||||
*
|
||||
* This is a layer holding a single texture. Normally, the texture's
|
||||
* backgound should be transparent so that lower layers and the panel
|
||||
* background can show through.
|
||||
*/
|
||||
class FGTexturedLayer : public FGInstrumentLayer {
|
||||
public:
|
||||
static void Init (const GLuint Program_Object,
|
||||
const GLint Position_Loc,
|
||||
const GLint Tex_Coord_Loc,
|
||||
const GLint MVP_Loc,
|
||||
const GLint Sampler_Loc);
|
||||
|
||||
FGTexturedLayer (const int w = -1, const int h = -1);
|
||||
FGTexturedLayer (const FGCroppedTexture_ptr texture, const int w = -1, const int h = -1);
|
||||
virtual ~FGTexturedLayer ();
|
||||
|
||||
virtual void draw ();
|
||||
|
||||
virtual void setTexture (const FGCroppedTexture_ptr texture);
|
||||
FGCroppedTexture_ptr getTexture () const;
|
||||
|
||||
void setEmissive (const bool emissive);
|
||||
|
||||
private:
|
||||
void getDisplayList ();
|
||||
|
||||
FGCroppedTexture_ptr m_texture;
|
||||
bool m_emissive;
|
||||
|
||||
static GLuint Textured_Layer_Program_Object;
|
||||
static GLint Textured_Layer_Position_Loc;
|
||||
static GLint Textured_Layer_Tex_Coord_Loc;
|
||||
static GLint Textured_Layer_MVP_Loc;
|
||||
static GLint Textured_Layer_Sampler_Loc;
|
||||
};
|
||||
|
||||
#endif
|
||||
385
utils/fgpanel/GLES_utils.cxx
Normal file
385
utils/fgpanel/GLES_utils.cxx
Normal file
@@ -0,0 +1,385 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef _RPI
|
||||
#include <bcm_host.h>
|
||||
#else
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
#endif
|
||||
|
||||
#include "GLES_utils.hxx"
|
||||
|
||||
/// esCreateWindow flag - RGB color buffer
|
||||
#define GLES_UTILS_WINDOW_RGB 0
|
||||
/// esCreateWindow flag - ALPHA color buffer
|
||||
#define GLES_UTILS_WINDOW_ALPHA 1
|
||||
/// esCreateWindow flag - depth buffer
|
||||
#define GLES_UTILS_WINDOW_DEPTH 2
|
||||
/// esCreateWindow flag - stencil buffer
|
||||
#define GLES_UTILS_WINDOW_STENCIL 4
|
||||
/// esCreateWindow flat - multi-sample buffer
|
||||
#define GLES_UTILS_WINDOW_MULTISAMPLE 8
|
||||
|
||||
GLES_utils::GLES_utils () :
|
||||
m_State (),
|
||||
display_func (NULL),
|
||||
idle_func (NULL),
|
||||
keyboard_func (NULL),
|
||||
reshape_func (NULL) {}
|
||||
|
||||
GLES_utils::~GLES_utils () {}
|
||||
|
||||
GLES_utils&
|
||||
GLES_utils::instance () {
|
||||
static GLES_utils* const The_Instance (new GLES_utils);
|
||||
return *The_Instance;
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::init (const string &title) {
|
||||
#ifdef _RPI
|
||||
bcm_host_init ();
|
||||
init_dispmanx (m_State.native_window);
|
||||
#else
|
||||
init_display (m_State, title);
|
||||
#endif
|
||||
init_egl (m_State, GLES_UTILS_WINDOW_RGB);
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::print_config_info (const int n, const EGLDisplay &display, EGLConfig &config) {
|
||||
int size;
|
||||
|
||||
cout << "EGL Configuration " << n << " is" << endl;
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_RED_SIZE, &size);
|
||||
cout << "EGL Red size is " << size << endl;
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_BLUE_SIZE, &size);
|
||||
cout << "EGL Blue size is " << size << endl;
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_GREEN_SIZE, &size);
|
||||
cout << "EGL Green size is " << size << endl;
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_BUFFER_SIZE, &size);
|
||||
cout << "EGL Buffer size is " << size << endl;
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_BIND_TO_TEXTURE_RGB , &size);
|
||||
if (size == EGL_TRUE) {
|
||||
cout << "EGL Can be bound to RGB texture" << endl;
|
||||
} else {
|
||||
cout << "EGL Can't be bound to RGB texture" << endl;
|
||||
}
|
||||
|
||||
eglGetConfigAttrib (display, config, EGL_BIND_TO_TEXTURE_RGBA , &size);
|
||||
if (size == EGL_TRUE) {
|
||||
cout << "EGL Can be bound to RGBA texture" << endl;
|
||||
} else {
|
||||
cout << "EGL Can't be bound to RGBA texture" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::init_egl (EGL_STATE_T &state, const GLuint flags) {
|
||||
EGLBoolean result;
|
||||
|
||||
static const EGLint attribute_list[] = {
|
||||
EGL_RED_SIZE, 5,
|
||||
EGL_GREEN_SIZE, 6,
|
||||
EGL_BLUE_SIZE, 5,
|
||||
EGL_ALPHA_SIZE, (flags & GLES_UTILS_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE,
|
||||
EGL_DEPTH_SIZE, (flags & GLES_UTILS_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE,
|
||||
EGL_STENCIL_SIZE, (flags & GLES_UTILS_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE,
|
||||
EGL_SAMPLE_BUFFERS, (flags & GLES_UTILS_WINDOW_MULTISAMPLE) ? 1 : 0,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
static const EGLint context_attributes[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_NONE
|
||||
#ifndef _RPI
|
||||
, EGL_NONE
|
||||
#endif
|
||||
};
|
||||
|
||||
EGLConfig *configs;
|
||||
|
||||
// get an EGL display connection
|
||||
#ifdef _RPI
|
||||
state.display = eglGetDisplay (EGL_DEFAULT_DISPLAY);
|
||||
#else
|
||||
state.display = eglGetDisplay ((EGLNativeDisplayType) state.x_display);
|
||||
#endif
|
||||
assert (state.display != EGL_NO_DISPLAY);
|
||||
|
||||
// initialize the EGL display connection
|
||||
result = eglInitialize (state.display, &(state.major_version), &(state.minor_version));
|
||||
assert (result != EGL_FALSE);
|
||||
|
||||
result = eglGetConfigs (state.display, NULL, 0, &(state.num_configs));
|
||||
assert (result != EGL_FALSE);
|
||||
|
||||
configs = (EGLConfig *) calloc (state.num_configs, sizeof (*configs));
|
||||
result = eglGetConfigs (state.display, configs, state.num_configs, &(state.num_configs));
|
||||
assert (result != EGL_FALSE);
|
||||
|
||||
cout << "EGL version = " << state.major_version << "." << state.minor_version << endl;
|
||||
cout << "EGL has " << state.num_configs << " configs" << endl;
|
||||
for (int i = 0; i < state.num_configs; ++i) {
|
||||
print_config_info (i, state.display, configs[i]);
|
||||
}
|
||||
|
||||
// get an appropriate EGL frame buffer configuration
|
||||
result = eglChooseConfig (state.display, attribute_list, &(state.config), 1, &(state.num_configs));
|
||||
assert (result != EGL_FALSE);
|
||||
|
||||
// Choose the OpenGL ES API
|
||||
result = eglBindAPI (EGL_OPENGL_ES_API);
|
||||
assert (result != EGL_FALSE);
|
||||
|
||||
#ifdef _RPI
|
||||
state.surface = eglCreateWindowSurface (state.display,
|
||||
state.config,
|
||||
(EGLNativeWindowType) &(state.native_window),
|
||||
NULL);
|
||||
#else
|
||||
state.surface = eglCreateWindowSurface (state.display,
|
||||
state.config,
|
||||
state.native_window,
|
||||
NULL);
|
||||
#endif
|
||||
assert (state.surface != EGL_NO_SURFACE);
|
||||
|
||||
// create an EGL rendering context
|
||||
state.context = eglCreateContext (state.display, state.config, EGL_NO_CONTEXT, context_attributes);
|
||||
assert (state.context != EGL_NO_CONTEXT);
|
||||
|
||||
// connect the context to the surface
|
||||
result = eglMakeCurrent (state.display, state.surface, state.surface, state.context);
|
||||
assert (result != EGL_FALSE);
|
||||
}
|
||||
|
||||
#ifdef _RPI
|
||||
void
|
||||
GLES_utils::init_dispmanx (EGL_DISPMANX_WINDOW_T &native_window) {
|
||||
int32_t success = 0;
|
||||
uint32_t screen_width;
|
||||
uint32_t screen_height;
|
||||
|
||||
DISPMANX_ELEMENT_HANDLE_T dispman_element;
|
||||
DISPMANX_DISPLAY_HANDLE_T dispman_display;
|
||||
DISPMANX_UPDATE_HANDLE_T dispman_update;
|
||||
VC_RECT_T dst_rect;
|
||||
VC_RECT_T src_rect;
|
||||
|
||||
// create an EGL window surface
|
||||
success = graphics_get_display_size (0 /* LCD */,
|
||||
&screen_width,
|
||||
&screen_height);
|
||||
assert (success >= 0);
|
||||
|
||||
dst_rect.x = 0;
|
||||
dst_rect.y = 0;
|
||||
dst_rect.width = screen_width;
|
||||
dst_rect.height = screen_height;
|
||||
|
||||
src_rect.x = 0;
|
||||
src_rect.y = 0;
|
||||
src_rect.width = screen_width << 16;
|
||||
src_rect.height = screen_height << 16;
|
||||
|
||||
dispman_display = vc_dispmanx_display_open (0 /* LCD */);
|
||||
dispman_update = vc_dispmanx_update_start (0);
|
||||
|
||||
dispman_element = vc_dispmanx_element_add (dispman_update,
|
||||
dispman_display,
|
||||
0 /*layer*/,
|
||||
&dst_rect,
|
||||
0 /*src*/,
|
||||
&src_rect,
|
||||
DISPMANX_PROTECTION_NONE,
|
||||
0 /*alpha*/,
|
||||
0 /*clamp*/,
|
||||
DISPMANX_TRANSFORM_T (0) /*transform*/);
|
||||
|
||||
// Build an EGL_DISPMANX_WINDOW_T from the Dispmanx window
|
||||
native_window.element = dispman_element;
|
||||
native_window.width = screen_width;
|
||||
native_window.height = screen_height;
|
||||
vc_dispmanx_update_submit_sync (dispman_update);
|
||||
|
||||
cout << "Got a Dispmanx window" << endl;
|
||||
}
|
||||
|
||||
GLboolean
|
||||
GLES_utils::user_interrupt () {
|
||||
return GL_FALSE;
|
||||
}
|
||||
#else
|
||||
void
|
||||
GLES_utils::init_display (EGL_STATE_T &state, const string &title) {
|
||||
Window root;
|
||||
XSetWindowAttributes swa;
|
||||
XSetWindowAttributes xattr;
|
||||
Atom wm_state;
|
||||
XWMHints hints;
|
||||
XEvent xev;
|
||||
Window win;
|
||||
|
||||
state.width = 1024;
|
||||
state.height = 768;
|
||||
|
||||
/*
|
||||
* X11 native display initialization
|
||||
*/
|
||||
|
||||
state.x_display = XOpenDisplay (NULL);
|
||||
assert (state.x_display != NULL);
|
||||
|
||||
root = DefaultRootWindow (state.x_display);
|
||||
|
||||
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;
|
||||
win = XCreateWindow (state.x_display,
|
||||
root,
|
||||
0,
|
||||
0,
|
||||
state.width,
|
||||
state.height,
|
||||
0,
|
||||
CopyFromParent,
|
||||
InputOutput,
|
||||
CopyFromParent,
|
||||
CWEventMask,
|
||||
&swa);
|
||||
|
||||
xattr.override_redirect = false;
|
||||
XChangeWindowAttributes (state.x_display, win, CWOverrideRedirect, &xattr);
|
||||
|
||||
hints.input = true;
|
||||
hints.flags = InputHint;
|
||||
XSetWMHints (state.x_display, win, &hints);
|
||||
|
||||
// make the window visible on the screen
|
||||
XMapWindow (state.x_display, win);
|
||||
XStoreName (state.x_display, win, title.c_str ());
|
||||
|
||||
// get identifiers for the provided atom name strings
|
||||
wm_state = XInternAtom (state.x_display, "_NET_WM_STATE", false);
|
||||
|
||||
memset (&xev, 0, sizeof (xev));
|
||||
xev.type = ClientMessage;
|
||||
xev.xclient.window = win;
|
||||
xev.xclient.message_type = wm_state;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = 1;
|
||||
xev.xclient.data.l[1] = false;
|
||||
XSendEvent (state.x_display, DefaultRootWindow (state.x_display), false, SubstructureNotifyMask, &xev);
|
||||
|
||||
state.native_window = (EGLNativeWindowType) win;
|
||||
}
|
||||
|
||||
GLboolean
|
||||
GLES_utils::user_interrupt () {
|
||||
XEvent xev;
|
||||
KeySym key;
|
||||
GLboolean user_interrupt = GL_FALSE;
|
||||
char text;
|
||||
|
||||
// Pump all messages from X server. Keypresses are directed to keyfunc (if defined)
|
||||
while (XPending (m_State.x_display)) {
|
||||
XNextEvent (m_State.x_display, &xev);
|
||||
if (xev.type == KeyPress) {
|
||||
if (XLookupString (&xev.xkey, &text, 1, &key, 0) == 1) {
|
||||
if (keyboard_func != NULL) {
|
||||
keyboard_func (text, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xev.type == DestroyNotify) {
|
||||
user_interrupt = GL_TRUE;
|
||||
}
|
||||
}
|
||||
return user_interrupt;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
GLES_utils::register_display_func (void (*display_func) ()) {
|
||||
this->display_func = display_func;
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::register_idle_func (void (*idle_func) ()) {
|
||||
this->idle_func = idle_func;
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::register_keyboard_func (void (*keyboard_func) (unsigned char, int, int)) {
|
||||
this->keyboard_func = keyboard_func;
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::register_reshape_func (void (*reshape_func) (int, int)) {
|
||||
this->reshape_func = reshape_func;
|
||||
}
|
||||
|
||||
void
|
||||
GLES_utils::main_loop () {
|
||||
struct timeval t1, t2;
|
||||
struct timezone tz;
|
||||
float delta_time;
|
||||
float total_time = 0.0f;
|
||||
unsigned int frames = 0;
|
||||
|
||||
gettimeofday (&t1 , &tz);
|
||||
|
||||
while (user_interrupt () == GL_FALSE) {
|
||||
gettimeofday (&t2, &tz);
|
||||
delta_time = (float) (t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6);
|
||||
t1 = t2;
|
||||
|
||||
if (reshape_func != NULL) {
|
||||
#ifdef _RPI
|
||||
reshape_func (m_State.native_window.width, m_State.native_window.height);
|
||||
#else
|
||||
reshape_func (m_State.width, m_State.height);
|
||||
#endif
|
||||
}
|
||||
if (idle_func != NULL) {
|
||||
idle_func ();
|
||||
}
|
||||
if (display_func != NULL) {
|
||||
display_func ();
|
||||
}
|
||||
|
||||
eglSwapBuffers (m_State.display, m_State.surface);
|
||||
|
||||
total_time += delta_time;
|
||||
++frames;
|
||||
if (total_time > 2.0f) {
|
||||
cout << frames << " frames rendered in " << total_time << " seconds -> FPS = " << (frames / total_time) << endl;
|
||||
total_time -= 2.0f;
|
||||
frames = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
utils/fgpanel/GLES_utils.hxx
Normal file
77
utils/fgpanel/GLES_utils.hxx
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <string>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
|
||||
class GLES_utils : private boost::noncopyable {
|
||||
public:
|
||||
static GLES_utils& instance ();
|
||||
|
||||
void init (const std::string &title);
|
||||
|
||||
void register_display_func (void (*display_func) ());
|
||||
void register_idle_func (void (*idle_func) ());
|
||||
void register_keyboard_func (void (*keyboard_func) (unsigned char, int, int));
|
||||
void register_reshape_func (void (*reshape_func) (int, int));
|
||||
|
||||
void main_loop ();
|
||||
|
||||
private:
|
||||
explicit GLES_utils ();
|
||||
virtual ~GLES_utils ();
|
||||
|
||||
typedef struct {
|
||||
#ifdef _RPI
|
||||
EGL_DISPMANX_WINDOW_T native_window;
|
||||
#else
|
||||
EGLNativeWindowType native_window;
|
||||
Display *x_display;
|
||||
GLint width;
|
||||
GLint height;
|
||||
#endif
|
||||
EGLint major_version;
|
||||
EGLint minor_version;
|
||||
EGLint num_configs;
|
||||
EGLDisplay display;
|
||||
EGLSurface surface;
|
||||
EGLContext context;
|
||||
EGLConfig config;
|
||||
} EGL_STATE_T;
|
||||
|
||||
EGL_STATE_T m_State;
|
||||
|
||||
void (*display_func) ();
|
||||
void (*idle_func) ();
|
||||
void (*keyboard_func) (unsigned char, int, int);
|
||||
void (*reshape_func) (int, int);
|
||||
|
||||
void print_config_info (const int n, const EGLDisplay &display, EGLConfig &config);
|
||||
void init_egl (EGL_STATE_T &state, const GLuint flags);
|
||||
#ifdef _RPI
|
||||
void init_dispmanx (EGL_DISPMANX_WINDOW_T &native_window);
|
||||
#else
|
||||
void init_display (EGL_STATE_T &state, const std::string &title);
|
||||
#endif
|
||||
GLboolean user_interrupt ();
|
||||
};
|
||||
374
utils/fgpanel/GL_utils.cxx
Normal file
374
utils/fgpanel/GL_utils.cxx
Normal file
@@ -0,0 +1,374 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "GL_utils.hxx"
|
||||
|
||||
const float PI (3.1415926535897932384626433832795);
|
||||
|
||||
GL_utils::GL_utils () {
|
||||
Matrix Tmp;
|
||||
memset (&Tmp, 0x0, sizeof (Matrix));
|
||||
int i;
|
||||
for (i = GL_UTILS_MODELVIEW; i < GL_UTILS_LAST; ++i) {
|
||||
m_Current_Matrix_Mode = (GLenum_Mode) i;
|
||||
m_Matrix[m_Current_Matrix_Mode].push (Tmp);
|
||||
glLoadIdentity ();
|
||||
}
|
||||
m_Current_Matrix_Mode = GL_utils::GL_UTILS_UNSET;
|
||||
}
|
||||
|
||||
GL_utils::~GL_utils () {}
|
||||
|
||||
GL_utils&
|
||||
GL_utils::instance () {
|
||||
static GL_utils* const The_Instance (new GL_utils);
|
||||
return *The_Instance;
|
||||
}
|
||||
|
||||
//
|
||||
///
|
||||
/// \brief Load a shader, check for compile errors, print error messages to std error
|
||||
/// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER)
|
||||
/// \param shader_src Shader source string
|
||||
/// \return A new shader object on success, 0 on failure
|
||||
//
|
||||
GLuint
|
||||
GL_utils::load_shader (GLenum type, const char *shader_src) {
|
||||
GLint compiled;
|
||||
|
||||
// Create the shader object
|
||||
GLuint shader (glCreateShader (type));
|
||||
|
||||
if (shader == 0) {
|
||||
cerr << "Error creating shader" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Load the shader source
|
||||
glShaderSource (shader, 1, &shader_src, NULL);
|
||||
|
||||
// Compile the shader
|
||||
glCompileShader (shader);
|
||||
|
||||
// Check the compile status
|
||||
glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled);
|
||||
|
||||
if (!compiled) {
|
||||
GLint info_len (0);
|
||||
|
||||
glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &info_len);
|
||||
|
||||
if (info_len > 1) {
|
||||
char* info_log ((char *) malloc (sizeof (char) * info_len));
|
||||
|
||||
glGetShaderInfoLog (shader, info_len, NULL, info_log);
|
||||
cerr << "Error compiling shader:" << endl << info_log << endl;
|
||||
|
||||
free (info_log);
|
||||
}
|
||||
|
||||
glDeleteShader (shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
//
|
||||
///
|
||||
/// \brief Load a vertex and fragment shader, create a program object, link program.
|
||||
// Errors output to std error.
|
||||
/// \param vertShaderSrc Vertex shader source code
|
||||
/// \param fragShaderSrc Fragment shader source code
|
||||
/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure
|
||||
//
|
||||
GLuint
|
||||
GL_utils::load_program (const char *vert_shader_src, const char *frag_shader_src) {
|
||||
GLint linked;
|
||||
|
||||
// Load the vertex/fragment shaders
|
||||
GLuint vertex_shader (load_shader (GL_VERTEX_SHADER, vert_shader_src));
|
||||
if (vertex_shader == 0) {
|
||||
cerr << "Error loading vertex shader" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLuint fragment_shader (load_shader (GL_FRAGMENT_SHADER, frag_shader_src));
|
||||
if (fragment_shader == 0) {
|
||||
cerr << "Error loading fragment shader" << endl;
|
||||
glDeleteShader (vertex_shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create the program object
|
||||
GLuint program_object (glCreateProgram ());
|
||||
|
||||
if (program_object == 0) {
|
||||
cerr << "Error creating program" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
glAttachShader (program_object, vertex_shader);
|
||||
glAttachShader (program_object, fragment_shader);
|
||||
|
||||
// Link the program
|
||||
glLinkProgram (program_object);
|
||||
|
||||
// Check the link status
|
||||
glGetProgramiv (program_object, GL_LINK_STATUS, &linked);
|
||||
|
||||
if (!linked) {
|
||||
GLint info_len (0);
|
||||
|
||||
glGetProgramiv (program_object, GL_INFO_LOG_LENGTH, &info_len);
|
||||
|
||||
if (info_len > 1) {
|
||||
char* info_log ((char *) malloc (sizeof (char) * info_len));
|
||||
|
||||
glGetProgramInfoLog (program_object, info_len, NULL, info_log);
|
||||
cerr << "Error linking program:" << endl << info_log << endl;
|
||||
|
||||
free (info_log);
|
||||
}
|
||||
|
||||
glDeleteProgram (program_object);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Free up no longer needed shader resources
|
||||
glDeleteShader (vertex_shader);
|
||||
glDeleteShader (fragment_shader);
|
||||
|
||||
return program_object;
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::glMatrixMode (const GLenum_Mode mode) {
|
||||
if (mode < GL_UTILS_LAST) {
|
||||
m_Current_Matrix_Mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::glLoadIdentity () {
|
||||
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
|
||||
memset (&(m_Matrix[m_Current_Matrix_Mode].top ()), 0x0, sizeof (Matrix));
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[0][0] = 1.0f;
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[1][1] = 1.0f;
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[2][2] = 1.0f;
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[3][3] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::gluOrtho2D (const GLfloat left,
|
||||
const GLfloat right,
|
||||
const GLfloat bottom,
|
||||
const GLfloat top) {
|
||||
GL_utils::glOrtho (left, right, bottom, top, -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::glOrtho (const GLfloat left,
|
||||
const GLfloat right,
|
||||
const GLfloat bottom,
|
||||
const GLfloat top,
|
||||
const GLfloat nearVal,
|
||||
const GLfloat farVal) {
|
||||
const GLfloat Delta_X (right - left);
|
||||
const GLfloat Delta_Y (top - bottom);
|
||||
const GLfloat Delta_Z (farVal - nearVal);
|
||||
Matrix Ortho;
|
||||
|
||||
if ((Delta_X == 0.0f) || (Delta_Y == 0.0f) || (Delta_Z == 0.0f) || (m_Current_Matrix_Mode < GL_UTILS_LAST)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset (&Ortho, 0x0, sizeof (Matrix));
|
||||
Ortho.m[0][0] = 2.0f / Delta_X;
|
||||
Ortho.m[3][0] = -(right + left) / Delta_X;
|
||||
Ortho.m[1][1] = 2.0f / Delta_Y;
|
||||
Ortho.m[3][1] = -(top + bottom) / Delta_Y;
|
||||
Ortho.m[2][2] = -2.0f / Delta_Z;
|
||||
Ortho.m[3][2] = -(nearVal + farVal) / Delta_Z;
|
||||
Ortho.m[3][3] = 1.0f;
|
||||
|
||||
GL_utils::glMultMatrixf (Ortho.m);
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::glTranslatef (const GLfloat x, const GLfloat y, const GLfloat z) {
|
||||
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[3][0] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][0] * x +
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[1][0] * y +
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[2][0] * z);
|
||||
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[3][1] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][1] * x +
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[1][1] * y +
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[2][1] * z);
|
||||
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[3][2] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][2] * x +
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[1][2] * y +
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[2][2] * z);
|
||||
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[3][3] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][3] * x +
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[1][3] * y +
|
||||
m_Matrix[m_Current_Matrix_Mode].top ().m[2][3] * z);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::glRotatef (const GLfloat angle, const GLfloat x, const GLfloat y, const GLfloat z) {
|
||||
const GLfloat xx (x * x);
|
||||
const GLfloat yy (y * y);
|
||||
const GLfloat zz (z * z);
|
||||
const GLfloat Mag (sqrtf (xx + yy + zz));
|
||||
|
||||
if ((Mag > 0.0f) && (m_Current_Matrix_Mode < GL_UTILS_LAST)) {
|
||||
const GLfloat Sin_Angle (sinf (-angle * PI / 180.0f));
|
||||
const GLfloat Cos_Angle (cosf (angle * PI / 180.0f));
|
||||
const GLfloat xy (x * y);
|
||||
const GLfloat yz (y * z);
|
||||
const GLfloat zx (z * x);
|
||||
const GLfloat xs (x * Sin_Angle);
|
||||
const GLfloat ys (y * Sin_Angle);
|
||||
const GLfloat zs (z * Sin_Angle);
|
||||
const GLfloat One_Minus_Cos (1.0f - Cos_Angle);
|
||||
Matrix Rot;
|
||||
|
||||
// x /= mag;
|
||||
// y /= mag;
|
||||
// z /= mag;
|
||||
|
||||
Rot.m[0][0] = (One_Minus_Cos * xx) + Cos_Angle;
|
||||
Rot.m[0][1] = (One_Minus_Cos * xy) - zs;
|
||||
Rot.m[0][2] = (One_Minus_Cos * zx) + ys;
|
||||
Rot.m[0][3] = 0.0f;
|
||||
|
||||
Rot.m[1][0] = (One_Minus_Cos * xy) + zs;
|
||||
Rot.m[1][1] = (One_Minus_Cos * yy) + Cos_Angle;
|
||||
Rot.m[1][2] = (One_Minus_Cos * yz) - xs;
|
||||
Rot.m[1][3] = 0.0f;
|
||||
|
||||
Rot.m[2][0] = (One_Minus_Cos * zx) - ys;
|
||||
Rot.m[2][1] = (One_Minus_Cos * yz) + xs;
|
||||
Rot.m[2][2] = (One_Minus_Cos * zz) + Cos_Angle;
|
||||
Rot.m[2][3] = 0.0f;
|
||||
|
||||
Rot.m[3][0] = 0.0f;
|
||||
Rot.m[3][1] = 0.0f;
|
||||
Rot.m[3][2] = 0.0f;
|
||||
Rot.m[3][3] = 1.0f;
|
||||
|
||||
GL_utils::glMultMatrixf (Rot.m);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::glScalef (GLfloat x, GLfloat y, GLfloat z) {
|
||||
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
|
||||
Matrix Scale;
|
||||
Scale.m[0][0] = x;
|
||||
Scale.m[0][1] = 0.0f;
|
||||
Scale.m[0][2] = 0.0f;
|
||||
Scale.m[0][3] = 0.0f;
|
||||
|
||||
Scale.m[1][0] = 0.0f;
|
||||
Scale.m[1][1] = y;
|
||||
Scale.m[1][2] = 0.0f;
|
||||
Scale.m[1][3] = 0.0f;
|
||||
|
||||
Scale.m[2][0] = 0.0f;
|
||||
Scale.m[2][1] = 0.0f;
|
||||
Scale.m[2][2] = z;
|
||||
Scale.m[2][3] = 0.0f;
|
||||
|
||||
Scale.m[3][0] = 0.0f;
|
||||
Scale.m[3][1] = 0.0f;
|
||||
Scale.m[3][2] = 0.0f;
|
||||
Scale.m[3][3] = 1.0f;
|
||||
|
||||
GL_utils::glMultMatrixf (Scale.m);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::glMultMatrixf (const GLfloat m[4][4]) {
|
||||
Matrix Tmp;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
Tmp.m[i][0] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][0] +
|
||||
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][0] +
|
||||
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][0] +
|
||||
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][0]);
|
||||
|
||||
Tmp.m[i][1] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][1] +
|
||||
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][1] +
|
||||
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][1] +
|
||||
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][1]);
|
||||
|
||||
Tmp.m[i][2] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][2] +
|
||||
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][2] +
|
||||
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][2] +
|
||||
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][2]);
|
||||
|
||||
Tmp.m[i][3] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][3] +
|
||||
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][3] +
|
||||
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][3] +
|
||||
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][3]);
|
||||
}
|
||||
memcpy (&(m_Matrix[m_Current_Matrix_Mode].top ()), &Tmp, sizeof (Matrix));
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::glPushMatrix () {
|
||||
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
|
||||
m_Matrix[m_Current_Matrix_Mode].push (m_Matrix[m_Current_Matrix_Mode].top ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::glPopMatrix () {
|
||||
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
|
||||
m_Matrix[m_Current_Matrix_Mode].pop ();
|
||||
}
|
||||
}
|
||||
|
||||
GLfloat*
|
||||
GL_utils::get_top_matrix (const GL_utils::GLenum_Mode mode) {
|
||||
if (mode < GL_UTILS_LAST) {
|
||||
return &(m_Matrix[mode].top ().m[0][0]);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GL_utils::Debug (const GL_utils::GLenum_Mode mode) const {
|
||||
if (mode < GL_UTILS_LAST) {
|
||||
for (int l = 0; l < 4; ++l) {
|
||||
cout << " ";
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
cout << m_Matrix[mode].top ().m[c][l] << " ";
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
81
utils/fgpanel/GL_utils.hxx
Normal file
81
utils/fgpanel/GL_utils.hxx
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <stack>
|
||||
|
||||
#if defined (SG_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#elif defined (_GLES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#else
|
||||
#include <GL/glew.h> // Must be included before <GL/gl.h>
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
|
||||
class GL_utils : private boost::noncopyable {
|
||||
public:
|
||||
static GL_utils& instance ();
|
||||
|
||||
enum GLenum_Mode {
|
||||
GL_UTILS_MODELVIEW,
|
||||
GL_UTILS_PROJECTION,
|
||||
GL_UTILS_TEXTURE,
|
||||
GL_UTILS_COLOR,
|
||||
GL_UTILS_LAST,
|
||||
GL_UTILS_UNSET
|
||||
};
|
||||
|
||||
GLuint load_program (const char *vert_shader_src, const char *frag_shader_src);
|
||||
|
||||
void glMatrixMode (const GL_utils::GLenum_Mode mode);
|
||||
void glLoadIdentity ();
|
||||
void gluOrtho2D (const GLfloat left,
|
||||
const GLfloat right,
|
||||
const GLfloat bottom,
|
||||
const GLfloat top);
|
||||
void glOrtho (const GLfloat left,
|
||||
const GLfloat right,
|
||||
const GLfloat bottom,
|
||||
const GLfloat top,
|
||||
const GLfloat nearVal,
|
||||
const GLfloat farVal);
|
||||
void glTranslatef (const GLfloat x, const GLfloat y, const GLfloat z);
|
||||
void glRotatef (const GLfloat angle, const GLfloat x, const GLfloat y, const GLfloat z);
|
||||
void glScalef (const GLfloat x, const GLfloat y, const GLfloat z);
|
||||
// C' = C X M
|
||||
void glMultMatrixf (const GLfloat m[4][4]);
|
||||
void glPushMatrix ();
|
||||
void glPopMatrix ();
|
||||
GLfloat* get_top_matrix (const GL_utils::GLenum_Mode mode);
|
||||
void Debug (const GL_utils::GLenum_Mode mode) const;
|
||||
|
||||
private:
|
||||
explicit GL_utils ();
|
||||
virtual ~GL_utils ();
|
||||
|
||||
GLuint load_shader (GLenum type, const char *shader_src);
|
||||
|
||||
typedef struct {
|
||||
GLfloat m[4][4];
|
||||
} Matrix;
|
||||
|
||||
std::stack <Matrix> m_Matrix[GL_UTILS_LAST];
|
||||
GLenum_Mode m_Current_Matrix_Mode;
|
||||
};
|
||||
148
utils/fgpanel/README
Normal file
148
utils/fgpanel/README
Normal file
@@ -0,0 +1,148 @@
|
||||
=====================================================================
|
||||
This is fgpanel - basically the stripped down 2D-Panel code from
|
||||
FlightGear. It is designed as a standalone lightweight panel
|
||||
rendering engine to draw 2d panels on a lowcost computer/graphic card
|
||||
without 3d acceleration at reasonablel framerates.
|
||||
|
||||
=====================================================================
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
=====================================================================
|
||||
Usage
|
||||
start fgpanel with
|
||||
fgpanel --fg-root=/path/to/fg/data --panel=Aircraft/MyAircraft/Panels/MyPanel.xml
|
||||
with the command args set to
|
||||
--fg-root shall point to the directory where your FGDATA lives
|
||||
NOTE: you don't need a full copy of FGDATA, just the panel definition files for
|
||||
your aircraft, e.g.
|
||||
- Aircraft/MyAircraft/Panels/*
|
||||
- Aircraft/Instruments/* (if referenced)
|
||||
|
||||
-panel shall point to a panel-configuration file, relative to FGDATA
|
||||
|
||||
start flightgear with
|
||||
fgfs --generic=socket,out,10,239.24.10.64,5432,udp,../Aircraft/MyAircraft/Panels/SampleProtocol
|
||||
|
||||
=====================================================================
|
||||
Sample:
|
||||
|
||||
Create the sample files within your aicraft directory, preferrable under Panels
|
||||
MyPanel.xml
|
||||
sample-2d-panel.xml
|
||||
SampleProtocol.xml
|
||||
|
||||
=====================================================================
|
||||
Sample panel configuration file (MyPanel.xml)
|
||||
<PropertyList>
|
||||
|
||||
<!-- true: run full-screen, false; run in window -->
|
||||
<game-mode type="bool">false</game-mode>
|
||||
|
||||
<!-- include the panel definitions (2d-panel syntax)-->
|
||||
<panel include="sample-2d-panel.xml"/>
|
||||
|
||||
<!-- compose your property-tree here -->
|
||||
<sim>
|
||||
<panel>
|
||||
<flip-x type="bool">false</flip-x>
|
||||
</panel>
|
||||
<instrument-options>
|
||||
<omit-knobs type="bool">true</omit-knobs>
|
||||
</instrument-options>
|
||||
</sim>
|
||||
|
||||
<!-- network communication settings -->
|
||||
<communication>
|
||||
<listen>
|
||||
<!-- interface to bind to,
|
||||
leave empty for all interfaces -->
|
||||
<host>239.24.10.64</host> <!-- multicast address! -->
|
||||
<port>5432</port> <!-- tcp port to listen to -->
|
||||
<style>udp</style> <!-- udp or tcp (forget about tcp!) -->
|
||||
</listen>
|
||||
|
||||
<!-- the generic protocol definition
|
||||
same as used for fgfs --generic=foobar option
|
||||
-->
|
||||
<protocol include="SampleProtocol.xml"/>
|
||||
</communication>
|
||||
</PropertyList>
|
||||
|
||||
=====================================================================
|
||||
Sampe 2d-panel configuration file sample-2d-panel.xml
|
||||
To be included from the panel configuration file
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<PropertyList>
|
||||
<name>Sample Instrument Panel</name>
|
||||
<w>375</w> <!-- screen width: 375mm -->
|
||||
<h>305</h> <!-- screen height: 305mm -->
|
||||
<instruments>
|
||||
<!-- use FlightGear's c172 attitude indicator -->
|
||||
<instrument include="../../Instruments/ati-c172s.xml">
|
||||
<name>Attitude Gyro</name>
|
||||
<x alias="../../../params/col-2"/>
|
||||
<y alias="../../../params/row-1"/>
|
||||
<w>80</w>
|
||||
<h>80</h>
|
||||
</instrument>
|
||||
</instruments>
|
||||
</PropertyList>
|
||||
|
||||
=====================================================================
|
||||
Sample protocol configuration file to drive the AI (SampleProtocol.xml)
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<PropertyList>
|
||||
<generic>
|
||||
|
||||
<output>
|
||||
<line_separator>newline</line_separator>
|
||||
<var_separator>,</var_separator>
|
||||
|
||||
<chunk>
|
||||
<type>float</type>
|
||||
<format>%.2f</format>
|
||||
<node>/position/altitude-agl-ft</node>
|
||||
</chunk>
|
||||
|
||||
<chunk>
|
||||
<type>float</type>
|
||||
<format>%.2f</format>
|
||||
<node>/instrumentation/attitude-indicator/indicated-roll-deg</node>
|
||||
</chunk>
|
||||
|
||||
<chunk>
|
||||
<type>float</type>
|
||||
<format>%.2f</format>
|
||||
<node>/instrumentation/attitude-indicator/indicated-pitch-deg</node>
|
||||
</chunk>
|
||||
|
||||
<chunk>
|
||||
<type>float</type>
|
||||
<format>%.2f</format>
|
||||
<node>/instrumentation/attitude-indicator/horizon-offset-deg</node>
|
||||
</chunk>
|
||||
|
||||
<chunk>
|
||||
<type>float</type>
|
||||
<format>%.4e</format>
|
||||
<node>/instrumentation/attitude-indicator/spin</node>
|
||||
</chunk>
|
||||
</output>
|
||||
</generic>
|
||||
</PropertyList>
|
||||
|
||||
=====================================================================
|
||||
55
utils/fgpanel/README.RPi
Normal file
55
utils/fgpanel/README.RPi
Normal file
@@ -0,0 +1,55 @@
|
||||
This is the FGPanel for the Raspberry Pi running Raspbian.
|
||||
It should work with other Linux distributions but it has not been tested.
|
||||
|
||||
INSTALLATION
|
||||
============
|
||||
|
||||
1. Build SimGear as usual.
|
||||
OSG, Plib, GLUT,... will be required even they are not strictly needed to run FGPanel.
|
||||
|
||||
2. Configure FlightGear using CMake as usual.
|
||||
CMakeLists.txt is used to compile FGPanel with OpenGL 2.0.
|
||||
This should make FGPanel faster on modern graphics cards.
|
||||
|
||||
CMakeLists.txt is used to compile FGPanel with OpenGL ES 2.0 for the Raspberry Pi.
|
||||
The source code of FGPanel can easily be adapted to other embedded devices supporting OpenGL ES 2.0.
|
||||
|
||||
3. Build FGPanel only (don't build all components on the Raspberry Pi as this will take ages!!!):
|
||||
make -- fgpanel-egl fgpanel
|
||||
|
||||
USAGE (fgpanel-egl)
|
||||
===================
|
||||
|
||||
1. Increase the amount of GPU memory by editing the /boot/config.txt file.
|
||||
Add the following line (this is for Raspberry Pi model 1B with 512 Mb of memory):
|
||||
gpu_mem_512=256
|
||||
|
||||
2. Reboot and check the amount of GPU memory:
|
||||
vcgencmd get_mem gpu
|
||||
|
||||
3. Stop X server. FGPanel runs in the console (Linux framebuffer).
|
||||
|
||||
4. Start FGPanel as usual but as ROOT or use the 'sudo' command (see README):
|
||||
sudo -- utils/fgpanel/fgpanel-egl --fg-root=/path/to/fg/data --panel=Aircraft/MyAircraft/Panels/MyPanel.xml
|
||||
|
||||
ROOT privileges are required to access the GPU of the Raspberry Pi.
|
||||
|
||||
USAGE (fgpanel)
|
||||
===================
|
||||
|
||||
1. Activate the Full KMS driver on the Raspberry Pi using the raspi-config program:
|
||||
Advanced Options -> GL Driver -> Full KMS
|
||||
|
||||
2. Reboot. The Full KMS driver should be activated.
|
||||
|
||||
3. When X server is running, start FGPanel as usual (see README):
|
||||
utils/fgpanel/fgpanel --fg-root=/path/to/fg/data --panel=Aircraft/MyAircraft/Panels/MyPanel.xml
|
||||
|
||||
FEATURES
|
||||
========
|
||||
|
||||
- Use OpenGL 2.0 instead of OpenGL 1.0 (fixed pipeline) using CMakeLists.txt.
|
||||
- Use OpenGL ES 2.0 to run on the Raspberry Pi using CMakeLists.txt.
|
||||
- Use VideoCore 4 graphics hardware acceleration (GPU) of the Raspberry Pi.
|
||||
- Run at 30 frames per second.
|
||||
- Don't use PLib anymore for the font rendering.
|
||||
30
utils/fgpanel/main.cxx
Normal file
30
utils/fgpanel/main.cxx
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Written and (c) Torsten Dreyer - Torsten(at)t3r_dot_de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
#include "FGPanelApplication.hxx"
|
||||
|
||||
int
|
||||
main (int argc, char ** argv) {
|
||||
try {
|
||||
FGPanelApplication app (argc,argv);
|
||||
app.Run ();
|
||||
return 0;
|
||||
}
|
||||
catch (...) {
|
||||
cerr << "Sorry, your program terminated." << endl;
|
||||
}
|
||||
}
|
||||
579
utils/fgpanel/panel_io.cxx
Normal file
579
utils/fgpanel/panel_io.cxx
Normal file
@@ -0,0 +1,579 @@
|
||||
// panel_io.cxx - I/O for 2D panel.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id: panel_io.cxx,v 1.3 2016/08/25 23:41:34 allaert Exp $
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <string.h> // for strcmp()
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/props/condition.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
|
||||
#include "panel_io.hxx"
|
||||
#include "ApplicationProperties.hxx"
|
||||
#include "FGGroupLayer.hxx"
|
||||
#include "FGLayeredInstrument.hxx"
|
||||
#include "FGSwitchLayer.hxx"
|
||||
#include "FGTextLayer.hxx"
|
||||
#include "FGTexturedLayer.hxx"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Read and construct a panel.
|
||||
//
|
||||
// The panel is specified as a regular property list, and each of the
|
||||
// instruments is its own, separate property list (and thus, a separate
|
||||
// XML document). The functions in this section read in the files
|
||||
// as property lists, then extract properties to set up the panel
|
||||
// itself.
|
||||
//
|
||||
// A panel contains zero or more instruments.
|
||||
//
|
||||
// An instrument contains one or more layers and zero or more actions.
|
||||
//
|
||||
// A layer contains zero or more transformations.
|
||||
//
|
||||
// Some special types of layers also contain other objects, such as
|
||||
// chunks of text or other layers.
|
||||
//
|
||||
// There are currently four types of layers:
|
||||
//
|
||||
// 1. Textured Layer (type="texture"), the default
|
||||
// 2. Text Layer (type="text")
|
||||
// 3. Switch Layer (type="switch")
|
||||
// 4. Built-in Layer (type="built-in", must also specify class)
|
||||
//
|
||||
// The only built-in layer so far is the ribbon for the magnetic compass
|
||||
// (class="compass-ribbon").
|
||||
//
|
||||
// There are three types of actions:
|
||||
//
|
||||
// 1. Adjust (type="adjust"), the default
|
||||
// 2. Swap (type="swap")
|
||||
// 3. Toggle (type="toggle")
|
||||
//
|
||||
// There are three types of transformations:
|
||||
//
|
||||
// 1. X shift (type="x-shift"), the default
|
||||
// 2. Y shift (type="y-shift")
|
||||
// 3. Rotation (type="rotation")
|
||||
//
|
||||
// Each of these may be associated with a property, so that a needle
|
||||
// will rotate with the airspeed, for example, or may have a fixed
|
||||
// floating-point value.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Read a cropped texture from the instrument's property list.
|
||||
*
|
||||
* The x1 and y1 properties give the starting position of the texture
|
||||
* (between 0.0 and 1.0), and the the x2 and y2 properties give the
|
||||
* ending position. For example, to use the bottom-left quarter of a
|
||||
* texture, x1=0.0, y1=0.0, x2=0.5, y2=0.5.
|
||||
*/
|
||||
static FGCroppedTexture_ptr
|
||||
readTexture (const SGPropertyNode *node) {
|
||||
SG_LOG(SG_COCKPIT, SG_DEBUG, "Read texture " << node->getName ());
|
||||
|
||||
return new FGCroppedTexture (node->getStringValue ("path"),
|
||||
node->getFloatValue ("x1"),
|
||||
node->getFloatValue ("y1"),
|
||||
node->getFloatValue ("x2", 1.0),
|
||||
node->getFloatValue ("y2", 1.0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a condition in the current node.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Read a condition and use it if necessary.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void
|
||||
readConditions (SGConditional *component, const SGPropertyNode *node) {
|
||||
const SGPropertyNode * conditionNode (node->getChild ("condition"));
|
||||
if (conditionNode != 0) {
|
||||
// The top level is implicitly AND
|
||||
component->setCondition (sgReadCondition (ApplicationProperties::Properties,
|
||||
conditionNode));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a transformation from the instrument's property list.
|
||||
*
|
||||
* The panel module uses the transformations to slide or spin needles,
|
||||
* knobs, and other indicators, and to place layers in the correct
|
||||
* positions. Every layer starts centered exactly on the x,y co-ordinate,
|
||||
* and many layers need to be moved or rotated simply to display the
|
||||
* instrument correctly.
|
||||
*
|
||||
* There are three types of transformations:
|
||||
*
|
||||
* "x-shift" - move the layer horizontally.
|
||||
*
|
||||
* "y-shift" - move the layer vertically.
|
||||
*
|
||||
* "rotation" - rotate the layer.
|
||||
*
|
||||
* Each transformation may have a fixed offset, and may also have
|
||||
* a floating-point property value to add to the offset. The
|
||||
* floating-point property may be clamped to a minimum and/or
|
||||
* maximum range and scaled (after clamping).
|
||||
*
|
||||
* Note that because of the way OpenGL works, transformations will
|
||||
* appear to be applied backwards.
|
||||
*/
|
||||
static FGPanelTransformation *
|
||||
readTransformation (const SGPropertyNode *node, const float w_scale, const float h_scale) {
|
||||
FGPanelTransformation *t (new FGPanelTransformation);
|
||||
|
||||
const string name (node->getName ());
|
||||
string type (node->getStringValue ("type"));
|
||||
const string propName (node->getStringValue ("property", ""));
|
||||
const SGPropertyNode *target (0);
|
||||
|
||||
if (type.empty ()) {
|
||||
SG_LOG(SG_COCKPIT, SG_INFO,
|
||||
"No type supplied for transformation " << name
|
||||
<< " assuming \"rotation\"");
|
||||
type = "rotation";
|
||||
}
|
||||
|
||||
if (!propName.empty ()) {
|
||||
target = ApplicationProperties::Properties->getNode (propName.c_str (), true);
|
||||
}
|
||||
t->node = target;
|
||||
t->min = node->getFloatValue ("min", -9999999);
|
||||
t->max = node->getFloatValue ("max", 99999999);
|
||||
t->has_mod = node->hasChild ("modulator");
|
||||
if (t->has_mod) {
|
||||
t->mod = node->getFloatValue ("modulator");
|
||||
}
|
||||
t->factor = node->getFloatValue ("scale", 1.0);
|
||||
t->offset = node->getFloatValue ("offset", 0.0);
|
||||
|
||||
// Check for an interpolation table
|
||||
const SGPropertyNode *trans_table (node->getNode ("interpolation"));
|
||||
if (trans_table != 0) {
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Found interpolation table with "
|
||||
<< trans_table->nChildren() << " children");
|
||||
t->table = new SGInterpTable();
|
||||
for (int i = 0; i < trans_table->nChildren(); i++) {
|
||||
const SGPropertyNode * node = trans_table->getChild(i);
|
||||
if (!strcmp(node->getName(), "entry")) {
|
||||
double ind = node->getDoubleValue("ind", 0.0);
|
||||
double dep = node->getDoubleValue("dep", 0.0);
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Adding interpolation entry "
|
||||
<< ind << "==>" << dep);
|
||||
t->table->addEntry(ind, dep);
|
||||
} else {
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
|
||||
<< " in interpolation");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t->table = 0;
|
||||
}
|
||||
|
||||
// Move the layer horizontally.
|
||||
if (type == "x-shift") {
|
||||
t->type = FGPanelTransformation::XSHIFT;
|
||||
// t->min *= w_scale; //removed by Martin Dressler
|
||||
// t->max *= w_scale; //removed by Martin Dressler
|
||||
t->offset *= w_scale;
|
||||
t->factor *= w_scale; //Added by Martin Dressler
|
||||
}
|
||||
|
||||
// Move the layer vertically.
|
||||
else if (type == "y-shift") {
|
||||
t->type = FGPanelTransformation::YSHIFT;
|
||||
//t->min *= h_scale; //removed
|
||||
//t->max *= h_scale; //removed
|
||||
t->offset *= h_scale;
|
||||
t->factor *= h_scale; //Added
|
||||
}
|
||||
|
||||
// Rotate the layer. The rotation
|
||||
// is in degrees, and does not need
|
||||
// to scale with the instrument size.
|
||||
else if (type == "rotation") {
|
||||
t->type = FGPanelTransformation::ROTATION;
|
||||
}
|
||||
|
||||
else {
|
||||
SG_LOG(SG_COCKPIT, SG_ALERT, "Unrecognized transformation type " << type);
|
||||
delete t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
readConditions(t, node);
|
||||
SG_LOG(SG_COCKPIT, SG_DEBUG, "Read transformation " << name);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a chunk of text from the instrument's property list.
|
||||
*
|
||||
* A text layer consists of one or more chunks of text. All chunks
|
||||
* share the same font size and color (and eventually, font), but
|
||||
* each can come from a different source. There are three types of
|
||||
* text chunks:
|
||||
*
|
||||
* "literal" - a literal text string (the default)
|
||||
*
|
||||
* "text-value" - the current value of a string property
|
||||
*
|
||||
* "number-value" - the current value of a floating-point property.
|
||||
*
|
||||
* All three may also include a printf-style format string.
|
||||
*/
|
||||
FGTextLayer::Chunk *
|
||||
readTextChunk (const SGPropertyNode *node) {
|
||||
FGTextLayer::Chunk *chunk;
|
||||
const string name (node->getStringValue ("name"));
|
||||
string type (node->getStringValue ("type"));
|
||||
const string format (node->getStringValue ("format"));
|
||||
|
||||
// Default to literal text.
|
||||
if (type.empty ()) {
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "No type provided for text chunk " << name
|
||||
<< " assuming \"literal\"");
|
||||
type = "literal";
|
||||
}
|
||||
|
||||
// A literal text string.
|
||||
if (type == "literal") {
|
||||
const string text (node->getStringValue ("text"));
|
||||
chunk = new FGTextLayer::Chunk (text, format);
|
||||
} else if (type == "text-value") {
|
||||
// The value of a string property.
|
||||
const SGPropertyNode *target
|
||||
(ApplicationProperties::Properties->getNode (node->getStringValue ("property"), true));
|
||||
chunk = new FGTextLayer::Chunk (FGTextLayer::TEXT_VALUE, target, format);
|
||||
} else if (type == "number-value") {
|
||||
// The value of a float property.
|
||||
const string propName (node->getStringValue ("property"));
|
||||
const float scale (node->getFloatValue ("scale", 1.0));
|
||||
const float offset (node->getFloatValue ("offset", 0.0));
|
||||
const bool truncation (node->getBoolValue ("truncate", false));
|
||||
const SGPropertyNode *target (ApplicationProperties::Properties->getNode (propName.c_str (), true));
|
||||
chunk = new FGTextLayer::Chunk (FGTextLayer::DOUBLE_VALUE, target,
|
||||
format, scale, offset, truncation);
|
||||
} else {
|
||||
// Unknown type.
|
||||
SG_LOG(SG_COCKPIT, SG_ALERT, "Unrecognized type " << type
|
||||
<< " for text chunk " << name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
readConditions (chunk, node);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a single layer from an instrument's property list.
|
||||
*
|
||||
* Each instrument consists of one or more layers stacked on top
|
||||
* of each other; the lower layers show through only where the upper
|
||||
* layers contain an alpha component. Each layer can be moved
|
||||
* horizontally and vertically and rotated using transformations.
|
||||
*
|
||||
* This module currently recognizes four kinds of layers:
|
||||
*
|
||||
* "texture" - a layer containing a texture (the default)
|
||||
*
|
||||
* "text" - a layer containing text
|
||||
*
|
||||
* "switch" - a layer that switches between two other layers
|
||||
* based on the current value of a boolean property.
|
||||
*
|
||||
* "built-in" - a hard-coded layer supported by C++ code in FlightGear.
|
||||
*
|
||||
* Currently, the only built-in layer class is "compass-ribbon".
|
||||
*/
|
||||
static FGInstrumentLayer *
|
||||
readLayer (const SGPropertyNode *node, const float w_scale, const float h_scale) {
|
||||
FGInstrumentLayer *layer (NULL);
|
||||
const string name (node->getStringValue ("name"));
|
||||
string type (node->getStringValue ("type"));
|
||||
int w (node->getIntValue ("w", -1));
|
||||
int h (node->getIntValue ("h", -1));
|
||||
const bool emissive (node->getBoolValue ("emissive", false));
|
||||
if (w != -1) {
|
||||
w = int (w * w_scale);
|
||||
}
|
||||
if (h != -1) {
|
||||
h = int (h * h_scale);
|
||||
}
|
||||
if (type.empty ()) {
|
||||
SG_LOG(SG_COCKPIT, SG_INFO,
|
||||
"No type supplied for layer " << name
|
||||
<< " assuming \"texture\"");
|
||||
type = "texture";
|
||||
}
|
||||
|
||||
// A textured instrument layer.
|
||||
if (type == "texture") {
|
||||
const FGCroppedTexture_ptr texture (readTexture (node->getNode ("texture")));
|
||||
layer = new FGTexturedLayer (texture, w, h);
|
||||
if (emissive) {
|
||||
FGTexturedLayer *tl = (FGTexturedLayer*) layer;
|
||||
tl->setEmissive (true);
|
||||
}
|
||||
} else if (type == "group") {
|
||||
// A group of sublayers.
|
||||
layer = new FGGroupLayer ();
|
||||
for (int i = 0; i < node->nChildren(); i++) {
|
||||
const SGPropertyNode *child = node->getChild (i);
|
||||
if (!strcmp (child->getName (), "layer")) {
|
||||
((FGGroupLayer *) layer)->addLayer (readLayer (child, w_scale, h_scale));
|
||||
}
|
||||
}
|
||||
} else if (type == "text") {
|
||||
// A textual instrument layer.
|
||||
FGTextLayer *tlayer (new FGTextLayer (w, h)); // FIXME
|
||||
|
||||
// Set the text color.
|
||||
const float red (node->getFloatValue ("color/red", 0.0));
|
||||
const float green (node->getFloatValue ("color/green", 0.0));
|
||||
const float blue (node->getFloatValue ("color/blue", 0.0));
|
||||
tlayer->setColor (red, green, blue);
|
||||
|
||||
// Set the point size.
|
||||
const float pointSize (node->getFloatValue ("point-size", 10.0) * w_scale);
|
||||
tlayer->setPointSize (pointSize);
|
||||
|
||||
// Set the font.
|
||||
const string fontName (node->getStringValue ("font", "7-Segment"));
|
||||
tlayer->setFontName (fontName);
|
||||
|
||||
const SGPropertyNode *chunk_group (node->getNode ("chunks"));
|
||||
if (chunk_group != 0) {
|
||||
const int nChunks (chunk_group->nChildren ());
|
||||
for (int i = 0; i < nChunks; i++) {
|
||||
const SGPropertyNode *node (chunk_group->getChild (i));
|
||||
if (!strcmp(node->getName (), "chunk")) {
|
||||
FGTextLayer::Chunk * const chunk (readTextChunk (node));
|
||||
if (chunk != 0) {
|
||||
tlayer->addChunk (chunk);
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
|
||||
<< " in chunks");
|
||||
}
|
||||
}
|
||||
layer = tlayer;
|
||||
}
|
||||
} else if (type == "switch") {
|
||||
// A switch instrument layer.
|
||||
layer = new FGSwitchLayer ();
|
||||
for (int i = 0; i < node->nChildren (); i++) {
|
||||
const SGPropertyNode *child (node->getChild (i));
|
||||
if (!strcmp (child->getName (), "layer")) {
|
||||
((FGGroupLayer *) layer)->addLayer (readLayer (child, w_scale, h_scale));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// An unknown type.
|
||||
SG_LOG(SG_COCKPIT, SG_ALERT, "Unrecognized layer type " << type);
|
||||
delete layer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the transformations for each layer.
|
||||
//
|
||||
const SGPropertyNode *trans_group (node->getNode ("transformations"));
|
||||
if (trans_group != 0) {
|
||||
const int nTransformations (trans_group->nChildren ());
|
||||
for (int i = 0; i < nTransformations; i++) {
|
||||
const SGPropertyNode *node (trans_group->getChild (i));
|
||||
if (!strcmp(node->getName (), "transformation")) {
|
||||
FGPanelTransformation * const t (readTransformation (node, w_scale, h_scale));
|
||||
if (t != 0) {
|
||||
layer->addTransformation (t);
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
|
||||
<< " in transformations");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readConditions (layer, node);
|
||||
SG_LOG(SG_COCKPIT, SG_DEBUG, "Read layer " << name);
|
||||
return layer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an instrument from a property list.
|
||||
*
|
||||
* The instrument consists of a preferred width and height
|
||||
* (the panel may override these), together with a list of layers
|
||||
* and a list of actions to be performed when the user clicks
|
||||
* the mouse over the instrument. All co-ordinates are relative
|
||||
* to the instrument's position, so instruments are fully relocatable;
|
||||
* likewise, co-ordinates for actions and transformations will be
|
||||
* scaled automatically if the instrument is not at its preferred size.
|
||||
*/
|
||||
static FGPanelInstrument *
|
||||
readInstrument (const SGPropertyNode *node) {
|
||||
const string name (node->getStringValue ("name"));
|
||||
const int x (node->getIntValue ("x", -1));
|
||||
const int y (node->getIntValue ("y", -1));
|
||||
const int real_w (node->getIntValue ("w", -1));
|
||||
const int real_h (node->getIntValue ("h", -1));
|
||||
int w (node->getIntValue ("w-base", -1));
|
||||
int h (node->getIntValue ("h-base", -1));
|
||||
|
||||
if (x == -1 || y == -1) {
|
||||
SG_LOG(SG_COCKPIT, SG_ALERT,
|
||||
"x and y positions must be specified and > 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
float w_scale (1.0);
|
||||
float h_scale (1.0);
|
||||
if (real_w != -1) {
|
||||
w_scale = float (real_w) / float (w);
|
||||
w = real_w;
|
||||
}
|
||||
if (real_h != -1) {
|
||||
h_scale = float (real_h) / float (h);
|
||||
h = real_h;
|
||||
}
|
||||
|
||||
SG_LOG(SG_COCKPIT, SG_DEBUG, "Reading instrument " << name);
|
||||
|
||||
FGLayeredInstrument * const instrument
|
||||
(new FGLayeredInstrument (x, y, w, h));
|
||||
|
||||
//
|
||||
// Get the layers for the instrument.
|
||||
//
|
||||
const SGPropertyNode *layer_group (node->getNode ("layers"));
|
||||
if (layer_group != 0) {
|
||||
const int nLayers (layer_group->nChildren ());
|
||||
for (int i = 0; i < nLayers; i++) {
|
||||
const SGPropertyNode *node (layer_group->getChild (i));
|
||||
if (!strcmp (node->getName (), "layer")) {
|
||||
FGInstrumentLayer * const layer (readLayer (node, w_scale, h_scale));
|
||||
if (layer != 0) {
|
||||
instrument->addLayer (layer);
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName ()
|
||||
<< " in layers");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readConditions (instrument, node);
|
||||
SG_LOG(SG_COCKPIT, SG_DEBUG, "Done reading instrument " << name);
|
||||
return instrument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the panel from a property tree.
|
||||
*/
|
||||
SGSharedPtr<FGPanel>
|
||||
FGReadablePanel::read (SGPropertyNode_ptr root) {
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Reading properties for panel " <<
|
||||
root->getStringValue ("name", "[Unnamed Panel]"));
|
||||
|
||||
FGPanel * const panel (new FGPanel (root));
|
||||
panel->setWidth (root->getIntValue ("w", 1024));
|
||||
panel->setHeight (root->getIntValue ("h", 443));
|
||||
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Size=" << panel->getWidth () << "x" << panel->getHeight ());
|
||||
|
||||
// Assign the background texture, if any, or a bogus chequerboard.
|
||||
//
|
||||
const string bgTexture (root->getStringValue ("background"));
|
||||
if (!bgTexture.empty ()) {
|
||||
panel->setBackground (new FGCroppedTexture (bgTexture));
|
||||
}
|
||||
panel->setBackgroundWidth (root->getDoubleValue( "background-width", 1.0));
|
||||
panel->setBackgroundHeight (root->getDoubleValue( "background-height", 1.0));
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Set background texture to " << bgTexture);
|
||||
|
||||
//
|
||||
// Get multibackground if any...
|
||||
//
|
||||
for (int i = 0; i < 8; i++) {
|
||||
SGPropertyNode * const mbgNode (root->getChild ("multibackground", i));
|
||||
string mbgTexture;
|
||||
if (mbgNode != NULL) {
|
||||
mbgTexture = mbgNode->getStringValue ();
|
||||
}
|
||||
if (mbgTexture.empty ()) {
|
||||
if (i == 0) {
|
||||
break; // if first texture is missing, ignore the rest
|
||||
} else {
|
||||
mbgTexture = "FOO"; // if others are missing - set default texture
|
||||
}
|
||||
}
|
||||
panel->setMultiBackground (new FGCroppedTexture (mbgTexture), i);
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Set multi-background texture" << i << " to " << mbgTexture);
|
||||
}
|
||||
//
|
||||
// Create each instrument.
|
||||
//
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Reading panel instruments" );
|
||||
const SGPropertyNode *instrument_group (root->getChild ("instruments"));
|
||||
if (instrument_group != 0) {
|
||||
const int nInstruments (instrument_group->nChildren ());
|
||||
for (int i = 0; i < nInstruments; i++) {
|
||||
const SGPropertyNode *node = instrument_group->getChild (i);
|
||||
if (!strcmp (node->getName (), "instrument")) {
|
||||
FGPanelInstrument * const instrument (readInstrument (node));
|
||||
if (instrument != 0) {
|
||||
panel->addInstrument (instrument);
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
|
||||
<< " in instruments section");
|
||||
}
|
||||
}
|
||||
}
|
||||
SG_LOG(SG_COCKPIT, SG_INFO, "Done reading panel instruments");
|
||||
|
||||
|
||||
//
|
||||
// Return the new panel.
|
||||
//
|
||||
return panel;
|
||||
}
|
||||
|
||||
// end of panel_io.cxx
|
||||
42
utils/fgpanel/panel_io.hxx
Normal file
42
utils/fgpanel/panel_io.hxx
Normal file
@@ -0,0 +1,42 @@
|
||||
// panel_io.cxx - I/O for 2D panel.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id: panel_io.hxx,v 1.2 2016/07/20 22:01:32 allaert Exp $
|
||||
|
||||
#ifndef __PANEL_IO_HXX
|
||||
#define __PANEL_IO_HXX
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "FGPanel.hxx"
|
||||
|
||||
class FGReadablePanel : public FGPanel {
|
||||
public:
|
||||
// Subsystem identification.
|
||||
static const char* staticSubsystemClassId() { return "readable-panel"; }
|
||||
|
||||
static SGSharedPtr<FGPanel> read (SGPropertyNode_ptr root);
|
||||
};
|
||||
|
||||
#endif // __PANEL_IO_HXX
|
||||
Reference in New Issue
Block a user