Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: ResourceManage-fixes

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