Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

orxonox/trunk: split open the text-engine

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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///////////////////
Note: See TracChangeset for help on using the changeset viewer.