Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: started function implementation for Shell

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