Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file was 9061, checked in by patrick, 18 years ago

merged the single_player branche to trunk

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