Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5179 was 5179, checked in by bensch, 20 years ago

orxonox/trunk: ShellInput is now almost perfectly extern.
ShellCompletion taken out.
Working again :)

File size: 24.2 KB
RevLine 
[4597]1/*
[3655]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:
[3766]12   main-programmer: Benjamin Grauer
[3655]13   co-programmer: ...
[3766]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
[4597]18   adding them to orxonox. This is really important, because we do not
[3767]19   want to offend anyone.
[3655]20*/
21
[3766]22#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_FONT
[3655]23
[3766]24#include "text_engine.h"
[3655]25
26using namespace std;
27
[3766]28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
[3655]31
[3766]32#include "graphics_engine.h"
[3769]33#include "resource_manager.h"
[5077]34#include "class_list.h"
[3769]35
[3766]36#include "p_node.h"
37#include "vector.h"
38#include "debug.h"
[3911]39#include "list.h"
[3766]40
41////////////
[3768]42/// TEXT ///
[3766]43////////////
[3773]44/**
[4836]45 *  creates a new Text Element
46 * @param font the Font to render this text in
47 * @param type The renderType to display this font in
[3773]48
[4597]49   this constructor is private, because the user should initialize
[3773]50   a text with the TextEngine.
51*/
[5122]52Text::Text(Font* font, TEXT_RENDER_TYPE type)
[3768]53{
[4320]54  this->setClassID(CL_TEXT, "Text");
[3833]55
[3769]56  // initialize this Text
[3770]57  this->font = font;
[3769]58  this->text = NULL;
[5122]59  this->externText = NULL;
[5089]60  this->setAlignment(TEXT_DEFAULT_ALIGNMENT);
[3769]61  this->texture = 0;
[5122]62  this->blending = TEXT_DEFAULT_BLENDING;
63  this->color = TEXT_DEFAULT_COLOR;
[3770]64  this->setType(type);
[3768]65
[5122]66  this->setText(NULL);
[3768]67}
68
[3773]69/**
[4836]70 *  deletes a Text out of memory
[5122]71 *
72 * This also ereases the text from the textList of the TextEngine
[3773]73*/
[4746]74Text::~Text()
[3768]75{
[5122]76  if (this->font != NULL)
77    ResourceManager::getInstance()->unload(this->font);
[5076]78
[5077]79  if (this->text)
[5121]80    delete[] this->text;
[3768]81}
82
[4458]83/**
[5179]84 * sets the Font of this Text to font
85 * @param font the Font (normaly from the ResourceManager) to allocate to this Text
86 */
87void Text::setFont(Font* font)
88{
89  if (this->font != NULL)
90    ResourceManager::getInstance()->unload(this->font);
91  this->font = font;
92}
93
94/**
95 * sets the Font of this Text to font from fontFile
96 * @param fontFile the File to load the Font from.
97 * @param fontSize the Size of the Font
98 */
99void Text::setFont(const char* fontFile, unsigned int fontSize)
100{
101  Font* tmpFont;
102  Text* newText;
103  Vector tmpVec;
104
105  tmpFont = (Font*)ResourceManager::getInstance()->load(fontFile, TTF, RP_GAME, &fontSize);
106  if (!tmpFont)
107  {
108    PRINTF(2)("Font %s could not be loaded, probably file not found\n", fontFile);
109    this->setFont(NULL);
110  }
111  else
112    this->setFont(tmpFont);
113}
114
115/**
[4836]116 *  sets the Type of this Text
117 * @param type the type to set.
[3768]118*/
[5122]119void Text::setType(TEXT_RENDER_TYPE type)
[3768]120{
[5179]121  if (this->font != NULL && this->font->font)
[4536]122    this->type = type;
123  else
[5122]124    this->type = TEXT_RENDER_DYNAMIC;
[3768]125}
126
127/**
[4836]128 *  Sets a new Text to the font
129 * @param text the new text to set
[3768]130*/
[5122]131void Text::setText(const char* text, bool isExtern)
[3768]132{
[5122]133  if (isExtern)
[5072]134  {
[5122]135    this->externText = text;
136
137    if (unlikely(this->text != NULL))
138    {
139      delete[] this->text;
140      this->text = NULL;
141    }
[5072]142  }
143  else
144  {
[5122]145    this->externText = NULL;
146    if (this->text)
147      delete[] this->text;
148    if (text != NULL)
149    {
150      this->text = new char[strlen(text)+1];
151      strcpy(this->text, text);
152    }
153    else
[5125]154      this->text = NULL;
[5072]155  }
[3843]156
157  // setting up the Text-Width if DYNAMIC
[5179]158  if (this->type & TEXT_RENDER_DYNAMIC && this->getAlignment() != TEXT_ALIGN_LEFT && this->font != NULL)
[3843]159    {
160      Glyph** glyphArray = this->font->getGlyphArray();
161
162      int width = 0;
[5122]163      const char* tmpText = this->externText;
164      if (this->externText == NULL)
165        tmpText = this->text;
[5125]166      if (tmpText != NULL)
167      {
168        while (*tmpText != '\0')
[4597]169        {
170          if(glyphArray[*tmpText])
[5125]171          {
172            width += glyphArray[*tmpText]->width;
173          }
[4597]174          tmpText++;
175        }
[5125]176        this->width = width;
177      }
[3843]178    }
[3768]179}
180
181/**
[4836]182 *  creates a texture out of the given parameters
[3769]183
184   this has to be called every time by the user, to if changes were made.
[4536]185   this is only for TEXT_STATIC-mode
[3769]186*/
[4746]187void Text::createTexture()
[3769]188{
189  SDL_Surface* tmpSurf;
190  if (this->texture)
191    glDeleteTextures(1, &this->texture);
[4536]192  if (likely(this->font != NULL))
[5121]193  {
194    SDL_Color theColor = { (int)(this->color.x*255), (int)(this->color.y*255), (int)(this->color.z*255) };
[4536]195    tmpSurf = TTF_RenderText_Blended(this->font->font,
[4597]196                                     this->text,
[5121]197                                     theColor);
198  }
[3769]199  if (tmpSurf)
200    this->texture = loadTexture(tmpSurf, &this->texCoord);
201
[5123]202  this->width = tmpSurf->w;
203  this->height = tmpSurf->h;
[3769]204  SDL_FreeSurface(tmpSurf);
205}
206
207/**
[4850]208 *  draws the Text
[3768]209*/
[4746]210void Text::draw() const
[3768]211{
[3843]212  glPushMatrix();
213  // transform for alignment.
[5089]214  if (this->getAlignment() == TEXT_ALIGN_RIGHT)
[5123]215    glTranslatef(-this->width, 0, 0);
[5089]216  else if (this->getAlignment() == TEXT_ALIGN_CENTER || this->getAlignment() == TEXT_ALIGN_SCREEN_CENTER)
[5123]217    glTranslatef(-this->width/2, 0, 0);
[3843]218
[3768]219  // drawing this Text.
[4856]220  // setting the Blending effects
[5121]221  glColor4f(this->color.x, this->color.y, this->color.z, this->blending);
[4856]222  glEnable(GL_BLEND);
223  glEnable(GL_TEXTURE_2D);
224  glBlendFunc(GL_SRC_ALPHA, GL_ONE);
225
[5121]226  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GL_MODULATE );
227
[5179]228  if(likely(type & TEXT_RENDER_DYNAMIC && this->font != NULL))
[3768]229    {
[5122]230      Glyph** glyphArray = this->font->getGlyphArray();
231      glBindTexture(GL_TEXTURE_2D, this->font->getFastTextureID());
232      //      glEnable(GL_TEXTURE_2D);
233      glTranslatef(getAbsCoor2D().x, getAbsCoor2D().y, 0);
234//      glRotatef(this->getAbsDir2D(), 0,0,1);
235
236      const char* tmpText = this->externText;
237      if (this->externText == NULL)
238        tmpText = this->text;
[5125]239      if (likely(tmpText != NULL))
[5122]240      {
[5125]241        while (*tmpText != '\0')
[5122]242        {
[5125]243          if(glyphArray[*tmpText])
244          {
245            glCallList(glyphArray[*tmpText]->displayList);
246            glTranslatef(glyphArray[*tmpText]->width, 0, 0);
247          }
248          tmpText++;
[5122]249        }
[5125]250      }
251    }
[5122]252  else //(if type & TEXT_RENDER_STATIC)
253    {
[3768]254      glBindTexture(GL_TEXTURE_2D, this->texture);
255      glBegin(GL_QUADS);
[4597]256
[3768]257      glTexCoord2f(this->texCoord.minU, this->texCoord.minV);
[5089]258      glVertex2f(this->getAbsCoor2D().x,   this->getAbsCoor2D().);
[4597]259
[3768]260      glTexCoord2f(this->texCoord.maxU, this->texCoord.minV);
[5123]261      glVertex2f(this->getAbsCoor2D().x + this->width, this->getAbsCoor2D().);
[4597]262
[3768]263      glTexCoord2f(this->texCoord.maxU, this->texCoord.maxV);
[5123]264      glVertex2f(this->getAbsCoor2D().x + this->width, getAbsCoor2D().y + this->height);
[4597]265
[3768]266      glTexCoord2f(this->texCoord.minU, this->texCoord.maxV);
[5123]267      glVertex2f(getAbsCoor2D().x, getAbsCoor2D().y + this->height);
[4597]268
[3768]269      glEnd();
270
271    }
[3843]272  glPopMatrix();
[3768]273}
274
[3774]275/**
[4836]276 *  prints out some nice debug information about this text
[3774]277*/
[4746]278void Text::debug() const
[3774]279{
[5122]280  if (this->externText == NULL)
281    PRINT(0)("=== TEXT: %s ===\n", this->text);
282  else
283    PRINT(0)("=== TEXT: %s ===\n", this->externText);
284
[5089]285  if (this->getBindNode())
286    PRINT(0)("is bind to %s; ref=%p\n", this->getBindNode()->getName(), this->getBindNode());
[5121]287  PRINT(0)("Color: %0.2f %0.2f %0.2f\n", this->color.x, this->color.y, this->color.z);
[3774]288}
[3768]289
290
291////////////
[4458]292/// UTIL ///
293////////////
294/**
[4836]295 *  Loads a Font from an SDL_surface into a texture.
296 * @param surface The surface to make the texture of
297 * @param texCoord The texture coordinates of the 4 corners of the texture
298 * @returns the ID of the texture
[4458]299*/
300GLuint Text::loadTexture(SDL_Surface *surface, TexCoord* texCoord)
301{
302  GLuint texture;
303  int w, h;
304  SDL_Surface *image;
305  SDL_Rect area;
306  Uint32 saved_flags;
307  Uint8  saved_alpha;
[4597]308
[4458]309  /* Use the surface width and height expanded to powers of 2 */
310  w = powerOfTwo(surface->w);
311  h = powerOfTwo(surface->h);
312  if (texCoord)
313    {
314      texCoord->minU = 0.0f;
315      texCoord->minV = 0.0f;
316      texCoord->maxU = (GLfloat)surface->w / w;
317      texCoord->maxV = (GLfloat)surface->h / h;
318    }
319  image = SDL_CreateRGBSurface(SDL_SWSURFACE,
[4597]320                               w, h,
321                               32,
[4458]322#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
[4597]323                               0x000000FF,
324                               0x0000FF00,
325                               0x00FF0000,
326                               0xFF000000
[4458]327#else
[4597]328                               0xFF000000,
329                               0x00FF0000,
330                               0x0000FF00,
331                               0x000000FF
[4458]332#endif
[4597]333                               );
[4458]334  if ( image == NULL ) {
335    return 0;
336  }
[4597]337
[4458]338  /* Save the alpha blending attributes */
339  saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
340  saved_alpha = surface->format->alpha;
341  if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
342    SDL_SetAlpha(surface, 0, 0);
343  }
[4597]344
[4458]345  /* Copy the surface into the GL texture image */
346  area.x = 0;
347  area.y = 0;
348  area.w = surface->w;
349  area.h = surface->h;
350  SDL_BlitSurface(surface, &area, image, &area);
[4597]351
[4458]352  /* Restore the alpha blending attributes */
353  if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
354    SDL_SetAlpha(surface, saved_flags, saved_alpha);
355  }
[4597]356
[4458]357  /* Create an OpenGL texture for the image */
358  glGenTextures(1, &texture);
359  glBindTexture(GL_TEXTURE_2D, texture);
360  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
361  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
362  glTexImage2D(GL_TEXTURE_2D,
[4597]363               0,
364               GL_RGBA,
365               w, h,
366               0,
367               GL_RGBA,
368               GL_UNSIGNED_BYTE,
369               image->pixels);
[4458]370  SDL_FreeSurface(image); /* No longer needed */
[4597]371
[4458]372  return texture;
373}
374
375/**
[4836]376 *  Quick utility function for texture creation
377 * @param input an integer
378 * @returns the next bigger 2^n-integer than input
[4458]379*/
380int Text::powerOfTwo(int input)
381{
382  int value = 1;
[4597]383
[4458]384  while ( value < input ) {
385    value <<= 1;
386  }
387  return value;
388}
389
390
391////////////
[3768]392/// FONT ///
393////////////
394/**
[4836]395 *  constructs a Font
396 * @param fontFile the File to load the font from
397 * @param fontSize the Size of the Font in Pixels
398 * @param r Red value of the Font.
399 * @param g Green value of the Font.
400 * @param b Blue value of the Font.
[3766]401*/
[5121]402Font::Font(const char* fontFile, unsigned int fontSize)
[3766]403{
[4597]404  this->setClassID(CL_FONT, "Font");
[3766]405  // setting default values.
406  this->font = NULL;
407  this->fontFile = NULL;
408  this->glyphArray = NULL;
[4597]409  this->fastTextureID = 0;
410
[3766]411  this->setSize(fontSize);
[3769]412
[5124]413  this->loadFont(fontFile);
[3766]414
[3840]415  this->setStyle("c");//TTF_STYLE_NORMAL);
[3766]416
417  this->fastTextureID = this->createFastTexture();
418}
419
420/**
[5124]421 * destructs a font
422 * this releases the memory a font uses to be opened.
[3767]423*/
[4746]424Font::~Font()
[3767]425{
[3769]426  // deleting the List of all Texts
[3767]427
[3769]428  // deleting all Glyphs
[3767]429  if (this->glyphArray)
430    {
431      for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
[4597]432        delete this->glyphArray[i];
[5121]433      delete[] this->glyphArray;
[3767]434    }
435
[3769]436  // erease this font out of the memory.
[4536]437  if (likely(this->font != NULL))
[3767]438    TTF_CloseFont(this->font);
439}
440
441/**
[4836]442 *  sets The Font.
443 * @param fontFile The file containing the font.
444 * @returns true if loaded, false if something went wrong, or if a font was loaded before.
[3766]445*/
[5124]446bool Font::loadFont(const char* fontFile)
[3766]447{
448  if (!this->fontFile)
449    {
[4597]450      this->setName(fontFile);
[3766]451      this->fontFile = new char[strlen(fontFile)+1];
452      strcpy(this->fontFile, fontFile);
[4597]453
[3766]454      this->font = TTF_OpenFont(this->fontFile, this->fontSize);
[4536]455      if(!this->font)
[4597]456        {
457          PRINTF(1)("TTF_OpenFont: %s\n", TTF_GetError());
458          return false;
459        }
[4518]460      else
[4597]461          return true;
[3766]462    }
463  else
464    {
465      PRINTF(2)("Font already initialized, unable to change it now.\n");
466      return false;
467    }
468}
469
470/**
[4836]471 *  sets a specific renderStyle
472 * @param renderStyle the Style to render: a char-array containing:
[3766]473   i: italic, b: bold, u, underline
474*/
[4458]475void Font::setStyle(const char* renderStyle)
[3766]476{
[3768]477  this->renderStyle = TTF_STYLE_NORMAL;
[4597]478
[3766]479  for (int i = 0; i < strlen(renderStyle); i++)
[4597]480    if (strncmp(renderStyle+i, "b", 1) == 0)
[3768]481      this->renderStyle |= TTF_STYLE_BOLD;
[3766]482    else if (strncmp(renderStyle+i, "i", 1) == 0)
[3768]483      this->renderStyle |= TTF_STYLE_ITALIC;
[4597]484    else if (strncmp(renderStyle+i, "u", 1) == 0)
[3768]485      this->renderStyle |= TTF_STYLE_UNDERLINE;
[3766]486
[4536]487  if (likely(this->font != NULL))
[3768]488    TTF_SetFontStyle(this->font, this->renderStyle);
[3766]489  else
490    PRINTF(2)("Font was not initialized, please do so before setting the Font-Style.\n");
491}
492
493/**
[4836]494 *  Sets a new Size to the font
495 * @param fontSize The new Size in pixels.
[3766]496*/
497void Font::setSize(unsigned int fontSize)
498{
499  this->fontSize = fontSize;
500}
501
502/**
[4836]503 * @returns the maximum height of the Font, if the font was initialized, 0 otherwise
[3766]504*/
[4746]505int Font::getMaxHeight()
[3766]506{
[4536]507  if (likely (this->font != NULL))
[3766]508    return TTF_FontHeight(this->font);
509  else
510    return 0;
511}
512
513/**
[4836]514 * @returns the maximum ascent of the Font, if the font was initialized, 0 otherwise
[3766]515
516   the ascent is the pixels of the font above the baseline
517*/
[4746]518int Font::getMaxAscent()
[3766]519{
[4536]520  if (likely(this->font != NULL))
[3766]521    return TTF_FontAscent(this->font);
522  else
523    return 0;
524}
525
526/**
[4836]527 * @returns the maximum descent of the Font, if the font was initialized, 0 otherwise
[3766]528
529   the descent is the pixels of the font below the baseline
530*/
[4746]531int Font::getMaxDescent()
[3766]532{
[4536]533  if (likely(this->font != NULL))
[3766]534    return TTF_FontDescent(this->font);
535  else
536    return 0;
537}
538
539/**
[4836]540 * @param character The character to get info about.
541 * @returns a Glyph struct of a character. This Glyph is a pointer,
[3766]542   and MUST be deleted by the user..
543
[4597]544   This only works for horizontal fonts. see
[3766]545   http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html
546   for more info about vertical Fonts
547*/
548Glyph* Font::getGlyphMetrics(Uint16 character)
549{
550  Glyph* rg = new Glyph;
551  rg->character = character;
[4536]552  if (likely (this->font!= NULL))
553    TTF_GlyphMetrics(this->font, rg->character,
[4597]554                     &rg->minX, &rg->maxX,
555                     &rg->minY, &rg->maxY,
556                     &rg->advance);
[3766]557  rg->height = rg->maxY - rg->minY;
558  rg->width = rg->maxX - rg->minX;
559  rg->bearingX = (rg->advance - rg->width) / 2;
560  rg->bearingY = rg->maxY;
561  return rg;
562}
563
[4746]564GLuint Font::createFastTexture()
[3766]565{
[4597]566  /* interesting GLYPHS:
[3776]567   *  32: space
[3766]568   *  33-47: Special Characters.
569   *  48-57: 0-9
570   *  58-63: some more special chars (minor)
571   *  65-90: A-Z
572   *  97-122: a-z
573   */
[3776]574  int numberOfGlyphs = 91;
[3766]575
[3776]576  this->initGlyphs(32, numberOfGlyphs);
[5121]577  this->glyphArray[32]->width = fontSize/2; //!< @todo find out the real size of a Space
[3766]578
579  int rectSize = this->findOptimalFastTextureSize();
580
581  // setting default values. (maybe not needed afterwards)
582  SDL_Color tmpColor;  tmpColor.r = tmpColor.g = tmpColor.b = 0;
583  // Surface definition.
584  SDL_Rect tmpRect; // this represents a Rectangle for blitting.
585  SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(SDL_SWSURFACE,
[4597]586                                               rectSize, rectSize,
587                                               32,
[3766]588#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
[4597]589                                               0x000000FF,
590                                               0x0000FF00,
591                                               0x00FF0000,
592                                               0xFF000000
[3766]593#else
[4597]594                                               0xFF000000,
595                                               0x00FF0000,
596                                               0x0000FF00,
597                                               0x000000FF
[3766]598#endif
[4597]599                                               );
[3766]600  tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h;
601  SDL_SetClipRect(tmpSurf, &tmpRect);
602  int maxLineHeight = 0;
603
604  // all the interessting Glyphs
[4536]605  for (int i = 0; i <= 127; i++)
[3766]606    {
607      SDL_Surface* glyphSurf = NULL;
608      Glyph* tmpGlyph;
609
610      if (tmpGlyph = this->glyphArray[i])
[4597]611        {
612          if (tmpGlyph->height > maxLineHeight)
613            maxLineHeight = tmpGlyph->height;
[3766]614
[5124]615          if (tmpRect.x+tmpGlyph->advance > tmpSurf->w)
[4597]616            {
617              tmpRect.x = 0;
[4709]618              tmpRect.y = tmpRect.y + maxLineHeight + 1;
[4597]619              maxLineHeight = 0;
620            }
621          if (tmpRect.y + maxLineHeight > tmpSurf->h)
622            {
623              PRINTF(1)("Protection, so font cannot write over the boundraries error (this should not heappen\n");
624              break;
625            }
626          // reading in the new Glyph
627          if (likely(this->font != NULL))
[5121]628          {
629            SDL_Color white = {255, 255, 255};
630            glyphSurf = TTF_RenderGlyph_Blended(this->font, i, white);
631          }
[4597]632          if( glyphSurf != NULL )
633            {
634              SDL_SetAlpha(glyphSurf, 0, 0);
[3766]635
[4597]636              SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect);
637              TexCoord tmpTexCoord;
638              tmpTexCoord.minU = (float)tmpRect.x/(float)tmpSurf->w;
[5124]639              tmpTexCoord.maxU = (float)(tmpRect.x + tmpGlyph->advance)/(float)tmpSurf->w;
[5121]640              tmpTexCoord.minV = (float)(tmpRect.y)/(float)tmpSurf->w;
[4597]641              tmpTexCoord.maxV = (float)(tmpRect.y+tmpGlyph->height)/(float)tmpSurf->w;
642              tmpGlyph->displayList = glGenLists(1);
[3766]643
[4597]644              glNewList(tmpGlyph->displayList, GL_COMPILE);
645              glBegin(GL_QUADS);
646              glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.minV);
[5124]647              glVertex2d(0, - tmpGlyph->bearingY);
[4597]648              glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.maxV);
[5124]649              glVertex2d(0, tmpGlyph->height - tmpGlyph->bearingY);
[4597]650              glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.maxV);
[5124]651              glVertex2d(tmpGlyph->width, tmpGlyph->height - tmpGlyph->bearingY);
[4597]652              glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.minV);
[5124]653              glVertex2d(tmpGlyph->width, - tmpGlyph->bearingY);
[4597]654              glEnd();
655              glEndList();
656              SDL_FreeSurface(glyphSurf);
[3766]657
[5124]658              tmpRect.x += tmpGlyph->advance;
[4597]659
660              // Outputting Glyphs to BMP-files.
[5113]661/*
662                char outname[512];
[4597]663                if (i < 10)
[5113]664                sprintf( outname, "%s-glyph-00%d.bmp", this->getName(), i );
[4597]665                else if (i <100)
[5113]666                  sprintf( outname, "%s-glyph-0%d.bmp", this->getName(), i );
[4597]667                else
[5113]668                  sprintf( outname, "%s-glyph-%d.bmp", this->getName(), i );
669                SDL_SaveBMP(tmpSurf, outname);*/
670
[4597]671            }
672        }
[3766]673    }
[3776]674
[3766]675  GLuint texture;
676  glGenTextures(1, &texture);
677  glBindTexture(GL_TEXTURE_2D, texture);
678  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
679  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
680  glTexImage2D(GL_TEXTURE_2D,
[4597]681               0,
682               GL_RGBA,
683               tmpSurf->w, tmpSurf->h,
684               0,
685               GL_RGBA,
686               GL_UNSIGNED_BYTE,
687               tmpSurf->pixels);
[3766]688  SDL_FreeSurface(tmpSurf);
689  return texture;
690}
691
692/**
[4836]693 *  stores Glyph Metrics in an Array.
694 * @param from The Glyph to start from.
695 * @param count The number of Glyphs to start From.
[3766]696*/
697void Font::initGlyphs(Uint16 from, Uint16 count)
698{
699  /* initialize the Array, and set all its entries to NULL
700   *  only if the Glyph-array has not been initialized
701   */
702  if (!this->glyphArray)
703    {
704      this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR];
705      for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
[4597]706        this->glyphArray[i] = NULL;
[3766]707    }
[4597]708
[3766]709  Uint16 lastGlyph = from + count;
[4597]710
[3766]711  for (int i = from; i <= lastGlyph; i++)
712    {
713      // setting up all the Glyphs we like.
714      glyphArray[i] = getGlyphMetrics(i);
715    }
716  return;
717}
718
719/**
[4836]720 * @returns the optimal size to use as the texture size
[3766]721
[4836]722   @todo: this algorithm can be a lot more faster, althought it does
[3766]723   not really matter within the init-context, and 128 glyphs.
724
[4597]725   This function searches for a 2^n sizes texture-size, this is for
[4536]726   openGL-version < 1.2 compatibility ( and because it is realy easy like this :))
[3766]727*/
[4746]728int Font::findOptimalFastTextureSize()
[3766]729{
730  int i;
731  int x,y; // the counters
[5124]732  int maxLineHeight = this->getMaxHeight();
[5121]733  unsigned int size = 32;  // starting Value, we have to start somewhere 32 seems reasonable. (take any small enough 2^i number)
[3766]734  bool sizeOK = false;
735  Glyph* tmpGlyph;
736
737  while (!sizeOK)
738    {
739      x = 0; y = 0;
740      for (i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++)
[4597]741        {
742          if(tmpGlyph = this->glyphArray[i])
743            {
744              // getting the height of the highest Glyph in the Line.
745              if (tmpGlyph->height > maxLineHeight)
746                maxLineHeight = tmpGlyph->height;
[3766]747
[5124]748              if (x + tmpGlyph->advance > size)
[4597]749                {
750                  x = 0;
751                  y = y + maxLineHeight;
[5113]752                  //maxLineHeight = 0;
[4597]753                }
754              if (y + maxLineHeight + 1 > size)
755                break;
[5124]756              x += tmpGlyph->advance;
[3766]757
[4597]758            }
759        }
[3766]760      if (i == FONT_HIGHEST_KNOWN_CHAR)
[4597]761        sizeOK = true;
[3766]762      else
[4597]763        size *= 2;
[3766]764    }
[5124]765    return size;
[3766]766}
767
768
769/**
[4836]770 *  a simple function to get some interesting information about this class
[3766]771*/
[4746]772void Font::debug()
[3766]773{
774  // print the loaded font's style
775  int style;
[4536]776  if (likely(this->font != NULL))
777    style = TTF_GetFontStyle(this->font);
[3766]778  PRINTF(0)("The font style is:");
779  if(style==TTF_STYLE_NORMAL)
780    PRINTF(0)(" normal");
781  else {
782    if(style&TTF_STYLE_BOLD)
783      PRINTF(0)(" bold");
784    if(style&TTF_STYLE_ITALIC)
785      PRINTF(0)(" italic");
786    if(style&TTF_STYLE_UNDERLINE)
787      PRINTF(0)(" underline");
788  }
789  PRINTF(0)("\n");
790}
791
792
[3768]793///////////////////
794/// TEXT-ENGINE ///
795///////////////////
[3766]796/**
[4836]797 *  standard constructor
[3655]798*/
[4597]799TextEngine::TextEngine ()
[3655]800{
[4320]801   this->setClassID(CL_TEXT_ENGINE, "TextEngine");
[4597]802   this->setName("TextEngine");
[3769]803   this->enableFonts();
[3655]804}
805
806/**
[4836]807 *  the singleton reference to this class
[3655]808*/
[3766]809TextEngine* TextEngine::singletonRef = NULL;
[3655]810
811/**
[4836]812 *  standard deconstructor
[3655]813
814*/
[4597]815TextEngine::~TextEngine ()
[3655]816{
[3769]817  this->disableFonts();
[4597]818
[3766]819  TextEngine::singletonRef = NULL;
[3655]820}
[3766]821
822/**
[4836]823 *  function to enable TTF_Fonts
[3766]824*/
[4746]825void TextEngine::enableFonts()
[3766]826{
827  if (!TTF_WasInit())
828    {
829      if(TTF_Init()==-1)
[4597]830        PRINTF(1)("TTF_Init: %s\n", TTF_GetError());
[3766]831
832      TextEngine::checkVersion();
833    }
834  else
835    PRINTF(4)("Fonts already initialized\n");
836}
837
838/**
[4836]839 *  function to disable TTF_fonts
[3766]840*/
[4746]841void TextEngine::disableFonts()
[3766]842{
843  if (TTF_WasInit())
844    {
845      TTF_Quit();
846    }
847  else
848    PRINTF(4)("Fonts were not initialized.\n");
849}
850
851/**
[4836]852 *  creates a new Text with a certain font.
[5078]853   @see Font::Font
854   @see Text::Text
[3769]855*/
[5121]856Text* TextEngine::createText(const char* fontFile, unsigned int fontSize, int textType)
[3769]857{
858  Font* tmpFont;
859  Text* newText;
[3775]860  Vector tmpVec;
[3769]861
[5121]862  tmpFont = (Font*)ResourceManager::getInstance()->load(fontFile, TTF, RP_GAME, &fontSize);
[3769]863  if (!tmpFont)
864    {
865      PRINTF(2)("Font %s could not be loaded, probably file not found\n", fontFile);
866      return NULL;
867    }
[5122]868  else
869    return new Text(tmpFont, TEXT_RENDER_DYNAMIC);
[3769]870}
871
[3772]872/**
[4836]873 *  outputs some nice Debug information
[4597]874
[4836]875   @todo there should also be something outputted about Font
[3774]876*/
[4746]877void TextEngine::debug() const
[3774]878{
879  PRINT(0)("+-------------------------------+\n");
880  PRINT(0)("+ TEXT ENGINE DEBUG INFORMATION +\n");
881  PRINT(0)("+-------------------------------+\n");
[5077]882  PRINT(0)("Reference: %p; Text Counts: %d\n", this, ClassList::getList(CL_TEXT)->getSize());
[4597]883
[5077]884  tIterator<BaseObject>* textIterator = ClassList::getList(CL_TEXT)->getIterator();
[5115]885  Text* text = dynamic_cast<Text*>(textIterator->firstElement());
[3774]886  while( text != NULL)
887    {
888      text->debug();
[5077]889      text = dynamic_cast<Text*>(textIterator->nextElement());
[3774]890    }
891  delete textIterator;
892  PRINT(0)("+---------------------------TE--+\n");
893}
894
895
896/**
[4836]897 *  checks if the compiled version and the local version of SDL_ttf match.
898 * @returns true if match, false otherwise
[3766]899*/
[4746]900bool TextEngine::checkVersion()
[3766]901{
902  SDL_version compile_version;
903  SDL_version link_version;
904  TTF_VERSION(&compile_version);
905  link_version = *TTF_Linked_Version();
906
907  if (compile_version.major == link_version.major &&
908      compile_version.minor == link_version.minor &&
909      compile_version.patch == link_version.patch)
910    {
911      return true;
912    }
913  else
914    {
[4597]915      PRINTF(2)("compiled with SDL_ttf version: %d.%d.%d\n",
916                compile_version.major,
917                compile_version.minor,
918                compile_version.patch);
919
920      PRINTF(2)("running with SDL_ttf version: %d.%d.%d\n",
921                link_version.major,
922                link_version.minor,
923                link_version.patch);
[3766]924      return false;
925    }
926}
Note: See TracBrowser for help on using the repository browser.