Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: changed all getInstances into inline functions to save some (minor) time

File size: 23.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  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      else
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   \brief standard deconstructor
817
818*/
819TextEngine::~TextEngine () 
820{
821  this->disableFonts();
822 
823  delete this->textList;
824
825  TextEngine::singletonRef = NULL;
826
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.