Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: setClassID implemented in all files

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