Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: font renders nicer, but not perfect

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