Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: ShellInput is now almost perfectly extern.
ShellCompletion taken out.
Working again :)

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