Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/textEngine/src/lib/graphics/font/glfont.cc @ 3718

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

orxonox/branches/textEngine: added a simple function, that will create a Fast-Texture-image from a ttf-font

File size: 16.9 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   ***
16   * This file is extended to the needs of the orxonox-project.         *
17   * the Copyright of the original file is below this copyright         *
18   *                                                                  ***
19
20   for some fonts and licenses visit: =http://www.dafont.com/en/font.php=
21
22   !! IMPORTANT !! When using ttf fonts clear the license issues prior to
23   adding them to orxonox. This is really important, because we do not
24   want to defend anyone.
25*/
26
27/*
28  glfont:  An example of using the SDL_ttf library with OpenGL.
29  Copyright (C) 1997-2004 Sam Lantinga
30 
31  This library is free software; you can redistribute it and/or
32  modify it under the terms of the GNU Library General Public
33  License as published by the Free Software Foundation; either
34  version 2 of the License, or (at your option) any later version.
35 
36  This library is distributed in the hope that it will be useful,
37  but WITHOUT ANY WARRANTY; without even the implied warranty of
38  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
39  Library General Public License for more details.
40 
41  You should have received a copy of the GNU Library General Public
42  License along with this library; if not, write to the Free
43  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
44 
45  The SDL_GL_* functions in this file are available in the public domain.
46 
47  Sam Lantinga
48  slouken@libsdl.org
49*/
50
51#include "glfont.h"
52
53#include <stdlib.h>
54#include <stdio.h>
55#include <string.h>
56
57#include "graphics_engine.h"
58#include "p_node.h"
59#include "vector.h"
60#include "debug.h"
61
62/**
63   \brief constructs a Font
64   \param fontFile the File to load the font from
65*/
66GLFont::GLFont(const char* fontFile)
67{
68  this->init(fontFile);
69}
70
71/**
72   \brief destructs a font
73*/
74GLFont::~GLFont(void)
75{
76  delete this->currentText;
77
78  if (this->font)
79    TTF_CloseFont(this->font);
80}
81
82/**
83   \brief function to enable TTF_Fonts
84*/
85void GLFont::enableFonts(void)
86{
87  if (!GLFont::ttfInitialized)
88    {
89      if(TTF_Init()==-1)
90        PRINTF(1)("TTF_Init: %s\n", TTF_GetError());
91
92      GLFont::checkVersion();
93      GLFont::ttfInitialized = true;
94    }
95  else
96    PRINTF(4)("Fonts already initialized\n");
97     
98}
99
100/**
101   \brief function to disable TTF_fonts
102*/
103void GLFont::disableFonts(void)
104{
105  if (GLFont::ttfInitialized)
106    {
107      TTF_Quit();
108      GLFont::ttfInitialized = false;
109    }
110  else
111    PRINTF(4)("Fonts were not initialized.\n");
112}
113
114//! A simple variable for checking if ttf was initialized
115bool GLFont::ttfInitialized = false;
116
117/**
118   \brief initializes a new Font
119   \param fontFile The file to load a Font from
120   \param fontSize the Size in pixels of the Font
121*/
122bool GLFont::init(const char* fontFile, unsigned int fontSize)
123{
124  if (!GLFont::ttfInitialized)
125    GLFont::enableFonts();
126
127  // setting default values.
128  this->font = NULL;
129  this->fontFile = NULL;
130
131  this->currentText = new Text;
132
133  this->currentText->bindNode = NULL;
134  this->currentText->text = NULL;
135  this->currentText->texture = 0;
136 
137  this->setSize(fontSize);
138 
139  this->currentText->renderStyle = TTF_STYLE_NORMAL;
140
141  this->setFont(fontFile);
142
143  this->setColor(0, 255, 0);
144  this->setPosition(0, 0);
145
146  this->setText(FONT_DEFAULT_TEXT);
147
148  this->createTexture();
149
150  this->createFastTexture();
151}
152
153/**
154   \brief sets The Font.
155   \param fontFile The file containing the font.
156   \returns true if loaded, false if something went wrong, or if a font was loaded before.
157*/
158bool GLFont::setFont(const char* fontFile)
159{
160  if (!this->fontFile)
161    {
162      this->fontFile = new char[strlen(fontFile)+1];
163      strcpy(this->fontFile, fontFile);
164     
165      this->font = TTF_OpenFont(this->fontFile, this->fontSize);
166      if(!this->font) 
167        {
168          PRINTF(1)("TTF_OpenFont: %s\n", TTF_GetError());
169          return false;
170      }
171      return true;
172    }
173  else
174    {
175      PRINTF(2)("Font already initialized, unable to change it now.\n");
176      return false;
177    }
178}
179
180void GLFont::setBindNode(PNode* bindNode)
181{
182  this->currentText->bindNode = bindNode;
183}
184
185
186/**
187   \brief Sets a new Text to the font
188   \param text the new text to set
189*/
190void GLFont::setText(const char* text)
191{
192  if (this->currentText->text)
193    delete []this->currentText->text;
194  this->currentText->text = new char[strlen(text)+1];
195  strcpy(this->currentText->text, text);
196}
197
198/**
199   \brief sets a specific renderStyle
200   \param renderStyle the Style to render: a char-array containing:
201   i: italic, b: bold, u, underline
202*/
203void GLFont::setStyle(char* renderStyle)
204{
205  this->currentText->renderStyle = TTF_STYLE_NORMAL;
206 
207  for (int i = 0; i < strlen(renderStyle); i++)
208    if (strncmp(renderStyle+i, "b", 1) == 0) 
209      this->currentText->renderStyle |= TTF_STYLE_BOLD;
210    else if (strncmp(renderStyle+i, "i", 1) == 0)
211      this->currentText->renderStyle |= TTF_STYLE_ITALIC;
212    else if (strncmp(renderStyle+i, "u", 1) == 0) 
213      this->currentText->renderStyle |= TTF_STYLE_UNDERLINE;
214
215  if (this->font)
216    TTF_SetFontStyle(this->font, this->currentText->renderStyle);
217  else
218    PRINTF(2)("Font was not initialized, please do so before setting the Font-Style.\n");
219}
220
221/**
222   \brief Sets a new Size to the font
223   \param fontSize The new Size in pixels.
224*/
225void GLFont::setSize(unsigned int fontSize)
226{
227  this->fontSize = fontSize;
228}
229
230/**
231   \brief sets a new color to the font
232   \param r Red
233   \param g Green
234   \param b Blue
235*/
236void GLFont::setColor(Uint8 r, Uint8 g, Uint8 b)
237{
238  this->currentText->color.r = r;
239  this->currentText->color.g = g;
240  this->currentText->color.b = b;
241}
242
243/**
244   \brief sets a Position.
245   \param x the x-position in pixels from the left border
246   \param y the y-position in pixels from the top border
247*/
248void GLFont::setPosition(int x, int y)
249{
250  this->currentText->textPosSize.x = x;
251  this->currentText->textPosSize.y = y;
252}
253
254/**
255   \brief draws the Font
256   \todo FIX this is to slow/static
257*/
258void GLFont::draw(void)
259{
260  GLdouble modMat[16];
261  GLint viewPort[4];
262  glGetDoublev(GL_PROJECTION_MATRIX, this->projMat);
263  glGetDoublev(GL_MODELVIEW_MATRIX, modMat);
264  glGetIntegerv(GL_VIEWPORT, viewPort);
265  this->enter2DMode();
266
267
268  Vector pos;
269  if (this->currentText->bindNode)
270    {
271      GLdouble x = this->currentText->bindNode->getAbsCoor().x;
272      GLdouble y = this->currentText->bindNode->getAbsCoor().y;
273      GLdouble z = this->currentText->bindNode->getAbsCoor().z;
274      GLdouble tmp[3];
275      gluProject(x, y, z, modMat, projMat, viewPort, tmp, tmp+1, tmp+2);
276      printf("test %f %f %f,\n", tmp[0], tmp[1], tmp[2]);
277      pos.x = tmp[0] + this->currentText->textPosSize.x;
278      pos.y = GraphicsEngine::getInstance()->getResolutionY() - tmp[1] + this->currentText->textPosSize.y;
279      pos.z = tmp[2];
280    }
281  else 
282    {
283      pos.x = this->currentText->textPosSize.x;
284      pos.y = this->currentText->textPosSize.y;
285      pos.z = 0;
286    }
287  glBindTexture(GL_TEXTURE_2D, this->currentText->texture);
288  glEnable(GL_TEXTURE_2D);
289  glBegin(GL_QUADS);
290 
291  glTexCoord2f(this->currentText->texCoord.minU, this->currentText->texCoord.minV);
292  glVertex2i(pos.x,   pos.);
293
294  glTexCoord2f(this->currentText->texCoord.maxU, this->currentText->texCoord.minV);
295  glVertex2i(pos.x + this->currentText->textPosSize.w, pos.);
296
297  glTexCoord2f(this->currentText->texCoord.maxU, this->currentText->texCoord.maxV);
298  glVertex2i(pos.x + this->currentText->textPosSize.w, pos.y + this->currentText->textPosSize.h);
299
300  glTexCoord2f(this->currentText->texCoord.minU, this->currentText->texCoord.maxV);
301  glVertex2i(pos.x, pos.y + this->currentText->textPosSize.h);
302
303  glEnd();
304
305  this->leave2DMode();
306}
307
308/**
309   \brief creates a texture out of the given parameters
310
311   this has to be called every time by the user, to if changes were made.
312*/
313void GLFont::createTexture(void)
314{
315  SDL_Surface* tmpSurf;
316  if (this->currentText->texture)
317    glDeleteTextures(1, &this->currentText->texture);
318  tmpSurf = TTF_RenderText_Blended(this->font,
319                                   this->currentText->text,
320                                   this->currentText->color);
321  if (tmpSurf)
322    this->currentText->texture = loadTexture(tmpSurf, &this->currentText->texCoord);
323
324  this->currentText->textPosSize.w = tmpSurf->w;
325  this->currentText->textPosSize.h = tmpSurf->h;
326  SDL_FreeSurface(tmpSurf);
327}
328
329
330/**
331   \returns the maximum height of the Font, if the font was initialized, 0 otherwise
332*/
333int GLFont::getMaxHeight(void)
334{
335  if (this->font)
336    return TTF_FontHeight(this->font);
337  else
338    return 0;
339}
340
341/**
342   \returns the maximum ascent of the Font, if the font was initialized, 0 otherwise
343
344   the ascent is the pixels of the font above the baseline
345*/
346int GLFont::getMaxAscent(void)
347{
348  if (this->font)
349    return TTF_FontAscent(this->font);
350  else
351    return 0;
352}
353
354/**
355   \returns the maximum descent of the Font, if the font was initialized, 0 otherwise
356
357   the descent is the pixels of the font below the baseline
358*/
359int GLFont::getMaxDescent(void)
360{
361  if (this->font)
362    return TTF_FontDescent(this->font);
363  else
364    return 0;
365}
366
367/**
368   \param character The character to get info about.
369   \returns a Glyph struct of a character.
370
371   This only works for horizontal fonts. see
372   http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html
373   for more info about vertical Fonts
374*/
375Glyph GLFont::getGlyphMetrics(Uint16 character)
376{
377  Glyph rg;
378  rg.character = character;
379  TTF_GlyphMetrics(this->font, rg.character,
380                   &rg.minX, &rg.maxX,
381                   &rg.minY, &rg.maxY,
382                   &rg.advance);
383  rg.height = rg.maxY - rg.minY;
384  rg.width = rg.maxX - rg.minX;
385  rg.bearingX = (rg.advance - rg.width) / 2;
386  rg.bearingY = rg.maxY;
387  return rg;
388}
389
390/**
391   \brief entering 2D Mode
392   
393   this is a GL-Projection-mode, that is orthogonal, for placing the font in fron of everything else
394*/
395void GLFont::enter2DMode(void)
396{
397  SDL_Surface *screen = SDL_GetVideoSurface();
398 
399  /* Note, there may be other things you need to change,
400     depending on how you have your OpenGL state set up.
401  */
402  glPushAttrib(GL_ENABLE_BIT);
403  glDisable(GL_DEPTH_TEST);
404  glDisable(GL_CULL_FACE);
405  glDisable(GL_LIGHTING);  // will be set back when leaving 2D-mode
406  glEnable(GL_TEXTURE_2D);
407
408  /* This allows alpha blending of 2D textures with the scene */
409  glEnable(GL_BLEND);
410  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
411 
412  glViewport(0, 0, screen->w, screen->h);
413 
414  glMatrixMode(GL_PROJECTION);
415  glPushMatrix();
416  glLoadIdentity();
417 
418  glOrtho(0.0, (GLdouble)screen->w, (GLdouble)screen->h, 0.0, 0.0, 1.0);
419 
420  glMatrixMode(GL_MODELVIEW);
421  glPushMatrix();
422  glLoadIdentity();
423 
424  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
425}
426
427/**
428   \brief leaves the 2DMode again also \see GLFont::enter2DMode(void)
429*/
430void GLFont::leave2DMode(void)
431{
432        glMatrixMode(GL_MODELVIEW);
433        glPopMatrix();
434
435        glMatrixMode(GL_PROJECTION);
436        glPopMatrix();
437
438        glPopAttrib();
439}
440
441
442GLuint GLFont::createFastTexture(void)
443{
444  /* interesting GLYPHS:
445   *  33-47: Special Characters.
446   *  48-57: 0-9
447   *  58-63: some more special chars (minor)
448   *  65-90: A-Z
449   *  97-122: a-z
450   */
451  SDL_Surface* tmpSurf =  SDL_CreateRGBSurface(
452                                               SDL_SWSURFACE,
453                                               100, 100,
454                                               32,
455#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
456                                               0x000000FF, 
457                                               0x0000FF00, 
458                                               0x00FF0000, 
459                                               0xFF000000
460#else
461                                               0xFF000000,
462                                               0x00FF0000, 
463                                               0x0000FF00, 
464                                               0x000000FF
465#endif
466                                               );
467  SDL_Rect tmpRect;
468  tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = 100; tmpRect.h = 100;
469  for ( int i = 65; i <= 90; i++ ) 
470    {
471      SDL_Surface* glyph = NULL;
472     
473      glyph = TTF_RenderGlyph_Blended( this->font, i, this->currentText->color );
474     
475      if( glyph ) {
476        char outname[64];
477        if (i<10)
478          sprintf( outname, "glyph-00%d.bmp", i );
479        else if (i <100)
480          sprintf( outname, "glyph-0%d.bmp", i );
481        else
482          sprintf( outname, "glyph-%d.bmp", i );
483
484        SDL_BlitSurface(glyph, NULL, tmpSurf, &tmpRect);
485        SDL_SaveBMP( tmpSurf, outname );
486      }
487    }
488  /*
489    tmpSurf = TTF_RenderText_Blended(this->font,
490    this->name,
491    this->currentText->color);
492  */
493}
494
495/**
496   \brief Loads a Font from an SDL_surface into a texture.
497   \param surface The surface to make the texture of
498   \param texCoord The texture coordinates of the 4 corners of the texture
499   \returns the ID of the texture
500*/
501GLuint GLFont::loadTexture(SDL_Surface *surface, TexCoord* texCoord)
502{
503  GLuint texture;
504  int w, h;
505  SDL_Surface *image;
506  SDL_Rect area;
507  Uint32 saved_flags;
508  Uint8  saved_alpha;
509 
510  /* Use the surface width and height expanded to powers of 2 */
511  w = powerOfTwo(surface->w);
512  h = powerOfTwo(surface->h);
513  texCoord->minU = 0.0f;
514  texCoord->minV = 0.0f;
515  texCoord->maxU = (GLfloat)surface->w / w;
516  texCoord->maxV = (GLfloat)surface->h / h;
517 
518  image = SDL_CreateRGBSurface(
519                               SDL_SWSURFACE,
520                               w, h,
521                               32,
522#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
523                               0x000000FF, 
524                               0x0000FF00, 
525                               0x00FF0000, 
526                               0xFF000000
527#else
528                               0xFF000000,
529                               0x00FF0000, 
530                               0x0000FF00, 
531                               0x000000FF
532#endif
533                               );
534  if ( image == NULL ) {
535    return 0;
536  }
537 
538  /* Save the alpha blending attributes */
539  saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
540  saved_alpha = surface->format->alpha;
541  if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
542    SDL_SetAlpha(surface, 0, 0);
543  }
544 
545  /* Copy the surface into the GL texture image */
546  area.x = 0;
547  area.y = 0;
548  area.w = surface->w;
549  area.h = surface->h;
550  SDL_BlitSurface(surface, &area, image, &area);
551 
552  /* Restore the alpha blending attributes */
553  if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
554    SDL_SetAlpha(surface, saved_flags, saved_alpha);
555  }
556 
557  /* Create an OpenGL texture for the image */
558  glGenTextures(1, &texture);
559  glBindTexture(GL_TEXTURE_2D, texture);
560  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
561  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
562  glTexImage2D(GL_TEXTURE_2D,
563               0,
564               GL_RGBA,
565               w, h,
566               0,
567               GL_RGBA,
568               GL_UNSIGNED_BYTE,
569               image->pixels);
570  SDL_FreeSurface(image); /* No longer needed */
571 
572  return texture;
573}
574
575/**
576   \brief Quick utility function for texture creation
577   \param input an integer
578   \returns the next bigger 2^n-integer than input
579*/
580int GLFont::powerOfTwo(int input)
581{
582  int value = 1;
583 
584  while ( value < input ) {
585    value <<= 1;
586  }
587  return value;
588}
589
590
591/**
592   \brief checks if the compiled version and the local version of SDL_ttf match.
593   \returns true if match, false otherwise
594*/
595bool GLFont::checkVersion(void)
596{
597  SDL_version compile_version;
598  SDL_version link_version;
599  TTF_VERSION(&compile_version);
600  link_version = *TTF_Linked_Version();
601
602  if (compile_version.major == link_version.major &&
603      compile_version.minor == link_version.minor &&
604      compile_version.patch == link_version.patch)
605    {
606      return true;
607    }
608  else
609    {
610      PRINTF(2)("compiled with SDL_ttf version: %d.%d.%d\n", 
611                compile_version.major,
612                compile_version.minor,
613                compile_version.patch);
614     
615      PRINTF(2)("running with SDL_ttf version: %d.%d.%d\n", 
616                link_version.major,
617                link_version.minor,
618                link_version.patch);
619      return false;
620    }
621}
622
623
624
625/**
626   \brief a simple function to get some interesting information about this class
627*/
628void GLFont::debug(void)
629{
630
631  // print the loaded font's style
632  int style;
633  style=TTF_GetFontStyle(this->font);
634  PRINTF(0)("The font style is:");
635  if(style==TTF_STYLE_NORMAL)
636    PRINTF(0)(" normal");
637  else {
638    if(style&TTF_STYLE_BOLD)
639      PRINTF(0)(" bold");
640    if(style&TTF_STYLE_ITALIC)
641      PRINTF(0)(" italic");
642    if(style&TTF_STYLE_UNDERLINE)
643      PRINTF(0)(" underline");
644  }
645  PRINTF(0)("\n");
646
647
648}
649
650
651void m_inverse(const float *m, float *out)
652{
653    float det;
654    det=  m[0]*m[5]*m[10];
655    det+= m[4]*m[9]*m[2];
656    det+= m[8]*m[1]*m[6];
657    det-= m[8]*m[5]*m[2];
658    det-= m[4]*m[1]*m[10];
659    det-= m[0]*m[9]*m[6];
660   
661    if(det!= 0.0)
662        det=1.0/det;
663    out[0]=  (m[5]*m[10]-m[9]*m[6])*det;
664    out[1]= -(m[1]*m[10]-m[9]*m[2])*det;
665    out[2]=  (m[1]*m[6]-m[5]*m[2])*det;
666    out[3]= 0.0;
667    out[4]= -(m[4]*m[10]-m[8]*m[6])*det;
668    out[5]=  (m[0]*m[10]-m[8]*m[2])*det;
669    out[6]= -(m[0]*m[6]-m[4]*m[2])*det;
670    out[7]= 0.0;
671    out[8]=  (m[4]*m[9]-m[8]*m[5])*det;
672    out[9]= -(m[0]*m[9]-m[8]*m[1])*det;
673    out[10]= (m[0]*m[5]-m[4]*m[1])*det;
674    out[11]= 0.0;
675    out[12]=- (m[12]*out[0]+m[13]*out[4]+m[14]*out[8]);
676    out[13]=- (m[12]*out[1]+m[13]*out[5]+m[14]*out[9]);
677    out[14]=- (m[12]*out[2]+m[13]*out[6]+m[14]*out[10]);
678    out[15]= 1.0;
679}
680
681
682Vector mvMult(const float *mat, const Vector* vec)
683{
684  Vector tmp;
685  tmp.x = mat[0]*vec->x+mat[1]*vec->y+mat[2]*vec->z;
686  tmp.y = mat[4]*vec->x+mat[5]*vec->y+mat[6]*vec->z;
687  tmp.z = mat[8]*vec->x+mat[9]*vec->y+mat[10]*vec->z;
688  return tmp;
689}
Note: See TracBrowser for help on using the repository browser.