Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: init-function of Font

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