Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: fonts are now correctly loaded (from IMAGE) by the FontEngine

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