Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Changeset 5343 in orxonox.OLD


Ignore:
Timestamp:
Oct 10, 2005, 12:16:19 AM (19 years ago)
Author:
bensch
Message:

orxonox/trunk: split open the text-engine

Location:
trunk/src/lib/graphics/text_engine
Files:
2 edited
4 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/lib/graphics/text_engine/font.cc

    r5330 r5343  
    1010
    1111   ### File Specific:
    12    main-programmer: ...
     12   main-programmer: Benjamin Grauer
    1313   co-programmer: ...
    1414*/
    1515
    16 //#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
    17 
    18 #include "proto_class.h"
     16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_FONT
     17
     18#include "font.h"
     19#include "text.h"
     20
     21#ifdef HAVE_SDL_IMAGE_H
     22#include <SDL_image.h>
     23#else
     24#include <SDL/SDL_image.h>
     25#endif
     26#include "font.xpm"
     27
     28#include "debug.h"
     29#include "compiler.h"
    1930
    2031using namespace std;
    2132
    22 
    23 /**
    24  * standard constructor
    25  * @todo this constructor is not jet implemented - do it
    26 */
    27 ProtoClass::ProtoClass ()
    28 {
    29    this->setClassID(CL_PROTO_ID, "ProtoClass");
    30 
    31    /* If you make a new class, what is most probably the case when you write this file
    32       don't forget to:
    33        1. Add the new file new_class.cc to the ./src/Makefile.am
    34        2. Add the class identifier to ./src/class_id.h eg. CL_NEW_CLASS
    35 
    36       Advanced Topics:
    37       - if you want to let your object be managed via the ObjectManager make sure to read
    38         the object_manager.h header comments. You will use this most certanly only if you
    39         make many objects of your class, like a weapon bullet.
    40    */
    41 }
    42 
    43 
    44 /**
    45  * standard deconstructor
    46 */
    47 ProtoClass::~ProtoClass ()
    48 {
    49   // delete what has to be deleted here
    50 }
     33/**
     34 * constructs a Font
     35 * @param fontFile the File to load the font from
     36 * @param fontSize the Size of the Font in Pixels
     37 */
     38Font::Font(const char* fontFile, unsigned int fontSize)
     39{
     40  this->init();
     41
     42  this->setSize(fontSize);
     43
     44  if (fontFile != NULL)
     45    this->loadFont(fontFile);
     46
     47  this->setStyle("c");//TTF_STYLE_NORMAL);
     48
     49  this->fastTextureID = this->createFastTexture();
     50
     51
     52//  this->createAsciiImage("test.bmp");
     53}
     54
     55/**
     56 * constructs a Font
     57 * @param fontFile the File to load the font from
     58 * @param fontSize the Size of the Font in Pixels
     59 */
     60Font::Font(char** xpmArray)
     61{
     62  this->init();
     63
     64  //  this->setSize(fontSize);
     65  SDL_Surface* image = NULL;
     66  if (xpmArray != NULL)
     67    image = IMG_ReadXPMFromArray(xpmArray);
     68  if (image != NULL)
     69  {
     70    this->loadFontFromSDL_Surface(image);
     71    SDL_FreeSurface(image);
     72  }
     73  else
     74    PRINTF(1)("loading from surface failed: %s\n", IMG_GetError());
     75
     76}
     77
     78
     79/**
     80 * destructs a font
     81 * this releases the memory a font uses to be opened.
     82 * deletes the glLists, and the TTF-handler, if present.
     83 */
     84Font::~Font()
     85{
     86  // deleting all Glyphs
     87  if (this->glyphArray != NULL)
     88  {
     89    for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
     90    {
     91      if (this->glyphArray[i] != NULL)
     92      {
     93        glDeleteLists(this->glyphArray[i]->displayList, 1);
     94        delete this->glyphArray[i];
     95      }
     96    }
     97    delete[] this->glyphArray;
     98  }
     99
     100  // erease this font out of the memory.
     101  if (likely(this->font != NULL))
     102    TTF_CloseFont(this->font);
     103}
     104
     105/**
     106 * initializes a Font (with default values)
     107 */
     108void Font::init()
     109{
     110  this->setClassID(CL_FONT, "Font");
     111  // setting default values.
     112  this->font = NULL;
     113  this->glyphArray = NULL;
     114  this->fastTextureID = 0;
     115}
     116
     117
     118/**
     119 * sets The Font.
     120 * @param fontFile The file containing the font.
     121 * @returns true if loaded, false if something went wrong, or if a font was loaded before.
     122 */
     123bool Font::loadFont(const char* fontFile)
     124{
     125  if (!this->getName())
     126  {
     127    this->setName(fontFile);
     128
     129    this->font = TTF_OpenFont(this->getName(), this->fontSize);
     130    if(!this->font)
     131    {
     132      PRINTF(1)("TTF_OpenFont: %s\n", TTF_GetError());
     133      return false;
     134    }
     135    else
     136      return true;
     137  }
     138  else
     139  {
     140    PRINTF(2)("Font already initialized, unable to change it now.\n");
     141    return false;
     142  }
     143}
     144
     145/**
     146 * loads a font From an XPM-array.
     147 * @param xpmArray the array of the XPM to load the font from.
     148 */
     149bool Font::loadFontFromSDL_Surface(SDL_Surface* surface)
     150{
     151  // loading to a texture.
     152  if(surface == NULL)
     153    return false;
     154  this->fastTextureID = Text::loadTexture(surface, NULL);
     155
     156  // initializing the Glyphs.
     157  if (this->glyphArray == NULL)
     158  {
     159    float cx,cy;
     160    Glyph* glyph;
     161    this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
     162    for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
     163    {
     164      glyph = this->glyphArray[i] = new Glyph;
     165      glyph->displayList = glGenLists(1);
     166      if (!glIsList(glyph->displayList))
     167      {
     168        PRINTF(2)("Error creating glList for Font character %c\n", i);
     169        this->glyphArray[i] = NULL;
     170        delete glyph;
     171        continue;
     172      }
     173      cx=(float)(i%16)/16.0f;                  // X Position Of Current Character
     174      cy=(float)(i/16)/16.0f;                  // Y Position Of Current Character
     175      glNewList(glyph->displayList, GL_COMPILE); // Start Building A List
     176      glBegin(GL_QUADS);                           // Use A Quad For Each Character
     177      glTexCoord2f(cx, cy+0.001f);            // Texture Coord (Bottom Left)
     178      glVertex2d(0,-16);                            // Vertex Coord (Bottom Left)
     179      glTexCoord2f(cx+0.0625f, cy+0.001f);    // Texture Coord (Bottom Right)
     180      glVertex2i(16,-16);                           // Vertex Coord (Bottom Right)
     181      glTexCoord2f(cx+0.0625f, cy+0.0625f);     // Texture Coord (Top Right)
     182      glVertex2i(16,0);                            // Vertex Coord (Top Right)
     183      glTexCoord2f(cx, cy+0.0625f);             // Texture Coord (Top Left)
     184      glVertex2i(0,0);                             // Vertex Coord (Top Left)
     185      glEnd();                                     // Done Building Our Quad (Character)
     186//       glTranslated(12,0,0);                        // Move To The Right Of The Character
     187      glEndList();                                 // Done Building The Display List
     188      this->glyphArray[i]->width = 12;
     189    }
     190  }
     191  return true;
     192}
     193
     194
     195/**
     196 *  sets a specific renderStyle
     197 * @param renderStyle the Style to render: a char-array containing:
     198   i: italic, b: bold, u, underline
     199 */
     200void Font::setStyle(const char* renderStyle)
     201{
     202  this->renderStyle = TTF_STYLE_NORMAL;
     203
     204  for (int i = 0; i < strlen(renderStyle); i++)
     205    if (strncmp(renderStyle+i, "b", 1) == 0)
     206      this->renderStyle |= TTF_STYLE_BOLD;
     207  else if (strncmp(renderStyle+i, "i", 1) == 0)
     208    this->renderStyle |= TTF_STYLE_ITALIC;
     209  else if (strncmp(renderStyle+i, "u", 1) == 0)
     210    this->renderStyle |= TTF_STYLE_UNDERLINE;
     211
     212  if (likely(this->font != NULL))
     213    TTF_SetFontStyle(this->font, this->renderStyle);
     214  else
     215    PRINTF(2)("Font was not initialized, please do so before setting the Font-Style.\n");
     216}
     217
     218/**
     219 *  Sets a new Size to the font
     220 * @param fontSize The new Size in pixels.
     221 */
     222void Font::setSize(unsigned int fontSize)
     223{
     224  this->fontSize = fontSize;
     225}
     226
     227Font* Font::defaultFont = NULL;
     228
     229void Font::createAsciiImage(const char* fileName)
     230{
     231  if (this->font == NULL)
     232    return;
     233  int height = this->getMaxHeight();
     234
     235  //
     236  SDL_Color tmpColor = {0, 0, 0};
     237  // Surface definition.
     238  SDL_Rect tmpRect; // this represents a Rectangle for blitting.
     239  SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(SDL_SWSURFACE,
     240                                               height*16, height*16,
     241                                               32,
     242#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
     243                                               0x000000FF,
     244                                               0x0000FF00,
     245                                               0x00FF0000,
     246                                               0xFF000000
     247#else
     248                                                   0xFF000000,
     249                                               0x00FF0000,
     250                                               0x0000FF00,
     251                                               0x000000FF
     252#endif
     253                                              );
     254  tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h;
     255  SDL_SetClipRect(tmpSurf, &tmpRect);
     256  int maxLineHeight = 0;
     257
     258  int posX, posY;
     259  // all the interessting Glyphs
     260  for (posY = 0; posY < 16; posY++)
     261  {
     262    for (posX = 0; posX < 16; posX++)
     263    {
     264      SDL_Surface* glyphSurf = NULL;
     265      if (likely(this->font != NULL))
     266      {
     267        SDL_Color white = {255, 255, 255};
     268        glyphSurf = TTF_RenderGlyph_Blended(this->font, posX+16*posY, white);
     269      }
     270      if( glyphSurf != NULL )
     271      {
     272        tmpRect.x = height*posX;
     273        tmpRect.y = height*posY;
     274        SDL_SetAlpha(glyphSurf, 0, 0);
     275
     276        SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect);
     277        SDL_FreeSurface(glyphSurf);
     278              // Outputting Glyphs to BMP-files.
     279/*
     280        char outname[512];
     281        if (i < 10)
     282        sprintf( outname, "%s-glyph-00%d.bmp", this->getName(), i );
     283        else if (i <100)
     284        sprintf( outname, "%s-glyph-0%d.bmp", this->getName(), i );
     285        else
     286        sprintf( outname, "%s-glyph-%d.bmp", this->getName(), i );
     287        SDL_SaveBMP(tmpSurf, outname);*/
     288
     289      }
     290    }
     291  }
     292  SDL_SaveBMP(tmpSurf, fileName);
     293  SDL_FreeSurface(tmpSurf);
     294}
     295
     296/**
     297 * initializes the default font
     298 */
     299void Font::initDefaultFont()
     300{
     301  if (Font::defaultFont == NULL)
     302    Font::defaultFont = new Font(font_xpm);
     303}
     304
     305/**
     306 * deletes the default font
     307 */
     308void Font::removeDefaultFont()
     309{
     310  if (Font::defaultFont != NULL)
     311    delete Font::defaultFont;
     312  Font::defaultFont = NULL;
     313}
     314
     315
     316/**
     317 * @returns the maximum height of the Font, if the font was initialized, 0 otherwise
     318 */
     319int Font::getMaxHeight()
     320{
     321  if (likely (this->font != NULL))
     322    return TTF_FontHeight(this->font);
     323  else
     324    return 0;
     325}
     326
     327/**
     328 * @returns the maximum ascent of the Font, if the font was initialized, 0 otherwise
     329
     330   the ascent is the pixels of the font above the baseline
     331 */
     332int Font::getMaxAscent()
     333{
     334  if (likely(this->font != NULL))
     335    return TTF_FontAscent(this->font);
     336  else
     337    return 0;
     338}
     339
     340/**
     341 * @returns the maximum descent of the Font, if the font was initialized, 0 otherwise
     342
     343   the descent is the pixels of the font below the baseline
     344 */
     345int Font::getMaxDescent()
     346{
     347  if (likely(this->font != NULL))
     348    return TTF_FontDescent(this->font);
     349  else
     350    return 0;
     351}
     352
     353/**
     354 * @param character The character to get info about.
     355 * @returns a Glyph struct of a character. This Glyph is a pointer,
     356   and MUST be deleted by the user..
     357
     358   This only works for horizontal fonts. see
     359   http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html
     360   for more info about vertical Fonts
     361 */
     362Glyph* Font::getGlyphMetrics(Uint16 character)
     363{
     364  Glyph* rg = new Glyph;
     365  rg->character = character;
     366  if (likely (this->font!= NULL))
     367    TTF_GlyphMetrics(this->font, rg->character,
     368                     &rg->minX, &rg->maxX,
     369                     &rg->minY, &rg->maxY,
     370                     &rg->advance);
     371  rg->height = rg->maxY - rg->minY;
     372  rg->width = rg->maxX - rg->minX;
     373  rg->bearingX = (rg->advance - rg->width) / 2;
     374  rg->bearingY = rg->maxY;
     375  return rg;
     376}
     377
     378/**
     379 * creates a Fast-Texture of this Font
     380 */
     381GLuint Font::createFastTexture()
     382{
     383  /* interesting GLYPHS:
     384  *  32: space
     385  *  33-47: Special Characters.
     386  *  48-57: 0-9
     387  *  58-63: some more special chars (minor)
     388  *  65-90: A-Z
     389  *  97-122: a-z
     390  */
     391  int numberOfGlyphs = 91;
     392
     393  this->initGlyphs(32, numberOfGlyphs);
     394  this->glyphArray[32]->width = fontSize/2; //!< @todo find out the real size of a Space
     395
     396  int rectSize = this->findOptimalFastTextureSize();
     397
     398  // setting default values. (maybe not needed afterwards)
     399  SDL_Color tmpColor;  tmpColor.r = tmpColor.g = tmpColor.b = 0;
     400  // Surface definition.
     401  SDL_Rect tmpRect; // this represents a Rectangle for blitting.
     402  SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(SDL_SWSURFACE,
     403                                               rectSize, rectSize,
     404                                               32,
     405#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
     406                                               0x000000FF,
     407                                               0x0000FF00,
     408                                               0x00FF0000,
     409                                               0xFF000000
     410#else
     411                                                   0xFF000000,
     412                                               0x00FF0000,
     413                                               0x0000FF00,
     414                                               0x000000FF
     415#endif
     416                                              );
     417  tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h;
     418  SDL_SetClipRect(tmpSurf, &tmpRect);
     419  int maxLineHeight = 0;
     420
     421  // all the interessting Glyphs
     422  for (int i = 0; i < 128; i++)
     423  {
     424    SDL_Surface* glyphSurf = NULL;
     425    Glyph* tmpGlyph;
     426
     427    if (tmpGlyph = this->glyphArray[i])
     428    {
     429      if (tmpGlyph->height > maxLineHeight)
     430        maxLineHeight = tmpGlyph->height;
     431
     432      if (tmpRect.x+tmpGlyph->advance > tmpSurf->w)
     433      {
     434        tmpRect.x = 0;
     435        tmpRect.y = tmpRect.y + maxLineHeight + 1;
     436        maxLineHeight = 0;
     437      }
     438      if (tmpRect.y + maxLineHeight > tmpSurf->h)
     439      {
     440        PRINTF(1)("Protection, so font cannot write over the boundraries error (this should not heappen\n");
     441        break;
     442      }
     443          // reading in the new Glyph
     444      if (likely(this->font != NULL))
     445      {
     446        SDL_Color white = {255, 255, 255};
     447        glyphSurf = TTF_RenderGlyph_Blended(this->font, i, white);
     448      }
     449      if( glyphSurf != NULL )
     450      {
     451        SDL_SetAlpha(glyphSurf, 0, 0);
     452
     453        SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect);
     454        TexCoord tmpTexCoord;
     455        tmpTexCoord.minU = (float)tmpRect.x/(float)tmpSurf->w;
     456        tmpTexCoord.maxU = (float)(tmpRect.x + tmpGlyph->advance)/(float)tmpSurf->w;
     457        tmpTexCoord.minV = (float)(tmpRect.y)/(float)tmpSurf->w;
     458        tmpTexCoord.maxV = (float)(tmpRect.y+tmpGlyph->height)/(float)tmpSurf->w;
     459        tmpGlyph->displayList = glGenLists(1);
     460
     461        glNewList(tmpGlyph->displayList, GL_COMPILE);
     462        glBegin(GL_QUADS);
     463        glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.minV);
     464        glVertex2d(0, - tmpGlyph->bearingY);
     465        glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.maxV);
     466        glVertex2d(0, tmpGlyph->height - tmpGlyph->bearingY);
     467        glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.maxV);
     468        glVertex2d(tmpGlyph->width, tmpGlyph->height - tmpGlyph->bearingY);
     469        glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.minV);
     470        glVertex2d(tmpGlyph->width, - tmpGlyph->bearingY);
     471        glEnd();
     472        glEndList();
     473        SDL_FreeSurface(glyphSurf);
     474
     475        tmpRect.x += tmpGlyph->advance;
     476
     477              // Outputting Glyphs to BMP-files.
     478/*
     479        char outname[512];
     480        if (i < 10)
     481        sprintf( outname, "%s-glyph-00%d.bmp", this->getName(), i );
     482        else if (i <100)
     483        sprintf( outname, "%s-glyph-0%d.bmp", this->getName(), i );
     484        else
     485        sprintf( outname, "%s-glyph-%d.bmp", this->getName(), i );
     486        SDL_SaveBMP(tmpSurf, outname);*/
     487
     488      }
     489    }
     490  }
     491
     492  GLuint texture;
     493  glGenTextures(1, &texture);
     494  glBindTexture(GL_TEXTURE_2D, texture);
     495  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     496  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     497  glTexImage2D(GL_TEXTURE_2D,
     498               0,
     499               GL_RGBA,
     500               tmpSurf->w, tmpSurf->h,
     501               0,
     502               GL_RGBA,
     503               GL_UNSIGNED_BYTE,
     504               tmpSurf->pixels);
     505  SDL_FreeSurface(tmpSurf);
     506  return texture;
     507}
     508
     509/**
     510 *  stores Glyph Metrics in an Array.
     511 * @param from The Glyph to start from.
     512 * @param count The number of Glyphs to start From.
     513 */
     514void Font::initGlyphs(Uint16 from, Uint16 count)
     515{
     516  /* initialize the Array, and set all its entries to NULL
     517  *  only if the Glyph-array has not been initialized
     518  */
     519  if (!this->glyphArray)
     520  {
     521    this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
     522    for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
     523      this->glyphArray[i] = NULL;
     524  }
     525
     526  Uint16 lastGlyph = from + count;
     527
     528  for (int i = from; i <= lastGlyph; i++)
     529  {
     530      // setting up all the Glyphs we like.
     531    glyphArray[i] = getGlyphMetrics(i);
     532  }
     533  return;
     534}
     535
     536/**
     537 * @returns the optimal size to use as the texture size
     538
     539   @todo: this algorithm can be a lot more faster, althought it does
     540   not really matter within the init-context, and 128 glyphs.
     541
     542   This function searches for a 2^n sizes texture-size, this is for
     543   openGL-version < 1.2 compatibility ( and because it is realy easy like this :))
     544 */
     545int Font::findOptimalFastTextureSize()
     546{
     547  int i;
     548  int x,y; // the counters
     549  int maxLineHeight = this->getMaxHeight();
     550  unsigned int size = 32;  // starting Value, we have to start somewhere 32 seems reasonable. (take any small enough 2^i number)
     551  bool sizeOK = false;
     552  Glyph* tmpGlyph;
     553
     554  while (!sizeOK)
     555  {
     556    x = 0; y = 0;
     557    for (i = 0; i <= FONT_HIGHEST_KNOWN_CHAR; i++)
     558    {
     559      if((tmpGlyph = this->glyphArray[i]) != NULL)
     560      {
     561              // getting the height of the highest Glyph in the Line.
     562        if (tmpGlyph->height > maxLineHeight)
     563          maxLineHeight = tmpGlyph->height;
     564
     565        if (x + tmpGlyph->advance > size)
     566        {
     567          x = 0;
     568          y = y + maxLineHeight;
     569                  //maxLineHeight = 0;
     570        }
     571        if (y + maxLineHeight + 1 > size)
     572          break;
     573        x += tmpGlyph->advance;
     574
     575      }
     576    }
     577    if (i >= FONT_HIGHEST_KNOWN_CHAR-1 || size > 8192)
     578      sizeOK = true;
     579    else
     580      size *= 2;
     581  }
     582  return size;
     583}
     584
     585
     586/**
     587 *  a simple function to get some interesting information about this class
     588 */
     589void Font::debug()
     590{
     591  // print the loaded font's style
     592  int style;
     593  if (likely(this->font != NULL))
     594    style = TTF_GetFontStyle(this->font);
     595  PRINTF(0)("The font style is:");
     596  if(style==TTF_STYLE_NORMAL)
     597    PRINTF(0)(" normal");
     598  else {
     599    if(style&TTF_STYLE_BOLD)
     600      PRINTF(0)(" bold");
     601    if(style&TTF_STYLE_ITALIC)
     602      PRINTF(0)(" italic");
     603    if(style&TTF_STYLE_UNDERLINE)
     604      PRINTF(0)(" underline");
     605  }
     606  PRINTF(0)("\n");
     607}
  • trunk/src/lib/graphics/text_engine/font.h

    r5330 r5343  
    11/*!
    2  * @file proto_class.h
    3  * @brief Definition of ...
    4 */
     2 * @file font.h
     3 * brief Definition of the FONT-loading class
     4 */
    55
    6 #ifndef _PROTO_CLASS_H
    7 #define _PROTO_CLASS_H
     6#ifndef _FONT_H
     7#define _FONT_H
    88
    99#include "base_object.h"
    1010
     11#include "glincl.h"
     12
     13
     14#ifdef HAVE_SDL_TTF_H
     15#include <SDL_ttf.h>
     16#else
     17#include <SDL/SDL_ttf.h>
     18#endif
     19
     20/* some default values */
     21#define FONT_NUM_COLORS              256                        //!< number of colors.
     22
     23#define FONT_HIGHEST_KNOWN_CHAR      128                        //!< The highest character known to the textEngine.
     24
    1125// FORWARD DECLARATION
    1226
     27//! A struct for handling glyphs
     28/**
     29   a Glyph is one letter of a certain font
     30 */
     31struct Glyph
     32{
     33  // Glyph-specific (size and so on)
     34  Uint16   character;         //!< The character
     35  int      minX;              //!< The minimum distance from the origin in X
     36  int      maxX;              //!< The maximum distance from the origin in X
     37  int      minY;              //!< The minimum distance from the origin in Y
     38  int      maxY;              //!< The maximum distance from the origin in Y
     39  int      width;             //!< The width of the Glyph
     40  int      height;            //!< The height of the Glyph
     41  int      bearingX;          //!< How much is right of the Origin
     42  int      bearingY;          //!< How much is above the Origin
     43  int      advance;           //!< How big a Glyph would be in monospace-mode
     44
     45  // OpenGL-specific
     46  //  TexCoord texCoord;      //!< A Texture Coordinate for this glyph.
     47  GLuint   displayList;       //!< DiplayList to render this Glyph.
     48};
    1349
    1450
    15 //! A class for ...
    16 class ProtoClass : public BaseObject {
     51////////////
     52/// FONT ///
     53////////////
     54//! A class to handle a Font of a certain ttf-File, Size and Color.
     55class Font : public BaseObject
     56{
     57  friend class Text;
    1758
    18  public:
    19   ProtoClass();
    20   virtual ~ProtoClass();
     59  public:
     60    Font(const char* fontFile,
     61         unsigned int fontSize);
     62    Font(char** xpmArray);
     63    virtual ~Font();
    2164
     65    void init();
    2266
    23  private:
     67  // font
     68    bool loadFont(const char* fontFile);
     69    bool loadFontFromSDL_Surface(SDL_Surface* surface);
    2470
     71    void setSize(unsigned int fontSize);
     72    void setStyle(const char* renderStyle);
     73
     74    /** @returns a Pointer to the Array of Glyphs */
     75    inline Glyph** getGlyphArray() const { return this->glyphArray; };
     76    /** @returns the texture to the fast-texture */
     77    inline GLuint getFastTextureID() const { return this->fastTextureID; };
     78    /** @returns the default Font */
     79    inline static Font* getDefaultFont() { return Font::defaultFont; };
     80
     81    void createAsciiImage(const char* fileName);
     82    static void initDefaultFont();
     83    static void removeDefaultFont();
     84
     85  private:
     86    int getMaxHeight();
     87    int getMaxAscent();
     88    int getMaxDescent();
     89    Glyph* getGlyphMetrics(Uint16 character);
     90
     91    GLuint createFastTexture();
     92
     93    void initGlyphs(Uint16 from, Uint16 count);
     94    int findOptimalFastTextureSize();
     95
     96    void debug();
     97
     98  private:
     99    static Font*  defaultFont;         //!< a default font, that is used, if other fonts were unable to be loaded.
     100  // information about the Font
     101    TTF_Font*     font;                //!< The font we use for this.
     102    unsigned int  fontSize;            //!< The size of the font in pixels. each Font has one size.
     103    int           renderStyle;         //!< The Renderstyle
     104
     105    Glyph**       glyphArray;          //!< An Array of all the Glyphs stored in the Array of Glyphs.
     106    GLuint        fastTextureID;       //!< The fast textureID.
    25107};
    26108
    27 #endif /* _PROTO_CLASS_H */
     109#endif /* _FONT_H */
  • trunk/src/lib/graphics/text_engine/text.cc

    r5330 r5343  
    1010
    1111   ### File Specific:
    12    main-programmer: ...
     12   main-programmer: Benjamin Grauer
    1313   co-programmer: ...
    1414*/
    1515
    16 //#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
    17 
    18 #include "proto_class.h"
     16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_FONT
     17
     18#include "text.h"
     19#include "font.h"
     20
     21#include "graphics_engine.h"
     22#include "resource_manager.h"
     23#include "class_list.h"
     24#include "debug.h"
     25#include "p_node.h"
    1926
    2027using namespace std;
    2128
    22 
    23 /**
    24  * standard constructor
    25  * @todo this constructor is not jet implemented - do it
    26 */
    27 ProtoClass::ProtoClass ()
    28 {
    29    this->setClassID(CL_PROTO_ID, "ProtoClass");
    30 
    31    /* If you make a new class, what is most probably the case when you write this file
    32       don't forget to:
    33        1. Add the new file new_class.cc to the ./src/Makefile.am
    34        2. Add the class identifier to ./src/class_id.h eg. CL_NEW_CLASS
    35 
    36       Advanced Topics:
    37       - if you want to let your object be managed via the ObjectManager make sure to read
    38         the object_manager.h header comments. You will use this most certanly only if you
    39         make many objects of your class, like a weapon bullet.
    40    */
    41 }
    42 
    43 
    44 /**
    45  * standard deconstructor
    46 */
    47 ProtoClass::~ProtoClass ()
    48 {
    49   // delete what has to be deleted here
    50 }
     29/**
     30 *  creates a new Text Element
     31 * @param fontFile the Font to render this text in
     32 * @param type The renderType to display this font in
     33 */
     34Text::Text(const char* fontFile, unsigned int fontSize, TEXT_RENDER_TYPE type)
     35{
     36  this->init();
     37
     38  if (fontFile != NULL)
     39    this->setFont(fontFile, fontSize);
     40  this->setType(type);
     41}
     42
     43/**
     44 *  creates a new Text Element
     45 * @param font the Font to render this text in
     46 * @param type The renderType to display this font in
     47 *
     48 * this constructor is private, because the user should initialize
     49 * a text with the TextEngine.
     50 */
     51Text::Text(Font* font, TEXT_RENDER_TYPE type)
     52{
     53  this->init();
     54
     55  this->font = font;
     56  this->setType(type);
     57}
     58
     59/**
     60 *  deletes a Text out of memory
     61 *
     62 * This also ereases the text from the textList of the TextEngine
     63 */
     64Text::~Text()
     65{
     66  if (this->font != NULL)
     67    ResourceManager::getInstance()->unload(this->font);
     68
     69  if (this->text)
     70    delete[] this->text;
     71}
     72
     73void Text::init()
     74{
     75  this->setClassID(CL_TEXT, "Text");
     76
     77  // initialize this Text
     78  this->font = NULL;
     79  this->text = NULL;
     80  this->externText = NULL;
     81  this->setAlignment(TEXT_DEFAULT_ALIGNMENT);
     82  this->texture = 0;
     83  this->blending = TEXT_DEFAULT_BLENDING;
     84  this->color = TEXT_DEFAULT_COLOR;
     85  this->setType(TEXT_RENDER_DYNAMIC);
     86
     87  this->setText(NULL);
     88}
     89
     90/**
     91 * sets the Font of this Text to font
     92 * @param font the Font (normaly from the ResourceManager) to allocate to this Text
     93 */
     94void Text::setFont(Font* font)
     95{
     96  if (this->font != NULL)
     97    ResourceManager::getInstance()->unload(this->font);
     98  this->font = font;
     99}
     100
     101/**
     102 * sets the Font of this Text to font from fontFile
     103 * @param fontFile the File to load the Font from.
     104 * @param fontSize the Size of the Font
     105 */
     106void Text::setFont(const char* fontFile, unsigned int fontSize)
     107{
     108  Font* tmpFont;
     109  Text* newText;
     110  Vector tmpVec;
     111
     112  tmpFont = (Font*)ResourceManager::getInstance()->load(fontFile, TTF, RP_GAME, &fontSize);
     113  if (tmpFont == NULL)
     114  {
     115    PRINTF(2)("Font %s could not be loaded, probably file not found\n", fontFile);
     116    this->setFont(NULL);
     117  }
     118  else
     119    this->setFont(tmpFont);
     120}
     121
     122/**
     123 *  sets the Type of this Text
     124 * @param type the type to set.
     125 */
     126void Text::setType(TEXT_RENDER_TYPE type)
     127{
     128  if (this->font != NULL && this->font->font)
     129    this->type = type;
     130  else
     131    this->type = TEXT_RENDER_DYNAMIC;
     132}
     133
     134/**
     135 *  Sets a new Text to the font
     136 * @param text the new text to set
     137 */
     138void Text::setText(const char* text, bool isExtern)
     139{
     140  if (isExtern)
     141  {
     142    this->externText = text;
     143
     144    if (unlikely(this->text != NULL))
     145    {
     146      delete[] this->text;
     147      this->text = NULL;
     148    }
     149  }
     150  else
     151  {
     152    this->externText = NULL;
     153    if (this->text)
     154      delete[] this->text;
     155    if (text != NULL)
     156    {
     157      this->text = new char[strlen(text)+1];
     158      strcpy(this->text, text);
     159    }
     160    else
     161      this->text = NULL;
     162  }
     163
     164  // setting up the Text-Width if DYNAMIC
     165  if (this->type & TEXT_RENDER_DYNAMIC && this->getAlignment() != TEXT_ALIGN_LEFT && this->font != NULL)
     166  {
     167    Glyph** glyphArray = this->font->getGlyphArray();
     168
     169    int width = 0;
     170    const char* tmpText = this->externText;
     171    if (this->externText == NULL)
     172      tmpText = this->text;
     173    if (tmpText != NULL)
     174    {
     175      while (*tmpText != '\0')
     176      {
     177        if(glyphArray[*tmpText])
     178        {
     179          width += glyphArray[*tmpText]->width;
     180        }
     181        tmpText++;
     182      }
     183      this->width = width;
     184    }
     185  }
     186}
     187
     188/**
     189 *  creates a texture out of the given parameters
     190
     191   this has to be called every time by the user, to if changes were made.
     192   this is only for TEXT_STATIC-mode
     193 */
     194void Text::createTexture()
     195{
     196  SDL_Surface* tmpSurf;
     197  if (this->texture)
     198    glDeleteTextures(1, &this->texture);
     199  if (likely(this->font != NULL))
     200  {
     201    SDL_Color theColor = { (int)(this->color.x*255), (int)(this->color.y*255), (int)(this->color.z*255) };
     202    tmpSurf = TTF_RenderText_Blended(this->font->font,
     203                                     this->text,
     204                                     theColor);
     205  }
     206  if (tmpSurf)
     207    this->texture = loadTexture(tmpSurf, &this->texCoord);
     208
     209  this->width = tmpSurf->w;
     210  this->height = tmpSurf->h;
     211  SDL_FreeSurface(tmpSurf);
     212}
     213
     214/**
     215 *  draws the Text
     216 */
     217void Text::draw() const
     218{
     219  glPushMatrix();
     220  // transform for alignment.
     221  if (this->getAlignment() == TEXT_ALIGN_RIGHT)
     222    glTranslatef(-this->width, 0, 0);
     223  else if (this->getAlignment() == TEXT_ALIGN_CENTER || this->getAlignment() == TEXT_ALIGN_SCREEN_CENTER)
     224    glTranslatef(-this->width/2, 0, 0);
     225
     226  // drawing this Text.
     227  // setting the Blending effects
     228  glColor4f(this->color.x, this->color.y, this->color.z, this->blending);
     229  glEnable(GL_BLEND);
     230  glEnable(GL_TEXTURE_2D);
     231  glBlendFunc(GL_SRC_ALPHA, GL_ONE);
     232
     233  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GL_MODULATE );
     234
     235  if(likely(type & TEXT_RENDER_DYNAMIC ))
     236  {
     237    Glyph** glyphArray;
     238    if (likely (this->font != NULL))
     239    {
     240      glyphArray = this->font->getGlyphArray();
     241      glBindTexture(GL_TEXTURE_2D, font->getFastTextureID());
     242    }
     243    else
     244    {
     245      if (unlikely(Font::getDefaultFont() == NULL))
     246        Font::initDefaultFont();
     247      glyphArray = Font::getDefaultFont()->getGlyphArray();
     248      glBindTexture(GL_TEXTURE_2D, Font::getDefaultFont()->getFastTextureID());
     249    }
     250    glTranslatef(getAbsCoor2D().x, getAbsCoor2D().y, 0);
     251//      glRotatef(this->getAbsDir2D(), 0,0,1);
     252    const char* tmpText = this->externText;
     253    if (this->externText == NULL)
     254      tmpText = this->text;
     255    if (likely(tmpText != NULL))
     256    {
     257      while (likely(*tmpText != '\0'))
     258      {
     259        if(likely(glyphArray[*tmpText] != NULL))
     260        {
     261          glCallList(glyphArray[*tmpText]->displayList);
     262          glTranslatef(glyphArray[*tmpText]->width, 0, 0);
     263        }
     264        tmpText++;
     265      }
     266    }
     267  }
     268  else //(if type & TEXT_RENDER_STATIC)
     269  {
     270    glBindTexture(GL_TEXTURE_2D, this->texture);
     271    glBegin(GL_QUADS);
     272
     273    glTexCoord2f(this->texCoord.minU, this->texCoord.minV);
     274    glVertex2f(this->getAbsCoor2D().x,   this->getAbsCoor2D().y  );
     275
     276    glTexCoord2f(this->texCoord.maxU, this->texCoord.minV);
     277    glVertex2f(this->getAbsCoor2D().x + this->width, this->getAbsCoor2D().y  );
     278
     279    glTexCoord2f(this->texCoord.maxU, this->texCoord.maxV);
     280    glVertex2f(this->getAbsCoor2D().x + this->width, getAbsCoor2D().y + this->height);
     281
     282    glTexCoord2f(this->texCoord.minU, this->texCoord.maxV);
     283    glVertex2f(getAbsCoor2D().x, getAbsCoor2D().y + this->height);
     284
     285    glEnd();
     286
     287  }
     288  glPopMatrix();
     289}
     290
     291/**
     292 *  prints out some nice debug information about this text
     293 */
     294void Text::debug() const
     295{
     296  if (this->externText == NULL)
     297    PRINT(0)("=== TEXT: %s ===\n", this->text);
     298  else
     299    PRINT(0)("=== TEXT: %s ===\n", this->externText);
     300
     301  if (this->getBindNode())
     302    PRINT(0)("is bind to %s; ref=%p\n", this->getBindNode()->getName(), this->getBindNode());
     303  PRINT(0)("Color: %0.2f %0.2f %0.2f\n", this->color.x, this->color.y, this->color.z);
     304}
     305
     306
     307////////////
     308/// UTIL ///
     309////////////
     310/**
     311 *  Loads a Font from an SDL_surface into a texture.
     312 * @param surface The surface to make the texture of
     313 * @param texCoord The texture coordinates of the 4 corners of the texture
     314 * @returns the ID of the texture
     315 */
     316GLuint Text::loadTexture(SDL_Surface *surface, TexCoord* texCoord)
     317{
     318  GLuint texture;
     319  int w, h;
     320  SDL_Surface *image;
     321  SDL_Rect area;
     322  Uint32 saved_flags;
     323  Uint8  saved_alpha;
     324
     325  /* Use the surface width and height expanded to powers of 2 */
     326  w = powerOfTwo(surface->w);
     327  h = powerOfTwo(surface->h);
     328  if (texCoord != NULL)
     329  {
     330    texCoord->minU = 0.0f;
     331    texCoord->minV = 0.0f;
     332    texCoord->maxU = (GLfloat)surface->w / w;
     333    texCoord->maxV = (GLfloat)surface->h / h;
     334  }
     335  image = SDL_CreateRGBSurface(SDL_SWSURFACE,
     336                               w, h,
     337                               32,
     338#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
     339                               0x000000FF,
     340                               0x0000FF00,
     341                               0x00FF0000,
     342                               0xFF000000
     343#else
     344                                   0xFF000000,
     345                               0x00FF0000,
     346                               0x0000FF00,
     347                               0x000000FF
     348#endif
     349                              );
     350  if ( image == NULL ) {
     351    return 0;
     352  }
     353
     354  /* Save the alpha blending attributes */
     355  saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
     356  saved_alpha = surface->format->alpha;
     357  if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
     358    SDL_SetAlpha(surface, 0, 0);
     359  }
     360
     361  /* Copy the surface into the GL texture image */
     362  area.x = 0;
     363  area.y = 0;
     364  area.w = surface->w;
     365  area.h = surface->h;
     366  SDL_BlitSurface(surface, &area, image, &area);
     367
     368  /* Restore the alpha blending attributes */
     369  if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
     370    SDL_SetAlpha(surface, saved_flags, saved_alpha);
     371  }
     372
     373  /* Create an OpenGL texture for the image */
     374  glGenTextures(1, &texture);
     375  glBindTexture(GL_TEXTURE_2D, texture);
     376  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     377  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     378  glTexImage2D(GL_TEXTURE_2D,
     379               0,
     380               GL_RGBA,
     381               w, h,
     382               0,
     383               GL_RGBA,
     384               GL_UNSIGNED_BYTE,
     385               image->pixels);
     386  SDL_FreeSurface(image); /* No longer needed the data */
     387
     388  return texture;
     389}
     390
     391/**
     392 *  Quick utility function for texture creation
     393 * @param input an integer
     394 * @returns the next bigger 2^n-integer than input
     395 */
     396int Text::powerOfTwo(int input)
     397{
     398  int value = 1;
     399
     400  while ( value < input )
     401    value <<= 1;
     402  return value;
     403}
  • trunk/src/lib/graphics/text_engine/text.h

    r5330 r5343  
    11/*!
    2  * @file proto_class.h
    3  * @brief Definition of ...
     2 * @file text.h
     3 * @brief Definition of a text Class, that is able to render text.
    44*/
    55
    6 #ifndef _PROTO_CLASS_H
    7 #define _PROTO_CLASS_H
     6#ifndef _TEXT_H
     7#define _TEXT_H
    88
    9 #include "base_object.h"
     9#include "element_2d.h"
     10
     11#include "glincl.h"
     12
     13#define  TEXT_ALIGN_LEFT             E2D_ALIGN_LEFT
     14#define  TEXT_ALIGN_RIGHT            E2D_ALIGN_RIGHT
     15#define  TEXT_ALIGN_CENTER           E2D_ALIGN_CENTER
     16#define  TEXT_ALIGN_SCREEN_CENTER    E2D_ALIGN_SCREEN_CENTER
     17#define  TEXT_DEFAULT_COLOR          Vector(1.0, 1.0, 1.0)      //!< the default Color (white)
     18#define  TEXT_DEFAULT_BLENDING       1.0f                       //!< the default blending of the text, (no blending at all)
     19
     20#define TEXT_DEFAULT_ALIGNMENT       TEXT_ALIGN_CENTER          //!< default alignment
     21#define TEXT_DEFAULT_SIZE            20                         //!< default size of the Text
     22
    1023
    1124// FORWARD DECLARATION
     25class Font;
    1226
    1327
     28/**
     29 * STATIC means: a font, that is only one GL-face.
     30 ** it is very fast, and can be used for all text
     31 ** that does not have to be changed anymore, or if
     32 ** the the text should look very nice
     33 * DYNAMIC means: a very fast font, that will is build
     34 ** from multiple quads.
     35 ** Use this type, if you want to create fast changing
     36 ** text like a counter.
     37 */typedef enum TEXT_RENDER_TYPE
     38{
     39  TEXT_RENDER_STATIC      = 1,
     40  TEXT_RENDER_DYNAMIC     = 2
     41};
    1442
    15 //! A class for ...
    16 class ProtoClass : public BaseObject {
    17 
    18  public:
    19   ProtoClass();
    20   virtual ~ProtoClass();
     43//! A Struct to handel Texture Coordinates for quads
     44struct TexCoord
     45{
     46  float    minU;              //!< The minimum U-Coordinate
     47  float    maxU;              //!< The maximum U-Coordinate
     48  float    minV;              //!< The minimum V-Coordinate
     49  float    maxV;              //!< The maximum V-Coordinate
     50};
    2151
    2252
    23  private:
     53////////////
     54/// TEXT ///
     55////////////
     56//! Represents one textElement.
     57class Text : public Element2D
     58{
     59  friend class TextEngine;
     60  public:
     61    Text(const char* fontFile, unsigned int fontSize = TEXT_DEFAULT_SIZE, TEXT_RENDER_TYPE type = TEXT_RENDER_DYNAMIC);
     62    ~Text();
    2463
     64    void init();
     65
     66    void setFont(const char* fontFile, unsigned int fontSize);
     67    void setType(TEXT_RENDER_TYPE type);
     68    void setText(const char* text, bool isExtern = false);
     69    /** @returns the String this Text displays */
     70    inline const char* getText() const { return (externText == NULL)?this->text:this->externText; };
     71    /** @param blending the blending intensity to set (between 0.0 and 1.0) */
     72    inline void setBlending(float blending) { this->blending = blending; };
     73
     74    /** sets the Color of the Text to render (values in [0-1]) @param r red @param g green @param b blue */
     75    void setColor(float r, float g, float b) { this->color = Vector(r,g,b); };
     76
     77    void createTexture();
     78
     79    virtual void draw() const;
     80
     81    void debug() const;
     82
     83  // helpers.
     84    static GLuint loadTexture(SDL_Surface* surface, TexCoord* texCoord);
     85    static int powerOfTwo(int input);
     86
     87  private:
     88    Text(Font* font = NULL, TEXT_RENDER_TYPE type = TEXT_RENDER_DYNAMIC);
     89    void setFont(Font* font);
     90
     91
     92  private:
     93    Font*             font;           //!< Font of this text
     94
     95    TEXT_RENDER_TYPE  type;           //!< The type of this Font.
     96    char*             text;           //!< The text to display
     97    const char*       externText;     //!< the text to Display from an external Source.
     98    Vector            color;          //!< The color of the font.
     99    float             blending;       //!< The blending intensity.
     100
     101  // placement in openGL
     102    GLuint            texture;        //!< A GL-texture to hold the text
     103    TexCoord          texCoord;       //!< Texture-coordinates @todo fix this to have a struct
     104    float             height;
     105    float             width;
    25106};
    26107
    27 #endif /* _PROTO_CLASS_H */
     108#endif /* _TEXT_H */
  • trunk/src/lib/graphics/text_engine/text_engine.cc

    r5342 r5343  
    3030#include <string.h>
    3131
    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 
    4032#include "graphics_engine.h"
    4133#include "resource_manager.h"
     
    4638#include "debug.h"
    4739#include "list.h"
    48 
    49 ////////////
    50 /// TEXT ///
    51 ////////////
    52 
    53 /**
    54  *  creates a new Text Element
    55  * @param fontFile the Font to render this text in
    56  * @param type The renderType to display this font in
    57  */
    58 Text::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
    69  * @param font the Font to render this text in
    70  * @param type The renderType to display this font in
    71  *
    72  * this constructor is private, because the user should initialize
    73  * a text with the TextEngine.
    74  */
    75 Text::Text(Font* font, TEXT_RENDER_TYPE type)
    76 {
    77   this->init();
    78 
    79   this->font = font;
    80   this->setType(type);
    81 }
    82 
    83 /**
    84  *  deletes a Text out of memory
    85  *
    86  * This also ereases the text from the textList of the TextEngine
    87 */
    88 Text::~Text()
    89 {
    90   if (this->font != NULL)
    91     ResourceManager::getInstance()->unload(this->font);
    92 
    93   if (this->text)
    94     delete[] this->text;
    95 }
    96 
    97 void 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 
    114 /**
    115  * sets the Font of this Text to font
    116  * @param font the Font (normaly from the ResourceManager) to allocate to this Text
    117  */
    118 void 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  */
    130 void 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);
    137   if (tmpFont == NULL)
    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 /**
    147  *  sets the Type of this Text
    148  * @param type the type to set.
    149 */
    150 void Text::setType(TEXT_RENDER_TYPE type)
    151 {
    152   if (this->font != NULL && this->font->font)
    153     this->type = type;
    154   else
    155     this->type = TEXT_RENDER_DYNAMIC;
    156 }
    157 
    158 /**
    159  *  Sets a new Text to the font
    160  * @param text the new text to set
    161 */
    162 void Text::setText(const char* text, bool isExtern)
    163 {
    164   if (isExtern)
    165   {
    166     this->externText = text;
    167 
    168     if (unlikely(this->text != NULL))
    169     {
    170       delete[] this->text;
    171       this->text = NULL;
    172     }
    173   }
    174   else
    175   {
    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
    185       this->text = NULL;
    186   }
    187 
    188   // setting up the Text-Width if DYNAMIC
    189   if (this->type & TEXT_RENDER_DYNAMIC && this->getAlignment() != TEXT_ALIGN_LEFT && this->font != NULL)
    190     {
    191       Glyph** glyphArray = this->font->getGlyphArray();
    192 
    193       int width = 0;
    194       const char* tmpText = this->externText;
    195       if (this->externText == NULL)
    196         tmpText = this->text;
    197       if (tmpText != NULL)
    198       {
    199         while (*tmpText != '\0')
    200         {
    201           if(glyphArray[*tmpText])
    202           {
    203             width += glyphArray[*tmpText]->width;
    204           }
    205           tmpText++;
    206         }
    207         this->width = width;
    208       }
    209     }
    210 }
    211 
    212 /**
    213  *  creates a texture out of the given parameters
    214 
    215    this has to be called every time by the user, to if changes were made.
    216    this is only for TEXT_STATIC-mode
    217 */
    218 void Text::createTexture()
    219 {
    220   SDL_Surface* tmpSurf;
    221   if (this->texture)
    222     glDeleteTextures(1, &this->texture);
    223   if (likely(this->font != NULL))
    224   {
    225     SDL_Color theColor = { (int)(this->color.x*255), (int)(this->color.y*255), (int)(this->color.z*255) };
    226     tmpSurf = TTF_RenderText_Blended(this->font->font,
    227                                      this->text,
    228                                      theColor);
    229   }
    230   if (tmpSurf)
    231     this->texture = loadTexture(tmpSurf, &this->texCoord);
    232 
    233   this->width = tmpSurf->w;
    234   this->height = tmpSurf->h;
    235   SDL_FreeSurface(tmpSurf);
    236 }
    237 
    238 /**
    239  *  draws the Text
    240 */
    241 void Text::draw() const
    242 {
    243   glPushMatrix();
    244   // transform for alignment.
    245   if (this->getAlignment() == TEXT_ALIGN_RIGHT)
    246     glTranslatef(-this->width, 0, 0);
    247   else if (this->getAlignment() == TEXT_ALIGN_CENTER || this->getAlignment() == TEXT_ALIGN_SCREEN_CENTER)
    248     glTranslatef(-this->width/2, 0, 0);
    249 
    250   // drawing this Text.
    251   // setting the Blending effects
    252   glColor4f(this->color.x, this->color.y, this->color.z, this->blending);
    253   glEnable(GL_BLEND);
    254   glEnable(GL_TEXTURE_2D);
    255   glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    256 
    257   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GL_MODULATE );
    258 
    259   if(likely(type & TEXT_RENDER_DYNAMIC ))
    260     {
    261       Glyph** glyphArray;
    262       if (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);
    275 //      glRotatef(this->getAbsDir2D(), 0,0,1);
    276       const char* tmpText = this->externText;
    277       if (this->externText == NULL)
    278         tmpText = this->text;
    279       if (likely(tmpText != NULL))
    280       {
    281         while (likely(*tmpText != '\0'))
    282         {
    283           if(likely(glyphArray[*tmpText] != NULL))
    284           {
    285             glCallList(glyphArray[*tmpText]->displayList);
    286             glTranslatef(glyphArray[*tmpText]->width, 0, 0);
    287           }
    288           tmpText++;
    289         }
    290       }
    291     }
    292   else //(if type & TEXT_RENDER_STATIC)
    293     {
    294       glBindTexture(GL_TEXTURE_2D, this->texture);
    295       glBegin(GL_QUADS);
    296 
    297       glTexCoord2f(this->texCoord.minU, this->texCoord.minV);
    298       glVertex2f(this->getAbsCoor2D().x,   this->getAbsCoor2D().y  );
    299 
    300       glTexCoord2f(this->texCoord.maxU, this->texCoord.minV);
    301       glVertex2f(this->getAbsCoor2D().x + this->width, this->getAbsCoor2D().y  );
    302 
    303       glTexCoord2f(this->texCoord.maxU, this->texCoord.maxV);
    304       glVertex2f(this->getAbsCoor2D().x + this->width, getAbsCoor2D().y + this->height);
    305 
    306       glTexCoord2f(this->texCoord.minU, this->texCoord.maxV);
    307       glVertex2f(getAbsCoor2D().x, getAbsCoor2D().y + this->height);
    308 
    309       glEnd();
    310 
    311     }
    312   glPopMatrix();
    313 }
    314 
    315 /**
    316  *  prints out some nice debug information about this text
    317 */
    318 void Text::debug() const
    319 {
    320   if (this->externText == NULL)
    321     PRINT(0)("=== TEXT: %s ===\n", this->text);
    322   else
    323     PRINT(0)("=== TEXT: %s ===\n", this->externText);
    324 
    325   if (this->getBindNode())
    326     PRINT(0)("is bind to %s; ref=%p\n", this->getBindNode()->getName(), this->getBindNode());
    327   PRINT(0)("Color: %0.2f %0.2f %0.2f\n", this->color.x, this->color.y, this->color.z);
    328 }
    329 
    330 
    331 ////////////
    332 /// UTIL ///
    333 ////////////
    334 /**
    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
    339 */
    340 GLuint 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;
    348 
    349   /* Use the surface width and height expanded to powers of 2 */
    350   w = powerOfTwo(surface->w);
    351   h = powerOfTwo(surface->h);
    352   if (texCoord != NULL)
    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,
    360                                w, h,
    361                                32,
    362 #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
    363                                0x000000FF,
    364                                0x0000FF00,
    365                                0x00FF0000,
    366                                0xFF000000
    367 #else
    368                                0xFF000000,
    369                                0x00FF0000,
    370                                0x0000FF00,
    371                                0x000000FF
    372 #endif
    373                                );
    374   if ( image == NULL ) {
    375     return 0;
    376   }
    377 
    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   }
    384 
    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);
    391 
    392   /* Restore the alpha blending attributes */
    393   if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
    394     SDL_SetAlpha(surface, saved_flags, saved_alpha);
    395   }
    396 
    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,
    403                0,
    404                GL_RGBA,
    405                w, h,
    406                0,
    407                GL_RGBA,
    408                GL_UNSIGNED_BYTE,
    409                image->pixels);
    410   SDL_FreeSurface(image); /* No longer needed the data */
    411 
    412   return texture;
    413 }
    414 
    415 /**
    416  *  Quick utility function for texture creation
    417  * @param input an integer
    418  * @returns the next bigger 2^n-integer than input
    419 */
    420 int Text::powerOfTwo(int input)
    421 {
    422   int value = 1;
    423 
    424   while ( value < input )
    425     value <<= 1;
    426   return value;
    427 }
    428 
    429 
    430 ////////////
    431 /// FONT ///
    432 ////////////
    433 /**
    434  * constructs a Font
    435  * @param fontFile the File to load the font from
    436  * @param fontSize the Size of the Font in Pixels
    437  */
    438 Font::Font(const char* fontFile, unsigned int fontSize)
    439 {
    440   this->init();
    441 
    442   this->setSize(fontSize);
    443 
    444   if (fontFile != NULL)
    445     this->loadFont(fontFile);
    446 
    447   this->setStyle("c");//TTF_STYLE_NORMAL);
    448 
    449   this->fastTextureID = this->createFastTexture();
    450 
    451 
    452 //  this->createAsciiImage("test.bmp");
    453 }
    454 
    455 /**
    456  * constructs a Font
    457  * @param fontFile the File to load the font from
    458  * @param fontSize the Size of the Font in Pixels
    459  */
    460 Font::Font(char** xpmArray)
    461 {
    462   this->init();
    463 
    464   //  this->setSize(fontSize);
    465   SDL_Surface* image = NULL;
    466   if (xpmArray != NULL)
    467     image = IMG_ReadXPMFromArray(xpmArray);
    468   if (image != NULL)
    469   {
    470     this->loadFontFromSDL_Surface(image);
    471     SDL_FreeSurface(image);
    472   }
    473   else
    474     PRINTF(1)("loading from surface failed: %s\n", IMG_GetError());
    475 
    476 }
    477 
    478 
    479 /**
    480  * destructs a font
    481  * this releases the memory a font uses to be opened.
    482  * deletes the glLists, and the TTF-handler, if present.
    483  */
    484 Font::~Font()
    485 {
    486   // deleting all Glyphs
    487   if (this->glyphArray != NULL)
    488     {
    489       for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
    490       {
    491         if (this->glyphArray[i] != NULL)
    492         {
    493           glDeleteLists(this->glyphArray[i]->displayList, 1);
    494           delete this->glyphArray[i];
    495         }
    496       }
    497       delete[] this->glyphArray;
    498     }
    499 
    500   // erease this font out of the memory.
    501   if (likely(this->font != NULL))
    502     TTF_CloseFont(this->font);
    503 }
    504 
    505 /**
    506  * initializes a Font (with default values)
    507  */
    508 void Font::init()
    509 {
    510     this->setClassID(CL_FONT, "Font");
    511   // setting default values.
    512   this->font = NULL;
    513   this->glyphArray = NULL;
    514   this->fastTextureID = 0;
    515 }
    516 
    517 
    518 /**
    519  * sets The Font.
    520  * @param fontFile The file containing the font.
    521  * @returns true if loaded, false if something went wrong, or if a font was loaded before.
    522 */
    523 bool Font::loadFont(const char* fontFile)
    524 {
    525   if (!this->getName())
    526     {
    527       this->setName(fontFile);
    528 
    529       this->font = TTF_OpenFont(this->getName(), this->fontSize);
    530       if(!this->font)
    531         {
    532           PRINTF(1)("TTF_OpenFont: %s\n", TTF_GetError());
    533           return false;
    534         }
    535       else
    536           return true;
    537     }
    538   else
    539     {
    540       PRINTF(2)("Font already initialized, unable to change it now.\n");
    541       return false;
    542     }
    543 }
    544 
    545 /**
    546  * loads a font From an XPM-array.
    547  * @param xpmArray the array of the XPM to load the font from.
    548  */
    549 bool Font::loadFontFromSDL_Surface(SDL_Surface* surface)
    550 {
    551   // loading to a texture.
    552   if(surface == NULL)
    553     return false;
    554   TexCoord texCoord;
    555   this->fastTextureID = Text::loadTexture(surface, &texCoord);
    556 
    557   // initializing the Glyphs.
    558   if (this->glyphArray == NULL)
    559   {
    560     float cx,cy;
    561     Glyph* glyph;
    562     this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
    563     for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
    564     {
    565       glyph = this->glyphArray[i] = new Glyph;
    566       glyph->displayList = glGenLists(1);
    567       if (!glIsList(glyph->displayList))
    568       {
    569         PRINTF(2)("Error creating glList for Font character %c\n", i);
    570         this->glyphArray[i] = NULL;
    571         delete glyph;
    572         continue;
    573       }
    574       cx=(float)(i%16)/16.0f;                  // X Position Of Current Character
    575       cy=(float)(i/16)/16.0f;                  // Y Position Of Current Character
    576       glNewList(glyph->displayList, GL_COMPILE); // Start Building A List
    577        glBegin(GL_QUADS);                           // Use A Quad For Each Character
    578         glTexCoord2f(cx, cy+0.001f);            // Texture Coord (Bottom Left)
    579         glVertex2d(0,-16);                            // Vertex Coord (Bottom Left)
    580         glTexCoord2f(cx+0.0625f, cy+0.001f);    // Texture Coord (Bottom Right)
    581         glVertex2i(16,-16);                           // Vertex Coord (Bottom Right)
    582         glTexCoord2f(cx+0.0625f, cy+0.0625f);     // Texture Coord (Top Right)
    583         glVertex2i(16,0);                            // Vertex Coord (Top Right)
    584         glTexCoord2f(cx, cy+0.0625f);             // Texture Coord (Top Left)
    585         glVertex2i(0,0);                             // Vertex Coord (Top Left)
    586        glEnd();                                     // Done Building Our Quad (Character)
    587 //       glTranslated(12,0,0);                        // Move To The Right Of The Character
    588       glEndList();                                 // Done Building The Display List
    589       this->glyphArray[i]->width = 12;
    590     }
    591   }
    592   return true;
    593 }
    594 
    595 
    596 /**
    597  *  sets a specific renderStyle
    598  * @param renderStyle the Style to render: a char-array containing:
    599    i: italic, b: bold, u, underline
    600 */
    601 void Font::setStyle(const char* renderStyle)
    602 {
    603   this->renderStyle = TTF_STYLE_NORMAL;
    604 
    605   for (int i = 0; i < strlen(renderStyle); i++)
    606     if (strncmp(renderStyle+i, "b", 1) == 0)
    607       this->renderStyle |= TTF_STYLE_BOLD;
    608     else if (strncmp(renderStyle+i, "i", 1) == 0)
    609       this->renderStyle |= TTF_STYLE_ITALIC;
    610     else if (strncmp(renderStyle+i, "u", 1) == 0)
    611       this->renderStyle |= TTF_STYLE_UNDERLINE;
    612 
    613   if (likely(this->font != NULL))
    614     TTF_SetFontStyle(this->font, this->renderStyle);
    615   else
    616     PRINTF(2)("Font was not initialized, please do so before setting the Font-Style.\n");
    617 }
    618 
    619 /**
    620  *  Sets a new Size to the font
    621  * @param fontSize The new Size in pixels.
    622 */
    623 void Font::setSize(unsigned int fontSize)
    624 {
    625   this->fontSize = fontSize;
    626 }
    627 
    628 Font* Font::defaultFont = NULL;
    629 
    630 void Font::createAsciiImage(const char* fileName)
    631 {
    632   if (this->font == NULL)
    633     return;
    634   int height = this->getMaxHeight();
    635 
    636   //
    637   SDL_Color tmpColor = {0, 0, 0};
    638   // Surface definition.
    639   SDL_Rect tmpRect; // this represents a Rectangle for blitting.
    640   SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(SDL_SWSURFACE,
    641       height*16, height*16,
    642       32,
    643 #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
    644                                                0x000000FF,
    645                                                0x0000FF00,
    646                                                0x00FF0000,
    647                                                0xFF000000
    648 #else
    649                                                    0xFF000000,
    650                                                0x00FF0000,
    651                                                0x0000FF00,
    652                                                0x000000FF
    653 #endif
    654                                                 );
    655     tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h;
    656     SDL_SetClipRect(tmpSurf, &tmpRect);
    657     int maxLineHeight = 0;
    658 
    659     int posX, posY;
    660   // all the interessting Glyphs
    661     for (posY = 0; posY < 16; posY++)
    662     {
    663       for (posX = 0; posX < 16; posX++)
    664       {
    665         SDL_Surface* glyphSurf = NULL;
    666         if (likely(this->font != NULL))
    667         {
    668           SDL_Color white = {255, 255, 255};
    669           glyphSurf = TTF_RenderGlyph_Blended(this->font, posX+16*posY, white);
    670         }
    671         if( glyphSurf != NULL )
    672         {
    673           tmpRect.x = height*posX;
    674           tmpRect.y = height*posY;
    675           SDL_SetAlpha(glyphSurf, 0, 0);
    676 
    677           SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect);
    678           SDL_FreeSurface(glyphSurf);
    679               // Outputting Glyphs to BMP-files.
    680 /*
    681           char outname[512];
    682           if (i < 10)
    683           sprintf( outname, "%s-glyph-00%d.bmp", this->getName(), i );
    684           else if (i <100)
    685           sprintf( outname, "%s-glyph-0%d.bmp", this->getName(), i );
    686           else
    687           sprintf( outname, "%s-glyph-%d.bmp", this->getName(), i );
    688           SDL_SaveBMP(tmpSurf, outname);*/
    689 
    690         }
    691       }
    692     }
    693     SDL_SaveBMP(tmpSurf, fileName);
    694     SDL_FreeSurface(tmpSurf);
    695 }
    696 
    697 /**
    698  * initializes the default font
    699  */
    700 void Font::initDefaultFont()
    701 {
    702   if (Font::defaultFont == NULL)
    703     Font::defaultFont = new Font(font_xpm);
    704 }
    705 
    706 /**
    707  * deletes the default font
    708  */
    709 void Font::removeDefaultFont()
    710 {
    711   if (Font::defaultFont != NULL)
    712     delete Font::defaultFont;
    713   Font::defaultFont = NULL;
    714 }
    715 
    716 
    717 /**
    718  * @returns the maximum height of the Font, if the font was initialized, 0 otherwise
    719 */
    720 int Font::getMaxHeight()
    721 {
    722   if (likely (this->font != NULL))
    723     return TTF_FontHeight(this->font);
    724   else
    725     return 0;
    726 }
    727 
    728 /**
    729  * @returns the maximum ascent of the Font, if the font was initialized, 0 otherwise
    730 
    731    the ascent is the pixels of the font above the baseline
    732 */
    733 int Font::getMaxAscent()
    734 {
    735   if (likely(this->font != NULL))
    736     return TTF_FontAscent(this->font);
    737   else
    738     return 0;
    739 }
    740 
    741 /**
    742  * @returns the maximum descent of the Font, if the font was initialized, 0 otherwise
    743 
    744    the descent is the pixels of the font below the baseline
    745 */
    746 int Font::getMaxDescent()
    747 {
    748   if (likely(this->font != NULL))
    749     return TTF_FontDescent(this->font);
    750   else
    751     return 0;
    752 }
    753 
    754 /**
    755  * @param character The character to get info about.
    756  * @returns a Glyph struct of a character. This Glyph is a pointer,
    757    and MUST be deleted by the user..
    758 
    759    This only works for horizontal fonts. see
    760    http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html
    761    for more info about vertical Fonts
    762 */
    763 Glyph* Font::getGlyphMetrics(Uint16 character)
    764 {
    765   Glyph* rg = new Glyph;
    766   rg->character = character;
    767   if (likely (this->font!= NULL))
    768     TTF_GlyphMetrics(this->font, rg->character,
    769                      &rg->minX, &rg->maxX,
    770                      &rg->minY, &rg->maxY,
    771                      &rg->advance);
    772   rg->height = rg->maxY - rg->minY;
    773   rg->width = rg->maxX - rg->minX;
    774   rg->bearingX = (rg->advance - rg->width) / 2;
    775   rg->bearingY = rg->maxY;
    776   return rg;
    777 }
    778 
    779 /**
    780  * creates a Fast-Texture of this Font
    781  */
    782 GLuint Font::createFastTexture()
    783 {
    784   /* interesting GLYPHS:
    785    *  32: space
    786    *  33-47: Special Characters.
    787    *  48-57: 0-9
    788    *  58-63: some more special chars (minor)
    789    *  65-90: A-Z
    790    *  97-122: a-z
    791    */
    792   int numberOfGlyphs = 91;
    793 
    794   this->initGlyphs(32, numberOfGlyphs);
    795   this->glyphArray[32]->width = fontSize/2; //!< @todo find out the real size of a Space
    796 
    797   int rectSize = this->findOptimalFastTextureSize();
    798 
    799   // setting default values. (maybe not needed afterwards)
    800   SDL_Color tmpColor;  tmpColor.r = tmpColor.g = tmpColor.b = 0;
    801   // Surface definition.
    802   SDL_Rect tmpRect; // this represents a Rectangle for blitting.
    803   SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(SDL_SWSURFACE,
    804                                                rectSize, rectSize,
    805                                                32,
    806 #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
    807                                                0x000000FF,
    808                                                0x0000FF00,
    809                                                0x00FF0000,
    810                                                0xFF000000
    811 #else
    812                                                0xFF000000,
    813                                                0x00FF0000,
    814                                                0x0000FF00,
    815                                                0x000000FF
    816 #endif
    817                                                );
    818   tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h;
    819   SDL_SetClipRect(tmpSurf, &tmpRect);
    820   int maxLineHeight = 0;
    821 
    822   // all the interessting Glyphs
    823   for (int i = 0; i < 128; i++)
    824     {
    825       SDL_Surface* glyphSurf = NULL;
    826       Glyph* tmpGlyph;
    827 
    828       if (tmpGlyph = this->glyphArray[i])
    829         {
    830           if (tmpGlyph->height > maxLineHeight)
    831             maxLineHeight = tmpGlyph->height;
    832 
    833           if (tmpRect.x+tmpGlyph->advance > tmpSurf->w)
    834             {
    835               tmpRect.x = 0;
    836               tmpRect.y = tmpRect.y + maxLineHeight + 1;
    837               maxLineHeight = 0;
    838             }
    839           if (tmpRect.y + maxLineHeight > tmpSurf->h)
    840             {
    841               PRINTF(1)("Protection, so font cannot write over the boundraries error (this should not heappen\n");
    842               break;
    843             }
    844           // reading in the new Glyph
    845           if (likely(this->font != NULL))
    846           {
    847             SDL_Color white = {255, 255, 255};
    848             glyphSurf = TTF_RenderGlyph_Blended(this->font, i, white);
    849           }
    850           if( glyphSurf != NULL )
    851             {
    852               SDL_SetAlpha(glyphSurf, 0, 0);
    853 
    854               SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect);
    855               TexCoord tmpTexCoord;
    856               tmpTexCoord.minU = (float)tmpRect.x/(float)tmpSurf->w;
    857               tmpTexCoord.maxU = (float)(tmpRect.x + tmpGlyph->advance)/(float)tmpSurf->w;
    858               tmpTexCoord.minV = (float)(tmpRect.y)/(float)tmpSurf->w;
    859               tmpTexCoord.maxV = (float)(tmpRect.y+tmpGlyph->height)/(float)tmpSurf->w;
    860               tmpGlyph->displayList = glGenLists(1);
    861 
    862               glNewList(tmpGlyph->displayList, GL_COMPILE);
    863               glBegin(GL_QUADS);
    864               glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.minV);
    865               glVertex2d(0, - tmpGlyph->bearingY);
    866               glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.maxV);
    867               glVertex2d(0, tmpGlyph->height - tmpGlyph->bearingY);
    868               glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.maxV);
    869               glVertex2d(tmpGlyph->width, tmpGlyph->height - tmpGlyph->bearingY);
    870               glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.minV);
    871               glVertex2d(tmpGlyph->width, - tmpGlyph->bearingY);
    872               glEnd();
    873               glEndList();
    874               SDL_FreeSurface(glyphSurf);
    875 
    876               tmpRect.x += tmpGlyph->advance;
    877 
    878               // Outputting Glyphs to BMP-files.
    879 /*
    880                 char outname[512];
    881                 if (i < 10)
    882                 sprintf( outname, "%s-glyph-00%d.bmp", this->getName(), i );
    883                 else if (i <100)
    884                   sprintf( outname, "%s-glyph-0%d.bmp", this->getName(), i );
    885                 else
    886                   sprintf( outname, "%s-glyph-%d.bmp", this->getName(), i );
    887                 SDL_SaveBMP(tmpSurf, outname);*/
    888 
    889             }
    890         }
    891     }
    892 
    893   GLuint texture;
    894   glGenTextures(1, &texture);
    895   glBindTexture(GL_TEXTURE_2D, texture);
    896   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    897   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    898   glTexImage2D(GL_TEXTURE_2D,
    899                0,
    900                GL_RGBA,
    901                tmpSurf->w, tmpSurf->h,
    902                0,
    903                GL_RGBA,
    904                GL_UNSIGNED_BYTE,
    905                tmpSurf->pixels);
    906   SDL_FreeSurface(tmpSurf);
    907   return texture;
    908 }
    909 
    910 /**
    911  *  stores Glyph Metrics in an Array.
    912  * @param from The Glyph to start from.
    913  * @param count The number of Glyphs to start From.
    914 */
    915 void Font::initGlyphs(Uint16 from, Uint16 count)
    916 {
    917   /* initialize the Array, and set all its entries to NULL
    918    *  only if the Glyph-array has not been initialized
    919    */
    920   if (!this->glyphArray)
    921     {
    922       this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
    923       for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
    924         this->glyphArray[i] = NULL;
    925     }
    926 
    927   Uint16 lastGlyph = from + count;
    928 
    929   for (int i = from; i <= lastGlyph; i++)
    930     {
    931       // setting up all the Glyphs we like.
    932       glyphArray[i] = getGlyphMetrics(i);
    933     }
    934   return;
    935 }
    936 
    937 /**
    938  * @returns the optimal size to use as the texture size
    939 
    940    @todo: this algorithm can be a lot more faster, althought it does
    941    not really matter within the init-context, and 128 glyphs.
    942 
    943    This function searches for a 2^n sizes texture-size, this is for
    944    openGL-version < 1.2 compatibility ( and because it is realy easy like this :))
    945 */
    946 int Font::findOptimalFastTextureSize()
    947 {
    948   int i;
    949   int x,y; // the counters
    950   int maxLineHeight = this->getMaxHeight();
    951   unsigned int size = 32;  // starting Value, we have to start somewhere 32 seems reasonable. (take any small enough 2^i number)
    952   bool sizeOK = false;
    953   Glyph* tmpGlyph;
    954 
    955   while (!sizeOK)
    956     {
    957       x = 0; y = 0;
    958       for (i = 0; i <= FONT_HIGHEST_KNOWN_CHAR; i++)
    959         {
    960           if((tmpGlyph = this->glyphArray[i]) != NULL)
    961             {
    962               // getting the height of the highest Glyph in the Line.
    963               if (tmpGlyph->height > maxLineHeight)
    964                 maxLineHeight = tmpGlyph->height;
    965 
    966               if (x + tmpGlyph->advance > size)
    967                 {
    968                   x = 0;
    969                   y = y + maxLineHeight;
    970                   //maxLineHeight = 0;
    971                 }
    972               if (y + maxLineHeight + 1 > size)
    973                 break;
    974               x += tmpGlyph->advance;
    975 
    976             }
    977         }
    978       if (i >= FONT_HIGHEST_KNOWN_CHAR-1 || size > 8192)
    979         sizeOK = true;
    980       else
    981         size *= 2;
    982     }
    983     return size;
    984 }
    985 
    986 
    987 /**
    988  *  a simple function to get some interesting information about this class
    989 */
    990 void Font::debug()
    991 {
    992   // print the loaded font's style
    993   int style;
    994   if (likely(this->font != NULL))
    995     style = TTF_GetFontStyle(this->font);
    996   PRINTF(0)("The font style is:");
    997   if(style==TTF_STYLE_NORMAL)
    998     PRINTF(0)(" normal");
    999   else {
    1000     if(style&TTF_STYLE_BOLD)
    1001       PRINTF(0)(" bold");
    1002     if(style&TTF_STYLE_ITALIC)
    1003       PRINTF(0)(" italic");
    1004     if(style&TTF_STYLE_UNDERLINE)
    1005       PRINTF(0)(" underline");
    1006   }
    1007   PRINTF(0)("\n");
    1008 }
    1009 
    101040
    101141///////////////////
  • trunk/src/lib/graphics/text_engine/text_engine.h

    r5342 r5343  
    1717#define _TEXT_ENGINE_H
    1818
    19 
    20 #include "glincl.h"
    21 
    22 #ifdef HAVE_SDL_TTF_H
    23 #include <SDL_ttf.h>
    24 #else
    25 #include <SDL/SDL_ttf.h>
    26 #endif
    27 
    2819#include "base_object.h"
    29 #include "element_2d.h"
     20#include "font.h"
     21#include "text.h"
    3022
    3123#include "vector.h"
     
    3426class PNode;
    3527class Font;
    36 
    37 #define  TEXT_ALIGN_LEFT             E2D_ALIGN_LEFT
    38 #define  TEXT_ALIGN_RIGHT            E2D_ALIGN_RIGHT
    39 #define  TEXT_ALIGN_CENTER           E2D_ALIGN_CENTER
    40 #define  TEXT_ALIGN_SCREEN_CENTER    E2D_ALIGN_SCREEN_CENTER
    41 #define  TEXT_DEFAULT_COLOR          Vector(1.0, 1.0, 1.0)      //!< the default Color (white)
    42 #define  TEXT_DEFAULT_BLENDING       1.0f                       //!< the default blending of the text, (no blending at all)
    43 
    44 /* some default values */
    45 #define FONT_DEFAULT_SIZE            50                         //!< default size of the Text
    46 #define FONT_NUM_COLORS              256                        //!< number of colors.
    47 
    48 #define FONT_HIGHEST_KNOWN_CHAR      128                        //!< The highest character known to the textEngine.
    49 
    50 #define TEXT_DEFAULT_ALIGNMENT       TEXT_ALIGN_CENTER          //!< default alignment
    51 
    52 typedef enum TEXT_RENDER_TYPE
    53 {
    54   TEXT_RENDER_STATIC      = 1,
    55   TEXT_RENDER_DYNAMIC     = 2
    56 };
    57 /**
    58  * STATIC means: a font, that is only one GL-face.
    59  ** it is very fast, and can be used for all text
    60  ** that does not have to be changed anymore, or if
    61  ** the the text should look very nice
    62  * DYNAMIC means: a very fast font, that will is build
    63  ** from multiple quads.
    64  ** Use this type, if you want to create fast changing
    65  ** text like a counter.
    66  */
    67 
    68 
    69 //! A Struct to handel Texture Coordinates for quads
    70 struct TexCoord
    71 {
    72   float    minU;              //!< The minimum U-Coordinate
    73   float    maxU;              //!< The maximum U-Coordinate
    74   float    minV;              //!< The minimum V-Coordinate
    75   float    maxV;              //!< The maximum V-Coordinate
    76 };
    77 
    78 //! A struct for handling glyphs
    79 /**
    80    a Glyph is one letter of a certain font
    81 */
    82 struct Glyph
    83 {
    84   // Glyph-specific (size and so on)
    85   Uint16   character;         //!< The character
    86   int      minX;              //!< The minimum distance from the origin in X
    87   int      maxX;              //!< The maximum distance from the origin in X
    88   int      minY;              //!< The minimum distance from the origin in Y
    89   int      maxY;              //!< The maximum distance from the origin in Y
    90   int      width;             //!< The width of the Glyph
    91   int      height;            //!< The height of the Glyph
    92   int      bearingX;          //!< How much is right of the Origin
    93   int      bearingY;          //!< How much is above the Origin
    94   int      advance;           //!< How big a Glyph would be in monospace-mode
    95 
    96   // OpenGL-specific
    97   //  TexCoord texCoord;      //!< A Texture Coordinate for this glyph.
    98   GLuint   displayList;       //!< DiplayList to render this Glyph.
    99 };
    100 
    101 ////////////
    102 /// TEXT ///
    103 ////////////
    104 //! Represents one textElement.
    105 class Text : public Element2D
    106 {
    107   friend class TextEngine;
    108  public:
    109    Text(const char* fontFile, unsigned int fontSize = FONT_DEFAULT_SIZE, TEXT_RENDER_TYPE type = TEXT_RENDER_DYNAMIC);
    110   ~Text();
    111 
    112   void init();
    113 
    114   void setFont(const char* fontFile, unsigned int fontSize);
    115   void setType(TEXT_RENDER_TYPE type);
    116   void setText(const char* text, bool isExtern = false);
    117   /** @returns the String this Text displays */
    118   inline const char* getText() const { return (externText == NULL)?this->text:this->externText; };
    119   /** @param blending the blending intensity to set (between 0.0 and 1.0) */
    120   inline void setBlending(float blending) { this->blending = blending; };
    121 
    122   /** sets the Color of the Text to render (values in [0-1]) @param r red @param g green @param b blue */
    123   void setColor(float r, float g, float b) { this->color = Vector(r,g,b); };
    124 
    125   void createTexture();
    126 
    127   virtual void draw() const;
    128 
    129   void debug() const;
    130 
    131   // helpers.
    132   static GLuint loadTexture(SDL_Surface* surface, TexCoord* texCoord);
    133   static int powerOfTwo(int input);
    134 
    135  private:
    136    Text(Font* font = NULL, TEXT_RENDER_TYPE type = TEXT_RENDER_DYNAMIC);
    137    void setFont(Font* font);
    138 
    139 
    140  private:
    141   Font*             font;           //!< Font of this text
    142 
    143   TEXT_RENDER_TYPE  type;           //!< The type of this Font.
    144   char*             text;           //!< The text to display
    145   const char*       externText;     //!< the text to Display from an external Source.
    146   Vector            color;          //!< The color of the font.
    147   float             blending;       //!< The blending intensity.
    148 
    149   // placement in openGL
    150   GLuint            texture;        //!< A GL-texture to hold the text
    151   TexCoord          texCoord;       //!< Texture-coordinates @todo fix this to have a struct
    152   float             height;
    153   float             width;
    154 };
    155 
    156 ////////////
    157 /// FONT ///
    158 ////////////
    159 //! A class to handle a Font of a certain ttf-File, Size and Color.
    160 class Font : public BaseObject
    161 {
    162   friend class Text;
    163 
    164  public:
    165   Font(const char* fontFile,
    166        unsigned int fontSize = FONT_DEFAULT_SIZE);
    167   Font(char** xpmArray);
    168   virtual ~Font();
    169 
    170   void init();
    171 
    172   // font
    173   bool loadFont(const char* fontFile);
    174   bool loadFontFromSDL_Surface(SDL_Surface* surface);
    175 
    176   void setSize(unsigned int fontSize);
    177   void setStyle(const char* renderStyle);
    178 
    179   /** @returns a Pointer to the Array of Glyphs */
    180   inline Glyph** getGlyphArray() const { return this->glyphArray; };
    181   /** @returns the texture to the fast-texture */
    182   inline GLuint getFastTextureID() const { return this->fastTextureID; };
    183   /** @returns the default Font */
    184   inline static Font* getDefaultFont() { return Font::defaultFont; };
    185 
    186   void createAsciiImage(const char* fileName);
    187   static void initDefaultFont();
    188   static void removeDefaultFont();
    189 
    190  private:
    191   int getMaxHeight();
    192   int getMaxAscent();
    193   int getMaxDescent();
    194   Glyph* getGlyphMetrics(Uint16 character);
    195 
    196   GLuint createFastTexture();
    197 
    198   void initGlyphs(Uint16 from, Uint16 count);
    199   int findOptimalFastTextureSize();
    200 
    201   void debug();
    202 
    203  private:
    204   static Font*  defaultFont;         //!< a default font, that is used, if other fonts were unable to be loaded.
    205   // information about the Font
    206   TTF_Font*     font;                //!< The font we use for this.
    207   unsigned int  fontSize;            //!< The size of the font in pixels. each Font has one size.
    208   int           renderStyle;         //!< The Renderstyle
    209 
    210   Glyph**       glyphArray;          //!< An Array of all the Glyphs stored in the Array of Glyphs.
    211   GLuint        fastTextureID;       //!< The fast textureID.
    212 
    213   tList<Text>*  textList;            //!< A list of texts this Font is mapped to.
    214 };
    21528
    21629///////////////////
     
    22639
    22740  Text* createText(const char* fontFile,
    228                    unsigned int fontSize = FONT_DEFAULT_SIZE,
     41                   unsigned int fontSize = TEXT_DEFAULT_SIZE,
    22942                   int textType = TEXT_RENDER_DYNAMIC);
    23043
Note: See TracChangeset for help on using the changeset viewer.