Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: Text is now too a Element2D, and it does not need the TextEngine anymore to draw it.
optimizing…

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