Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: commited crap in last commit

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