Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: fixed another 'BUG' inside of the deletion of the Fonts.
Now the fonts are deleted when deleting the TextEngine.

File size: 24.6 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   for some fonts and licenses visit: =http://www.dafont.com/en/font.php=
16
17   !! IMPORTANT !! When using ttf fonts clear the license issues prior to
18   adding them to orxonox. This is really important, because we do not
19   want to offend anyone.
20*/
21
22#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_FONT
23
24#include "text_engine.h"
25
26using namespace std;
27
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31
32#include "graphics_engine.h"
33#include "resource_manager.h"
34#include "class_list.h"
35
36#include "p_node.h"
37#include "vector.h"
38#include "debug.h"
39#include "list.h"
40
41////////////
42/// TEXT ///
43////////////
44/**
45 *  creates a new Text Element
46 * @param font the Font to render this text in
47 * @param type The renderType to display this font in
48
49   this constructor is private, because the user should initialize
50   a text with the TextEngine.
51*/
52Text::Text(Font* font, TEXT_RENDER_TYPE type)
53{
54  this->setClassID(CL_TEXT, "Text");
55
56  // initialize this Text
57  this->font = font;
58  this->text = NULL;
59  this->externText = NULL;
60  this->setAlignment(TEXT_DEFAULT_ALIGNMENT);
61  this->texture = 0;
62  this->blending = TEXT_DEFAULT_BLENDING;
63  this->color = TEXT_DEFAULT_COLOR;
64  this->setType(type);
65
66  this->setText(NULL);
67}
68
69/**
70 *  deletes a Text out of memory
71 *
72 * This also ereases the text from the textList of the TextEngine
73*/
74Text::~Text()
75{
76  if (this->font != NULL)
77    ResourceManager::getInstance()->unload(this->font);
78
79  if (this->text)
80    delete[] this->text;
81}
82
83/**
84 * sets the Font of this Text to font
85 * @param font the Font (normaly from the ResourceManager) to allocate to this Text
86 */
87void Text::setFont(Font* font)
88{
89  if (this->font != NULL)
90    ResourceManager::getInstance()->unload(this->font);
91  this->font = font;
92}
93
94/**
95 * sets the Font of this Text to font from fontFile
96 * @param fontFile the File to load the Font from.
97 * @param fontSize the Size of the Font
98 */
99void Text::setFont(const char* fontFile, unsigned int fontSize)
100{
101  Font* tmpFont;
102  Text* newText;
103  Vector tmpVec;
104
105  tmpFont = (Font*)ResourceManager::getInstance()->load(fontFile, TTF, RP_GAME, &fontSize);
106  if (tmpFont == NULL)
107  {
108    PRINTF(2)("Font %s could not be loaded, probably file not found\n", fontFile);
109    this->setFont(NULL);
110  }
111  else
112    this->setFont(tmpFont);
113}
114
115/**
116 *  sets the Type of this Text
117 * @param type the type to set.
118*/
119void Text::setType(TEXT_RENDER_TYPE type)
120{
121  if (this->font != NULL && this->font->font)
122    this->type = type;
123  else
124    this->type = TEXT_RENDER_DYNAMIC;
125}
126
127/**
128 *  Sets a new Text to the font
129 * @param text the new text to set
130*/
131void Text::setText(const char* text, bool isExtern)
132{
133  if (isExtern)
134  {
135    this->externText = text;
136
137    if (unlikely(this->text != NULL))
138    {
139      delete[] this->text;
140      this->text = NULL;
141    }
142  }
143  else
144  {
145    this->externText = NULL;
146    if (this->text)
147      delete[] this->text;
148    if (text != NULL)
149    {
150      this->text = new char[strlen(text)+1];
151      strcpy(this->text, text);
152    }
153    else
154      this->text = NULL;
155  }
156
157  // setting up the Text-Width if DYNAMIC
158  if (this->type & TEXT_RENDER_DYNAMIC && this->getAlignment() != TEXT_ALIGN_LEFT && this->font != NULL)
159    {
160      Glyph** glyphArray = this->font->getGlyphArray();
161
162      int width = 0;
163      const char* tmpText = this->externText;
164      if (this->externText == NULL)
165        tmpText = this->text;
166      if (tmpText != NULL)
167      {
168        while (*tmpText != '\0')
169        {
170          if(glyphArray[*tmpText])
171          {
172            width += glyphArray[*tmpText]->width;
173          }
174          tmpText++;
175        }
176        this->width = width;
177      }
178    }
179}
180
181/**
182 *  creates a texture out of the given parameters
183
184   this has to be called every time by the user, to if changes were made.
185   this is only for TEXT_STATIC-mode
186*/
187void Text::createTexture()
188{
189  SDL_Surface* tmpSurf;
190  if (this->texture)
191    glDeleteTextures(1, &this->texture);
192  if (likely(this->font != NULL))
193  {
194    SDL_Color theColor = { (int)(this->color.x*255), (int)(this->color.y*255), (int)(this->color.z*255) };
195    tmpSurf = TTF_RenderText_Blended(this->font->font,
196                                     this->text,
197                                     theColor);
198  }
199  if (tmpSurf)
200    this->texture = loadTexture(tmpSurf, &this->texCoord);
201
202  this->width = tmpSurf->w;
203  this->height = tmpSurf->h;
204  SDL_FreeSurface(tmpSurf);
205}
206
207/**
208 *  draws the Text
209*/
210void Text::draw() const
211{
212  glPushMatrix();
213  // transform for alignment.
214  if (this->getAlignment() == TEXT_ALIGN_RIGHT)
215    glTranslatef(-this->width, 0, 0);
216  else if (this->getAlignment() == TEXT_ALIGN_CENTER || this->getAlignment() == TEXT_ALIGN_SCREEN_CENTER)
217    glTranslatef(-this->width/2, 0, 0);
218
219  // drawing this Text.
220  // setting the Blending effects
221  glColor4f(this->color.x, this->color.y, this->color.z, this->blending);
222  glEnable(GL_BLEND);
223  glEnable(GL_TEXTURE_2D);
224  glBlendFunc(GL_SRC_ALPHA, GL_ONE);
225
226  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GL_MODULATE );
227
228  if(likely(type & TEXT_RENDER_DYNAMIC && this->font != NULL))
229    {
230      Glyph** glyphArray = this->font->getGlyphArray();
231      glBindTexture(GL_TEXTURE_2D, this->font->getFastTextureID());
232      //      glEnable(GL_TEXTURE_2D);
233      glTranslatef(getAbsCoor2D().x, getAbsCoor2D().y, 0);
234//      glRotatef(this->getAbsDir2D(), 0,0,1);
235
236      const char* tmpText = this->externText;
237      if (this->externText == NULL)
238        tmpText = this->text;
239      if (likely(tmpText != NULL))
240      {
241        while (*tmpText != '\0')
242        {
243          if(glyphArray[*tmpText])
244          {
245            glCallList(glyphArray[*tmpText]->displayList);
246            glTranslatef(glyphArray[*tmpText]->width, 0, 0);
247          }
248          tmpText++;
249        }
250      }
251    }
252  else //(if type & TEXT_RENDER_STATIC)
253    {
254      glBindTexture(GL_TEXTURE_2D, this->texture);
255      glBegin(GL_QUADS);
256
257      glTexCoord2f(this->texCoord.minU, this->texCoord.minV);
258      glVertex2f(this->getAbsCoor2D().x,   this->getAbsCoor2D().);
259
260      glTexCoord2f(this->texCoord.maxU, this->texCoord.minV);
261      glVertex2f(this->getAbsCoor2D().x + this->width, this->getAbsCoor2D().);
262
263      glTexCoord2f(this->texCoord.maxU, this->texCoord.maxV);
264      glVertex2f(this->getAbsCoor2D().x + this->width, getAbsCoor2D().y + this->height);
265
266      glTexCoord2f(this->texCoord.minU, this->texCoord.maxV);
267      glVertex2f(getAbsCoor2D().x, getAbsCoor2D().y + this->height);
268
269      glEnd();
270
271    }
272  glPopMatrix();
273}
274
275/**
276 *  prints out some nice debug information about this text
277*/
278void Text::debug() const
279{
280  if (this->externText == NULL)
281    PRINT(0)("=== TEXT: %s ===\n", this->text);
282  else
283    PRINT(0)("=== TEXT: %s ===\n", this->externText);
284
285  if (this->getBindNode())
286    PRINT(0)("is bind to %s; ref=%p\n", this->getBindNode()->getName(), this->getBindNode());
287  PRINT(0)("Color: %0.2f %0.2f %0.2f\n", this->color.x, this->color.y, this->color.z);
288}
289
290
291////////////
292/// UTIL ///
293////////////
294/**
295 *  Loads a Font from an SDL_surface into a texture.
296 * @param surface The surface to make the texture of
297 * @param texCoord The texture coordinates of the 4 corners of the texture
298 * @returns the ID of the texture
299*/
300GLuint Text::loadTexture(SDL_Surface *surface, TexCoord* texCoord)
301{
302  GLuint texture;
303  int w, h;
304  SDL_Surface *image;
305  SDL_Rect area;
306  Uint32 saved_flags;
307  Uint8  saved_alpha;
308
309  /* Use the surface width and height expanded to powers of 2 */
310  w = powerOfTwo(surface->w);
311  h = powerOfTwo(surface->h);
312  if (texCoord)
313    {
314      texCoord->minU = 0.0f;
315      texCoord->minV = 0.0f;
316      texCoord->maxU = (GLfloat)surface->w / w;
317      texCoord->maxV = (GLfloat)surface->h / h;
318    }
319  image = SDL_CreateRGBSurface(SDL_SWSURFACE,
320                               w, h,
321                               32,
322#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
323                               0x000000FF,
324                               0x0000FF00,
325                               0x00FF0000,
326                               0xFF000000
327#else
328                               0xFF000000,
329                               0x00FF0000,
330                               0x0000FF00,
331                               0x000000FF
332#endif
333                               );
334  if ( image == NULL ) {
335    return 0;
336  }
337
338  /* Save the alpha blending attributes */
339  saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
340  saved_alpha = surface->format->alpha;
341  if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
342    SDL_SetAlpha(surface, 0, 0);
343  }
344
345  /* Copy the surface into the GL texture image */
346  area.x = 0;
347  area.y = 0;
348  area.w = surface->w;
349  area.h = surface->h;
350  SDL_BlitSurface(surface, &area, image, &area);
351
352  /* Restore the alpha blending attributes */
353  if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
354    SDL_SetAlpha(surface, saved_flags, saved_alpha);
355  }
356
357  /* Create an OpenGL texture for the image */
358  glGenTextures(1, &texture);
359  glBindTexture(GL_TEXTURE_2D, texture);
360  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
361  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
362  glTexImage2D(GL_TEXTURE_2D,
363               0,
364               GL_RGBA,
365               w, h,
366               0,
367               GL_RGBA,
368               GL_UNSIGNED_BYTE,
369               image->pixels);
370  SDL_FreeSurface(image); /* No longer needed */
371
372  return texture;
373}
374
375/**
376 *  Quick utility function for texture creation
377 * @param input an integer
378 * @returns the next bigger 2^n-integer than input
379*/
380int Text::powerOfTwo(int input)
381{
382  int value = 1;
383
384  while ( value < input ) {
385    value <<= 1;
386  }
387  return value;
388}
389
390
391////////////
392/// FONT ///
393////////////
394/**
395 *  constructs a Font
396 * @param fontFile the File to load the font from
397 * @param fontSize the Size of the Font in Pixels
398 * @param r Red value of the Font.
399 * @param g Green value of the Font.
400 * @param b Blue value of the Font.
401*/
402Font::Font(const char* fontFile, unsigned int fontSize)
403{
404  this->setClassID(CL_FONT, "Font");
405  // setting default values.
406  this->font = NULL;
407  this->glyphArray = NULL;
408  this->fastTextureID = 0;
409
410  this->setSize(fontSize);
411
412  this->loadFont(fontFile);
413
414  this->setStyle("c");//TTF_STYLE_NORMAL);
415
416  this->fastTextureID = this->createFastTexture();
417}
418
419/**
420 * destructs a font
421 * this releases the memory a font uses to be opened.
422*/
423Font::~Font()
424{
425  // deleting the List of all Texts
426
427  // deleting all Glyphs
428  if (this->glyphArray)
429    {
430      for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
431        delete this->glyphArray[i];
432      delete[] this->glyphArray;
433    }
434
435  // erease this font out of the memory.
436  if (likely(this->font != NULL))
437    TTF_CloseFont(this->font);
438}
439
440/**
441 *  sets The Font.
442 * @param fontFile The file containing the font.
443 * @returns true if loaded, false if something went wrong, or if a font was loaded before.
444*/
445bool Font::loadFont(const char* fontFile)
446{
447  if (!this->getName())
448    {
449      this->setName(fontFile);
450
451      this->font = TTF_OpenFont(this->getName(), this->fontSize);
452      if(!this->font)
453        {
454          PRINTF(1)("TTF_OpenFont: %s\n", TTF_GetError());
455          return false;
456        }
457      else
458          return true;
459    }
460  else
461    {
462      PRINTF(2)("Font already initialized, unable to change it now.\n");
463      return false;
464    }
465}
466
467/**
468 *  sets a specific renderStyle
469 * @param renderStyle the Style to render: a char-array containing:
470   i: italic, b: bold, u, underline
471*/
472void Font::setStyle(const char* renderStyle)
473{
474  this->renderStyle = TTF_STYLE_NORMAL;
475
476  for (int i = 0; i < strlen(renderStyle); i++)
477    if (strncmp(renderStyle+i, "b", 1) == 0)
478      this->renderStyle |= TTF_STYLE_BOLD;
479    else if (strncmp(renderStyle+i, "i", 1) == 0)
480      this->renderStyle |= TTF_STYLE_ITALIC;
481    else if (strncmp(renderStyle+i, "u", 1) == 0)
482      this->renderStyle |= TTF_STYLE_UNDERLINE;
483
484  if (likely(this->font != NULL))
485    TTF_SetFontStyle(this->font, this->renderStyle);
486  else
487    PRINTF(2)("Font was not initialized, please do so before setting the Font-Style.\n");
488}
489
490/**
491 *  Sets a new Size to the font
492 * @param fontSize The new Size in pixels.
493*/
494void Font::setSize(unsigned int fontSize)
495{
496  this->fontSize = fontSize;
497}
498
499/**
500 * @returns the maximum height of the Font, if the font was initialized, 0 otherwise
501*/
502int Font::getMaxHeight()
503{
504  if (likely (this->font != NULL))
505    return TTF_FontHeight(this->font);
506  else
507    return 0;
508}
509
510/**
511 * @returns the maximum ascent of the Font, if the font was initialized, 0 otherwise
512
513   the ascent is the pixels of the font above the baseline
514*/
515int Font::getMaxAscent()
516{
517  if (likely(this->font != NULL))
518    return TTF_FontAscent(this->font);
519  else
520    return 0;
521}
522
523/**
524 * @returns the maximum descent of the Font, if the font was initialized, 0 otherwise
525
526   the descent is the pixels of the font below the baseline
527*/
528int Font::getMaxDescent()
529{
530  if (likely(this->font != NULL))
531    return TTF_FontDescent(this->font);
532  else
533    return 0;
534}
535
536/**
537 * @param character The character to get info about.
538 * @returns a Glyph struct of a character. This Glyph is a pointer,
539   and MUST be deleted by the user..
540
541   This only works for horizontal fonts. see
542   http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html
543   for more info about vertical Fonts
544*/
545Glyph* Font::getGlyphMetrics(Uint16 character)
546{
547  Glyph* rg = new Glyph;
548  rg->character = character;
549  if (likely (this->font!= NULL))
550    TTF_GlyphMetrics(this->font, rg->character,
551                     &rg->minX, &rg->maxX,
552                     &rg->minY, &rg->maxY,
553                     &rg->advance);
554  rg->height = rg->maxY - rg->minY;
555  rg->width = rg->maxX - rg->minX;
556  rg->bearingX = (rg->advance - rg->width) / 2;
557  rg->bearingY = rg->maxY;
558  return rg;
559}
560
561GLuint Font::createFastTexture()
562{
563  /* interesting GLYPHS:
564   *  32: space
565   *  33-47: Special Characters.
566   *  48-57: 0-9
567   *  58-63: some more special chars (minor)
568   *  65-90: A-Z
569   *  97-122: a-z
570   */
571  int numberOfGlyphs = 91;
572
573  this->initGlyphs(32, numberOfGlyphs);
574  this->glyphArray[32]->width = fontSize/2; //!< @todo find out the real size of a Space
575
576  int rectSize = this->findOptimalFastTextureSize();
577
578  // setting default values. (maybe not needed afterwards)
579  SDL_Color tmpColor;  tmpColor.r = tmpColor.g = tmpColor.b = 0;
580  // Surface definition.
581  SDL_Rect tmpRect; // this represents a Rectangle for blitting.
582  SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(SDL_SWSURFACE,
583                                               rectSize, rectSize,
584                                               32,
585#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
586                                               0x000000FF,
587                                               0x0000FF00,
588                                               0x00FF0000,
589                                               0xFF000000
590#else
591                                               0xFF000000,
592                                               0x00FF0000,
593                                               0x0000FF00,
594                                               0x000000FF
595#endif
596                                               );
597  tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h;
598  SDL_SetClipRect(tmpSurf, &tmpRect);
599  int maxLineHeight = 0;
600
601  // all the interessting Glyphs
602  for (int i = 0; i <= 127; i++)
603    {
604      SDL_Surface* glyphSurf = NULL;
605      Glyph* tmpGlyph;
606
607      if (tmpGlyph = this->glyphArray[i])
608        {
609          if (tmpGlyph->height > maxLineHeight)
610            maxLineHeight = tmpGlyph->height;
611
612          if (tmpRect.x+tmpGlyph->advance > tmpSurf->w)
613            {
614              tmpRect.x = 0;
615              tmpRect.y = tmpRect.y + maxLineHeight + 1;
616              maxLineHeight = 0;
617            }
618          if (tmpRect.y + maxLineHeight > tmpSurf->h)
619            {
620              PRINTF(1)("Protection, so font cannot write over the boundraries error (this should not heappen\n");
621              break;
622            }
623          // reading in the new Glyph
624          if (likely(this->font != NULL))
625          {
626            SDL_Color white = {255, 255, 255};
627            glyphSurf = TTF_RenderGlyph_Blended(this->font, i, white);
628          }
629          if( glyphSurf != NULL )
630            {
631              SDL_SetAlpha(glyphSurf, 0, 0);
632
633              SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect);
634              TexCoord tmpTexCoord;
635              tmpTexCoord.minU = (float)tmpRect.x/(float)tmpSurf->w;
636              tmpTexCoord.maxU = (float)(tmpRect.x + tmpGlyph->advance)/(float)tmpSurf->w;
637              tmpTexCoord.minV = (float)(tmpRect.y)/(float)tmpSurf->w;
638              tmpTexCoord.maxV = (float)(tmpRect.y+tmpGlyph->height)/(float)tmpSurf->w;
639              tmpGlyph->displayList = glGenLists(1);
640
641              glNewList(tmpGlyph->displayList, GL_COMPILE);
642              glBegin(GL_QUADS);
643              glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.minV);
644              glVertex2d(0, - tmpGlyph->bearingY);
645              glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.maxV);
646              glVertex2d(0, tmpGlyph->height - tmpGlyph->bearingY);
647              glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.maxV);
648              glVertex2d(tmpGlyph->width, tmpGlyph->height - tmpGlyph->bearingY);
649              glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.minV);
650              glVertex2d(tmpGlyph->width, - tmpGlyph->bearingY);
651              glEnd();
652              glEndList();
653              SDL_FreeSurface(glyphSurf);
654
655              tmpRect.x += tmpGlyph->advance;
656
657              // Outputting Glyphs to BMP-files.
658/*
659                char outname[512];
660                if (i < 10)
661                sprintf( outname, "%s-glyph-00%d.bmp", this->getName(), i );
662                else if (i <100)
663                  sprintf( outname, "%s-glyph-0%d.bmp", this->getName(), i );
664                else
665                  sprintf( outname, "%s-glyph-%d.bmp", this->getName(), i );
666                SDL_SaveBMP(tmpSurf, outname);*/
667
668            }
669        }
670    }
671
672  GLuint texture;
673  glGenTextures(1, &texture);
674  glBindTexture(GL_TEXTURE_2D, texture);
675  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
676  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
677  glTexImage2D(GL_TEXTURE_2D,
678               0,
679               GL_RGBA,
680               tmpSurf->w, tmpSurf->h,
681               0,
682               GL_RGBA,
683               GL_UNSIGNED_BYTE,
684               tmpSurf->pixels);
685  SDL_FreeSurface(tmpSurf);
686  return texture;
687}
688
689/**
690 *  stores Glyph Metrics in an Array.
691 * @param from The Glyph to start from.
692 * @param count The number of Glyphs to start From.
693*/
694void Font::initGlyphs(Uint16 from, Uint16 count)
695{
696  /* initialize the Array, and set all its entries to NULL
697   *  only if the Glyph-array has not been initialized
698   */
699  if (!this->glyphArray)
700    {
701      this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
702      for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
703        this->glyphArray[i] = NULL;
704    }
705
706  Uint16 lastGlyph = from + count;
707
708  for (int i = from; i <= lastGlyph; i++)
709    {
710      // setting up all the Glyphs we like.
711      glyphArray[i] = getGlyphMetrics(i);
712    }
713  return;
714}
715
716/**
717 * @returns the optimal size to use as the texture size
718
719   @todo: this algorithm can be a lot more faster, althought it does
720   not really matter within the init-context, and 128 glyphs.
721
722   This function searches for a 2^n sizes texture-size, this is for
723   openGL-version < 1.2 compatibility ( and because it is realy easy like this :))
724*/
725int Font::findOptimalFastTextureSize()
726{
727  int i;
728  int x,y; // the counters
729  int maxLineHeight = this->getMaxHeight();
730  unsigned int size = 32;  // starting Value, we have to start somewhere 32 seems reasonable. (take any small enough 2^i number)
731  bool sizeOK = false;
732  Glyph* tmpGlyph;
733
734  while (!sizeOK)
735    {
736      x = 0; y = 0;
737      for (i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
738        {
739          if(tmpGlyph = this->glyphArray[i])
740            {
741              // getting the height of the highest Glyph in the Line.
742              if (tmpGlyph->height > maxLineHeight)
743                maxLineHeight = tmpGlyph->height;
744
745              if (x + tmpGlyph->advance > size)
746                {
747                  x = 0;
748                  y = y + maxLineHeight;
749                  //maxLineHeight = 0;
750                }
751              if (y + maxLineHeight + 1 > size)
752                break;
753              x += tmpGlyph->advance;
754
755            }
756        }
757      if (i == FONT_HIGHEST_KNOWN_CHAR)
758        sizeOK = true;
759      else
760        size *= 2;
761    }
762    return size;
763}
764
765
766/**
767 *  a simple function to get some interesting information about this class
768*/
769void Font::debug()
770{
771  // print the loaded font's style
772  int style;
773  if (likely(this->font != NULL))
774    style = TTF_GetFontStyle(this->font);
775  PRINTF(0)("The font style is:");
776  if(style==TTF_STYLE_NORMAL)
777    PRINTF(0)(" normal");
778  else {
779    if(style&TTF_STYLE_BOLD)
780      PRINTF(0)(" bold");
781    if(style&TTF_STYLE_ITALIC)
782      PRINTF(0)(" italic");
783    if(style&TTF_STYLE_UNDERLINE)
784      PRINTF(0)(" underline");
785  }
786  PRINTF(0)("\n");
787}
788
789
790///////////////////
791/// TEXT-ENGINE ///
792///////////////////
793/**
794 *  standard constructor
795*/
796TextEngine::TextEngine ()
797{
798   this->setClassID(CL_TEXT_ENGINE, "TextEngine");
799   this->setName("TextEngine");
800   this->enableFonts();
801}
802
803/**
804 *  the singleton reference to this class
805*/
806TextEngine* TextEngine::singletonRef = NULL;
807
808/**
809 *  standard deconstructor
810
811*/
812TextEngine::~TextEngine ()
813{
814  // delete all remaining fonts (this is done in the ResourceManager)
815  tList<BaseObject>* fontList = ClassList::getList(CL_FONT);
816  if (fontList != NULL)
817  {
818    tIterator<BaseObject>* fontIterator = fontList->getIterator();
819    Font* font = dynamic_cast<Font*>(fontIterator->firstElement());
820    while( font != NULL)
821    {
822      ResourceManager::getInstance()->unload(font, RP_GAME);
823      font = dynamic_cast<Font*>(fontIterator->nextElement());
824    }
825    delete fontIterator;
826  }
827
828  this->disableFonts();
829
830  TextEngine::singletonRef = NULL;
831}
832
833/**
834 *  function to enable TTF_Fonts
835*/
836void TextEngine::enableFonts()
837{
838  if (!TTF_WasInit())
839    {
840      if(TTF_Init()==-1)
841        PRINTF(1)("TTF_Init: %s\n", TTF_GetError());
842
843      TextEngine::checkVersion();
844    }
845  else
846    PRINTF(4)("Fonts already initialized\n");
847}
848
849/**
850 *  function to disable TTF_fonts
851*/
852void TextEngine::disableFonts()
853{
854  if (TTF_WasInit())
855    {
856      TTF_Quit();
857    }
858  else
859    PRINTF(4)("Fonts were not initialized.\n");
860}
861
862/**
863 *  creates a new Text with a certain font.
864 * @see Font::Font
865 * @see Text::Text
866*/
867Text* TextEngine::createText(const char* fontFile, unsigned int fontSize, int textType)
868{
869  Font* tmpFont;
870  Text* newText;
871  Vector tmpVec;
872
873  tmpFont = (Font*)ResourceManager::getInstance()->load(fontFile, TTF, RP_GAME, &fontSize);
874  if (!tmpFont)
875    {
876      PRINTF(2)("Font %s could not be loaded, probably file not found\n", fontFile);
877      return NULL;
878    }
879  else
880    return new Text(tmpFont, TEXT_RENDER_DYNAMIC);
881}
882
883/**
884 *  outputs some nice Debug information
885
886   @todo there should also be something outputted about Font
887*/
888void TextEngine::debug() const
889{
890  tList<BaseObject>* textList = ClassList::getList(CL_TEXT);
891  if (textList != NULL)
892  {
893    PRINT(0)("+-------------------------------+\n");
894    PRINT(0)("+ TEXT ENGINE DEBUG INFORMATION +\n");
895    PRINT(0)("+-------------------------------+\n");
896    PRINT(0)("Reference: %p; Text Counts: %d\n", this, textList->getSize());
897
898    tIterator<BaseObject>* textIterator = textList->getIterator();
899    Text* text = dynamic_cast<Text*>(textIterator->firstElement());
900    while( text != NULL)
901      {
902        text->debug();
903        text = dynamic_cast<Text*>(textIterator->nextElement());
904      }
905    delete textIterator;
906    PRINT(0)("+---------------------------TE--+\n");
907  }
908}
909
910
911/**
912 *  checks if the compiled version and the local version of SDL_ttf match.
913 * @returns true if match, false otherwise
914*/
915bool TextEngine::checkVersion()
916{
917  SDL_version compile_version;
918  SDL_version link_version;
919  TTF_VERSION(&compile_version);
920  link_version = *TTF_Linked_Version();
921
922  if (compile_version.major == link_version.major &&
923      compile_version.minor == link_version.minor &&
924      compile_version.patch == link_version.patch)
925    {
926      return true;
927    }
928  else
929    {
930      PRINTF(2)("compiled with SDL_ttf version: %d.%d.%d\n",
931                compile_version.major,
932                compile_version.minor,
933                compile_version.patch);
934
935      PRINTF(2)("running with SDL_ttf version: %d.%d.%d\n",
936                link_version.major,
937                link_version.minor,
938                link_version.patch);
939      return false;
940    }
941}
Note: See TracBrowser for help on using the repository browser.