Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: loading of text more modular

File size: 31.3 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14
15   for some fonts and licenses visit: =http://www.dafont.com/en/font.php=
16
17   !! IMPORTANT !! When using ttf fonts clear the license issues prior to
18   adding them to orxonox. This is really important, because we do not
19   want to offend anyone.
20*/
21
22#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_FONT
23
24#include "text_engine.h"
25
26using namespace std;
27
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31
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
40#include "graphics_engine.h"
41#include "resource_manager.h"
42#include "class_list.h"
43
44#include "p_node.h"
45#include "vector.h"
46#include "debug.h"
47#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 */
58Text::Text(const char* fontFile, unsigned int fontSize, TEXT_RENDER_TYPE type)
59{
60  this->init();
61
62  if (fontFile != NULL)
63    this->setFont(fontFile, fontSize);
64  this->setType(type);
65}
66
67/**
68 *  creates a new Text Element
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 */
75Text::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*/
88Text::~Text()
89{
90  if (this->font != NULL)
91    ResourceManager::getInstance()->unload(this->font);
92
93  if (this->text)
94    delete[] this->text;
95}
96
97void Text::init()
98{
99  this->setClassID(CL_TEXT, "Text");
100
101  // initialize this Text
102  this->font = NULL;
103  this->text = NULL;
104  this->externText = NULL;
105  this->setAlignment(TEXT_DEFAULT_ALIGNMENT);
106  this->texture = 0;
107  this->blending = TEXT_DEFAULT_BLENDING;
108  this->color = TEXT_DEFAULT_COLOR;
109  this->setType(TEXT_RENDER_DYNAMIC);
110
111  this->setText(NULL);
112}
113
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 */
118void Text::setFont(Font* font)
119{
120  if (this->font != NULL)
121    ResourceManager::getInstance()->unload(this->font);
122  this->font = font;
123}
124
125/**
126 * sets the Font of this Text to font from fontFile
127 * @param fontFile the File to load the Font from.
128 * @param fontSize the Size of the Font
129 */
130void Text::setFont(const char* fontFile, unsigned int fontSize)
131{
132  Font* tmpFont;
133  Text* newText;
134  Vector tmpVec;
135
136  tmpFont = (Font*)ResourceManager::getInstance()->load(fontFile, TTF, RP_GAME, &fontSize);
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*/
150void 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*/
162void 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*/
218void 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*/
241void 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 (false /*likely (this->font != NULL)*/)
263      {
264        glyphArray = this->font->getGlyphArray();
265        glBindTexture(GL_TEXTURE_2D, font->getFastTextureID());
266      }
267      else
268      {
269        if (unlikely(Font::getDefaultFont() == NULL))
270          Font::initDefaultFont();
271        glyphArray = Font::getDefaultFont()->getGlyphArray();
272        glBindTexture(GL_TEXTURE_2D, Font::getDefaultFont()->getFastTextureID());
273      }
274        glTranslatef(getAbsCoor2D().x, getAbsCoor2D().y, 0);
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().);
299
300      glTexCoord2f(this->texCoord.maxU, this->texCoord.minV);
301      glVertex2f(this->getAbsCoor2D().x + this->width, this->getAbsCoor2D().);
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*/
318void 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*/
340GLuint Text::loadTexture(SDL_Surface *surface, TexCoord* texCoord)
341{
342  GLuint texture;
343  int w, h;
344  SDL_Surface *image;
345  SDL_Rect area;
346  Uint32 saved_flags;
347  Uint8  saved_alpha;
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*/
420int 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 */
438Font::Font(const char* fontFile, unsigned int fontSize)
439{
440  this->setClassID(CL_FONT, "Font");
441  // setting default values.
442  this->font = NULL;
443  this->glyphArray = NULL;
444  this->fastTextureID = 0;
445
446  this->setSize(fontSize);
447
448  if (fontFile != NULL)
449    this->loadFont(fontFile);
450
451  this->setStyle("c");//TTF_STYLE_NORMAL);
452
453  this->fastTextureID = this->createFastTexture();
454
455
456//  this->createAsciiImage("test.bmp");
457}
458
459/**
460 * constructs a Font
461 * @param fontFile the File to load the font from
462 * @param fontSize the Size of the Font in Pixels
463 */
464Font::Font(char** xpmArray)
465{
466  this->setClassID(CL_FONT, "Font");
467  // setting default values.
468  this->font = NULL;
469  this->glyphArray = NULL;
470  this->fastTextureID = 0;
471
472//  this->setSize(fontSize);
473  SDL_Surface* image = NULL;
474  if (xpmArray != NULL)
475    image = IMG_ReadXPMFromArray(xpmArray);
476  if (image != NULL)
477  {
478    this->loadFontFromSDL_Surface(image);
479    SDL_FreeSurface(image);
480  }
481  else
482    PRINTF(1)("loading from surface failed: %s\n", IMG_GetError());
483
484}
485
486
487/**
488 * destructs a font
489 * this releases the memory a font uses to be opened.
490 * deletes the glLists, and the TTF-handler, if present.
491 */
492Font::~Font()
493{
494  // deleting all Glyphs
495  if (this->glyphArray != NULL)
496    {
497      for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
498      {
499        if (this->glyphArray[i] != NULL)
500        {
501          glDeleteLists(this->glyphArray[i]->displayList, 1);
502          delete this->glyphArray[i];
503        }
504      }
505      delete[] this->glyphArray;
506    }
507
508  // erease this font out of the memory.
509  if (likely(this->font != NULL))
510    TTF_CloseFont(this->font);
511}
512
513
514/**
515 * sets The Font.
516 * @param fontFile The file containing the font.
517 * @returns true if loaded, false if something went wrong, or if a font was loaded before.
518*/
519bool Font::loadFont(const char* fontFile)
520{
521  if (!this->getName())
522    {
523      this->setName(fontFile);
524
525      this->font = TTF_OpenFont(this->getName(), this->fontSize);
526      if(!this->font)
527        {
528          PRINTF(1)("TTF_OpenFont: %s\n", TTF_GetError());
529          return false;
530        }
531      else
532          return true;
533    }
534  else
535    {
536      PRINTF(2)("Font already initialized, unable to change it now.\n");
537      return false;
538    }
539}
540
541/**
542 * loads a font From an XPM-array.
543 * @param xpmArray the array of the XPM to load the font from.
544 */
545bool Font::loadFontFromSDL_Surface(SDL_Surface* surface)
546{
547  // loading to a texture.
548  if(surface == NULL)
549    return false;
550  TexCoord texCoord;
551  this->fastTextureID = Text::loadTexture(surface, &texCoord);
552
553  // initializing the Glyphs.
554  if (this->glyphArray == NULL)
555  {
556    float cx,cy;
557    Glyph* glyph;
558    this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
559    for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
560    {
561      glyph = this->glyphArray[i] = new Glyph;
562      glyph->displayList = glGenLists(1);
563      if (!glIsList(glyph->displayList))
564      {
565        PRINTF(2)("Error creating glList for Font character %c\n", i);
566        this->glyphArray[i] = NULL;
567        delete glyph;
568        continue;
569      }
570      cx=(float)(i%16)/16.0f;                  // X Position Of Current Character
571      cy=(float)(i/16)/16.0f;                  // Y Position Of Current Character
572      glNewList(glyph->displayList, GL_COMPILE); // Start Building A List
573       glBegin(GL_QUADS);                           // Use A Quad For Each Character
574        glTexCoord2f(cx, cy+0.001f);            // Texture Coord (Bottom Left)
575        glVertex2d(0,-16);                            // Vertex Coord (Bottom Left)
576        glTexCoord2f(cx+0.0625f, cy+0.001f);    // Texture Coord (Bottom Right)
577        glVertex2i(16,-16);                           // Vertex Coord (Bottom Right)
578        glTexCoord2f(cx+0.0625f, cy+0.0625f);     // Texture Coord (Top Right)
579        glVertex2i(16,0);                            // Vertex Coord (Top Right)
580        glTexCoord2f(cx, cy+0.0625f);             // Texture Coord (Top Left)
581        glVertex2i(0,0);                             // Vertex Coord (Top Left)
582       glEnd();                                     // Done Building Our Quad (Character)
583//       glTranslated(12,0,0);                        // Move To The Right Of The Character
584      glEndList();                                 // Done Building The Display List
585      this->glyphArray[i]->width = 12;
586    }
587  }
588  return true;
589}
590
591
592/**
593 *  sets a specific renderStyle
594 * @param renderStyle the Style to render: a char-array containing:
595   i: italic, b: bold, u, underline
596*/
597void Font::setStyle(const char* renderStyle)
598{
599  this->renderStyle = TTF_STYLE_NORMAL;
600
601  for (int i = 0; i < strlen(renderStyle); i++)
602    if (strncmp(renderStyle+i, "b", 1) == 0)
603      this->renderStyle |= TTF_STYLE_BOLD;
604    else if (strncmp(renderStyle+i, "i", 1) == 0)
605      this->renderStyle |= TTF_STYLE_ITALIC;
606    else if (strncmp(renderStyle+i, "u", 1) == 0)
607      this->renderStyle |= TTF_STYLE_UNDERLINE;
608
609  if (likely(this->font != NULL))
610    TTF_SetFontStyle(this->font, this->renderStyle);
611  else
612    PRINTF(2)("Font was not initialized, please do so before setting the Font-Style.\n");
613}
614
615/**
616 *  Sets a new Size to the font
617 * @param fontSize The new Size in pixels.
618*/
619void Font::setSize(unsigned int fontSize)
620{
621  this->fontSize = fontSize;
622}
623
624Font* Font::defaultFont = NULL;
625
626void Font::createAsciiImage(const char* fileName)
627{
628  if (this->font == NULL)
629    return;
630  int height = this->getMaxHeight();
631
632  //
633  SDL_Color tmpColor = {0, 0, 0};
634  // Surface definition.
635  SDL_Rect tmpRect; // this represents a Rectangle for blitting.
636  SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(SDL_SWSURFACE,
637      height*16, height*16,
638      32,
639#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
640                                               0x000000FF,
641                                               0x0000FF00,
642                                               0x00FF0000,
643                                               0xFF000000
644#else
645                                                   0xFF000000,
646                                               0x00FF0000,
647                                               0x0000FF00,
648                                               0x000000FF
649#endif
650                                                );
651    tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h;
652    SDL_SetClipRect(tmpSurf, &tmpRect);
653    int maxLineHeight = 0;
654
655    int posX, posY;
656  // all the interessting Glyphs
657    for (posY = 0; posY < 16; posY++)
658    {
659      for (posX = 0; posX < 16; posX++)
660      {
661        SDL_Surface* glyphSurf = NULL;
662        if (likely(this->font != NULL))
663        {
664          SDL_Color white = {255, 255, 255};
665          glyphSurf = TTF_RenderGlyph_Blended(this->font, posX+16*posY, white);
666        }
667        if( glyphSurf != NULL )
668        {
669          tmpRect.x = height*posX;
670          tmpRect.y = height*posY;
671          SDL_SetAlpha(glyphSurf, 0, 0);
672
673          SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect);
674          SDL_FreeSurface(glyphSurf);
675              // Outputting Glyphs to BMP-files.
676/*
677          char outname[512];
678          if (i < 10)
679          sprintf( outname, "%s-glyph-00%d.bmp", this->getName(), i );
680          else if (i <100)
681          sprintf( outname, "%s-glyph-0%d.bmp", this->getName(), i );
682          else
683          sprintf( outname, "%s-glyph-%d.bmp", this->getName(), i );
684          SDL_SaveBMP(tmpSurf, outname);*/
685
686        }
687      }
688    }
689    SDL_SaveBMP(tmpSurf, fileName);
690    SDL_FreeSurface(tmpSurf);
691}
692
693/**
694 * initializes the default font
695 */
696void Font::initDefaultFont()
697{
698  if (Font::defaultFont == NULL)
699    Font::defaultFont = new Font(font_xpm);
700}
701
702/**
703 * deletes the default font
704 */
705void Font::removeDefaultFont()
706{
707  if (Font::defaultFont != NULL)
708    delete Font::defaultFont;
709  Font::defaultFont = NULL;
710}
711
712
713/**
714 * @returns the maximum height of the Font, if the font was initialized, 0 otherwise
715*/
716int Font::getMaxHeight()
717{
718  if (likely (this->font != NULL))
719    return TTF_FontHeight(this->font);
720  else
721    return 0;
722}
723
724/**
725 * @returns the maximum ascent of the Font, if the font was initialized, 0 otherwise
726
727   the ascent is the pixels of the font above the baseline
728*/
729int Font::getMaxAscent()
730{
731  if (likely(this->font != NULL))
732    return TTF_FontAscent(this->font);
733  else
734    return 0;
735}
736
737/**
738 * @returns the maximum descent of the Font, if the font was initialized, 0 otherwise
739
740   the descent is the pixels of the font below the baseline
741*/
742int Font::getMaxDescent()
743{
744  if (likely(this->font != NULL))
745    return TTF_FontDescent(this->font);
746  else
747    return 0;
748}
749
750/**
751 * @param character The character to get info about.
752 * @returns a Glyph struct of a character. This Glyph is a pointer,
753   and MUST be deleted by the user..
754
755   This only works for horizontal fonts. see
756   http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html
757   for more info about vertical Fonts
758*/
759Glyph* Font::getGlyphMetrics(Uint16 character)
760{
761  Glyph* rg = new Glyph;
762  rg->character = character;
763  if (likely (this->font!= NULL))
764    TTF_GlyphMetrics(this->font, rg->character,
765                     &rg->minX, &rg->maxX,
766                     &rg->minY, &rg->maxY,
767                     &rg->advance);
768  rg->height = rg->maxY - rg->minY;
769  rg->width = rg->maxX - rg->minX;
770  rg->bearingX = (rg->advance - rg->width) / 2;
771  rg->bearingY = rg->maxY;
772  return rg;
773}
774
775/**
776 * creates a Fast-Texture of this Font
777 */
778GLuint Font::createFastTexture()
779{
780  /* interesting GLYPHS:
781   *  32: space
782   *  33-47: Special Characters.
783   *  48-57: 0-9
784   *  58-63: some more special chars (minor)
785   *  65-90: A-Z
786   *  97-122: a-z
787   */
788  int numberOfGlyphs = 91;
789
790  this->initGlyphs(32, numberOfGlyphs);
791  this->glyphArray[32]->width = fontSize/2; //!< @todo find out the real size of a Space
792
793  int rectSize = this->findOptimalFastTextureSize();
794
795  // setting default values. (maybe not needed afterwards)
796  SDL_Color tmpColor;  tmpColor.r = tmpColor.g = tmpColor.b = 0;
797  // Surface definition.
798  SDL_Rect tmpRect; // this represents a Rectangle for blitting.
799  SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(SDL_SWSURFACE,
800                                               rectSize, rectSize,
801                                               32,
802#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
803                                               0x000000FF,
804                                               0x0000FF00,
805                                               0x00FF0000,
806                                               0xFF000000
807#else
808                                               0xFF000000,
809                                               0x00FF0000,
810                                               0x0000FF00,
811                                               0x000000FF
812#endif
813                                               );
814  tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h;
815  SDL_SetClipRect(tmpSurf, &tmpRect);
816  int maxLineHeight = 0;
817
818  // all the interessting Glyphs
819  for (int i = 0; i < 128; i++)
820    {
821      SDL_Surface* glyphSurf = NULL;
822      Glyph* tmpGlyph;
823
824      if (tmpGlyph = this->glyphArray[i])
825        {
826          if (tmpGlyph->height > maxLineHeight)
827            maxLineHeight = tmpGlyph->height;
828
829          if (tmpRect.x+tmpGlyph->advance > tmpSurf->w)
830            {
831              tmpRect.x = 0;
832              tmpRect.y = tmpRect.y + maxLineHeight + 1;
833              maxLineHeight = 0;
834            }
835          if (tmpRect.y + maxLineHeight > tmpSurf->h)
836            {
837              PRINTF(1)("Protection, so font cannot write over the boundraries error (this should not heappen\n");
838              break;
839            }
840          // reading in the new Glyph
841          if (likely(this->font != NULL))
842          {
843            SDL_Color white = {255, 255, 255};
844            glyphSurf = TTF_RenderGlyph_Blended(this->font, i, white);
845          }
846          if( glyphSurf != NULL )
847            {
848              SDL_SetAlpha(glyphSurf, 0, 0);
849
850              SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect);
851              TexCoord tmpTexCoord;
852              tmpTexCoord.minU = (float)tmpRect.x/(float)tmpSurf->w;
853              tmpTexCoord.maxU = (float)(tmpRect.x + tmpGlyph->advance)/(float)tmpSurf->w;
854              tmpTexCoord.minV = (float)(tmpRect.y)/(float)tmpSurf->w;
855              tmpTexCoord.maxV = (float)(tmpRect.y+tmpGlyph->height)/(float)tmpSurf->w;
856              tmpGlyph->displayList = glGenLists(1);
857
858              glNewList(tmpGlyph->displayList, GL_COMPILE);
859              glBegin(GL_QUADS);
860              glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.minV);
861              glVertex2d(0, - tmpGlyph->bearingY);
862              glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.maxV);
863              glVertex2d(0, tmpGlyph->height - tmpGlyph->bearingY);
864              glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.maxV);
865              glVertex2d(tmpGlyph->width, tmpGlyph->height - tmpGlyph->bearingY);
866              glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.minV);
867              glVertex2d(tmpGlyph->width, - tmpGlyph->bearingY);
868              glEnd();
869              glEndList();
870              SDL_FreeSurface(glyphSurf);
871
872              tmpRect.x += tmpGlyph->advance;
873
874              // Outputting Glyphs to BMP-files.
875/*
876                char outname[512];
877                if (i < 10)
878                sprintf( outname, "%s-glyph-00%d.bmp", this->getName(), i );
879                else if (i <100)
880                  sprintf( outname, "%s-glyph-0%d.bmp", this->getName(), i );
881                else
882                  sprintf( outname, "%s-glyph-%d.bmp", this->getName(), i );
883                SDL_SaveBMP(tmpSurf, outname);*/
884
885            }
886        }
887    }
888
889  GLuint texture;
890  glGenTextures(1, &texture);
891  glBindTexture(GL_TEXTURE_2D, texture);
892  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
893  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
894  glTexImage2D(GL_TEXTURE_2D,
895               0,
896               GL_RGBA,
897               tmpSurf->w, tmpSurf->h,
898               0,
899               GL_RGBA,
900               GL_UNSIGNED_BYTE,
901               tmpSurf->pixels);
902  SDL_FreeSurface(tmpSurf);
903  return texture;
904}
905
906/**
907 *  stores Glyph Metrics in an Array.
908 * @param from The Glyph to start from.
909 * @param count The number of Glyphs to start From.
910*/
911void Font::initGlyphs(Uint16 from, Uint16 count)
912{
913  /* initialize the Array, and set all its entries to NULL
914   *  only if the Glyph-array has not been initialized
915   */
916  if (!this->glyphArray)
917    {
918      this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
919      for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
920        this->glyphArray[i] = NULL;
921    }
922
923  Uint16 lastGlyph = from + count;
924
925  for (int i = from; i <= lastGlyph; i++)
926    {
927      // setting up all the Glyphs we like.
928      glyphArray[i] = getGlyphMetrics(i);
929    }
930  return;
931}
932
933/**
934 * @returns the optimal size to use as the texture size
935
936   @todo: this algorithm can be a lot more faster, althought it does
937   not really matter within the init-context, and 128 glyphs.
938
939   This function searches for a 2^n sizes texture-size, this is for
940   openGL-version < 1.2 compatibility ( and because it is realy easy like this :))
941*/
942int Font::findOptimalFastTextureSize()
943{
944  int i;
945  int x,y; // the counters
946  int maxLineHeight = this->getMaxHeight();
947  unsigned int size = 32;  // starting Value, we have to start somewhere 32 seems reasonable. (take any small enough 2^i number)
948  bool sizeOK = false;
949  Glyph* tmpGlyph;
950
951  while (!sizeOK)
952    {
953      x = 0; y = 0;
954      for (i = 0; i <= FONT_HIGHEST_KNOWN_CHAR; i++)
955        {
956          if((tmpGlyph = this->glyphArray[i]) != NULL)
957            {
958              // getting the height of the highest Glyph in the Line.
959              if (tmpGlyph->height > maxLineHeight)
960                maxLineHeight = tmpGlyph->height;
961
962              if (x + tmpGlyph->advance > size)
963                {
964                  x = 0;
965                  y = y + maxLineHeight;
966                  //maxLineHeight = 0;
967                }
968              if (y + maxLineHeight + 1 > size)
969                break;
970              x += tmpGlyph->advance;
971
972            }
973        }
974      if (i >= FONT_HIGHEST_KNOWN_CHAR-1 || size > 8192)
975        sizeOK = true;
976      else
977        size *= 2;
978    }
979    return size;
980}
981
982
983/**
984 *  a simple function to get some interesting information about this class
985*/
986void Font::debug()
987{
988  // print the loaded font's style
989  int style;
990  if (likely(this->font != NULL))
991    style = TTF_GetFontStyle(this->font);
992  PRINTF(0)("The font style is:");
993  if(style==TTF_STYLE_NORMAL)
994    PRINTF(0)(" normal");
995  else {
996    if(style&TTF_STYLE_BOLD)
997      PRINTF(0)(" bold");
998    if(style&TTF_STYLE_ITALIC)
999      PRINTF(0)(" italic");
1000    if(style&TTF_STYLE_UNDERLINE)
1001      PRINTF(0)(" underline");
1002  }
1003  PRINTF(0)("\n");
1004}
1005
1006
1007///////////////////
1008/// TEXT-ENGINE ///
1009///////////////////
1010/**
1011 *  standard constructor
1012*/
1013TextEngine::TextEngine ()
1014{
1015   this->setClassID(CL_TEXT_ENGINE, "TextEngine");
1016   this->setName("TextEngine");
1017   this->enableFonts();
1018}
1019
1020/**
1021 *  the singleton reference to this class
1022*/
1023TextEngine* TextEngine::singletonRef = NULL;
1024
1025/**
1026 *  standard deconstructor
1027
1028*/
1029TextEngine::~TextEngine ()
1030{
1031  // first remove all the remaining Texts (if any).
1032  tList<BaseObject>* textList = ClassList::getList(CL_TEXT);
1033  if (textList != NULL)
1034  {
1035    tIterator<BaseObject>* textIterator = textList->getIterator();
1036    Text* text = dynamic_cast<Text*>(textIterator->firstElement());
1037    while( text != NULL)
1038    {
1039      delete text;
1040      text = dynamic_cast<Text*>(textIterator->nextElement());
1041    }
1042    delete textIterator;
1043  }
1044  // delete all remaining fonts (this is done in the ResourceManager)
1045  tList<BaseObject>* fontList = ClassList::getList(CL_FONT);
1046  if (fontList != NULL)
1047  {
1048    tIterator<BaseObject>* fontIterator = fontList->getIterator();
1049    Font* font = dynamic_cast<Font*>(fontIterator->firstElement());
1050    while( font != NULL)
1051    {
1052      ResourceManager::getInstance()->unload(font, RP_GAME);
1053      font = dynamic_cast<Font*>(fontIterator->nextElement());
1054    }
1055    delete fontIterator;
1056  }
1057
1058  this->disableFonts();
1059
1060  TextEngine::singletonRef = NULL;
1061}
1062
1063/**
1064 *  function to enable TTF_Fonts
1065*/
1066void TextEngine::enableFonts()
1067{
1068  if (!TTF_WasInit())
1069    {
1070      if(TTF_Init()==-1)
1071        PRINTF(1)("TTF_Init: %s\n", TTF_GetError());
1072
1073      TextEngine::checkVersion();
1074    }
1075  else
1076    PRINTF(4)("Fonts already initialized\n");
1077}
1078
1079/**
1080 *  function to disable TTF_fonts
1081*/
1082void TextEngine::disableFonts()
1083{
1084  if (TTF_WasInit())
1085    {
1086      Font::removeDefaultFont();
1087      TTF_Quit();
1088    }
1089  else
1090    PRINTF(4)("Fonts were not initialized.\n");
1091}
1092
1093/**
1094 *  creates a new Text with a certain font.
1095 * @see Font::Font
1096 * @see Text::Text
1097*/
1098Text* TextEngine::createText(const char* fontFile, unsigned int fontSize, int textType)
1099{
1100  Font* tmpFont;
1101  Text* newText;
1102  Vector tmpVec;
1103
1104  tmpFont = (Font*)ResourceManager::getInstance()->load(fontFile, TTF, RP_GAME, &fontSize);
1105  if (!tmpFont)
1106    {
1107      PRINTF(2)("Font %s could not be loaded, probably file not found\n", fontFile);
1108      return NULL;
1109    }
1110  else
1111    return new Text(tmpFont, TEXT_RENDER_DYNAMIC);
1112}
1113
1114/**
1115 *  outputs some nice Debug information
1116
1117   @todo there should also be something outputted about Font
1118*/
1119void TextEngine::debug() const
1120{
1121  tList<BaseObject>* textList = ClassList::getList(CL_TEXT);
1122  if (textList != NULL)
1123  {
1124    PRINT(0)("+-------------------------------+\n");
1125    PRINT(0)("+ TEXT ENGINE DEBUG INFORMATION +\n");
1126    PRINT(0)("+-------------------------------+\n");
1127    PRINT(0)("Reference: %p; Text Counts: %d\n", this, textList->getSize());
1128
1129    tIterator<BaseObject>* textIterator = textList->getIterator();
1130    Text* text = dynamic_cast<Text*>(textIterator->firstElement());
1131    while( text != NULL)
1132      {
1133        text->debug();
1134        text = dynamic_cast<Text*>(textIterator->nextElement());
1135      }
1136    delete textIterator;
1137    PRINT(0)("+---------------------------TE--+\n");
1138  }
1139}
1140
1141
1142/**
1143 *  checks if the compiled version and the local version of SDL_ttf match.
1144 * @returns true if match, false otherwise
1145*/
1146bool TextEngine::checkVersion()
1147{
1148  SDL_version compile_version;
1149  SDL_version link_version;
1150  TTF_VERSION(&compile_version);
1151  link_version = *TTF_Linked_Version();
1152
1153  if (compile_version.major == link_version.major &&
1154      compile_version.minor == link_version.minor &&
1155      compile_version.patch == link_version.patch)
1156    {
1157      return true;
1158    }
1159  else
1160    {
1161      PRINTF(2)("compiled with SDL_ttf version: %d.%d.%d\n",
1162                compile_version.major,
1163                compile_version.minor,
1164                compile_version.patch);
1165
1166      PRINTF(2)("running with SDL_ttf version: %d.%d.%d\n",
1167                link_version.major,
1168                link_version.minor,
1169                link_version.patch);
1170      return false;
1171    }
1172}
Note: See TracBrowser for help on using the repository browser.