Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branches/textEngine: some new functions to get the optimum size (sqare) of the FastTexture-Array, and to initialize all the Glyphs

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