Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: text-read from XPM works, but there still is an error in displaying them

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