Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: font renders nicer, but not perfect

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