flightgear/3rdparty/fonts/fnt.cxx

258 lines
6.8 KiB
C++
Raw Normal View History

2022-10-20 20:29:11 +08:00
/*
PLIB - A Suite of Portable Game Libraries
Copyright (C) 1998,2002 Steve Baker
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information visit http://plib.sourceforge.net
$Id: fnt.cxx 1939 2004-08-05 00:41:53Z puggles $
*/
#include "fntLocal.h"
#include <simgear/misc/sg_path.hxx>
#include <simgear/debug/logstream.hxx>
fntFont:: fntFont () {}
fntFont::~fntFont () {}
int fntTexFont::load ( const SGPath& path, GLenum mag, GLenum min )
{
if (path.extension() == "txf") {
return loadTXF ( path, mag, min ) ;
} else {
const auto ps = path.utf8Str();
fntSetError ( SG_WARN,
"fnt::load: Error - Unrecognised file format for '%s'", ps.c_str() ) ;
return FNT_FALSE ;
}
}
float fntTexFont::low_putch ( sgVec3 curpos, float pointsize,
float italic, char c )
{
unsigned int cc = (unsigned char) c ;
/* Auto case-convert if character is absent from font. */
if ( ! exists [ cc ] )
{
if ( cc >= 'A' && cc <= 'Z' )
cc = cc - 'A' + 'a' ;
else
if ( cc >= 'a' && cc <= 'z' )
cc = cc - 'a' + 'A' ;
if ( cc == ' ' )
{
curpos [ 0 ] += pointsize / 2.0f ;
return pointsize / 2.0f ;
}
}
/*
We might want to consider making some absent characters from
others (if they exist): lowercase 'l' could be made into digit '1'
or letter 'O' into digit '0'...or vice versa. We could also
make 'b', 'd', 'p' and 'q' by mirror-imaging - this would
save a little more texture memory in some fonts.
*/
if ( ! exists [ cc ] )
return 0.0f ;
glBegin ( GL_TRIANGLE_STRIP ) ;
glTexCoord2f ( t_left [cc], t_bot[cc] ) ;
glVertex3f ( curpos[0] + v_left [cc] * pointsize,
curpos[1] + v_bot [cc] * pointsize,
curpos[2] ) ;
glTexCoord2f ( t_left [cc], t_top[cc] ) ;
glVertex3f ( curpos[0] + (italic + v_left [cc]) * pointsize,
curpos[1] + v_top [cc] * pointsize,
curpos[2] ) ;
glTexCoord2f ( t_right[cc], t_bot[cc] ) ;
glVertex3f ( curpos[0] + v_right[cc] * pointsize,
curpos[1] + v_bot [cc] * pointsize,
curpos[2] ) ;
glTexCoord2f ( t_right[cc], t_top[cc] ) ;
glVertex3f ( curpos[0] + (italic + v_right[cc]) * pointsize,
curpos[1] + v_top [cc] * pointsize,
curpos[2] ) ;
glEnd () ;
float ww = ( gap + ( fixed_pitch ? width : widths[cc] ) ) * pointsize ;
curpos[0] += ww ;
return ww ;
}
void fntTexFont::setGlyph ( char c, float wid,
float tex_left, float tex_right,
float tex_bot , float tex_top ,
float vtx_left, float vtx_right,
float vtx_bot , float vtx_top )
{
unsigned int cc = (unsigned char) c ;
exists[cc] = FNT_TRUE ;
widths[cc] = wid;
t_left[cc] = tex_left ; t_right[cc] = tex_right ;
t_bot [cc] = tex_bot ; t_top [cc] = tex_top ;
v_left[cc] = vtx_left ; v_right[cc] = vtx_right ;
v_bot [cc] = vtx_bot ; v_top [cc] = vtx_top ;
}
int fntTexFont::getGlyph ( char c, float* wid,
float *tex_left, float *tex_right,
float *tex_bot , float *tex_top ,
float *vtx_left, float *vtx_right,
float *vtx_bot , float *vtx_top )
{
unsigned int cc = (unsigned char) c ;
if ( ! exists[cc] ) return FNT_FALSE ;
if ( wid != NULL ) *wid = widths [cc] ;
if ( tex_left != NULL ) *tex_left = t_left [cc] ;
if ( tex_right != NULL ) *tex_right = t_right[cc] ;
if ( tex_bot != NULL ) *tex_bot = t_bot [cc] ;
if ( tex_top != NULL ) *tex_top = t_top [cc] ;
if ( vtx_left != NULL ) *vtx_left = v_left [cc] ;
if ( vtx_right != NULL ) *vtx_right = v_right[cc] ;
if ( vtx_bot != NULL ) *vtx_bot = v_bot [cc] ;
if ( vtx_top != NULL ) *vtx_top = v_top [cc] ;
return FNT_TRUE ;
}
void fntTexFont::getBBox ( const char *s,
float pointsize, float italic,
float *left, float *right,
float *bot , float *top )
{
float h_pos = 0.0f ;
float v_pos = 0.0f ;
float l, r, b, t ;
l = r = b = t = 0.0f ;
while ( *s != '\0' )
{
if ( *s == '\n' )
{
h_pos = 0.0f ;
v_pos -= 1.333f ;
s++ ;
continue ;
}
unsigned int cc = (unsigned char) *(s++) ;
if ( ! exists [ cc ] )
{
if ( cc >= 'A' && cc <= 'Z' )
cc = cc - 'A' + 'a' ;
else
if ( cc >= 'a' && cc <= 'z' )
cc = cc - 'a' + 'A' ;
if ( cc == ' ' )
{
r += 0.5f ;
h_pos += 0.5f ;
continue ;
}
}
if ( ! exists [ cc ] )
continue ;
if ( italic >= 0 )
{
if ( l > h_pos + v_left [cc] ) l = h_pos + v_left [cc] ;
if ( r < gap + h_pos + v_right[cc]+italic ) r = gap + h_pos + v_right[cc] + italic ;
}
else
{
if ( l > h_pos + v_left [cc]+italic ) l = h_pos + v_left [cc] + italic ;
if ( r < gap + h_pos + v_right[cc] ) r = gap + h_pos + v_right[cc] ;
}
if ( b > v_pos + v_bot [cc] ) b = v_pos + v_bot [cc] ;
if ( t < v_pos + v_top [cc] ) t = v_pos + v_top [cc] ;
h_pos += gap + ( fixed_pitch ? width : widths[cc] ) ;
}
if ( left != NULL ) *left = l * pointsize ;
if ( right != NULL ) *right = r * pointsize ;
if ( top != NULL ) *top = t * pointsize ;
if ( bot != NULL ) *bot = b * pointsize ;
}
void fntTexFont::puts ( sgVec3 curpos, float pointsize, float italic, const char *s )
{
SGfloat origx = curpos[0] ;
if ( ! bound )
bind_texture () ;
while ( *s != '\0' )
{
if (*s == '\n')
{
curpos[0] = origx ;
curpos[1] -= pointsize ;
}
else
low_putch ( curpos, pointsize, italic, *s ) ;
s++ ;
}
}
void fntInit ()
{
/* Empty right now */
}
void fntSetError(int level, const char* format, ...)
{
const int bufferLength = 2048;
char buffer[2048];
va_list args;
va_start (args, format);
vsnprintf(buffer,bufferLength,format, args);
va_end (args);
SG_LOG(SG_GUI, static_cast<sgDebugPriority>(level), buffer);
}