Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: implemented default font.

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