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
RevLine 
[3478]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
[3691]20   for some fonts and licenses visit: =http://www.dafont.com/en/font.php=
[3701]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.
[3478]25*/
26
27/*
[3701]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
[3478]49*/
50
51#include "glfont.h"
52
53#include <stdlib.h>
54#include <stdio.h>
55#include <string.h>
56
[3716]57#include "graphics_engine.h"
[3715]58#include "p_node.h"
59#include "vector.h"
[3682]60#include "debug.h"
[3478]61
[3696]62/**
63   \brief constructs a Font
64   \param fontFile the File to load the font from
65*/
66GLFont::GLFont(const char* fontFile)
[3478]67{
[3696]68  this->init(fontFile);
[3478]69}
[3692]70
[3696]71/**
72   \brief destructs a font
73*/
[3693]74GLFont::~GLFont(void)
[3478]75{
[3714]76  delete this->currentText;
77
[3691]78  if (this->font)
79    TTF_CloseFont(this->font);
[3478]80}
81
[3692]82/**
[3696]83   \brief function to enable TTF_Fonts
[3692]84*/
[3691]85void GLFont::enableFonts(void)
86{
87  if (!GLFont::ttfInitialized)
88    {
[3714]89      if(TTF_Init()==-1)
[3691]90        PRINTF(1)("TTF_Init: %s\n", TTF_GetError());
[3714]91
[3691]92      GLFont::checkVersion();
93      GLFont::ttfInitialized = true;
94    }
95  else
96    PRINTF(4)("Fonts already initialized\n");
97     
98}
[3692]99
100/**
101   \brief function to disable TTF_fonts
102*/
[3691]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
[3694]114//! A simple variable for checking if ttf was initialized
[3691]115bool GLFont::ttfInitialized = false;
116
[3694]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*/
[3693]122bool GLFont::init(const char* fontFile, unsigned int fontSize)
[3478]123{
[3693]124  if (!GLFont::ttfInitialized)
125    GLFont::enableFonts();
126
[3478]127  // setting default values.
[3691]128  this->font = NULL;
129  this->fontFile = NULL;
[3714]130
131  this->currentText = new Text;
132
[3715]133  this->currentText->bindNode = NULL;
[3714]134  this->currentText->text = NULL;
135  this->currentText->texture = 0;
[3691]136 
[3693]137  this->setSize(fontSize);
138 
[3714]139  this->currentText->renderStyle = TTF_STYLE_NORMAL;
[3478]140
[3693]141  this->setFont(fontFile);
[3478]142
[3700]143  this->setColor(0, 255, 0);
[3718]144  this->setPosition(0, 0);
[3700]145
[3696]146  this->setText(FONT_DEFAULT_TEXT);
[3693]147
[3696]148  this->createTexture();
[3718]149
150  this->createFastTexture();
[3691]151}
152
[3694]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*/
[3691]158bool GLFont::setFont(const char* fontFile)
159{
160  if (!this->fontFile)
[3478]161    {
[3691]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());
[3694]169          return false;
[3691]170      }
[3694]171      return true;
[3478]172    }
[3691]173  else
[3694]174    {
175      PRINTF(2)("Font already initialized, unable to change it now.\n");
176      return false;
177    }
[3478]178}
179
[3715]180void GLFont::setBindNode(PNode* bindNode)
181{
182  this->currentText->bindNode = bindNode;
183}
184
185
[3694]186/**
187   \brief Sets a new Text to the font
188   \param text the new text to set
189*/
[3478]190void GLFont::setText(const char* text)
191{
[3714]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);
[3478]196}
197
[3691]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)
[3478]204{
[3714]205  this->currentText->renderStyle = TTF_STYLE_NORMAL;
[3478]206 
[3691]207  for (int i = 0; i < strlen(renderStyle); i++)
208    if (strncmp(renderStyle+i, "b", 1) == 0) 
[3714]209      this->currentText->renderStyle |= TTF_STYLE_BOLD;
[3691]210    else if (strncmp(renderStyle+i, "i", 1) == 0)
[3714]211      this->currentText->renderStyle |= TTF_STYLE_ITALIC;
[3691]212    else if (strncmp(renderStyle+i, "u", 1) == 0) 
[3714]213      this->currentText->renderStyle |= TTF_STYLE_UNDERLINE;
[3478]214
[3691]215  if (this->font)
[3714]216    TTF_SetFontStyle(this->font, this->currentText->renderStyle);
[3691]217  else
218    PRINTF(2)("Font was not initialized, please do so before setting the Font-Style.\n");
219}
[3478]220
[3694]221/**
222   \brief Sets a new Size to the font
223   \param fontSize The new Size in pixels.
224*/
[3692]225void GLFont::setSize(unsigned int fontSize)
[3478]226{
[3692]227  this->fontSize = fontSize;
228}
[3478]229
[3694]230/**
231   \brief sets a new color to the font
232   \param r Red
233   \param g Green
234   \param b Blue
235*/
[3692]236void GLFont::setColor(Uint8 r, Uint8 g, Uint8 b)
237{
[3714]238  this->currentText->color.r = r;
239  this->currentText->color.g = g;
240  this->currentText->color.b = b;
[3478]241}
[3691]242
[3694]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*/
[3693]248void GLFont::setPosition(int x, int y)
249{
[3714]250  this->currentText->textPosSize.x = x;
251  this->currentText->textPosSize.y = y;
[3693]252}
[3692]253
[3694]254/**
255   \brief draws the Font
256   \todo FIX this is to slow/static
257*/
[3693]258void GLFont::draw(void)
259{
[3715]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);
[3693]265  this->enter2DMode();
[3714]266
[3715]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]);
[3718]277      pos.x = tmp[0] + this->currentText->textPosSize.x;
278      pos.y = GraphicsEngine::getInstance()->getResolutionY() - tmp[1] + this->currentText->textPosSize.y;
[3715]279      pos.z = tmp[2];
280    }
[3718]281  else 
282    {
283      pos.x = this->currentText->textPosSize.x;
284      pos.y = this->currentText->textPosSize.y;
285      pos.z = 0;
286    }
[3714]287  glBindTexture(GL_TEXTURE_2D, this->currentText->texture);
[3693]288  glEnable(GL_TEXTURE_2D);
289  glBegin(GL_QUADS);
[3715]290 
[3714]291  glTexCoord2f(this->currentText->texCoord.minU, this->currentText->texCoord.minV);
[3715]292  glVertex2i(pos.x,   pos.);
[3714]293
294  glTexCoord2f(this->currentText->texCoord.maxU, this->currentText->texCoord.minV);
[3715]295  glVertex2i(pos.x + this->currentText->textPosSize.w, pos.);
[3714]296
297  glTexCoord2f(this->currentText->texCoord.maxU, this->currentText->texCoord.maxV);
[3715]298  glVertex2i(pos.x + this->currentText->textPosSize.w, pos.y + this->currentText->textPosSize.h);
[3714]299
300  glTexCoord2f(this->currentText->texCoord.minU, this->currentText->texCoord.maxV);
[3715]301  glVertex2i(pos.x, pos.y + this->currentText->textPosSize.h);
[3714]302
[3693]303  glEnd();
[3714]304
[3693]305  this->leave2DMode();
306}
307
[3694]308/**
309   \brief creates a texture out of the given parameters
[3713]310
311   this has to be called every time by the user, to if changes were made.
[3694]312*/
[3692]313void GLFont::createTexture(void)
314{
[3696]315  SDL_Surface* tmpSurf;
[3714]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);
[3693]321  if (tmpSurf)
[3714]322    this->currentText->texture = loadTexture(tmpSurf, &this->currentText->texCoord);
[3694]323
[3714]324  this->currentText->textPosSize.w = tmpSurf->w;
325  this->currentText->textPosSize.h = tmpSurf->h;
[3694]326  SDL_FreeSurface(tmpSurf);
[3692]327}
328
329
[3691]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*/
[3694]375Glyph GLFont::getGlyphMetrics(Uint16 character)
[3691]376{
[3694]377  Glyph rg;
[3691]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
[3694]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)
[3478]396{
[3682]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);
[3700]405  glDisable(GL_LIGHTING);  // will be set back when leaving 2D-mode
[3682]406  glEnable(GL_TEXTURE_2D);
[3700]407
[3682]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);
[3478]425}
426
[3694]427/**
428   \brief leaves the 2DMode again also \see GLFont::enter2DMode(void)
429*/
430void GLFont::leave2DMode(void)
[3478]431{
[3682]432        glMatrixMode(GL_MODELVIEW);
433        glPopMatrix();
[3478]434
[3682]435        glMatrixMode(GL_PROJECTION);
436        glPopMatrix();
437
438        glPopAttrib();
[3478]439}
440
[3718]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
[3694]495/**
496   \brief Loads a Font from an SDL_surface into a texture.
497   \param surface The surface to make the texture of
[3700]498   \param texCoord The texture coordinates of the 4 corners of the texture
[3694]499   \returns the ID of the texture
500*/
[3700]501GLuint GLFont::loadTexture(SDL_Surface *surface, TexCoord* texCoord)
[3478]502{
[3682]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 */
[3691]511  w = powerOfTwo(surface->w);
512  h = powerOfTwo(surface->h);
[3700]513  texCoord->minU = 0.0f;
514  texCoord->minV = 0.0f;
515  texCoord->maxU = (GLfloat)surface->w / w;
516  texCoord->maxV = (GLfloat)surface->h / h;
[3682]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;
[3478]573}
574
[3696]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}
[3682]589
[3696]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*/
[3691]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
[3694]625/**
626   \brief a simple function to get some interesting information about this class
627*/
[3691]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}
[3715]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.