307 lines
10 KiB
C++
307 lines
10 KiB
C++
//
|
|
// 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 "";
|
|
}
|
|
}
|