Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: Shell is running, but only in orxonox-world, not all-over
I do not know why this behaviour occurs, but maybe it is because of some errors in other pointers…
who knows

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