Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Changeset 5343 in orxonox.OLD for trunk/src/lib/graphics/text_engine/font.cc


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

orxonox/trunk: split open the text-engine

File:
1 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}
Note: See TracChangeset for help on using the changeset viewer.