Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: text-read from XPM works, but there still is an error in displaying them

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