Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4506 was 4458, checked in by bensch, 20 years ago

orxonox/trunk: graphicsEngine and TextEngine documented

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