Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: hups

File size: 23.7 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  // 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->fontFile = new char[strlen(fontFile)+1];
444      strcpy(this->fontFile, fontFile);
445     
446      this->font = TTF_OpenFont(this->fontFile, this->fontSize);
447      if(!this->font)
448        {
449          PRINTF(1)("TTF_OpenFont: %s\n", TTF_GetError());
450          return false;
451        }
452      else
453          return true;
454    }
455  else
456    {
457      PRINTF(2)("Font already initialized, unable to change it now.\n");
458      return false;
459    }
460}
461
462/**
463   \brief sets a specific renderStyle
464   \param renderStyle the Style to render: a char-array containing:
465   i: italic, b: bold, u, underline
466*/
467void Font::setStyle(const char* renderStyle)
468{
469  this->renderStyle = TTF_STYLE_NORMAL;
470 
471  for (int i = 0; i < strlen(renderStyle); i++)
472    if (strncmp(renderStyle+i, "b", 1) == 0) 
473      this->renderStyle |= TTF_STYLE_BOLD;
474    else if (strncmp(renderStyle+i, "i", 1) == 0)
475      this->renderStyle |= TTF_STYLE_ITALIC;
476    else if (strncmp(renderStyle+i, "u", 1) == 0) 
477      this->renderStyle |= TTF_STYLE_UNDERLINE;
478
479  if (likely(this->font != NULL))
480    TTF_SetFontStyle(this->font, this->renderStyle);
481  else
482    PRINTF(2)("Font was not initialized, please do so before setting the Font-Style.\n");
483}
484
485/**
486   \brief Sets a new Size to the font
487   \param fontSize The new Size in pixels.
488*/
489void Font::setSize(unsigned int fontSize)
490{
491  this->fontSize = fontSize;
492}
493
494/**
495   \brief sets a new color to the font
496   \param r Red
497   \param g Green
498   \param b Blue
499*/
500void Font::setFastColor(Uint8 r, Uint8 g, Uint8 b)
501{
502  this->fastColor.r = r;
503  this->fastColor.g = g;
504  this->fastColor.b = b;
505}
506
507/**
508   \returns the maximum height of the Font, if the font was initialized, 0 otherwise
509*/
510int Font::getMaxHeight(void)
511{
512  if (likely (this->font != NULL))
513    return TTF_FontHeight(this->font);
514  else
515    return 0;
516}
517
518/**
519   \returns the maximum ascent of the Font, if the font was initialized, 0 otherwise
520
521   the ascent is the pixels of the font above the baseline
522*/
523int Font::getMaxAscent(void)
524{
525  if (likely(this->font != NULL))
526    return TTF_FontAscent(this->font);
527  else
528    return 0;
529}
530
531/**
532   \returns the maximum descent of the Font, if the font was initialized, 0 otherwise
533
534   the descent is the pixels of the font below the baseline
535*/
536int Font::getMaxDescent(void)
537{
538  if (likely(this->font != NULL))
539    return TTF_FontDescent(this->font);
540  else
541    return 0;
542}
543
544/**
545   \param character The character to get info about.
546   \returns a Glyph struct of a character. This Glyph is a pointer,
547   and MUST be deleted by the user..
548
549   This only works for horizontal fonts. see
550   http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html
551   for more info about vertical Fonts
552*/
553Glyph* Font::getGlyphMetrics(Uint16 character)
554{
555  Glyph* rg = new Glyph;
556  rg->character = character;
557  if (likely (this->font!= NULL))
558    TTF_GlyphMetrics(this->font, rg->character,
559                     &rg->minX, &rg->maxX,
560                     &rg->minY, &rg->maxY,
561                     &rg->advance);
562  rg->height = rg->maxY - rg->minY;
563  rg->width = rg->maxX - rg->minX;
564  rg->bearingX = (rg->advance - rg->width) / 2;
565  rg->bearingY = rg->maxY;
566  return rg;
567}
568
569GLuint Font::createFastTexture(void)
570{
571  /* interesting GLYPHS:
572   *  32: space
573   *  33-47: Special Characters.
574   *  48-57: 0-9
575   *  58-63: some more special chars (minor)
576   *  65-90: A-Z
577   *  97-122: a-z
578   */
579  int numberOfGlyphs = 91;
580
581  this->initGlyphs(32, numberOfGlyphs);
582  this->glyphArray[32]->width = fontSize/3; //!< \todo find out the real size of a Space
583
584  int rectSize = this->findOptimalFastTextureSize();
585
586  // setting default values. (maybe not needed afterwards)
587  SDL_Color tmpColor;  tmpColor.r = tmpColor.g = tmpColor.b = 0;
588  // Surface definition.
589  SDL_Rect tmpRect; // this represents a Rectangle for blitting.
590  SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(SDL_SWSURFACE,
591                                               rectSize, rectSize,
592                                               32,
593#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
594                                               0x000000FF, 
595                                               0x0000FF00, 
596                                               0x00FF0000, 
597                                               0xFF000000
598#else
599                                               0xFF000000,
600                                               0x00FF0000, 
601                                               0x0000FF00, 
602                                               0x000000FF
603#endif
604                                               );
605  tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h;
606  SDL_SetClipRect(tmpSurf, &tmpRect);
607  int maxLineHeight = 0;
608
609  // all the interessting Glyphs
610  for (int i = 0; i <= 127; i++)
611    {
612      SDL_Surface* glyphSurf = NULL;
613      Glyph* tmpGlyph;
614
615      if (tmpGlyph = this->glyphArray[i])
616        {
617          if (tmpGlyph->height > maxLineHeight)
618            maxLineHeight = tmpGlyph->height;
619         
620          if (tmpRect.x+tmpGlyph->width > tmpSurf->w)
621            {
622              tmpRect.x = 0;
623              tmpRect.y = tmpRect.y + maxLineHeight + 1;
624              maxLineHeight = 0;
625            }
626          if (tmpRect.y + maxLineHeight > tmpSurf->h)
627            {
628              PRINTF(1)("Protection, so font cannot write over the boundraries error (this should not heappen\n");
629              break;
630            }
631          // reading in the new Glyph
632          if (likely(this->font != NULL))
633            glyphSurf = TTF_RenderGlyph_Blended(this->font, i, this->fastColor);
634          if( glyphSurf != NULL )
635            {
636
637              SDL_SetAlpha(glyphSurf, 0, 0);
638
639              SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect);
640              TexCoord tmpTexCoord;
641              tmpTexCoord.minU = (float)tmpRect.x/(float)tmpSurf->w;
642              tmpTexCoord.maxU = (float)(tmpRect.x+tmpGlyph->width)/(float)tmpSurf->w;
643              tmpTexCoord.minV = (float)tmpRect.y/(float)tmpSurf->w;
644              tmpTexCoord.maxV = (float)(tmpRect.y+tmpGlyph->height)/(float)tmpSurf->w;
645              tmpGlyph->displayList = glGenLists(1);
646
647              glNewList(tmpGlyph->displayList, GL_COMPILE);
648              glBegin(GL_QUADS);
649              glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.minV);
650              glVertex2d(0, 0);
651              glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.maxV);
652              glVertex2d(0, tmpGlyph->height);
653              glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.maxV);
654              glVertex2d(tmpGlyph->width, tmpGlyph->height);
655              glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.minV);
656              glVertex2d(tmpGlyph->width, 0);
657              glEnd();
658              glEndList();
659              SDL_FreeSurface(glyphSurf);
660
661              tmpRect.x += tmpGlyph->width + 1;
662
663              // Outputting Glyphs to BMP-files.
664              /*
665                char outname[64];
666                if (i < 10)
667                sprintf( outname, "glyph-00%d.bmp", i );
668                else if (i <100)
669                sprintf( outname, "glyph-0%d.bmp", i );
670                else
671                sprintf( outname, "glyph-%d.bmp", i );
672                SDL_SaveBMP(tmpSurf, outname);
673              */
674            }
675        }
676    }
677
678  GLuint texture;
679  glGenTextures(1, &texture);
680  glBindTexture(GL_TEXTURE_2D, texture);
681  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
682  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
683  glTexImage2D(GL_TEXTURE_2D,
684               0,
685               GL_RGBA,
686               tmpSurf->w, tmpSurf->h,
687               0,
688               GL_RGBA,
689               GL_UNSIGNED_BYTE,
690               tmpSurf->pixels);
691  SDL_FreeSurface(tmpSurf);
692  return texture;
693}
694
695/**
696   \brief stores Glyph Metrics in an Array.
697   \param from The Glyph to start from.
698   \param count The number of Glyphs to start From.
699*/
700void Font::initGlyphs(Uint16 from, Uint16 count)
701{
702  /* initialize the Array, and set all its entries to NULL
703   *  only if the Glyph-array has not been initialized
704   */
705  if (!this->glyphArray)
706    {
707      this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
708      for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
709        this->glyphArray[i] = NULL;
710    }
711 
712  Uint16 lastGlyph = from + count;
713 
714  for (int i = from; i <= lastGlyph; i++)
715    {
716      // setting up all the Glyphs we like.
717      glyphArray[i] = getGlyphMetrics(i);
718    }
719  return;
720}
721
722/**
723   \returns the optimal size to use as the texture size
724
725   \todo: this algorithm can be a lot more faster, althought it does
726   not really matter within the init-context, and 128 glyphs.
727
728   This function searches for a 2^n sizes texture-size, this is for
729   openGL-version < 1.2 compatibility ( and because it is realy easy like this :))
730*/
731int Font::findOptimalFastTextureSize(void)
732{
733  int i;
734  int x,y; // the counters
735  int maxLineHeight;
736  int size = 32;      // starting Value, we have to start somewhere 32 seems reasonable.
737  bool sizeOK = false;
738  Glyph* tmpGlyph;
739
740  while (!sizeOK)
741    {
742      x = 0; y = 0;
743      maxLineHeight = 0;
744      for (i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
745        {
746          if(tmpGlyph = this->glyphArray[i])
747            {
748              // getting the height of the highest Glyph in the Line.
749              if (tmpGlyph->height > maxLineHeight)
750                maxLineHeight = tmpGlyph->height;
751
752              if (x + tmpGlyph->width > size)
753                {
754                  x = 0;
755                  y = y + maxLineHeight;
756                  maxLineHeight = 0;
757                }
758              if (y + maxLineHeight + 1 > size)
759                break;
760              x += tmpGlyph->width + 1;
761
762            }
763        }
764      if (i == FONT_HIGHEST_KNOWN_CHAR)
765        sizeOK = true;
766      else
767        size *= 2;
768    }
769  return size;
770}
771
772
773/**
774   \brief a simple function to get some interesting information about this class
775*/
776void Font::debug(void)
777{
778  // print the loaded font's style
779  int style;
780  if (likely(this->font != NULL))
781    style = TTF_GetFontStyle(this->font);
782  PRINTF(0)("The font style is:");
783  if(style==TTF_STYLE_NORMAL)
784    PRINTF(0)(" normal");
785  else {
786    if(style&TTF_STYLE_BOLD)
787      PRINTF(0)(" bold");
788    if(style&TTF_STYLE_ITALIC)
789      PRINTF(0)(" italic");
790    if(style&TTF_STYLE_UNDERLINE)
791      PRINTF(0)(" underline");
792  }
793  PRINTF(0)("\n");
794}
795
796
797///////////////////
798/// TEXT-ENGINE ///
799///////////////////
800/**
801   \brief standard constructor
802*/
803TextEngine::TextEngine () 
804{
805   this->setClassID(CL_TEXT_ENGINE, "TextEngine");
806   this->enableFonts();
807
808   this->textList = new tList<Text>;
809}
810
811/**
812   \brief the singleton reference to this class
813*/
814TextEngine* TextEngine::singletonRef = NULL;
815
816/**
817   \brief standard deconstructor
818
819*/
820TextEngine::~TextEngine () 
821{
822  this->disableFonts();
823 
824  delete this->textList;
825
826  TextEngine::singletonRef = NULL;
827}
828
829/**
830   \brief function to enable TTF_Fonts
831*/
832void TextEngine::enableFonts(void)
833{
834  if (!TTF_WasInit())
835    {
836      if(TTF_Init()==-1)
837        PRINTF(1)("TTF_Init: %s\n", TTF_GetError());
838
839      TextEngine::checkVersion();
840    }
841  else
842    PRINTF(4)("Fonts already initialized\n");
843}
844
845/**
846   \brief function to disable TTF_fonts
847*/
848void TextEngine::disableFonts(void)
849{
850  if (TTF_WasInit())
851    {
852      TTF_Quit();
853    }
854  else
855    PRINTF(4)("Fonts were not initialized.\n");
856}
857
858/**
859   \brief creates a new Text with a certain font.
860   \see Font::Font
861   \see Text::Text
862*/
863Text* TextEngine::createText(const char* fontFile, unsigned int fontSize, int textType, Uint8 r, Uint8 g, Uint8 b)
864{
865  Font* tmpFont;
866  Text* newText;
867  Vector tmpVec;
868
869  tmpVec = Vector(r, g, b);
870  tmpFont = (Font*)ResourceManager::getInstance()->load(fontFile, TTF, RP_GAME, &fontSize, &tmpVec);
871  if (!tmpFont)
872    {
873      PRINTF(2)("Font %s could not be loaded, probably file not found\n", fontFile);
874      return NULL;
875    }
876
877  newText = new Text(tmpFont, TEXT_DYNAMIC);
878  textList->add(newText);
879
880  return newText;
881}
882
883/**
884   \brief removes a Text from the List
885   \param text: the text to delete
886
887   this only ereases allocated memory, and removes the text
888   The normal way to call it, is through "delete text;"
889   So you do not have to concetn yourselves with this.
890*/
891void TextEngine::deleteText(Text* text)
892{
893  ResourceManager::getInstance()->unload(text->font);
894  textList->remove(text);
895}
896
897/**
898   \brief deletes all the Text, and tries to delete all allocated fonts
899*/
900void TextEngine::flush(void)
901{
902  tIterator<Text>* textIterator = textList->getIterator();
903  Text* text = textIterator->nextElement();
904  while( text != NULL)
905    {
906      delete text;
907      text = textIterator->nextElement();
908    }
909  delete textIterator;
910}
911
912/**
913   \brief draws all the Texts that have been initialized
914*/
915void TextEngine::draw(void) const
916{
917  // entering 3D-mode
918  GraphicsEngine::enter2DMode();
919  // drawing all the texts
920  tIterator<Text>* textIterator = textList->getIterator();
921  Text* text = textIterator->nextElement();
922  while( text != NULL)
923    {
924      text->draw();
925      text = textIterator->nextElement();
926    }
927  delete textIterator;
928  // retruning to the previous mode
929  GraphicsEngine::leave2DMode();
930}
931
932/**
933   \brief outputs some nice Debug information
934   
935   \todo there should also be something outputted about Font
936*/
937void TextEngine::debug(void) const
938{
939  PRINT(0)("+-------------------------------+\n");
940  PRINT(0)("+ TEXT ENGINE DEBUG INFORMATION +\n");
941  PRINT(0)("+-------------------------------+\n");
942  PRINT(0)("Reference: %p; Text Counts: %d\n", this, this->textList->getSize());
943 
944  tIterator<Text>* textIterator = textList->getIterator();
945  Text* text = textIterator->nextElement();
946  while( text != NULL)
947    {
948      text->debug();
949      text = textIterator->nextElement();
950    }
951  delete textIterator;
952  PRINT(0)("+---------------------------TE--+\n");
953}
954
955
956/**
957   \brief checks if the compiled version and the local version of SDL_ttf match.
958   \returns true if match, false otherwise
959*/
960bool TextEngine::checkVersion(void)
961{
962  SDL_version compile_version;
963  SDL_version link_version;
964  TTF_VERSION(&compile_version);
965  link_version = *TTF_Linked_Version();
966
967  if (compile_version.major == link_version.major &&
968      compile_version.minor == link_version.minor &&
969      compile_version.patch == link_version.patch)
970    {
971      return true;
972    }
973  else
974    {
975      PRINTF(2)("compiled with SDL_ttf version: %d.%d.%d\n", 
976                compile_version.major,
977                compile_version.minor,
978                compile_version.patch);
979     
980      PRINTF(2)("running with SDL_ttf version: %d.%d.%d\n", 
981                link_version.major,
982                link_version.minor,
983                link_version.patch);
984      return false;
985    }
986}
Note: See TracBrowser for help on using the repository browser.