Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: ResourceManage-fixes

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