00001 #include "fonttex.h"
00002
00015 #include <algorithm>
00016 #include <iostream>
00017 #include <cstdio>
00018 #include <cassert>
00019 using namespace std;
00020
00021 #include <misc/endian.h>
00022 #include <misc/image.h>
00023 #include <math/real.h>
00024
00025 GltFontTexture::GltFontTexture(void *data)
00026 {
00027 if (data)
00028 init(data);
00029 }
00030
00031 GltFontTexture::~GltFontTexture()
00032 {
00033 clear();
00034 }
00035
00036 void
00037 GltFontTexture::init(void *data)
00038 {
00039 clear();
00040
00041 if (data)
00042 {
00043 char *ptr = (char *) data;
00044
00045
00046
00047 if (strncmp(ptr,"\377txf",4))
00048 {
00049 cerr << "ERROR: Texture font not recognised" << endl;
00050 return;
00051 }
00052
00053 ptr+=4;
00054
00055
00056
00057 const uint32 code = *reinterpret_cast<uint32 *>(ptr);
00058 if (code!=0x12345678 && code!=0x78563412)
00059 {
00060 cerr << "ERROR: Texture font not recognised" << endl;
00061 return;
00062 }
00063
00064 const bool swap = code==0x78563412;
00065
00066 ptr+=4;
00067
00068 _init = true;
00069
00070
00071
00072 int32 format = *reinterpret_cast<int32 *>(ptr); ptr+=4;
00073 int32 width = *reinterpret_cast<int32 *>(ptr); ptr+=4;
00074 int32 height = *reinterpret_cast<int32 *>(ptr); ptr+=4;
00075
00076 _maxAscent = *reinterpret_cast<int32 *>(ptr); ptr+=4;
00077 _maxDescent = *reinterpret_cast<int32 *>(ptr); ptr+=4;
00078 _numGlyphs = *reinterpret_cast<int32 *>(ptr); ptr+=4;
00079
00080 if (swap)
00081 {
00082 format = flip(format);
00083 width = flip(width);
00084 height = flip(height);
00085
00086 _maxAscent = flip(_maxAscent);
00087 _maxDescent = flip(_maxDescent);
00088 _numGlyphs = flip(_numGlyphs);
00089 }
00090
00091
00092
00093 _glyph = new GlyphInfo[_numGlyphs];
00094 memcpy(_glyph,ptr,sizeof(GlyphInfo)*_numGlyphs);
00095 ptr += sizeof(GlyphInfo)*_numGlyphs;
00096
00097 uint32 i;
00098
00099 if (swap)
00100 for (i=0; i<_numGlyphs; i++)
00101 {
00102 _glyph[i].glyph = flip(_glyph[i].glyph);
00103 _glyph[i].x = flip(_glyph[i].x);
00104 _glyph[i].y = flip(_glyph[i].y);
00105 }
00106
00107
00108
00109 if (!_numGlyphs)
00110 {
00111 cerr << "ERROR: Texture font contains no glyphs" << endl;
00112 clear();
00113 return;
00114 }
00115
00116 uint16 minGlyph = _glyph[0].glyph;
00117 uint16 maxGlyph = _glyph[0].glyph;
00118
00119 _hStep = _glyph[0].advance;
00120 _vStep = _glyph[0].height;
00121
00122 for (i=1; i<_numGlyphs; i++)
00123 {
00124 minGlyph = MIN(minGlyph,_glyph[i].glyph);
00125 maxGlyph = MAX(maxGlyph,_glyph[i].glyph);
00126 _hStep = MAX(_hStep,_glyph[i].advance);
00127 _vStep = MAX(_vStep,_glyph[i].height);
00128 }
00129
00130 _minGlyph = minGlyph;
00131 _range = maxGlyph - minGlyph + 1;
00132
00133
00134
00135 _glyphVertex = new GlyphVertexInfo[_numGlyphs];
00136
00137 const GLfloat w = width;
00138 const GLfloat h = height;
00139 const GLfloat xstep = 0.5f/w;
00140 const GLfloat ystep = 0.5f/h;
00141
00142 for (i=0; i<_numGlyphs; i++)
00143 {
00144 const GlyphInfo &tgi = _glyph[i];
00145 GlyphVertexInfo &vi = _glyphVertex[i];
00146
00147
00148
00149 {
00150 const GLfloat left = tgi.x/w + xstep;
00151 const GLfloat right = (tgi.x + tgi.width)/w + xstep;
00152 const GLfloat bottom = (tgi.y + tgi.height)/h + ystep;
00153 const GLfloat top = tgi.y/h + ystep;
00154
00155 vi.t0[0] = left; vi.t0[1] = top;
00156 vi.t1[0] = right; vi.t1[1] = top;
00157 vi.t2[0] = right; vi.t2[1] = bottom;
00158 vi.t3[0] = left; vi.t3[1] = bottom;
00159 }
00160
00161
00162
00163 {
00164 const GLshort left = 0;
00165 const GLshort right = tgi.width;
00166 const GLshort bottom = _vStep - tgi.yoffset - tgi.height;
00167 const GLshort top = _vStep - tgi.yoffset;
00168
00169 vi.v0[0] = left; vi.v0[1] = top;
00170 vi.v1[0] = right; vi.v1[1] = top;
00171 vi.v2[0] = right; vi.v2[1] = bottom;
00172 vi.v3[0] = left; vi.v3[1] = bottom;
00173
00174 vi.advance = tgi.advance;
00175 vi.width = tgi.width;
00176 }
00177 }
00178
00179
00180
00181 _glyphLut = new GlyphVertexInfo *[_range];
00182 memset(_glyphLut,0,_range*sizeof(GlyphVertexInfo *));
00183
00184 for (i=0; i<_numGlyphs; i++)
00185 _glyphLut[_glyph[i].glyph-_minGlyph] = _glyphVertex + i;
00186
00187
00188 const bool mipmap = true;
00189
00190 switch (format)
00191 {
00192 case 0:
00193 {
00194 byte *buffer = new byte[width*height*2];
00195 for (i=0; i<width*height; i++)
00196 buffer[i*2] = buffer[i*2+1] = ptr[i];
00197 _texture.init(width,height,buffer,2,mipmap);
00198 delete [] buffer;
00199 }
00200 break;
00201
00202 case 1:
00203 break;
00204 }
00205 }
00206 }
00207
00208 void
00209 GltFontTexture::clear()
00210 {
00211 if (_init)
00212 {
00213 _init = false;
00214
00215 delete [] _glyph;
00216 delete [] _glyphVertex;
00217 delete [] _glyphLut;
00218
00219 _glyph = NULL;
00220 _glyphVertex = NULL;
00221 _glyphLut = NULL;
00222
00223 _texture.clear();
00224 }
00225 }
00226
00227 void
00228 GltFontTexture::compileLists(void *data)
00229 {
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 }
00248
00249 bool
00250 GltFontTexture::print(const wchar_t ch) const
00251 {
00252 assert(_init);
00253
00254 if (_init)
00255 return print(char(ch));
00256 else
00257 return false;
00258 }
00259
00260 bool
00261 GltFontTexture::print(const wstring &str) const
00262 {
00263 assert(_init);
00264
00265 if (_init)
00266 {
00267 string s;
00268 wstring2string(s,str);
00269 return print(s);
00270 }
00271 else
00272 return false;
00273 }
00274
00275 bool
00276 GltFontTexture::print(const char ch) const
00277 {
00278 assert(_init);
00279
00280 if (_init)
00281 {
00282 if (uint16(ch)<_minGlyph || uint16(ch)>=_minGlyph+_range)
00283 return false;
00284
00285 const GlyphVertexInfo *vi = _glyphLut[uint16(ch)-_minGlyph];
00286
00287 if (vi)
00288 {
00289 glPushAttrib(GL_ENABLE_BIT);
00290 _texture.set();
00291 glEnable(GL_TEXTURE_2D);
00292 glEnable(GL_BLEND);
00293 glBegin(GL_QUADS);
00294 glTexCoord2fv(vi->t0); glVertex2sv(vi->v0);
00295 glTexCoord2fv(vi->t1); glVertex2sv(vi->v1);
00296 glTexCoord2fv(vi->t2); glVertex2sv(vi->v2);
00297 glTexCoord2fv(vi->t3); glVertex2sv(vi->v3);
00298 glEnd();
00299 glTranslatef(vi->advance,0,0);
00300 glPopAttrib();
00301 return true;
00302 }
00303 }
00304
00305 return false;
00306 }
00307
00308 bool
00309 GltFontTexture::print(const string &str) const
00310 {
00311 assert(_init);
00312
00313 if (_init)
00314 {
00315 glPushMatrix();
00316 for (int i=0; i<str.size(); i++)
00317 print(str[i]);
00318 glPopMatrix();
00319 glTranslatef(0,_vStep,0);
00320 return true;
00321 }
00322 else
00323 return false;
00324 }
00325
00326 int
00327 GltFontTexture::width(const wchar_t ch) const
00328 {
00329 assert(_init);
00330
00331 if (_init)
00332 {
00333 if (uint16(ch)<_minGlyph || uint16(ch)>=_minGlyph+_range)
00334 return false;
00335
00336 const GlyphVertexInfo *vi = _glyphLut[uint16(ch)-_minGlyph];
00337 if (vi)
00338 return vi->advance;
00339 }
00340
00341 return 0;
00342 }
00343
00345
00346
00347
00348 bool
00349 GltFontTexture::makeHeader
00350 (
00351 string &header,
00352 const int width,
00353 const int height
00354 )
00355 {
00356
00357
00358 char buffer[5+11+11];
00359 sprintf(buffer,"GLTF %u %u",width,height);
00360 header = buffer;
00361 header += '\0';
00362
00363 return true;
00364 }
00365
00366
00367
00368 void *
00369 GltFontTexture::getHeader
00370 (
00371 const void * const data,
00372 int &width,
00373 int &height
00374 )
00375 {
00376 const char * const h = (const char * const) data;
00377
00378 if (h[0]=='G' && h[1]=='L' && h[2]=='T' && h[3]=='F' && h[4]==' ')
00379 {
00380 if (sscanf(h+5,"%i %i",&width,&height)==2)
00381 return (void *) (h + strlen(h) + 1);
00382 }
00383
00384 return NULL;
00385 }