Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/graphics/text_engine/font_data.cc @ 8764

Last change on this file since 8764 was 8764, checked in by bensch, 19 years ago

load-implementation of font in font-data

File size: 11.9 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14*/
15
16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_IMPORTER
17
18#include "font_data.h"
19
20#include "debug.h"
21#include "compiler.h"
22
23#include "texture.h"
24
25
26/**
27 * @brief creates a new Font Data.
28 */
29FontData::FontData()
30  : texData(new TextureData)
31{
32  printf("CREATE FONT_DATA\n");
33  this->fontTTF = NULL;
34  this->glyphArray = NULL;
35  this->renderStyle = TTF_STYLE_NORMAL;
36  this->renderSize = FONT_DEFAULT_RENDER_SIZE;
37}
38
39
40/**
41 * @brief Destructor of a Font
42 *
43 *  Frees Data, and deletes the fonts from GL
44 */
45FontData::~FontData()
46{
47  // deleting all Glyphs
48  if (this->glyphArray != NULL)
49  {
50    for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
51    {
52      if (this->glyphArray[i] != NULL)
53        delete this->glyphArray[i];
54    }
55    delete[] this->glyphArray;
56  }
57
58  //! @todo check if we really do not need to delete the fastTextureID here.
59  //   if (this->fastTextureID != 0)
60  //     if(glIsTexture(this->fastTextureID))
61  //       glDeleteTextures(1, &this->fastTextureID);
62
63  // erease this font out of the memory.
64  if (likely(this->fontTTF != NULL))
65    TTF_CloseFont(this->fontTTF);
66}
67
68/**
69 * @returns the maximum height of the Font, if the font was initialized, 0 otherwise
70 */
71int FontData::getMaxHeight() const
72{
73  if (likely (this->fontTTF != NULL))
74    return TTF_FontHeight(this->fontTTF);
75  else
76    return 1;
77}
78
79/**
80 * @returns the maximum ascent of the Font, if the font was initialized, 0 otherwise
81 *
82 * the ascent is the pixels of the font above the baseline
83 */
84int FontData::getMaxAscent() const
85{
86  if (likely(this->fontTTF != NULL))
87    return TTF_FontAscent(this->fontTTF);
88  else
89    return 0;
90}
91
92/**
93 * @returns the maximum descent of the Font, if the font was initialized, 0 otherwise
94 *
95 * the descent is the pixels of the font below the baseline
96 */
97int FontData::getMaxDescent() const
98{
99  if (likely(this->fontTTF != NULL))
100    return TTF_FontDescent(this->fontTTF);
101  else
102    return 0;
103}
104
105
106
107/**
108 * @brief sets The Font.
109 * @param fontFile The file containing the font.
110 * @returns true if loaded, false if something went wrong, or if a font was loaded before.
111 */
112bool FontData::loadFontFromTTF(const std::string& fontFile, unsigned int renderSize)
113{
114  //this->setName(fontFile);
115  this->fontTTF = TTF_OpenFont(fontFile.c_str(), renderSize);
116  this->renderSize = renderSize;
117
118  if(this->fontTTF != NULL)
119  {
120    this->setStyle("c");
121    if (this->createFastTexture())
122      return true;
123    else
124    {
125      return false;
126    }
127  }
128  else
129  {
130    PRINTF(1)("TTF_OpenFont: %s\n", TTF_GetError());
131    return false;
132  }
133
134}
135
136
137
138/**
139 * @brief loads a font From an XPM-array.
140 * @param xpmArray the array of the XPM to load the font from.
141 */
142bool FontData::loadFontFromSDL_Surface(SDL_Surface* surface)
143{
144  if(surface == NULL)
145    return false;
146
147
148  bool hasAlpha;
149  SDL_Surface* newSurf = Texture::prepareSurface(surface, hasAlpha);
150  if (newSurf != NULL)
151  {
152    this->texData->setSurface(newSurf);
153    this->texData->setAlpha(hasAlpha);
154    this->texData->setTexture(Texture::loadTexToGL(newSurf));
155  }
156  else
157  {
158    return false;
159  }
160
161  // initializing the Glyphs.
162  if (this->glyphArray == NULL)
163  {
164    float cx,cy;
165    Glyph* tmpGlyph;
166    this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
167    for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
168    {
169      tmpGlyph = this->glyphArray[i] = new Glyph;
170      cx=(float)(i%16)/16.0f;                  // X Position Of Current Character
171      cy=(float)(i/16)/16.0f;                  // Y Position Of Current Character
172
173      tmpGlyph->texCoord[0] = cx;
174      tmpGlyph->texCoord[1] = cx+0.0625f;
175      tmpGlyph->texCoord[2] = cy;
176      tmpGlyph->texCoord[3] = cy+0.0625f;
177      tmpGlyph->minX = 0.0f;
178      tmpGlyph->maxX = 1.0f;
179      tmpGlyph->minY = 0.0f;
180      tmpGlyph->maxY = 1.0f;
181      tmpGlyph->width = 1.0f;
182      tmpGlyph->advance = 1.0f;
183      tmpGlyph->bearingX = 0.0f;
184      tmpGlyph->bearingY = 0.0f;
185      tmpGlyph->height = 1.0f;
186    }
187  }
188  return true;
189}
190
191/**
192 * @brief sets a specific data->renderStyle
193 * @param data->renderStyle the Style to render: a string (char-array) containing:
194 *   i: italic, b: bold, u, underline
195 */
196void FontData::setStyle(const std::string& renderStyle)
197{
198  this->renderStyle = TTF_STYLE_NORMAL;
199
200  for (unsigned int i = 0; i < renderStyle.size(); i++)
201  {
202    if (renderStyle[i] == 'b')
203      this->renderStyle |= TTF_STYLE_BOLD;
204    else if (renderStyle[i] == 'i')
205      this->renderStyle |= TTF_STYLE_ITALIC;
206    else if (renderStyle[i] == 'u')
207      this->renderStyle |= TTF_STYLE_UNDERLINE;
208  }
209  if (likely(this->fontTTF != NULL))
210    TTF_SetFontStyle(this->fontTTF, this->renderStyle);
211  //  else
212  //    PRINTF(2)("Font was not initialized, please do so before setting the Font-Style.\n");
213}
214
215
216
217/**
218 * @param glyph: The Glyph to set the Parameters to.
219 * @param character: The character to get info about.
220 * @returns a Glyph struct of a character. This Glyph is a pointer,
221 * and MUST be deleted by the user..
222 *
223 * This only works for horizontal fonts. see
224 * http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html
225 * for more info about vertical Fonts
226 */
227bool FontData::getGlyphMetrics(Glyph* glyph, Uint16 character)
228{
229  glyph->character = character;
230  if (likely (this->fontTTF!= NULL))
231  {
232    int miX, maX, miY, maY, adv;
233    if (TTF_GlyphMetrics(this->fontTTF, glyph->character,
234        &miX, &maX,
235        &miY, &maY,
236        &adv) == -1)
237      return false;
238    glyph->minX = (float)miX / (float)this->renderSize;
239    glyph->maxX = (float)maX / (float)this->renderSize;
240    glyph->minY = (float)miY / (float)this->renderSize;
241    glyph->maxY = (float)maY / (float)this->renderSize;
242    glyph->advance = (float)adv / (float)this->renderSize;
243
244    // Calculate the Rest.
245    glyph->height = glyph->maxY - glyph->minY;
246    glyph->width = glyph->maxX - glyph->minX;
247    glyph->bearingX = (glyph->advance - glyph->width) / 2;
248    glyph->bearingY = glyph->maxY;
249
250    //printf("%c:: %d %d %d %d %d\n", character, miX, maX, miY, maY, adv);
251
252    return true;
253  }
254  return false;
255}
256
257
258/**
259 * @brief creates a Fast-Texture of this Font
260 */
261bool FontData::createFastTexture()
262{
263  /* interesting GLYPHS:
264  *  32: space
265  *  33-47: Special Characters.
266  *  48-57: 0-9
267  *  58-63: some more special chars (minor)
268  *  65-90: A-Z
269  *  97-122: a-z
270  */
271  int numberOfGlyphs = 91;
272
273  this->initGlyphs(32, numberOfGlyphs);
274  //  this->glyphArray[32]->width = .5f; //!< @todo find out the real size of a Space
275
276  int rectSize = this->findOptimalFastTextureSize();
277
278  // setting default values. (maybe not needed afterwards)
279  SDL_Color tmpColor;  tmpColor.r = tmpColor.g = tmpColor.b = 0;
280  // Surface definition.
281  SDL_Rect tmpRect; // this represents a Rectangle for blitting.
282  SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(SDL_HWSURFACE,
283                                               rectSize, rectSize,
284                                               32,
285#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
286                          0x000000FF,
287                          0x0000FF00,
288                          0x00FF0000,
289                          0xFF000000
290#else
291                              0xFF000000,
292                          0x00FF0000,
293                          0x0000FF00,
294                          0x000000FF
295#endif
296                                              );
297  tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h;
298  SDL_SetClipRect(tmpSurf, &tmpRect);
299  int maxLineHeight = this->getMaxHeight();
300
301  // all the interessting Glyphs
302  for (int i = 0; i < 128; i++)
303  {
304    SDL_Surface* glyphSurf = NULL;
305    Glyph* tmpGlyph;
306
307    if (tmpGlyph = this->glyphArray[i])
308    {
309      if (tmpGlyph->height*this->renderSize > maxLineHeight)
310        maxLineHeight = (int)(tmpGlyph->height*this->renderSize);
311
312      if (tmpRect.x+tmpGlyph->advance*this->renderSize > tmpSurf->w)
313      {
314        tmpRect.x = 0;
315        tmpRect.y = tmpRect.y + maxLineHeight;
316      }
317      if (tmpRect.y + maxLineHeight > tmpSurf->h)
318      {
319        PRINTF(1)("Protection, so font cannot write over the boundraries (!!this should not heappen!!)\n");
320        break;
321      }
322      // reading in the new Glyph
323      if (likely(this->fontTTF != NULL))
324      {
325        SDL_Color white = {255, 255, 255};
326        glyphSurf = TTF_RenderGlyph_Blended(this->fontTTF, i, white);
327      }
328      if( glyphSurf != NULL )
329      {
330        SDL_SetAlpha(glyphSurf, 0, 0);
331        int tmpY = tmpRect.y;
332        tmpRect.y += this->getMaxAscent()-(int)((float)tmpGlyph->bearingY*this->renderSize);
333        SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect);
334        tmpRect.y = tmpY;
335
336        tmpGlyph->texCoord[0] = (float)((float)tmpRect.x )/(float)tmpSurf->w;
337        tmpGlyph->texCoord[1] = (float)((float)tmpRect.x + tmpGlyph->width*(float)this->renderSize)/(float)tmpSurf->w;
338        tmpGlyph->texCoord[2] = (float)(tmpRect.y)/(float)tmpSurf->w;
339        tmpGlyph->texCoord[3] = (float)((float)tmpRect.y+(float)this->getMaxHeight())/(float)tmpSurf->w;
340        SDL_FreeSurface(glyphSurf);
341        tmpRect.x += (int)(tmpGlyph->width * this->renderSize) + 1;
342      }
343    }
344  }
345  // outputting the GLYPH-table
346//       char outName[1024];
347//       sprintf( outName, "%s-glyphs.bmp", this->getName());
348//       SDL_SaveBMP(tmpSurf, outName);
349  this->texData->setAlpha(true);
350  if (this->texData->setSurface(tmpSurf))
351    this->texData->setTexture(Texture::loadTexToGL(tmpSurf));
352  return true;
353}
354
355/**
356 * @brief stores Glyph Metrics in an Array.
357 * @param from The Glyph to start from.
358 * @param count The number of Glyphs to start From.
359 */
360void FontData::initGlyphs(Uint16 from, Uint16 count)
361{
362  /* initialize the Array, and set all its entries to NULL
363  *  only if the Glyph-array has not been initialized
364  */
365  if (!this->glyphArray)
366  {
367    this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
368    for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
369      this->glyphArray[i] = NULL;
370  }
371
372  Uint16 lastGlyph = from + count;
373
374  for (int i = from; i <= lastGlyph; i++)
375  {
376    // setting up all the Glyphs we like.
377    Glyph* newGlyph = new Glyph;
378    if (getGlyphMetrics(newGlyph, i))
379      this->glyphArray[i] = newGlyph;
380    else
381    {
382      delete newGlyph;
383      this->glyphArray[i] = NULL;
384    }
385  }
386  return;
387}
388
389/**
390 * @returns the optimal size to use as the texture size
391 *
392 * @todo: this algorithm can be a lot faster, althought it does
393 * not really matter within the init-context, and 128 glyphs.
394 *
395 * This function searches for a 2^n sizes texture-size, this is for
396 * openGL-version < 1.2 compatibility ( and because it is realy easy like this :))
397 */
398int FontData::findOptimalFastTextureSize()
399{
400  if (this->glyphArray == NULL)
401    return 0;
402
403  unsigned int i;
404  unsigned int x,y; // the counters
405  int maxLineHeight = this->getMaxHeight();
406  unsigned int size = 32;  // starting Value, we have to start somewhere 32 seems reasonable. (take any small enough 2^i number)
407  bool sizeOK = false;
408  Glyph* tmpGlyph;
409
410  while (!sizeOK)
411  {
412    x = 0; y = 0;
413    for (i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
414    {
415      if((tmpGlyph = this->glyphArray[i]) != NULL)
416      {
417        // getting the height of the highest Glyph in the Line.
418        if (tmpGlyph->height*this->renderSize > maxLineHeight)
419          maxLineHeight = (int)(tmpGlyph->height*this->renderSize);
420
421        if (x + tmpGlyph->advance*this->renderSize > size)
422        {
423          x = 0;
424          y = y + maxLineHeight;
425          //maxLineHeight = 0;
426        }
427        if (y + maxLineHeight + 1 > size)
428          break;
429        x += (int)(tmpGlyph->advance*this->renderSize)+1;
430
431      }
432    }
433    if (i >= FONT_HIGHEST_KNOWN_CHAR-1 || size > 8192)
434      sizeOK = true;
435    else
436      size *= 2;
437  }
438  return size;
439}
440
Note: See TracBrowser for help on using the repository browser.