Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: fixed another 'BUG' inside of the deletion of the Fonts.
Now the fonts are deleted when deleting the TextEngine.

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