Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: a first command can be executed 'clear'
also improved the seg-fault-protection of the TextEngine

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