libmoldeo (Moldeo 1.0 Core)  1.0
libmoldeo es el conjunto de objetos y funciones, que permiten ejecutar las operaciones básicas de la plataforma Moldeo, y que compone su núcleo.
 Todo Clases Namespaces Archivos Funciones Variables 'typedefs' Enumeraciones Valores de enumeraciones Amigas 'defines' Grupos Páginas
moOGLFT.cpp
Ir a la documentación de este archivo.
1 /*
2  * OGLFT: A library for drawing text with OpenGL using the FreeType library
3  * Copyright (C) 2002 lignum Computing, Inc. <oglft@lignumcomputing.com>
4  * $Id: OGLFT.cpp,v 1.11 2003/10/01 14:21:18 allen Exp $
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 #include <moOGLFT.h>
22 
23 namespace OGLFT {
24 
25  // This is the static instance of the FreeType library wrapper ...
26 
27  Library Library::library;
28 
29  // ... and this is the FreeType library handle itself.
30 
31  FT_Library Library::library_;
32 
33  // The static instance above causes this constructor to be called
34  // when the object module is loaded.
35 
37  {
38 
39  FT_Error error = FT_Init_FreeType( &library_ );
40 
41  if ( error != 0 ) {
42  std::cerr << "Could not initialize the FreeType library. Exiting." << std::endl;
43  exit( 1 );
44  }
45  }
46 
48  {
49  FT_Error error = FT_Done_FreeType( library_ );
50 
51  if ( error != 0 ) {
52  std::cerr << "Could not terminate the FreeType library." << std::endl;
53  }
54  }
55 
56  // Return the only instance in the process
57 
58  FT_Library& Library::instance ( void )
59  {
60  return library_;
61  }
62 
63  // Load a new face
64 
65  Face::Face ( const char* filename, float point_size, FT_UInt resolution )
66  : point_size_( point_size ), resolution_( resolution )
67  {
68  valid_ = true; // Assume the best :-)
69 
70  FT_Face ft_face;
71 
72  FT_Error error = FT_New_Face( Library::instance(), filename, 0, &ft_face );
73 
74  if ( error != 0 ) {
75  valid_ = false;
76  return;
77  }
78 
79  // As of FreeType 2.1: only a UNICODE charmap is automatically activated.
80  // If no charmap is activated automatically, just use the first one.
81  if ( ft_face->charmap == 0 && ft_face->num_charmaps > 0 )
82  FT_Select_Charmap( ft_face, ft_face->charmaps[0]->encoding );
83 
84  faces_.push_back( FaceData( ft_face ) );
85 
86  init();
87  }
88 
89  // Go with a face that the user has already opened.
90 
91  Face::Face ( FT_Face face, float point_size, FT_UInt resolution )
92  : point_size_( point_size ), resolution_( resolution )
93  {
94  valid_ = true;
95 
96  // As of FreeType 2.1: only a UNICODE charmap is automatically activated.
97  // If no charmap is activated automatically, just use the first one.
98  if ( face->charmap == 0 && face->num_charmaps > 0 )
99  FT_Select_Charmap( face, face->charmaps[0]->encoding );
100 
101  faces_.push_back( FaceData( face, false ) );
102 
103  init();
104  }
105 
106  // Standard initialization behavior once the font file is opened.
107 
108  void Face::init ( void )
109  {
110  // By default, each glyph is compiled into a display list the first
111  // time it is encountered
112 
114 
115  // By default, all drawing is wrapped with push/pop matrix so that the
116  // MODELVIEW matrix is not modified. If advance_ is set, then subsequent
117  // drawings follow from the advance of the last glyph rendered.
118 
119  advance_ = false;
120 
121  // Initialize the default colors
122 
123  foreground_color_[R] = 0.;
124  foreground_color_[G] = 0.;
125  foreground_color_[B] = 0.;
126  foreground_color_[A] = 1.;
127 
128  background_color_[R] = 1.;
129  background_color_[G] = 1.;
130  background_color_[B] = 1.;
131  background_color_[A] = 0.;
132 
133  // The default positioning of the text is at the origin of the first glyph
136 
137  // By default, strings are rendered in their nominal direction
138  string_rotation_ = 0;
139 
140  // setCharacterRotationReference calls the virtual function clearCaches()
141  // so it is up to a subclass to set the real default
144  rotation_offset_y_ = 0.;
145  }
146 
147  Face::~Face ( void )
148  {
149  for ( unsigned int i = 0; i < faces_.size(); i++ )
150  if ( faces_[i].free_on_exit_ )
151  FT_Done_Face( faces_[i].face_ );
152  }
153 
154  // Add another Face to select characters from
155 
156  bool Face::addAuxiliaryFace ( const char* filename )
157  {
158  FT_Face ft_face;
159 
160  FT_Error error = FT_New_Face( Library::instance(), filename, 0, &ft_face );
161 
162  if ( error != 0 )
163  return false;
164 
165  faces_.push_back( FaceData( ft_face ) );
166 
167  setCharSize();
168 
169  return true;
170  }
171 
172  // Add another Face to select characters from
173 
174  bool Face::addAuxiliaryFace ( FT_Face face )
175  {
176  faces_.push_back( FaceData( face, false ) );
177 
178  setCharSize();
179 
180  return true;
181  }
182 
183  // Note: Changing the point size also clears the display list cache
184 
185  void Face::setPointSize ( float point_size )
186  {
187  if ( point_size != point_size_ ) {
188 
189  point_size_ = point_size;
190 
191  clearCaches();
192 
193  setCharSize();
194  }
195  }
196 
197  // Note: Changing the resolution also clears the display list cache
198 
199  void Face::setResolution ( FT_UInt resolution )
200  {
201  if ( resolution != resolution_ ) {
202 
204 
205  clearCaches();
206 
207  setCharSize();
208  }
209  }
210 
211  // Note: Changing the background color also clears the display list cache.
212 
213  void Face::setBackgroundColor ( GLfloat red, GLfloat green, GLfloat blue,
214  GLfloat alpha )
215  {
216  if ( background_color_[R] != red ||
217  background_color_[G] != green ||
218  background_color_[B] != blue ||
219  background_color_[A] != alpha ) {
220 
221  background_color_[R] = red;
222  background_color_[G] = green;
223  background_color_[B] = blue;
224  background_color_[A] = alpha;
225 
226  clearCaches();
227  }
228  }
229 
230  // Note: Changing the foreground color also clears the display list cache.
231 
232  void Face::setForegroundColor ( GLfloat red, GLfloat green, GLfloat blue,
233  GLfloat alpha )
234  {
235  if ( foreground_color_[R] != red ||
236  foreground_color_[G] != green ||
237  foreground_color_[B] != blue ||
238  foreground_color_[A] != alpha ) {
239 
240  foreground_color_[R] = red;
241  foreground_color_[G] = green;
242  foreground_color_[B] = blue;
243  foreground_color_[A] = alpha;
244 
245  clearCaches();
246  }
247  }
248 
249  // Note: Changing the foreground color also clears the display list cache.
250 
251  void Face::setForegroundColor ( const GLfloat foreground_color[4] )
252  {
253  if ( foreground_color_[R] != foreground_color[R] ||
254  foreground_color_[G] != foreground_color[G] ||
255  foreground_color_[B] != foreground_color[B] ||
256  foreground_color_[A] != foreground_color[A] ) {
257 
258  foreground_color_[R] = foreground_color[R];
259  foreground_color_[G] = foreground_color[G];
260  foreground_color_[B] = foreground_color[B];
261  foreground_color_[A] = foreground_color[A];
262 
263  clearCaches();
264  }
265  }
266 
267  // Note: Changing the background color also clears the display list cache.
268 
269  void Face::setBackgroundColor ( const GLfloat background_color[4] )
270  {
271  if ( background_color_[R] != background_color[R] ||
272  background_color_[G] != background_color[G] ||
273  background_color_[B] != background_color[B] ||
274  background_color_[A] != background_color[A] ) {
275 
276  background_color_[R] = background_color[R];
277  background_color_[G] = background_color[G];
278  background_color_[B] = background_color[B];
279  background_color_[A] = background_color[A];
280 
281  clearCaches();
282  }
283  }
284 #ifndef OGLFT_NO_QT
285  // Note: Changing the foreground color also clears the display list cache.
286 
287  void Face::setForegroundColor ( const QRgb foreground_rgba )
288  {
289  GLfloat foreground_color[4];
290  foreground_color[R] = qRed( foreground_rgba ) / 255.;
291  foreground_color[G] = qGreen( foreground_rgba ) / 255.;
292  foreground_color[B] = qBlue( foreground_rgba ) / 255.;
293  foreground_color[A] = qAlpha( foreground_rgba ) / 255.;
294 
295  if ( foreground_color_[R] != foreground_color[R] ||
296  foreground_color_[G] != foreground_color[G] ||
297  foreground_color_[B] != foreground_color[B] ||
298  foreground_color_[A] != foreground_color[A] ) {
299 
300  foreground_color_[R] = foreground_color[R];
301  foreground_color_[G] = foreground_color[G];
302  foreground_color_[B] = foreground_color[B];
303  foreground_color_[A] = foreground_color[A];
304 
305  clearCaches();
306  }
307  }
308 
309  // Note: Changing the background color also clears the display list cache.
310 
311  void Face::setBackgroundColor ( const QRgb background_rgba )
312  {
313  GLfloat background_color[4];
314  background_color[R] = qRed( background_rgba ) / 255.;
315  background_color[G] = qGreen( background_rgba ) / 255.;
316  background_color[B] = qBlue( background_rgba ) / 255.;
317  background_color[A] = qAlpha( background_rgba ) / 255.;
318 
319  if ( background_color_[R] != background_color[R] ||
320  background_color_[G] != background_color[G] ||
321  background_color_[B] != background_color[B] ||
322  background_color_[A] != background_color[A] ) {
323 
324  background_color_[R] = background_color[R];
325  background_color_[G] = background_color[G];
326  background_color_[B] = background_color[B];
327  background_color_[A] = background_color[A];
328 
329  clearCaches();
330  }
331  }
332 #endif /* OGLFT_NO_QT */
333  // Note: Changing the string rotation angle clears the display list cache
334 
335  void Face::setStringRotation ( GLfloat string_rotation )
336  {
337  if ( string_rotation != string_rotation_ ) {
338  string_rotation_ = string_rotation;
339 
340  clearCaches();
341 
342  // Note that this affects ALL glyphs accessed through
343  // the Face, both the vector and the raster glyphs. Very nice!
344 
345  if ( string_rotation_ != 0. ) {
346  float angle;
347  if ( string_rotation_ < 0. ) {
348  angle = 360. - fmod( fabs( string_rotation_ ), 360.f );
349  }
350  else {
351  angle = fmod( string_rotation_, 360.f );
352  }
353 
354  FT_Matrix rotation_matrix;
355  FT_Vector sinus;
356 
357  FT_Vector_Unit( &sinus, (FT_Angle)(angle * 0x10000L) );
358 
359  rotation_matrix.xx = sinus.x;
360  rotation_matrix.xy = -sinus.y;
361  rotation_matrix.yx = sinus.y;
362  rotation_matrix.yy = sinus.x;
363 
364  for ( unsigned int i = 0; i < faces_.size(); i++ )
365  FT_Set_Transform( faces_[i].face_, &rotation_matrix, 0 );
366  }
367  else
368  for ( unsigned int i = 0; i < faces_.size(); i++ )
369  FT_Set_Transform( faces_[i].face_, 0, 0 );
370  }
371  }
372 
373  // Note: Changing the rotation reference character clears the display list cache.
374 
375  void Face::setCharacterRotationReference ( unsigned char c )
376  {
377  unsigned int f;
378  FT_UInt glyph_index = 0;
379 
380  for ( f = 0; f < faces_.size(); f++ ) {
381  glyph_index = FT_Get_Char_Index( faces_[f].face_, c );
382  if ( glyph_index != 0 ) break;
383  }
384 
385  if ( f < faces_.size() && glyph_index != rotation_reference_glyph_ ) {
386 
387  FT_Error error = FT_Load_Glyph( faces_[f].face_, glyph_index,
388  FT_LOAD_DEFAULT );
389 
390  if ( error != 0 ) return;
391 
392  rotation_reference_glyph_ = glyph_index;
393 
395 
397 
398  clearCaches();
399  }
400  }
401 
402  BBox Face::measure ( const char* s )
403  {
404  BBox bbox;
405  char c;
406 
407  if ( ( c = *s++ ) != 0 ) {
408 
409  bbox = measure( c );
410 
411  for ( c = *s; c != 0; c = *++s ) {
412 
413  BBox char_bbox = measure( c );
414 
415  bbox += char_bbox;
416  }
417  }
418 
419  return bbox;
420  }
421 
422  BBox Face::measureRaw ( const char* s )
423  {
424  BBox bbox;
425 
426  for ( char c = *s; c != 0; c = *++s ) {
427  BBox char_bbox;
428 
429  unsigned int f;
430  FT_UInt glyph_index = 0;
431 
432  for ( f = 0; f < faces_.size(); f++ ) {
433  glyph_index = FT_Get_Char_Index( faces_[f].face_, c );
434  if ( glyph_index != 0 ) break;
435  }
436 
437  if ( glyph_index == 0 ) continue;
438 
439  FT_Error error = FT_Load_Glyph( faces_[f].face_, glyph_index,
440  FT_LOAD_DEFAULT );
441  if ( error != 0 ) continue;
442 
443  FT_Glyph glyph;
444  error = FT_Get_Glyph( faces_[f].face_->glyph, &glyph );
445  if ( error != 0 ) continue;
446 
447  FT_BBox ft_bbox;
448  FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_unscaled, &ft_bbox );
449 
450  FT_Done_Glyph( glyph );
451 
452  char_bbox = ft_bbox;
453  char_bbox.advance_ = faces_[f].face_->glyph->advance;
454 
455  bbox += char_bbox;
456  }
457 
458  return bbox;
459  }
460 
461 #ifndef OGLFT_NO_QT
462  BBox Face::measure ( const QString& s )
463  {
464  BBox bbox;
465 
466  if ( s.length() > 0 ) {
467 
468  bbox = measure( s.at( 0 ) );
469 
470  for ( unsigned int i = 1; i < s.length(); i++ ) {
471 
472  BBox char_bbox = measure( s.at( i ) );
473 
474  bbox += char_bbox;
475  }
476  }
477 
478  return bbox;
479  }
480 
481  BBox Face::measure ( const QString& format, double number )
482  {
483  return measure( format_number( format, number ) );
484  }
485 
486  BBox Face::measureRaw ( const QString& s )
487  {
488  BBox bbox;
489 
490  for ( unsigned int i = 0; i < s.length(); i++ ) {
491  BBox char_bbox;
492 
493  unsigned int f;
494  FT_UInt glyph_index = 0;
495 
496  for ( f = 0; f < faces_.size(); f++ ) {
497  glyph_index = FT_Get_Char_Index( faces_[f].face_, s.at( i ).unicode() );
498  if ( glyph_index != 0 ) break;
499  }
500 
501  if ( glyph_index == 0 ) {
502  continue;
503  }
504 
505  FT_Error error = FT_Load_Glyph( faces_[f].face_, glyph_index,
506  FT_LOAD_DEFAULT );
507  if ( error != 0 ) continue;
508 
509  FT_Glyph glyph;
510  error = FT_Get_Glyph( faces_[f].face_->glyph, &glyph );
511  if ( error != 0 ) continue;
512 
513  FT_BBox ft_bbox;
514  FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_unscaled, &ft_bbox );
515 
516  FT_Done_Glyph( glyph );
517 
518  char_bbox = ft_bbox;
519  char_bbox.advance_ = faces_[f].face_->glyph->advance;
520 
521  bbox += char_bbox;
522  }
523 
524  return bbox;
525  }
526 #endif /* OGLFT_NO_QT */
527 
528  // Measure the bounding box as if the (latin1) string were not rotated
529 
530  BBox Face::measure_nominal ( const char* s )
531  {
532  if ( string_rotation_ == 0. )
533  return measure( s );
534 
535  for ( unsigned int f = 0; f < faces_.size(); f++ )
536  FT_Set_Transform( faces_[f].face_, 0, 0 );
537 
538  BBox bbox = measure( s );
539 
540  float angle;
541  if ( string_rotation_ < 0. ) {
542  angle = 360. - fmod( fabs( string_rotation_ ), 360.f );
543  }
544  else {
545  angle = fmod( string_rotation_, 360.f );
546  }
547 
548  FT_Matrix rotation_matrix;
549  FT_Vector sinus;
550 
551  FT_Vector_Unit( &sinus, (FT_Angle)(angle * 0x10000L) );
552 
553  rotation_matrix.xx = sinus.x;
554  rotation_matrix.xy = -sinus.y;
555  rotation_matrix.yx = sinus.y;
556  rotation_matrix.yy = sinus.x;
557 
558  for ( unsigned int f = 0; f < faces_.size(); f++ )
559  FT_Set_Transform( faces_[f].face_, &rotation_matrix, 0 );
560 
561  return bbox;
562  }
563 
564 #ifndef OGLFT_NO_QT
565  // Measure the bounding box as if the (UNICODE) string were not rotated
566 
567  BBox Face::measure_nominal ( const QString& s )
568  {
569  if ( string_rotation_ == 0. )
570  return measure( s );
571 
572  for ( unsigned int f = 0; f < faces_.size(); f++ )
573  FT_Set_Transform( faces_[f].face_, 0, 0 );
574 
575  BBox bbox = measure( s );
576 
577  float angle;
578  if ( string_rotation_ < 0. ) {
579  angle = 360. - fmod( fabs( string_rotation_ ), 360.f );
580  }
581  else {
582  angle = fmod( string_rotation_, 360.f );
583  }
584 
585  FT_Matrix rotation_matrix;
586  FT_Vector sinus;
587 
588  FT_Vector_Unit( &sinus, (FT_Angle)(angle * 0x10000L) );
589 
590  rotation_matrix.xx = sinus.x;
591  rotation_matrix.xy = -sinus.y;
592  rotation_matrix.yx = sinus.y;
593  rotation_matrix.yy = sinus.x;
594 
595  for ( unsigned int f = 0; f < faces_.size(); f++ )
596  FT_Set_Transform( faces_[f].face_, &rotation_matrix, 0 );
597 
598  return bbox;
599  }
600 
601  // Format the number per the given format. Mostly pointless
602  // for the standard formats, e.g. %12e. You can use the regular
603  // Qt functions to format such a string and avoid the parsing
604  // which is done here.
605 
606  QString Face::format_number ( const QString& format, double number )
607  {
608  // This regexp says:
609  // 1. optionally match any thing up to a format,
610  // 2. the optional format (%...), and
611  // 3. optionally anything after it.
612  // Note that since everything is optional, the match always succeeds.
613  QRegExp format_regexp("((?:[^%]|%%)*)(%[0-9]*\\.?[0-9]*[efgp])?((?:[^%]|%%)*)");
614  /*int pos = */ format_regexp.search( format );
615 
616  QStringList list = format_regexp.capturedTexts();
617 
618  QStringList::Iterator it = list.begin();
619 
620  it = list.remove( it ); // Remove the "matched" string, leaving the pieces
621 
622  if ( it == list.end() ) return QString::null; // Probably an error
623 
624  // Extract each piece from the list
625 
626  QString prefix, value_format, postfix;
627  char type = '\0';
628 
629  if ( !(*it).isEmpty() )
630  prefix = *it;
631 
632  ++it;
633 
634  if ( it != list.end() ) {
635  if ( !(*it).isEmpty() ) {
636  // Reparse this to extract the details of the format
637  QRegExp specifier_regexp( "([0-9]*)\\.?([0-9]*)([efgp])" );
638  (void)specifier_regexp.search( *it );
639  QStringList specifier_list = specifier_regexp.capturedTexts();
640 
641  QStringList::Iterator sit = specifier_list.begin();
642 
643  sit = specifier_list.remove( sit );
644 
645  int width = (*sit).toInt();
646  ++sit;
647  int precision = (*sit).toInt();
648  ++sit;
649 
650  type = (*sit).at(0).latin1();
651 
652  // The regular formats just use Qt's number formatting capability
653  if ( type == 'e' || type == 'f' || type == 'g' )
654  value_format = QString( "%1" ).arg( number, width, type, precision );
655 
656  // For the fraction, though, we have to convert it the special
657  // UNICODE encoding
658  else if ( type == 'p' ) {
659  // Fixed for now...
660  if ( fabs( number ) < 1./256. )
661  value_format = "0";
662  else {
663  // Extract the integral part
664  int a = (int)number;
665 
666  if ( a != 0 )
667  value_format = QString::number( a );
668 
669  // Extract the fractional part: NOTE: THIS IS LIMITED TO
670  // REPRESENTING ALL FRACTIONS AS n/256
671  int b = (int)rint( 256. * fabs( number - a ) );
672 
673  // If b is exactly 256, then the original number was
674  // essentially an integer (to within 1/256-th)
675  if ( b == 256 )
676  value_format = QString::number( rint( number ) );
677 
678  else if ( b != 0 ) {
679  int c = 256;
680  // Remove common factors of two from the numerator and denominator
681  for ( ; ( b & 0x1 ) == 0; b >>= 1, c >>= 1 );
682 
683  // Format the numerator and shift to 0xE000 sequence
684  QString numerator = QString::number( b );
685  for ( uint i = 0; i < numerator.length(); i++ ) {
686  numerator.at(i) = QChar( numerator.at(i).unicode() -
687  QChar('0').unicode() +
688  0xE000 );
689  }
690  value_format += numerator;
691  value_format += QChar( 0xE00a ); // The '/'
692  // Format the denominator and shift to 0xE010 sequence
693  QString denominator = QString::number( c );
694  for ( uint i = 0; i < denominator.length(); i++ ) {
695  denominator.at(i) = QChar( denominator.at(i).unicode() -
696  QChar('0').unicode() +
697  0xE010 );
698  }
699  value_format += denominator;
700  }
701  }
702  }
703  }
704 
705  ++it;
706 
707  if ( it != list.end() && !(*it).isEmpty() )
708  postfix = *it;
709  }
710 
711  return prefix + value_format + postfix;
712  }
713 #endif /* OGLFT_NO_QT */
714 
715  // Compile a (latin1) string into a display list
716 
717  GLuint Face::compile ( const char* s )
718  {
719  // First, make sure all the characters in the string are themselves
720  // in display lists
721  const char* s_tmp = s;
722 
723  for ( char c = *s_tmp; c != 0; c = *++s_tmp ) {
724  compile( c );
725  }
726 
727  GLuint dlist = glGenLists( 1 );
728  glNewList( dlist, GL_COMPILE );
729 
731  foreground_color_[A] );
732  if ( !advance_ )
733  glPushMatrix();
734 
735  draw( s );
736 
737  if ( !advance_ )
738  glPopMatrix();
739 
740  glEndList();
741 
742  return dlist;
743  }
744 #ifndef OGLFT_NO_QT
745  // Compile a (UNICODE) string into a display list
746 
747  GLuint Face::compile ( const QString& s )
748  {
749  // First, make sure all the characters in the string are themselves
750  // in display lists
751  for ( unsigned int i = 0; i < s.length(); i++ ) {
752  compile( s.at( i ) );
753  }
754 
755  GLuint dlist = glGenLists( 1 );
756  glNewList( dlist, GL_COMPILE );
757 
759  foreground_color_[A] );
760  if ( !advance_ )
761  glPushMatrix();
762 
763  draw( s );
764 
765  if ( !advance_ )
766  glPopMatrix();
767 
768  glEndList();
769 
770  return dlist;
771  }
772 #endif /* OGLFT_NO_QT */
773  // Compile a (latin1) character glyph into a display list and cache
774  // it for later
775 
776  GLuint Face::compile ( unsigned char c )
777  {
778  // See if we've done it already
779 
780  GDLCI fgi = glyph_dlists_.find( c );
781 
782  if ( fgi != glyph_dlists_.end() )
783  return fgi->second;
784 
785  unsigned int f;
786  FT_UInt glyph_index = 0;
787 
788  for ( f = 0; f < faces_.size(); f++ ) {
789  glyph_index = FT_Get_Char_Index( faces_[f].face_, c );
790  if ( glyph_index != 0 ) break;
791  }
792 
793  if ( glyph_index == 0 )
794  return 0;
795 
796  GLuint dlist = compileGlyph( faces_[f].face_, glyph_index );
797 
798  glyph_dlists_[ c ] = dlist;
799 
800  return dlist;
801  }
802 
803 #ifndef OGLFT_NO_QT
804  // Compile a (UNICODE) character glyph into a display list and cache
805  // it for later
806 
807  GLuint Face::compile ( const QChar c )
808  {
809  // See if we've done it already
810 
811  GDLCI fgi = glyph_dlists_.find( c.unicode() );
812 
813  if ( fgi != glyph_dlists_.end() )
814  return fgi->second;
815 
816  unsigned int f;
817  FT_UInt glyph_index = 0;
818 
819  for ( f = 0; f < faces_.size(); f++ ) {
820  glyph_index = FT_Get_Char_Index( faces_[f].face_, c.unicode() );
821  if ( glyph_index != 0 ) break;
822  }
823 
824  if ( glyph_index == 0 )
825  return 0;
826 
827  GLuint dlist = compileGlyph( faces_[f].face_, glyph_index );
828 
829  glyph_dlists_[ c.unicode() ] = dlist;
830 
831  return dlist;
832  }
833 #endif /* OGLFT_NO_QT */
834  // Assume the MODELVIEW matrix is already set and draw the (latin1)
835  // string. Note: this routine now ignores almost all settings:
836  // including the position (both modelview and raster), color,
837  // justification and advance settings. Consider this to be the raw
838  // drawing routine for which you are responsible for most of the
839  // setup.
840 
841  void Face::draw ( const char* s )
842  {
843  DLCI character_display_list = character_display_lists_.begin();
844 
845  for ( char c = *s; c != 0; c = *++s ) {
846 
847  if ( character_display_list != character_display_lists_.end() ) {
848  glCallList( *character_display_list );
849  character_display_list++;
850  }
851 
852  draw( c );
853  }
854  }
855 #ifndef OGLFT_NO_QT
856  // Assume the MODELVIEW matrix is already set and draw the (UNICODE)
857  // string. Note: this routine now ignores almost all settings:
858  // including the position (both modelview and raster), color,
859  // justification and advance settings. Consider this to be the raw
860  // drawing routine for which you are responsible for most of the
861  // setup.
862 
863  void Face::draw ( const QString& s )
864  {
865  DLCI character_display_list = character_display_lists_.begin();
866 
867  for ( unsigned int i = 0; i < s.length(); i++ ) {
868 
869  if ( character_display_list != character_display_lists_.end() ) {
870  glCallList( *character_display_list );
871  character_display_list++;
872  }
873 
874  draw( s.at( i ) );
875  }
876  }
877 #endif /* OGLFT_NO_QT */
878 
879  // Assume the MODELVIEW matrix is already setup and draw the
880  // (latin1) character.
881 
882  void Face::draw ( unsigned char c )
883  {
884  // See if we've done it already
885 
886  GDLCI fgi = glyph_dlists_.find( c );
887 
888  if ( fgi != glyph_dlists_.end( ) ) {
889  glCallList( fgi->second );
890  return;
891  }
892 
893  unsigned int f;
894  FT_UInt glyph_index = 0;
895 
896  for ( f = 0; f < faces_.size(); f++ ) {
897  glyph_index = FT_Get_Char_Index( faces_[f].face_, c );
898  if ( glyph_index != 0 ) break;
899  }
900 
901  if ( glyph_index == 0 )
902  return;
903 
904  // Otherwise, either compile it (and call it) or ...
905 
906  else if ( compile_mode_ == COMPILE ) {
907  GLuint dlist = compile( c );
908  glCallList( dlist );
909  }
910 
911  // ... render it immediately
912 
913  else {
914  renderGlyph( faces_[f].face_, glyph_index );
915  }
916  }
917 #ifndef OGLFT_NO_QT
918  // Assume the MODELVIEW matrix is already setup and draw the
919  // (UNICODE) character.
920 
921  void Face::draw ( const QChar c )
922  {
923  // See if we've done it already
924 
925  GDLCI fgi = glyph_dlists_.find( c.unicode() );
926 
927  if ( fgi != glyph_dlists_.end( ) ) {
928  glCallList( fgi->second );
929  return;
930  }
931 
932  unsigned int f;
933  FT_UInt glyph_index = 0;
934 
935  for ( f = 0; f < faces_.size(); f++ ) {
936  glyph_index = FT_Get_Char_Index( faces_[f].face_, c.unicode() );
937  if ( glyph_index != 0 ) {
938  break;
939  }
940  }
941 
942  if ( glyph_index == 0 )
943  return;
944 
945  // Otherwise, either compile it (and call it) or ...
946 
947  if ( compile_mode_ == COMPILE ) {
948  GLuint dlist = compile( c );
949  glCallList( dlist );
950  }
951 
952  // ... render it immediately
953 
954  else {
955  renderGlyph( faces_[f].face_, glyph_index );
956  }
957  }
958 #endif /* OGLFT_NO_QT */
959  // Draw the (latin1) character at the given position. The MODELVIEW
960  // matrix is modified by the glyph advance.
961 
962  void Face::draw ( GLfloat x, GLfloat y, unsigned char c )
963  {
964  glTranslatef( x, y, 0. );
965 
967  foreground_color_[A] );
968 
969  glRasterPos2i( 0, 0 );
970 
971  draw( c );
972  }
973 
974  // Draw the (latin1) character at the given position. The MODELVIEW
975  // matrix is modified by the glyph advance.
976 
977  void Face::draw ( GLfloat x, GLfloat y, GLfloat z, unsigned char c )
978  {
979  glTranslatef( x, y, z );
980 
982  foreground_color_[A] );
983 
984  glRasterPos2i( 0, 0 );
985 
986  draw( c );
987  }
988 #ifndef OGLFT_NO_QT
989  // Draw the (UNICODE) character at the given position. The MODELVIEW
990  // matrix is modified by the glyph advance.
991 
992  void Face::draw ( GLfloat x, GLfloat y, QChar c )
993  {
994  glTranslatef( x, y, 0. );
995 
997  foreground_color_[A] );
998 
999  glRasterPos2i( 0, 0 );
1000 
1001  draw( c );
1002  }
1003 
1004  // Draw the (UNICODE) character at the given position. The MODELVIEW
1005  // matrix is modified by the glyph advance.
1006 
1007  void Face::draw ( GLfloat x, GLfloat y, GLfloat z, QChar c )
1008  {
1009  glTranslatef( x, y, z );
1010 
1012  foreground_color_[A] );
1013 
1014  glRasterPos2i( 0, 0 );
1015 
1016  draw( c );
1017  }
1018 #endif /* OGLFT_NO_QT */
1019 
1020  // Draw the (latin1) string at the given position.
1021 
1022  void Face::draw ( GLfloat x, GLfloat y, const char* s )
1023  {
1024  if ( !advance_ )
1025  glPushMatrix();
1026 
1029  glPushMatrix();
1030 
1031  BBox bbox = measure_nominal( s );
1032 
1033  GLfloat dx = 0, dy = 0;
1034 
1035  switch ( horizontal_justification_ ) {
1036  case LEFT:
1037  dx = -bbox.x_min_; break;
1038  case CENTER:
1039  dx = -( bbox.x_min_ + bbox.x_max_ ) / 2.; break;
1040  case RIGHT:
1041  dx = -bbox.x_max_; break;
1042  default:
1043  break;
1044  }
1045  switch ( vertical_justification_ ) {
1046  case BOTTOM:
1047  dy = -bbox.y_min_; break;
1048  case MIDDLE:
1049  dy = -( bbox.y_min_ + bbox.y_max_ ) / 2.; break;
1050  case TOP:
1051  dy = -bbox.y_max_; break;
1052  default:
1053  break;
1054  }
1055 
1056  // There is probably a less expensive way to compute this
1057 
1058  glRotatef( string_rotation_, 0., 0., 1. );
1059  glTranslatef( dx, dy, 0 );
1060  glRotatef( -string_rotation_, 0., 0., 1. );
1061  }
1062 
1063  glTranslatef( x, y, 0. );
1064 
1066  foreground_color_[A] );
1067 
1068  glRasterPos2i( 0, 0 );
1069 
1070  draw( s );
1071 
1074  glPopMatrix();
1075 
1076  if ( !advance_ )
1077  glPopMatrix();
1078  }
1079 
1080  // Draw the (latin1) string at the given position.
1081 
1082  void Face::draw ( GLfloat x, GLfloat y, GLfloat z, const char* s )
1083  {
1084  if ( !advance_ )
1085  glPushMatrix();
1086 
1089  glPushMatrix();
1090 
1091  BBox bbox = measure_nominal( s );
1092 
1093  GLfloat dx = 0, dy = 0;
1094 
1095  switch ( horizontal_justification_ ) {
1096  case LEFT:
1097  dx = -bbox.x_min_; break;
1098  case CENTER:
1099  dx = -( bbox.x_min_ + bbox.x_max_ ) / 2.; break;
1100  case RIGHT:
1101  dx = -bbox.x_max_; break;
1102  default:
1103  break;
1104  }
1105  switch ( vertical_justification_ ) {
1106  case BOTTOM:
1107  dy = -bbox.y_min_; break;
1108  case MIDDLE:
1109  dy = -( bbox.y_min_ + bbox.y_max_ ) / 2.; break;
1110  case TOP:
1111  dy = -bbox.y_max_; break;
1112  default:
1113  break;
1114  }
1115 
1116  // There is probably a less expensive way to compute this
1117 
1118  glRotatef( string_rotation_, 0., 0., 1. );
1119  glTranslatef( dx, dy, 0 );
1120  glRotatef( -string_rotation_, 0., 0., 1. );
1121  }
1122 
1123  glTranslatef( x, y, z );
1124 
1126  foreground_color_[A] );
1127 
1128  glRasterPos2i( 0, 0 );
1129 
1130  draw( s );
1131 
1134  glPopMatrix();
1135 
1136  if ( !advance_ )
1137  glPopMatrix();
1138  }
1139 
1140 #ifndef OGLFT_NO_QT
1141  // Draw the (UNICODE) string at the given position.
1142 
1143  void Face::draw ( GLfloat x, GLfloat y, const QString& s )
1144  {
1145  if ( !advance_ )
1146  glPushMatrix();
1147 
1150  glPushMatrix();
1151 
1152  BBox bbox = measure_nominal( s );
1153 
1154  GLfloat dx = 0, dy = 0;
1155 
1156  switch ( horizontal_justification_ ) {
1157  case LEFT:
1158  dx = -bbox.x_min_; break;
1159  case CENTER:
1160  dx = -( bbox.x_min_ + bbox.x_max_ ) / 2.; break;
1161  case RIGHT:
1162  dx = -bbox.x_max_; break;
1163  }
1164  switch ( vertical_justification_ ) {
1165  case BOTTOM:
1166  dy = -bbox.y_min_; break;
1167  case MIDDLE:
1168  dy = -( bbox.y_min_ + bbox.y_max_ ) / 2.; break;
1169  case TOP:
1170  dy = -bbox.y_max_; break;
1171  }
1172 
1173  // There is probably a less expensive way to compute this
1174 
1175  glRotatef( string_rotation_, 0., 0., 1. );
1176  glTranslatef( dx, dy, 0 );
1177  glRotatef( -string_rotation_, 0., 0., 1. );
1178  }
1179 
1180  glTranslatef( x, y, 0. );
1181 
1183  foreground_color_[A] );
1184 
1185  glRasterPos2i( 0, 0 );
1186 
1187  draw( s );
1188 
1191  glPopMatrix();
1192 
1193  if ( !advance_ )
1194  glPopMatrix();
1195  }
1196 
1197  // Draw the (UNICODE) string at the given position.
1198 
1199  void Face::draw ( GLfloat x, GLfloat y, GLfloat z, const QString& s )
1200  {
1201  if ( !advance_ )
1202  glPushMatrix();
1203 
1206  glPushMatrix();
1207 
1208  // In 3D, we need to exert more care in the computation of the
1209  // bounding box of the text. NOTE: Needs to be fixed up for
1210  // polygonal faces, too...
1211 
1212  BBox bbox;
1213  // Code from measure_nominal, but changed to use measureRaw instead
1214  if ( string_rotation_ == 0. )
1215  bbox = measureRaw( s );
1216 
1217  else {
1218  // Undo rotation
1219  for ( unsigned int f = 0; f < faces_.size(); f++ )
1220  FT_Set_Transform( faces_[f].face_, 0, 0 );
1221 
1222  bbox = measureRaw( s );
1223 
1224  // Redo rotation
1225  float angle;
1226  if ( string_rotation_ < 0. ) {
1227  angle = 360. - fmod( fabs( string_rotation_ ), 360.f );
1228  }
1229  else {
1230  angle = fmod( string_rotation_, 360.f );
1231  }
1232 
1233  FT_Matrix rotation_matrix;
1234  FT_Vector sinus;
1235 
1236  FT_Vector_Unit( &sinus, (FT_Angle)(angle * 0x10000L) );
1237 
1238  rotation_matrix.xx = sinus.x;
1239  rotation_matrix.xy = -sinus.y;
1240  rotation_matrix.yx = sinus.y;
1241  rotation_matrix.yy = sinus.x;
1242 
1243  for ( unsigned int f = 0; f < faces_.size(); f++ )
1244  FT_Set_Transform( faces_[f].face_, &rotation_matrix, 0 );
1245  }
1246 
1247  // Determine the offset into the bounding box which will appear
1248  // at the user's specified position.
1249  GLfloat dx = 0, dy = 0;
1250  switch ( horizontal_justification_ ) {
1251  case LEFT:
1252  dx = bbox.x_min_; break;
1253  case CENTER:
1254  dx = ( bbox.x_min_ + bbox.x_max_ ) / 2; break;
1255  case RIGHT:
1256  dx = bbox.x_max_; break;
1257  }
1258  switch ( vertical_justification_ ) {
1259  case BOTTOM:
1260  dy = bbox.y_min_; break;
1261  case MIDDLE:
1262  dy = ( bbox.y_min_ + bbox.y_max_ ) /2; break;
1263  case TOP:
1264  dy = bbox.y_max_; break;
1265  }
1266 
1267  // **Now** rotate these coordinates around into 3D modeling coordinates!
1268  GLint viewport[4];
1269  GLdouble modelview[16], projection[16];
1270 
1271  glGetIntegerv( GL_VIEWPORT, viewport );
1272  glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
1273  glGetDoublev( GL_PROJECTION_MATRIX, projection );
1274 
1275  GLdouble x0, y0, z0;
1276  gluUnProject( 0, 0, 0, modelview, projection, viewport, &x0, &y0, &z0 );
1277 
1278  GLdouble dx_m, dy_m, dz_m;
1279  gluUnProject( dx, dy, 0., modelview, projection, viewport,&dx_m,&dy_m,&dz_m );
1280 
1281  glTranslated( x0-dx_m, y0-dy_m, z0-dz_m );
1282  }
1283 
1284  glTranslatef( x, y, z );
1285 
1287  foreground_color_[A] );
1288 
1289  glRasterPos2i( 0, 0 );
1290 
1291  draw( s );
1292 
1295  glPopMatrix();
1296 
1297  if ( !advance_ )
1298  glPopMatrix();
1299  }
1300 
1301  // Draw the number at the given position per the given format.
1302 
1303  void Face::draw ( GLfloat x, GLfloat y, const QString& format, double number )
1304  {
1305  draw( x, y, format_number( format, number ) );
1306  }
1307 
1308  // Draw the number at the given position per the given format.
1309 
1310  void Face::draw ( GLfloat x, GLfloat y, GLfloat z, const QString& format,
1311  double number )
1312  {
1313  draw( x, y, z, format_number( format, number ) );
1314  }
1315 #endif /* OGLFT_NO_QT */
1316 
1317  Raster::Raster ( const char* filename, float point_size, FT_UInt resolution )
1318  : Face( filename, point_size, resolution )
1319  {
1320  if ( !isValid() ) return;
1321 
1322  init();
1323  }
1324 
1325  Raster::Raster ( FT_Face face, float point_size, FT_UInt resolution )
1326  : Face( face, point_size, resolution )
1327  {
1328  init();
1329  }
1330 
1331  void Raster::init ( void )
1332  {
1334 
1335  setCharSize();
1336 
1338  }
1339 
1341  {
1342  clearCaches();
1343  }
1344 
1345  void Raster::setCharacterRotationZ ( GLfloat character_rotation_z )
1346  {
1347  if ( character_rotation_z != character_rotation_z_ ) {
1348  character_rotation_z_ = character_rotation_z;
1349 
1350  clearCaches();
1351  }
1352  }
1353 
1354  double Raster::height ( void ) const
1355  {
1356  if ( faces_[0].face_->height > 0 )
1357  return faces_[0].face_->height / 64.;
1358  else
1359  return faces_[0].face_->size->metrics.y_ppem;
1360  }
1361 
1362  BBox Raster::measure ( unsigned char c )
1363  {
1364  BBox bbox;
1365  // For starters, just get the unscaled glyph bounding box
1366  unsigned int f;
1367  FT_UInt glyph_index = 0;
1368 
1369  for ( f = 0; f < faces_.size(); f++ ) {
1370  glyph_index = FT_Get_Char_Index( faces_[f].face_, c );
1371  if ( glyph_index != 0 ) break;
1372  }
1373 
1374  if ( glyph_index == 0 )
1375  return bbox;
1376 
1377  FT_Error error = FT_Load_Glyph( faces_[f].face_, glyph_index,
1378  FT_LOAD_DEFAULT );
1379  if ( error != 0 )
1380  return bbox;
1381 
1382  FT_Glyph glyph;
1383  error = FT_Get_Glyph( faces_[f].face_->glyph, &glyph );
1384  if ( error != 0 )
1385  return bbox;
1386 
1387  FT_BBox ft_bbox;
1388  FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_unscaled, &ft_bbox );
1389 
1390  FT_Done_Glyph( glyph );
1391 
1392  bbox = ft_bbox;
1393  bbox.advance_ = faces_[f].face_->glyph->advance;
1394 
1395  // In order to be accurate regarding the placement of text not
1396  // aligned at the glyph's origin (CENTER/MIDDLE), the bounding box
1397  // of the raster format has to be projected back into the
1398  // view's coordinates
1399 
1400  GLint viewport[4];
1401  GLdouble modelview[16], projection[16];
1402 
1403  glGetIntegerv( GL_VIEWPORT, viewport );
1404  glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
1405  glGetDoublev( GL_PROJECTION_MATRIX, projection );
1406 
1407  // Well, first we have to get the Origin, since that is the basis
1408  // of the bounding box
1409  GLdouble x0, y0, z0;
1410  gluUnProject( 0., 0., 0., modelview, projection, viewport, &x0, &y0, &z0 );
1411 
1412  GLdouble x, y, z;
1413  gluUnProject( bbox.x_min_, bbox.y_min_, 0., modelview, projection, viewport,
1414  &x, &y, &z );
1415  bbox.x_min_ = x - x0;
1416  bbox.y_min_ = y - y0;
1417 
1418  gluUnProject( bbox.x_max_, bbox.y_max_, 0., modelview, projection, viewport,
1419  &x, &y, &z );
1420  bbox.x_max_ = x - x0;
1421  bbox.y_max_ = y - y0;
1422 
1423  gluUnProject( bbox.advance_.dx_, bbox.advance_.dy_, 0., modelview, projection,
1424  viewport,
1425  &x, &y, &z );
1426  bbox.advance_.dx_ = x - x0;
1427  bbox.advance_.dy_ = y - y0;
1428 
1429  return bbox;
1430  }
1431 
1432 #ifndef OGLFT_NO_QT
1433  BBox Raster::measure ( const QChar c )
1434  {
1435  BBox bbox;
1436  // For starters, just get the unscaled glyph bounding box
1437  unsigned int f;
1438  FT_UInt glyph_index = 0;
1439 
1440  for ( f = 0; f < faces_.size(); f++ ) {
1441  glyph_index = FT_Get_Char_Index( faces_[f].face_, c.unicode() );
1442  if ( glyph_index != 0 ) break;
1443  }
1444 
1445  if ( glyph_index == 0 )
1446  return bbox;
1447 
1448  FT_Error error = FT_Load_Glyph( faces_[f].face_, glyph_index,
1449  FT_LOAD_DEFAULT );
1450  if ( error != 0 )
1451  return bbox;
1452 
1453  FT_Glyph glyph;
1454  error = FT_Get_Glyph( faces_[f].face_->glyph, &glyph );
1455  if ( error != 0 )
1456  return bbox;
1457 
1458  FT_BBox ft_bbox;
1459  FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_unscaled, &ft_bbox );
1460 
1461  FT_Done_Glyph( glyph );
1462 
1463  bbox = ft_bbox;
1464  bbox.advance_ = faces_[f].face_->glyph->advance;
1465 
1466  // In order to be accurate regarding the placement of text not
1467  // aligned at the glyph's origin (CENTER/MIDDLE), the bounding box
1468  // of the raster format has to be projected back into the
1469  // view's coordinates
1470 
1471  GLint viewport[4];
1472  GLdouble modelview[16], projection[16];
1473 
1474  glGetIntegerv( GL_VIEWPORT, viewport );
1475  glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
1476  glGetDoublev( GL_PROJECTION_MATRIX, projection );
1477 
1478  // Well, first we have to get the Origin, since that is the basis
1479  // of the bounding box
1480  GLdouble x0, y0, z0;
1481  gluUnProject( 0., 0., 0., modelview, projection, viewport, &x0, &y0, &z0 );
1482 
1483  GLdouble x, y, z;
1484  gluUnProject( bbox.x_min_, bbox.y_min_, 0., modelview, projection, viewport,
1485  &x, &y, &z );
1486  bbox.x_min_ = x - x0;
1487  bbox.y_min_ = y - y0;
1488 
1489  gluUnProject( bbox.x_max_, bbox.y_max_, 0., modelview, projection, viewport,
1490  &x, &y, &z );
1491  bbox.x_max_ = x - x0;
1492  bbox.y_max_ = y - y0;
1493 
1494  gluUnProject( bbox.advance_.dx_, bbox.advance_.dy_, 0., modelview, projection,
1495  viewport,
1496  &x, &y, &z );
1497  bbox.advance_.dx_ = x - x0;
1498  bbox.advance_.dy_ = y - y0;
1499 
1500  return bbox;
1501  }
1502 #endif /* OGLFT_NO_QT */
1503 
1504  GLuint Raster::compileGlyph ( FT_Face face, FT_UInt glyph_index )
1505  {
1506  GLuint dlist = glGenLists( 1 );
1507  glNewList( dlist, GL_COMPILE );
1508 
1509  renderGlyph( face, glyph_index );
1510 
1511  glEndList( );
1512 
1513  return dlist;
1514  }
1515 
1516  void Raster::setCharSize ( void )
1517  {
1518  FT_Error error;
1519  for ( unsigned int i = 0; i < faces_.size(); i++ ) {
1520  error = FT_Set_Char_Size( faces_[i].face_,
1521  (FT_F26Dot6)( point_size_ * 64 ),
1522  (FT_F26Dot6)( point_size_ * 64 ),
1523  resolution_,
1524  resolution_ );
1525  if ( error != 0 ) return;
1526  }
1527 
1528  if ( rotation_reference_glyph_ != 0 )
1529  setRotationOffset();
1530  }
1531 
1532  void Raster::setRotationOffset ( void )
1533  {
1534  FT_Error error = FT_Load_Glyph( rotation_reference_face_,
1536  FT_LOAD_RENDER );
1537 
1538  if ( error != 0 )
1539  return;
1540 
1541  rotation_offset_y_ = rotation_reference_face_->glyph->bitmap.rows / 2.;
1542  }
1543 
1544  void Raster::clearCaches ( void )
1545  {
1546  GDLI fgi = glyph_dlists_.begin();
1547 
1548  for ( ; fgi != glyph_dlists_.end(); ++fgi ) {
1549  glDeleteLists( fgi->second, 1 );
1550  }
1551 
1552  glyph_dlists_.clear();
1553  }
1554 
1555  Monochrome::Monochrome ( const char* filename, float point_size,
1556  FT_UInt resolution )
1557  : Raster( filename, point_size, resolution )
1558  {}
1559 
1560  Monochrome::Monochrome ( FT_Face face, float point_size, FT_UInt resolution )
1561  : Raster( face, point_size, resolution )
1562  {}
1563 
1565  {}
1566 
1567  GLubyte* Monochrome::invertBitmap ( const FT_Bitmap& bitmap )
1568  {
1569  // In FreeType 2.0.9, the pitch of bitmaps was rounded up to an
1570  // even number. In general, this disagrees with what we had been
1571  // using for OpenGL.
1572 
1573  int width = bitmap.width / 8 + ( ( bitmap.width & 7 ) > 0 ? 1 : 0 );
1574 
1575  GLubyte* inverse = new GLubyte[ bitmap.rows * width ];
1576  GLubyte* inverse_ptr = inverse;
1577 
1578  for ( int r = 0; r < bitmap.rows; r++ ) {
1579 
1580  GLubyte* bitmap_ptr = &bitmap.buffer[bitmap.pitch * ( bitmap.rows - r - 1 )];
1581 
1582  for ( int p = 0; p < width; p++ )
1583  *inverse_ptr++ = *bitmap_ptr++;
1584  }
1585 
1586  return inverse;
1587  }
1588 
1589  void Monochrome::renderGlyph ( FT_Face face, FT_UInt glyph_index )
1590  {
1591  // Start by retrieving the glyph's data.
1592 
1593  FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
1594 
1595  if ( error != 0 )
1596  return;
1597 
1598  FT_Glyph original_glyph;
1599  FT_Glyph glyph;
1600 
1601  error = FT_Get_Glyph( face->glyph, &original_glyph );
1602 
1603  if ( error != 0 )
1604  return;
1605 
1606  error = FT_Glyph_Copy( original_glyph, &glyph );
1607 
1608  FT_Done_Glyph( original_glyph );
1609 
1610  if ( error != 0 )
1611  return;
1612 
1613  // If the individual characters are rotated (as distinct from string
1614  // rotation), then apply that extra rotation here. This is equivalent
1615  // to the sequence
1616  // glTranslate(x_center,y_center);
1617  // glRotate(angle);
1618  // glTranslate(-x_center,-y_center);
1619  // which is used for the polygonal styles. The deal with the raster
1620  // styles is that you must retain the advance from the string rotation
1621  // so that the glyphs are laid out properly. So, we make a copy of
1622  // the string rotated glyph, and then rotate that and add back an
1623  // additional offset to (in effect) restore the proper origin and
1624  // advance of the glyph.
1625 
1626  if ( character_rotation_z_ != 0. ) {
1627  FT_Matrix rotation_matrix;
1628  FT_Vector sinus;
1629 
1630  FT_Vector_Unit( &sinus, (FT_Angle)(character_rotation_z_ * 0x10000L) );
1631 
1632  rotation_matrix.xx = sinus.x;
1633  rotation_matrix.xy = -sinus.y;
1634  rotation_matrix.yx = sinus.y;
1635  rotation_matrix.yy = sinus.x;
1636 
1637  FT_Vector original_offset, rotation_offset;
1638 
1639  original_offset.x = ( face->glyph->metrics.width / 2
1640  + face->glyph->metrics.horiBearingX ) / 64 * 0x10000L;
1641  original_offset.y = (FT_Pos)(rotation_offset_y_ * 0x10000L);
1642 
1643  rotation_offset = original_offset;
1644 
1645  FT_Vector_Rotate( &rotation_offset,
1646  (FT_Angle)(character_rotation_z_ * 0x10000L) );
1647 
1648  rotation_offset.x = original_offset.x - rotation_offset.x;
1649  rotation_offset.y = original_offset.y - rotation_offset.y;
1650 
1651  rotation_offset.x /= 1024;
1652  rotation_offset.y /= 1024;
1653 
1654  error = FT_Glyph_Transform( glyph, &rotation_matrix, &rotation_offset );
1655  }
1656 
1657  error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_MONO, 0, 1 );
1658 
1659  if ( error != 0 ) {
1660  FT_Done_Glyph( glyph );
1661  return;
1662  }
1663 
1664  FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
1665 
1666  // Evidently, in FreeType2, you can only get "upside-down" bitmaps and
1667  // OpenGL won't invert a bitmap with PixelZoom, so we have to invert the
1668  // glyph's bitmap ourselves.
1669 
1670  GLubyte* inverted_bitmap = invertBitmap( bitmap_glyph->bitmap );
1671 
1672  glBitmap( bitmap_glyph->bitmap.width, bitmap_glyph->bitmap.rows,
1673  -bitmap_glyph->left,
1674  bitmap_glyph->bitmap.rows - bitmap_glyph->top,
1675  face->glyph->advance.x / 64.,
1676  face->glyph->advance.y / 64.,
1677  inverted_bitmap );
1678 
1679  FT_Done_Glyph( glyph );
1680 
1681  delete[] inverted_bitmap;
1682  }
1683 
1684  Grayscale::Grayscale ( const char* filename, float point_size,
1685  FT_UInt resolution )
1686  : Raster( filename, point_size, resolution )
1687  {}
1688 
1689  Grayscale::Grayscale ( FT_Face face, float point_size, FT_UInt resolution )
1690  : Raster( face, point_size, resolution )
1691  {}
1692 
1694  {}
1695 
1696  GLubyte* Grayscale::invertPixmap ( const FT_Bitmap& bitmap )
1697  {
1698  GLubyte* inverse = new GLubyte[ bitmap.rows * bitmap.pitch ];
1699  GLubyte* inverse_ptr = inverse;
1700 
1701  for ( int r = 0; r < bitmap.rows; r++ ) {
1702 
1703  GLubyte* bitmap_ptr = &bitmap.buffer[bitmap.pitch * ( bitmap.rows - r - 1 )];
1704 
1705  for ( int p = 0; p < bitmap.pitch; p++ ) {
1706  *inverse_ptr++ = *bitmap_ptr++;
1707  }
1708  }
1709 
1710  return inverse;
1711  }
1712 
1713  void Grayscale::renderGlyph ( FT_Face face, FT_UInt glyph_index )
1714  {
1715  FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
1716 
1717  if ( error != 0 )
1718  return;
1719 
1720  FT_Glyph original_glyph;
1721  FT_Glyph glyph;
1722 
1723  error = FT_Get_Glyph( face->glyph, &original_glyph );
1724 
1725  if ( error != 0 ) return;
1726 
1727  error = FT_Glyph_Copy( original_glyph, &glyph );
1728 
1729  FT_Done_Glyph( original_glyph );
1730 
1731  if ( error != 0 ) return;
1732 
1733  if ( character_rotation_z_ != 0. ) {
1734  FT_Matrix rotation_matrix;
1735  FT_Vector sinus;
1736 
1737  FT_Vector_Unit( &sinus, (FT_Angle)(character_rotation_z_ * 0x10000L) );
1738 
1739  rotation_matrix.xx = sinus.x;
1740  rotation_matrix.xy = -sinus.y;
1741  rotation_matrix.yx = sinus.y;
1742  rotation_matrix.yy = sinus.x;
1743 
1744  FT_Vector original_offset, rotation_offset;
1745 
1746  original_offset.x = ( face->glyph->metrics.width / 2
1747  + face->glyph->metrics.horiBearingX ) / 64 * 0x10000L;
1748  original_offset.y = (FT_Pos)(rotation_offset_y_ * 0x10000L);
1749 
1750  rotation_offset = original_offset;
1751 
1752  FT_Vector_Rotate( &rotation_offset,
1753  (FT_Angle)(character_rotation_z_ * 0x10000L) );
1754 
1755  rotation_offset.x = original_offset.x - rotation_offset.x;
1756  rotation_offset.y = original_offset.y - rotation_offset.y;
1757 
1758  rotation_offset.x /= 1024;
1759  rotation_offset.y /= 1024;
1760 
1761  error = FT_Glyph_Transform( glyph, &rotation_matrix, &rotation_offset );
1762  }
1763 
1764  error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1765 
1766  if ( error != 0 ) {
1767  FT_Done_Glyph( glyph );
1768  return;
1769  }
1770 
1771  FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
1772 
1773  // Evidently, in FreeType2, you can only get "upside-down" bitmaps
1774  // (this could be cured with PixelZoom, but that an additional function)
1775 
1776  GLubyte* inverted_pixmap = invertPixmap( bitmap_glyph->bitmap );
1777 
1778  // :-( If this is compiled in a display list, it may or not be in effect
1779  // later when the list is actually called. So, the client should be alerted
1780  // to this fact: unpack alignment must be 1
1781 
1782  glPushAttrib( GL_PIXEL_MODE_BIT );
1783  glPixelTransferf( GL_RED_SCALE, foreground_color_[R] - background_color_[R] );
1784  glPixelTransferf( GL_GREEN_SCALE, foreground_color_[G] - background_color_[G] );
1785  glPixelTransferf( GL_BLUE_SCALE, foreground_color_[B] - background_color_[B] );
1786  glPixelTransferf( GL_ALPHA_SCALE, foreground_color_[A] );
1787  glPixelTransferf( GL_RED_BIAS, background_color_[R] );
1788  glPixelTransferf( GL_GREEN_BIAS, background_color_[G] );
1789  glPixelTransferf( GL_BLUE_BIAS, background_color_[B] );
1790  glPixelTransferf( GL_ALPHA_BIAS, background_color_[A] );
1791 
1792  glBitmap( 0, 0, 0, 0,
1793  bitmap_glyph->left,
1794  bitmap_glyph->top - bitmap_glyph->bitmap.rows,
1795  0 );
1796 
1797  glDrawPixels( bitmap_glyph->bitmap.width, bitmap_glyph->bitmap.rows,
1798  GL_LUMINANCE, GL_UNSIGNED_BYTE,
1799  inverted_pixmap );
1800 
1801  // This is how you advance the raster position when drawing PIXMAPS
1802  // (without querying the state)
1803 
1804  glBitmap( 0, 0, 0, 0,
1805  -bitmap_glyph->left + face->glyph->advance.x / 64.,
1806  bitmap_glyph->bitmap.rows - bitmap_glyph->top +
1807  face->glyph->advance.y / 64.,
1808  0 );
1809 
1810  FT_Done_Glyph( glyph );
1811 
1812  glPopAttrib();
1813 
1814  delete[] inverted_pixmap;
1815  }
1816 
1817  Translucent::Translucent ( const char* filename, float point_size,
1818  FT_UInt resolution )
1819  : Raster( filename, point_size, resolution )
1820  {}
1821 
1822  Translucent::Translucent ( FT_Face face, float point_size, FT_UInt resolution )
1823  : Raster( face, point_size, resolution )
1824  {}
1825 
1827  {}
1828 
1829  // The simplest format which glDrawPixels can render with (varying) transparency
1830  // is GL_LUMINANCE_ALPHA; so, we take the grayscale bitmap from FreeType
1831  // and treat all non-zero values as full luminance (basically the mask for
1832  // rendering) and duplicate the grayscale values as alpha values
1833  // (as well as turn it upside-down).
1834 
1835  GLubyte* Translucent::invertPixmapWithAlpha ( const FT_Bitmap& bitmap )
1836  {
1837  GLubyte* inverse = new GLubyte[ 2 * bitmap.rows * bitmap.pitch ];
1838  GLubyte* inverse_ptr = inverse;
1839 
1840  for ( int r = 0; r < bitmap.rows; r++ ) {
1841 
1842  GLubyte* bitmap_ptr = &bitmap.buffer[bitmap.pitch * ( bitmap.rows - r - 1 )];
1843 
1844  for ( int p = 0; p < bitmap.pitch; p++ ) {
1845  *inverse_ptr++ = *bitmap_ptr ? 255 : 0;
1846  *inverse_ptr++ = *bitmap_ptr++;
1847  }
1848  }
1849 
1850  return inverse;
1851  }
1852 
1853  void Translucent::renderGlyph ( FT_Face face, FT_UInt glyph_index )
1854  {
1855  FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
1856 
1857  if ( error != 0 )
1858  return;
1859 
1860  FT_Glyph original_glyph;
1861  FT_Glyph glyph;
1862 
1863  error = FT_Get_Glyph( face->glyph, &original_glyph );
1864 
1865  if ( error != 0 ) return;
1866 
1867  error = FT_Glyph_Copy( original_glyph, &glyph );
1868 
1869  FT_Done_Glyph( original_glyph );
1870 
1871  if ( error != 0 ) return;
1872 
1873  if ( character_rotation_z_ != 0. ) {
1874  FT_Matrix rotation_matrix;
1875  FT_Vector sinus;
1876 
1877  FT_Vector_Unit( &sinus, (FT_Angle)(character_rotation_z_ * 0x10000L) );
1878 
1879  rotation_matrix.xx = sinus.x;
1880  rotation_matrix.xy = -sinus.y;
1881  rotation_matrix.yx = sinus.y;
1882  rotation_matrix.yy = sinus.x;
1883 
1884  FT_Vector original_offset, rotation_offset;
1885 
1886  original_offset.x = ( face->glyph->metrics.width / 2
1887  + face->glyph->metrics.horiBearingX ) / 64 * 0x10000L;
1888  original_offset.y = (FT_Pos)(rotation_offset_y_ * 0x10000L);
1889 
1890  rotation_offset = original_offset;
1891 
1892  FT_Vector_Rotate( &rotation_offset,
1893  (FT_Angle)(character_rotation_z_ * 0x10000L) );
1894 
1895  rotation_offset.x = original_offset.x - rotation_offset.x;
1896  rotation_offset.y = original_offset.y - rotation_offset.y;
1897 
1898  rotation_offset.x /= 1024;
1899  rotation_offset.y /= 1024;
1900 
1901  error = FT_Glyph_Transform( glyph, &rotation_matrix, &rotation_offset );
1902  }
1903 
1904  error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1905 
1906  if ( error != 0 ) {
1907  FT_Done_Glyph( glyph );
1908  return;
1909  }
1910 
1911  FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
1912 
1913  // Evidently, in FreeType2, you can only get "upside-down" bitmaps. For
1914  // translucency, the grayscale bitmap generated by FreeType is expanded
1915  // to include an alpha value (and the non-zero values of the
1916  // grayscale bitmap are saturated to provide a "mask" of the glyph).
1917 
1918  GLubyte* inverted_pixmap = invertPixmapWithAlpha( bitmap_glyph->bitmap );
1919 
1920  glPushAttrib( GL_PIXEL_MODE_BIT );
1921  glPixelTransferf( GL_RED_SCALE, foreground_color_[R] - background_color_[R] );
1922  glPixelTransferf( GL_GREEN_SCALE, foreground_color_[G] -background_color_[G] );
1923  glPixelTransferf( GL_BLUE_SCALE, foreground_color_[B] - background_color_[B] );
1924  glPixelTransferf( GL_ALPHA_SCALE, foreground_color_[A] );
1925  glPixelTransferf( GL_RED_BIAS, background_color_[R] );
1926  glPixelTransferf( GL_GREEN_BIAS, background_color_[G] );
1927  glPixelTransferf( GL_BLUE_BIAS, background_color_[B] );
1928  glPixelTransferf( GL_ALPHA_BIAS, background_color_[A] );
1929 
1930  // Set the proper raster position for rendering this glyph (why doesn't
1931  // OpenGL have a similar function for pixmaps?)
1932 
1933  glBitmap( 0, 0, 0, 0,
1934  bitmap_glyph->left,
1935  bitmap_glyph->top - bitmap_glyph->bitmap.rows,
1936  0 );
1937 
1938  glDrawPixels( bitmap_glyph->bitmap.width, bitmap_glyph->bitmap.rows,
1939  GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
1940  inverted_pixmap );
1941 
1942  // This is how you advance the raster position when drawing PIXMAPS
1943  // (without querying the state)
1944 
1945  glBitmap( 0, 0, 0, 0,
1946  -bitmap_glyph->left + face->glyph->advance.x / 64.,
1947  bitmap_glyph->bitmap.rows - bitmap_glyph->top +
1948  face->glyph->advance.y / 64.,
1949  0 );
1950 
1951  FT_Done_Glyph( glyph );
1952 
1953  glPopAttrib();
1954 
1955  delete[] inverted_pixmap;
1956  }
1957 
1958  Polygonal::Polygonal ( const char* filename, float point_size, FT_UInt resolution )
1959  : Face( filename, point_size, resolution )
1960  {
1961  if ( !isValid() ) return;
1962 
1963  init();
1964  }
1965 
1966  Polygonal::Polygonal ( FT_Face face, float point_size, FT_UInt resolution )
1967  : Face( face, point_size, resolution )
1968  {
1969  init();
1970  }
1971 
1972  void Polygonal::init ( void )
1973  {
1974  character_rotation_.active_ = false;
1975  character_rotation_.x_ = 0;
1976  character_rotation_.y_ = 0;
1977  character_rotation_.z_ = 0;
1978 
1980 
1981  delta_ = 1. / (double)tessellation_steps_;
1982  delta2_ = delta_ * delta_;
1983  delta3_ = delta2_ * delta_;
1984 
1985  // For vector rendition modes, FreeType is allowed to generate the
1986  // lines and arcs at the original face definition resolution. To
1987  // get to the proper glyph size, the vertices are scaled before
1988  // they're passed to the GLU tessellation routines.
1989 
1990  if ( resolution_ != 0 )
1991  vector_scale_ = (GLdouble)( point_size_ * resolution_ ) /
1992  (GLdouble)( faces_.front().face_->units_per_EM * 72 );
1993  else // According to the FreeType documentation, resolution == 0 -> 72 DPI
1994  vector_scale_ = (GLdouble)( point_size_ ) /
1995  (GLdouble)( faces_.front().face_->units_per_EM );
1996 
1997  color_tess_ = 0;
1998  texture_tess_ = 0;
1999 
2000  setCharSize();
2001 
2002  // Can't call this until a valid character size is set!
2003 
2005  }
2006 
2008  {
2009  clearCaches();
2010  }
2011 
2012  // Note: Changing the color tessellation object also clears the
2013  // display list cache
2014 
2015  void Polygonal::setColorTess ( ColorTess* color_tess )
2016  {
2017  color_tess_ = color_tess;
2018 
2019  clearCaches();
2020  }
2021 
2022  // Note: Changing the texture coordinate tessellation object also
2023  // clears the display list cache
2024 
2026  {
2027  texture_tess_ = texture_tess;
2028 
2029  clearCaches();
2030  }
2031 
2032  // Note: Changing the appoximation steps also clears the display list cache
2033 
2034  void Polygonal::setTessellationSteps ( unsigned int tessellation_steps )
2035  {
2036  if ( tessellation_steps != tessellation_steps_ ) {
2037 
2038  tessellation_steps_ = tessellation_steps;
2039 
2040  delta_ = 1. / (double)tessellation_steps_;
2041  delta2_ = delta_ * delta_;
2042  delta3_ = delta2_ * delta_;
2043 
2044  clearCaches();
2045  }
2046  }
2047 
2048  // Note: Changing the character rotation also clears the display list cache.
2049 
2050  void Polygonal::setCharacterRotationX ( GLfloat character_rotation_x )
2051  {
2052  if ( character_rotation_x != character_rotation_.x_ ) {
2053  character_rotation_.x_ = character_rotation_x;
2054 
2055  if ( character_rotation_.x_ != 0. || character_rotation_.y_ != 0. ||
2056  character_rotation_.z_ != 0. )
2057  character_rotation_.active_ = true;
2058  else
2059  character_rotation_.active_ = false;
2060 
2061  clearCaches();
2062  }
2063  }
2064 
2065  void Polygonal::setCharacterRotationY ( GLfloat character_rotation_y )
2066  {
2067  if ( character_rotation_y != character_rotation_.y_ ) {
2068  character_rotation_.y_ = character_rotation_y;
2069 
2070  if ( character_rotation_.x_ != 0. || character_rotation_.y_ != 0. ||
2071  character_rotation_.z_ != 0. )
2072  character_rotation_.active_ = true;
2073  else
2074  character_rotation_.active_ = false;
2075 
2076  clearCaches();
2077  }
2078  }
2079 
2080  void Polygonal::setCharacterRotationZ ( GLfloat character_rotation_z )
2081  {
2082  if ( character_rotation_z != character_rotation_.z_ ) {
2083  character_rotation_.z_ = character_rotation_z;
2084 
2085  if ( character_rotation_.x_ != 0. || character_rotation_.y_ != 0. ||
2086  character_rotation_.z_ != 0. )
2087  character_rotation_.active_ = true;
2088  else
2089  character_rotation_.active_ = false;
2090 
2091  clearCaches();
2092  }
2093  }
2094 
2095  void Polygonal::setCharSize ( void )
2096  {
2097  for ( unsigned int i = 0; i < faces_.size(); i++ ) {
2098  FT_Error error = FT_Set_Char_Size( faces_[i].face_,
2099  0,
2100  faces_[i].face_->units_per_EM * 64,
2101  0,
2102  0 );
2103  if ( error != 0 ) return;
2104  }
2105 
2106  if ( rotation_reference_glyph_ != 0 )
2107  setRotationOffset();
2108  }
2109 
2110  void Polygonal::setRotationOffset ( void )
2111  {
2112  FT_Error error = FT_Load_Glyph( rotation_reference_face_,
2114  FT_LOAD_RENDER );
2115 
2116  if ( error != 0 )
2117  return;
2118 
2120  ( 72. * rotation_reference_face_->units_per_EM );
2121 
2123  ( rotation_reference_face_->glyph->metrics.horiBearingY / 2. ) / 64.
2124  * vector_scale_;
2125  }
2126 
2127  double Polygonal::height ( void ) const
2128  {
2129  if ( faces_[0].face_->height > 0 )
2130  return ( faces_[0].face_->height * point_size_ * resolution_ ) /
2131  ( 72. * faces_[0].face_->units_per_EM );
2132  else
2133  return ( faces_[0].face_->size->metrics.y_ppem * point_size_ * resolution_ ) /
2134  ( 72. * faces_[0].face_->units_per_EM );
2135  }
2136 
2137  BBox Polygonal::measure ( unsigned char c )
2138  {
2139  BBox bbox;
2140  // For starters, just get the unscaled glyph bounding box
2141  unsigned int f;
2142  FT_UInt glyph_index = 0;
2143 
2144  for ( f = 0; f < faces_.size(); f++ ) {
2145  glyph_index = FT_Get_Char_Index( faces_[f].face_, c );
2146  if ( glyph_index != 0 ) break;
2147  }
2148 
2149  if ( glyph_index == 0 )
2150  return bbox;
2151 
2152  FT_Error error = FT_Load_Glyph( faces_[f].face_, glyph_index,
2153  FT_LOAD_DEFAULT );
2154  if ( error != 0 )
2155  return bbox;
2156 
2157  FT_Glyph glyph;
2158  error = FT_Get_Glyph( faces_[f].face_->glyph, &glyph );
2159  if ( error != 0 )
2160  return bbox;
2161 
2162  FT_BBox ft_bbox;
2163  FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_unscaled, &ft_bbox );
2164 
2165  FT_Done_Glyph( glyph );
2166 
2167  bbox = ft_bbox;
2168  bbox.advance_ = faces_[f].face_->glyph->advance;
2169 
2170  bbox *= ( point_size_ * resolution_ ) / ( 72. * faces_[f].face_->units_per_EM );
2171 
2172  return bbox;
2173  }
2174 #ifndef OGLFT_NO_QT
2175  BBox Polygonal::measure ( const QChar c )
2176  {
2177  BBox bbox;
2178  // For starters, just get the unscaled glyph bounding box
2179  unsigned int f;
2180  FT_UInt glyph_index = 0;
2181 
2182  for ( f = 0; f < faces_.size(); f++ ) {
2183  glyph_index = FT_Get_Char_Index( faces_[f].face_, c.unicode() );
2184  if ( glyph_index != 0 ) break;
2185  }
2186 
2187  if ( glyph_index == 0 )
2188  return bbox;
2189 
2190  FT_Error error = FT_Load_Glyph( faces_[f].face_, glyph_index,
2191  FT_LOAD_DEFAULT );
2192  if ( error != 0 )
2193  return bbox;
2194 
2195  FT_Glyph glyph;
2196  error = FT_Get_Glyph( faces_[f].face_->glyph, &glyph );
2197  if ( error != 0 )
2198  return bbox;
2199 
2200  FT_BBox ft_bbox;
2201  FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_unscaled, &ft_bbox );
2202 
2203  FT_Done_Glyph( glyph );
2204 
2205  bbox = ft_bbox;
2206  bbox.advance_ = faces_[f].face_->glyph->advance;
2207 
2208  bbox *= ( point_size_ * resolution_ ) / ( 72. * faces_[f].face_->units_per_EM );
2209 
2210  return bbox;
2211  }
2212 #endif /* OGLFT_NO_QT */
2213 
2214  GLuint Polygonal::compileGlyph ( FT_Face face, FT_UInt glyph_index )
2215  {
2216  GLuint dlist = glGenLists( 1 );
2217 
2218  glNewList( dlist, GL_COMPILE );
2219 
2220  renderGlyph( face, glyph_index );
2221 
2222  glEndList( );
2223 
2224  return dlist;
2225  }
2226 
2228  {
2229  GDLI fgi = glyph_dlists_.begin();
2230 
2231  for ( ; fgi != glyph_dlists_.end(); ++fgi ) {
2232  glDeleteLists( fgi->second, 1 );
2233  }
2234 
2235  glyph_dlists_.clear();
2236  }
2237 
2238  Outline::Outline ( const char* filename, float point_size, FT_UInt resolution )
2239  : Polygonal( filename, point_size, resolution )
2240  {
2241  if ( !isValid() ) return;
2242 
2243  init();
2244  }
2245 
2246  Outline::Outline ( FT_Face face, float point_size, FT_UInt resolution )
2247  : Polygonal( face, point_size, resolution )
2248  {
2249  init();
2250  }
2251 
2252  void Outline::init ( void )
2253  {
2254  interface_.move_to = (FT_Outline_MoveTo_Func)moveToCallback;
2255  interface_.line_to = (FT_Outline_LineTo_Func)lineToCallback;
2256  interface_.conic_to = (FT_Outline_ConicTo_Func)conicToCallback;
2257  interface_.cubic_to = (FT_Outline_CubicTo_Func)cubicToCallback;
2258  interface_.shift = 0;
2259  interface_.delta = 0;
2260  }
2261 
2263  {}
2264 
2265  void Outline::renderGlyph ( FT_Face face, FT_UInt glyph_index )
2266  {
2267  FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
2268 
2269  if ( error != 0 )
2270  return;
2271 
2272  FT_OutlineGlyph g;
2273 
2274  error = FT_Get_Glyph( face->glyph, (FT_Glyph*)&g );
2275 
2276  if ( error != 0 )
2277  return;
2278 
2279  vector_scale_ = ( point_size_ * resolution_ ) / ( 72. * face->units_per_EM );
2280 
2281  if ( character_rotation_.active_ ) {
2282  glPushMatrix();
2283  glTranslatef( ( face->glyph->metrics.width / 2. +
2284  face->glyph->metrics.horiBearingX ) / 64.
2285  * vector_scale_,
2287  0. );
2288 
2289  if ( character_rotation_.x_ != 0. )
2290  glRotatef( character_rotation_.x_, 1., 0., 0. );
2291 
2292  if ( character_rotation_.y_ != 0. )
2293  glRotatef( character_rotation_.y_, 0., 1., 0. );
2294 
2295  if ( character_rotation_.z_ != 0. )
2296  glRotatef( character_rotation_.z_, 0., 0., 1. );
2297 
2298  glTranslatef( -( face->glyph->metrics.width / 2. +
2299  face->glyph->metrics.horiBearingX ) / 64.
2300  * vector_scale_,
2302  0. );
2303  }
2304 
2305  contour_open_ = false;
2306 
2307  // The Big Kahuna: the FreeType glyph decomposition routine traverses
2308  // the outlines of the font by calling the various routines stored in
2309  // outline_interface_. These routines in turn call the GL vertex routines.
2310 
2311  error = FT_Outline_Decompose( &g->outline, &interface_, this );
2312 
2313  FT_Done_Glyph( (FT_Glyph)g );
2314 
2315  // Some glyphs may be empty (the 'blank' for instance!)
2316 
2317  if ( contour_open_ )
2318  glEnd( );
2319 
2320 
2321  if ( character_rotation_.active_ ) {
2322  glPopMatrix();
2323  }
2324 
2325  // Drawing a character always advances the MODELVIEW.
2326 
2327  glTranslatef( face->glyph->advance.x / 64. * vector_scale_,
2328  face->glyph->advance.y / 64. * vector_scale_,
2329  0. );
2330 
2331  for ( VILI vili = vertices_.begin(); vili != vertices_.end(); vili++ )
2332  delete *vili;
2333 
2334  vertices_.clear();
2335  }
2336 
2337  int Outline::moveToCallback ( FT_Vector* to, Outline* outline )
2338  {
2339  if ( outline->contour_open_ ) {
2340  glEnd();
2341  }
2342 
2343  outline->last_vertex_ = VertexInfo( to,
2344  outline->colorTess(),
2345  outline->textureTess() );
2346 
2347  glBegin( GL_LINE_LOOP );
2348 
2349  outline->contour_open_ = true;
2350 
2351  return 0;
2352  }
2353 
2354  int Outline::lineToCallback ( FT_Vector* to, Outline* outline )
2355  {
2356  outline->last_vertex_ = VertexInfo( to,
2357  outline->colorTess(),
2358  outline->textureTess() );
2359  GLdouble g[2];
2360 
2361  g[X] = outline->last_vertex_.v_[X] * outline->vector_scale_;
2362  g[Y] = outline->last_vertex_.v_[Y] * outline->vector_scale_;
2363 
2364  glVertex2dv( g );
2365 
2366  return 0;
2367  }
2368 
2369  int Outline::conicToCallback ( FT_Vector* control, FT_Vector* to, Outline* outline )
2370  {
2371  // This is crude: Step off conics with a fixed number of increments
2372 
2373  VertexInfo to_vertex( to, outline->colorTess(), outline->textureTess() );
2374  VertexInfo control_vertex( control, outline->colorTess(), outline->textureTess() );
2375 
2376  double b[2], c[2], d[2], f[2], df[2], d2f[2];
2377  GLdouble g[3];
2378 
2379  g[Z] = 0.;
2380 
2381  b[X] = outline->last_vertex_.v_[X] - 2 * control_vertex.v_[X] +
2382  to_vertex.v_[X];
2383  b[Y] = outline->last_vertex_.v_[Y] - 2 * control_vertex.v_[Y] +
2384  to_vertex.v_[Y];
2385 
2386  c[X] = -2 * outline->last_vertex_.v_[X] + 2 * control_vertex.v_[X];
2387  c[Y] = -2 * outline->last_vertex_.v_[Y] + 2 * control_vertex.v_[Y];
2388 
2389  d[X] = outline->last_vertex_.v_[X];
2390  d[Y] = outline->last_vertex_.v_[Y];
2391 
2392  f[X] = d[X];
2393  f[Y] = d[Y];
2394  df[X] = c[X] * outline->delta_ + b[X] * outline->delta2_;
2395  df[Y] = c[Y] * outline->delta_ + b[Y] * outline->delta2_;
2396  d2f[X] = 2 * b[X] * outline->delta2_;
2397  d2f[Y] = 2 * b[Y] * outline->delta2_;
2398 
2399  for ( unsigned int i = 0; i < outline->tessellation_steps_-1; i++ ) {
2400 
2401  f[X] += df[X];
2402  f[Y] += df[Y];
2403 
2404  g[X] = f[X] * outline->vector_scale_;
2405  g[Y] = f[Y] * outline->vector_scale_;
2406 
2407  if ( outline->colorTess() )
2408  glColor4fv( outline->colorTess()->color( g ) );
2409 
2410  glVertex2dv( g );
2411 
2412  df[X] += d2f[X];
2413  df[Y] += d2f[Y];
2414  }
2415 
2416  g[X] = to_vertex.v_[X] * outline->vector_scale_;
2417  g[Y] = to_vertex.v_[Y] * outline->vector_scale_;
2418 
2419  if ( outline->colorTess() )
2420  glColor4fv( outline->colorTess()->color( g ) );
2421 
2422  glVertex2dv( g );
2423 
2424  outline->last_vertex_ = to_vertex;
2425 
2426  return 0;
2427  }
2428 
2429  int Outline::cubicToCallback ( FT_Vector* control1, FT_Vector* control2,
2430  FT_Vector* to, Outline* outline )
2431  {
2432  // This is crude: Step off cubics with a fixed number of increments
2433 
2434  VertexInfo to_vertex( to, outline->colorTess(), outline->textureTess() );
2435  VertexInfo control1_vertex( control1, outline->colorTess(), outline->textureTess() );
2436  VertexInfo control2_vertex( control2, outline->colorTess(), outline->textureTess() );
2437 
2438  double a[2], b[2], c[2], d[2], f[2], df[2], d2f[2], d3f[2];
2439  GLdouble g[3];
2440 
2441  g[Z] = 0.;
2442 
2443  a[X] = -outline->last_vertex_.v_[X] + 3 * control1_vertex.v_[X]
2444  -3 * control2_vertex.v_[X] + to_vertex.v_[X];
2445  a[Y] = -outline->last_vertex_.v_[Y] + 3 * control1_vertex.v_[Y]
2446  -3 * control2_vertex.v_[Y] + to_vertex.v_[Y];
2447 
2448  b[X] = 3 * outline->last_vertex_.v_[X] - 6 * control1_vertex.v_[X] +
2449  3 * control2_vertex.v_[X];
2450  b[Y] = 3 * outline->last_vertex_.v_[Y] - 6 * control1_vertex.v_[Y] +
2451  3 * control2_vertex.v_[Y];
2452 
2453  c[X] = -3 * outline->last_vertex_.v_[X] + 3 * control1_vertex.v_[X];
2454  c[Y] = -3 * outline->last_vertex_.v_[Y] + 3 * control1_vertex.v_[Y];
2455 
2456  d[X] = outline->last_vertex_.v_[X];
2457  d[Y] = outline->last_vertex_.v_[Y];
2458 
2459  f[X] = d[X];
2460  f[Y] = d[Y];
2461  df[X] = c[X] * outline->delta_ + b[X] * outline->delta2_
2462  + a[X] * outline->delta3_;
2463  df[Y] = c[Y] * outline->delta_ + b[Y] * outline->delta2_
2464  + a[Y] * outline->delta3_;
2465  d2f[X] = 2 * b[X] * outline->delta2_ + 6 * a[X] * outline->delta3_;
2466  d2f[Y] = 2 * b[Y] * outline->delta2_ + 6 * a[Y] * outline->delta3_;
2467  d3f[X] = 6 * a[X] * outline->delta3_;
2468  d3f[Y] = 6 * a[Y] * outline->delta3_;
2469 
2470  for ( unsigned int i = 0; i < outline->tessellation_steps_-1; i++ ) {
2471 
2472  f[X] += df[X];
2473  f[Y] += df[Y];
2474 
2475  g[X] = f[X] * outline->vector_scale_;
2476  g[Y] = f[Y] * outline->vector_scale_;
2477 
2478  if ( outline->colorTess() )
2479  glColor4fv( outline->colorTess()->color( g ) );
2480 
2481  glVertex2dv( g );
2482 
2483  df[X] += d2f[X];
2484  df[Y] += d2f[Y];
2485  d2f[X] += d3f[X];
2486  d2f[Y] += d3f[Y];
2487  }
2488 
2489  g[X] = to_vertex.v_[X] * outline->vector_scale_;
2490  g[Y] = to_vertex.v_[Y] * outline->vector_scale_;
2491 
2492  if ( outline->colorTess() )
2493  glColor4fv( outline->colorTess()->color( g ) );
2494 
2495  glVertex2dv( g );
2496 
2497  outline->last_vertex_ = to_vertex;
2498 
2499  return 0;
2500  }
2501 
2502  Filled::Filled ( const char* filename, float point_size, FT_UInt resolution )
2503  : Polygonal( filename, point_size, resolution )
2504  {
2505  if ( !isValid() ) return;
2506 
2507  init();
2508  }
2509 
2510  Filled::Filled ( FT_Face face, float point_size, FT_UInt resolution )
2511  : Polygonal( face, point_size, resolution )
2512  {
2513  init();
2514  }
2515 
2516  void Filled::init ( void )
2517  {
2518  depth_offset_ = 0;
2519 
2520  interface_.move_to = (FT_Outline_MoveTo_Func)moveToCallback;
2521  interface_.line_to = (FT_Outline_LineTo_Func)lineToCallback;
2522  interface_.conic_to = (FT_Outline_ConicTo_Func)conicToCallback;
2523  interface_.cubic_to = (FT_Outline_CubicTo_Func)cubicToCallback;
2524  interface_.shift = 0;
2525  interface_.delta = 0;
2526 
2527  tess_obj_ = gluNewTess();
2528 
2529  gluTessCallback( (GLUtriangulatorObj *)tess_obj_, GLU_TESS_VERTEX, (GLUTessCallback)vertexCallback );
2530  gluTessCallback( (GLUtriangulatorObj *)tess_obj_, GLU_TESS_BEGIN, (GLUTessCallback)beginCallback );
2531  gluTessCallback( (GLUtriangulatorObj *)tess_obj_, GLU_TESS_END, (GLUTessCallback)endCallback );
2532  gluTessCallback( (GLUtriangulatorObj *)tess_obj_, GLU_TESS_COMBINE_DATA, (GLUTessCallback)combineCallback );
2533  gluTessCallback( (GLUtriangulatorObj *)tess_obj_, GLU_TESS_ERROR, (GLUTessCallback)errorCallback );
2534  }
2535 
2537  {
2538  gluDeleteTess( tess_obj_ );
2539  }
2540 
2541  void Filled::renderGlyph ( FT_Face face, FT_UInt glyph_index )
2542  {
2543  FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
2544 
2545  if ( error != 0 )
2546  return;
2547 
2548  FT_OutlineGlyph g;
2549 
2550  error = FT_Get_Glyph( face->glyph, (FT_Glyph*)&g );
2551 
2552  if ( error != 0 )
2553  return;
2554 
2555  vector_scale_ = ( point_size_ * resolution_ ) / ( 72. * face->units_per_EM );
2556 
2557  if ( character_rotation_.active_ ) {
2558  glPushMatrix();
2559  glTranslatef( ( face->glyph->metrics.width / 2. +
2560  face->glyph->metrics.horiBearingX ) / 64.
2561  * vector_scale_,
2563  0. );
2564 
2565  if ( character_rotation_.x_ != 0. )
2566  glRotatef( character_rotation_.x_, 1., 0., 0. );
2567 
2568  if ( character_rotation_.y_ != 0. )
2569  glRotatef( character_rotation_.y_, 0., 1., 0. );
2570 
2571  if ( character_rotation_.z_ != 0. )
2572  glRotatef( character_rotation_.z_, 0., 0., 1. );
2573 
2574  glTranslatef( -( face->glyph->metrics.width / 2. +
2575  face->glyph->metrics.horiBearingX ) / 64.
2576  * vector_scale_,
2578  0. );
2579  }
2580 
2581  if ( depth_offset_ != 0. ) {
2582  glPushMatrix();
2583  glTranslatef( 0., 0., depth_offset_ );
2584  glNormal3f( 0., 0., 1. );
2585  }
2586  else {
2587  glNormal3f( 0., 0., -1. );
2588  }
2589 
2590  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
2591 
2592  contour_open_ = false;
2593 
2594  gluTessBeginPolygon( tess_obj_, this );
2595 
2596  // The Big Kahuna: the FreeType glyph decomposition routine traverses
2597  // the outlines of the font by calling the various routines stored in
2598  // interface_. These routines in turn call the GLU tessellation routines
2599  // to create OGL polygons.
2600 
2601  error = FT_Outline_Decompose( &g->outline, &interface_, this );
2602 
2603  FT_Done_Glyph( (FT_Glyph)g );
2604 
2605  // Some glyphs may be empty (the 'blank' for instance!)
2606 
2607  if ( contour_open_ )
2608  gluTessEndContour( tess_obj_ );
2609 
2610  gluTessEndPolygon( tess_obj_ );
2611 
2612  if ( depth_offset_ != 0. ) {
2613  glPopMatrix();
2614  }
2615  if ( character_rotation_.active_ ) {
2616  glPopMatrix();
2617  }
2618 
2619  // Drawing a character always advances the MODELVIEW.
2620 
2621  glTranslatef( face->glyph->advance.x / 64 * vector_scale_,
2622  face->glyph->advance.y / 64 * vector_scale_,
2623  0. );
2624 
2625  for ( VILI vili = extra_vertices_.begin(); vili != extra_vertices_.end(); vili++ )
2626  delete *vili;
2627 
2628  extra_vertices_.clear();
2629 
2630  for ( VILI vili = vertices_.begin(); vili != vertices_.end(); vili++ )
2631  delete *vili;
2632 
2633  vertices_.clear();
2634  }
2635 
2636  int Filled::moveToCallback ( FT_Vector* to, Filled* filled )
2637  {
2638  if ( filled->contour_open_ ) {
2639  gluTessEndContour( filled->tess_obj_ );
2640  }
2641 
2642  filled->last_vertex_ = VertexInfo( to, filled->colorTess(), filled->textureTess() );
2643 
2644  gluTessBeginContour( filled->tess_obj_ );
2645 
2646  filled->contour_open_ = true;
2647 
2648  return 0;
2649  }
2650 
2651  int Filled::lineToCallback ( FT_Vector* to, Filled* filled )
2652  {
2653  filled->last_vertex_ = VertexInfo( to, filled->colorTess(), filled->textureTess() );
2654 
2655  VertexInfo* vertex = new VertexInfo( to, filled->colorTess(), filled->textureTess() );
2656 
2657  vertex->v_[X] *= filled->vector_scale_;
2658  vertex->v_[Y] *= filled->vector_scale_;
2659 
2660  gluTessVertex( filled->tess_obj_, vertex->v_, vertex );
2661 
2662  filled->vertices_.push_back( vertex );
2663 
2664  return 0;
2665  }
2666 
2667  int Filled::conicToCallback ( FT_Vector* control, FT_Vector* to, Filled* filled )
2668  {
2669  // This is crude: Step off conics with a fixed number of increments
2670 
2671  VertexInfo to_vertex( to, filled->colorTess(), filled->textureTess() );
2672  VertexInfo control_vertex( control, filled->colorTess(), filled->textureTess() );
2673 
2674  double b[2], c[2], d[2], f[2], df[2], d2f[2];
2675 
2676  b[X] = filled->last_vertex_.v_[X] - 2 * control_vertex.v_[X] +
2677  to_vertex.v_[X];
2678  b[Y] = filled->last_vertex_.v_[Y] - 2 * control_vertex.v_[Y] +
2679  to_vertex.v_[Y];
2680 
2681  c[X] = -2 * filled->last_vertex_.v_[X] + 2 * control_vertex.v_[X];
2682  c[Y] = -2 * filled->last_vertex_.v_[Y] + 2 * control_vertex.v_[Y];
2683 
2684  d[X] = filled->last_vertex_.v_[X];
2685  d[Y] = filled->last_vertex_.v_[Y];
2686 
2687  f[X] = d[X];
2688  f[Y] = d[Y];
2689  df[X] = c[X] * filled->delta_ + b[X] * filled->delta2_;
2690  df[Y] = c[Y] * filled->delta_ + b[Y] * filled->delta2_;
2691  d2f[X] = 2 * b[X] * filled->delta2_;
2692  d2f[Y] = 2 * b[Y] * filled->delta2_;
2693 
2694  for ( unsigned int i = 0; i < filled->tessellation_steps_-1; i++ ) {
2695 
2696  f[X] += df[X];
2697  f[Y] += df[Y];
2698 
2699  VertexInfo* vertex = new VertexInfo( f, filled->colorTess(), filled->textureTess() );
2700 
2701  vertex->v_[X] *= filled->vector_scale_;
2702  vertex->v_[Y] *= filled->vector_scale_;
2703 
2704  filled->vertices_.push_back( vertex );
2705 
2706  gluTessVertex( filled->tess_obj_, vertex->v_, vertex );
2707 
2708  df[X] += d2f[X];
2709  df[Y] += d2f[Y];
2710  }
2711 
2712  VertexInfo* vertex = new VertexInfo( to, filled->colorTess(), filled->textureTess() );
2713 
2714  vertex->v_[X] *= filled->vector_scale_;
2715  vertex->v_[Y] *= filled->vector_scale_;
2716 
2717  filled->vertices_.push_back( vertex );
2718 
2719  gluTessVertex( filled->tess_obj_, vertex->v_, vertex );
2720 
2721  filled->last_vertex_ = to_vertex;
2722 
2723  return 0;
2724  }
2725 
2726  int Filled::cubicToCallback ( FT_Vector* control1, FT_Vector* control2,
2727  FT_Vector* to, Filled* filled )
2728  {
2729  // This is crude: Step off cubics with a fixed number of increments
2730 
2731  VertexInfo to_vertex( to, filled->colorTess(), filled->textureTess() );
2732  VertexInfo control1_vertex( control1, filled->colorTess(), filled->textureTess() );
2733  VertexInfo control2_vertex( control2, filled->colorTess(), filled->textureTess() );
2734 
2735  double a[2], b[2], c[2], d[2], f[2], df[2], d2f[2], d3f[2];
2736 
2737  a[X] = -filled->last_vertex_.v_[X] + 3 * control1_vertex.v_[X]
2738  -3 * control2_vertex.v_[X] + to_vertex.v_[X];
2739  a[Y] = -filled->last_vertex_.v_[Y] + 3 * control1_vertex.v_[Y]
2740  -3 * control2_vertex.v_[Y] + to_vertex.v_[Y];
2741 
2742  b[X] = 3 * filled->last_vertex_.v_[X] - 6 * control1_vertex.v_[X] +
2743  3 * control2_vertex.v_[X];
2744  b[Y] = 3 * filled->last_vertex_.v_[Y] - 6 * control1_vertex.v_[Y] +
2745  3 * control2_vertex.v_[Y];
2746 
2747  c[X] = -3 * filled->last_vertex_.v_[X] + 3 * control1_vertex.v_[X];
2748  c[Y] = -3 * filled->last_vertex_.v_[Y] + 3 * control1_vertex.v_[Y];
2749 
2750  d[X] = filled->last_vertex_.v_[X];
2751  d[Y] = filled->last_vertex_.v_[Y];
2752 
2753  f[X] = d[X];
2754  f[Y] = d[Y];
2755  df[X] = c[X] * filled->delta_ + b[X] * filled->delta2_
2756  + a[X] * filled->delta3_;
2757  df[Y] = c[Y] * filled->delta_ + b[Y] * filled->delta2_
2758  + a[Y] * filled->delta3_;
2759  d2f[X] = 2 * b[X] * filled->delta2_ + 6 * a[X] * filled->delta3_;
2760  d2f[Y] = 2 * b[Y] * filled->delta2_ + 6 * a[Y] * filled->delta3_;
2761  d3f[X] = 6 * a[X] * filled->delta3_;
2762  d3f[Y] = 6 * a[Y] * filled->delta3_;
2763 
2764  for ( unsigned int i = 0; i < filled->tessellation_steps_-1; i++ ) {
2765 
2766  f[X] += df[X];
2767  f[Y] += df[Y];
2768 
2769  VertexInfo* vertex = new VertexInfo( f, filled->colorTess(), filled->textureTess() );
2770 
2771  vertex->v_[X] *= filled->vector_scale_;
2772  vertex->v_[Y] *= filled->vector_scale_;
2773 
2774  filled->vertices_.push_back( vertex );
2775 
2776  gluTessVertex( filled->tess_obj_, vertex->v_, vertex );
2777 
2778  df[X] += d2f[X];
2779  df[Y] += d2f[Y];
2780  d2f[X] += d3f[X];
2781  d2f[Y] += d3f[Y];
2782  }
2783 
2784  VertexInfo* vertex = new VertexInfo( to, filled->colorTess(), filled->textureTess() );
2785 
2786  vertex->v_[X] *= filled->vector_scale_;
2787  vertex->v_[Y] *= filled->vector_scale_;
2788 
2789  filled->vertices_.push_back( vertex );
2790 
2791  gluTessVertex( filled->tess_obj_, vertex->v_, vertex );
2792 
2793  filled->last_vertex_ = to_vertex;
2794 
2795  return 0;
2796  }
2797 
2798  void Filled::vertexCallback ( VertexInfo* vertex )
2799  {
2800  if ( vertex->color_tess_ != 0 )
2801  glColor4fv( vertex->color_tess_->color( vertex->v_ ) );
2802 
2803  if ( vertex->texture_tess_ != 0 )
2804  glTexCoord2fv( vertex->texture_tess_->texCoord( vertex->v_ ) );
2805 
2806  glVertex3dv( vertex->v_ );
2807  }
2808 
2809  void Filled::beginCallback ( GLenum which )
2810  {
2811  glBegin( which );
2812  }
2813 
2814  void Filled::endCallback ( void )
2815  {
2816  glEnd();
2817  }
2818 
2819  void Filled::combineCallback ( GLdouble coords[3], void* vertex_data[4],
2820  GLfloat weight[4], void** out_data,
2821  Filled* filled )
2822  {
2823  (void)vertex_data;
2824  (void)weight;
2825  // std::cerr << "called combine" << std::endl;
2826  VertexInfo* vertex = new VertexInfo( coords );
2827  *out_data = vertex;
2828  filled->extraVertices().push_back( vertex );
2829  }
2830 
2831  void Filled::errorCallback ( GLenum error_code )
2832  {
2833  std::cerr << "hmm. error during tessellation?:" << gluErrorString( error_code ) << std::endl;
2834  }
2835 
2836 #ifndef OGLFT_NO_SOLID
2837  Solid::Solid ( const char* filename, float point_size, FT_UInt resolution )
2838  : Filled( filename, point_size, resolution )
2839  {
2840  if ( !isValid() ) return;
2841 
2842  init();
2843  }
2844 
2845  Solid::Solid ( FT_Face face, float point_size, FT_UInt resolution )
2846  : Filled( face, point_size, resolution )
2847  {
2848  init();
2849  }
2850 
2851  void Solid::init ( void )
2852  {
2853  interface_.move_to = (FT_Outline_MoveTo_Func)moveToCallback;
2854  interface_.line_to = (FT_Outline_LineTo_Func)lineToCallback;
2855  interface_.conic_to = (FT_Outline_ConicTo_Func)conicToCallback;
2856  interface_.cubic_to = (FT_Outline_CubicTo_Func)cubicToCallback;
2857  interface_.shift = 0;
2858  interface_.delta = 0;
2859 
2860  // Set up for extrusion. Default depth is 1 (units of what?)
2861  extrusion_.depth_ = 1.;
2862  extrusion_.up_[X] = 0.;
2863  extrusion_.up_[Y] = 1.;
2864  extrusion_.up_[Z] = 0.;
2865  extrusion_.n_polyline_pts_ = N_POLYLINE_PTS;
2866 
2867  assign( extrusion_.point_array_[0], 0., 0., extrusion_.depth_ + 1. );
2868  assign( extrusion_.point_array_[1], 0., 0., extrusion_.depth_ );
2869  assign( extrusion_.point_array_[2], 0., 0., 0. );
2870  assign( extrusion_.point_array_[3], 0., 0., -1. );
2871 
2872  // Turn on closed contours and smooth vertices; turn off end capping
2873 
2874  gleSetJoinStyle( TUBE_JN_RAW | TUBE_CONTOUR_CLOSED | TUBE_NORM_EDGE );
2875  }
2876 
2877  Solid::~Solid ( void )
2878  {}
2879 
2880  // Note: as usual, setting this clears the caches
2881 
2882  void Solid::setDepth ( double depth )
2883  {
2884  if ( depth > 0. && depth != extrusion_.depth_ ) {
2885  extrusion_.depth_ = depth;
2886 
2887  assign( extrusion_.point_array_[0], 0., 0., extrusion_.depth_ + 1. );
2888  assign( extrusion_.point_array_[1], 0., 0., extrusion_.depth_ );
2889 
2890  clearCaches();
2891  }
2892  }
2893 
2894  void Solid::renderGlyph ( FT_Face face, FT_UInt glyph_index )
2895  {
2896  FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
2897 
2898  if ( error != 0 )
2899  return;
2900 
2901  FT_OutlineGlyph g;
2902 
2903  error = FT_Get_Glyph( face->glyph, (FT_Glyph*)&g );
2904 
2905  if ( error != 0 )
2906  return;
2907 
2908  vector_scale_ = ( point_size_ * resolution_ ) / ( 72. * face->units_per_EM );
2909 
2910  if ( character_rotation_.active_ ) {
2911  glPushMatrix();
2912 
2913  glTranslatef( ( face->glyph->metrics.width / 2. +
2914  face->glyph->metrics.horiBearingX ) / 64.
2915  * vector_scale_,
2917  0. );
2918 
2919  if ( character_rotation_.x_ != 0. )
2920  glRotatef( character_rotation_.x_, 1., 0., 0. );
2921 
2922  if ( character_rotation_.y_ != 0. )
2923  glRotatef( character_rotation_.y_, 0., 1., 0. );
2924 
2925  if ( character_rotation_.z_ != 0. )
2926  glRotatef( character_rotation_.z_, 0., 0., 1. );
2927 
2928  glTranslatef( -( face->glyph->metrics.width / 2. +
2929  face->glyph->metrics.horiBearingX ) / 64.
2930  * vector_scale_,
2932  0. );
2933  }
2934 
2935  contour_open_ = false;
2936 
2937  // In theory, TrueType contours are defined clockwise and Type1 contours
2938  // are defined counter-clockwise. Trust the flag set by FreeType to
2939  // indicate this since it is critical to getting the orientation of the
2940  // surface normals correct.
2941  if ( g->outline.flags & FT_OUTLINE_REVERSE_FILL ) {
2942  extrusion_.normal_sign_.x_ = -1;
2943  extrusion_.normal_sign_.y_ = 1;
2944  }
2945  else {
2946  extrusion_.normal_sign_.x_ = 1;
2947  extrusion_.normal_sign_.y_ = -1;
2948  }
2949  // The Big Kahuna: the FreeType glyph decomposition routine traverses
2950  // the outlines of the font by calling the various routines stored in
2951  // extrude_interface_. These in turn call the gleExtrusion routine.
2952 
2953  error = FT_Outline_Decompose( &g->outline, &interface_, this );
2954 
2955  FT_Done_Glyph( (FT_Glyph)g );
2956 
2957  // Some glyphs may be empty (the 'blank' for instance!)
2958 
2959  if ( contour_open_ ) {
2960  extrusion_.contour_normals_.push_back( extrusion_.contour_normals_.front() );
2961 
2962  gleExtrusion( extrusion_.contour_.size(),
2963  &extrusion_.contour_.begin()->p_,
2964  &extrusion_.contour_normals_[1].p_,
2965  extrusion_.up_,
2966  extrusion_.n_polyline_pts_,
2967  extrusion_.point_array_,
2968  0 );
2969 
2970  extrusion_.contour_.clear();
2971  extrusion_.contour_normals_.clear();
2972  }
2973 
2974  if ( character_rotation_.active_ ) {
2975  glPopMatrix();
2976  }
2977 
2978  // Apply the front and back faces of the solid character (recall that
2979  // drawing a character advances the MODELVIEW, so defend against that
2980  // with the stack operations)
2981 
2982  glPushMatrix();
2983  depth_offset_ = 0.;
2984  Filled::renderGlyph( face, glyph_index );
2985  glPopMatrix();
2986 
2987  glPushMatrix();
2988  depth_offset_ = extrusion_.depth_;
2989  Filled::renderGlyph( face, glyph_index );
2990  glPopMatrix();
2991 
2992  // Drawing a character always advances the MODELVIEW.
2993 
2994  glTranslatef( face->glyph->advance.x / 64. * vector_scale_,
2995  face->glyph->advance.y / 64. * vector_scale_,
2996  0. );
2997 
2998  for ( VILI vili = vertices_.begin(); vili != vertices_.end(); vili++ )
2999  delete *vili;
3000 
3001  vertices_.clear();
3002  }
3003 
3004  int Solid::moveToCallback ( FT_Vector* to, Solid* solid )
3005  {
3006  if ( solid->contour_open_ ) {
3007 
3008  // A word of explanation: since you can't predict when the
3009  // contour is going to end (its end is signaled by calling this
3010  // routine, i.e., the contour ends when another is started
3011  // abruptly), only the lineTo and arcTo functions generate contour
3012  // points. The upshot is that the normals, which are computed for the
3013  // current segment, are one behind the segment described in the
3014  // the contour array. To make things match up at the end, the first
3015  // normal is copied to the end of the normal array and the extrusion
3016  // routine is passed the list of normals starting at the second entry.
3017 
3018  solid->extrusion_.contour_normals_.
3019  push_back( solid->extrusion_.contour_normals_.front() );
3020 #if 1
3021  gleExtrusion( solid->extrusion_.contour_.size(),
3022  &solid->extrusion_.contour_.begin()->p_,
3023  &solid->extrusion_.contour_normals_[1].p_,
3024  solid->extrusion_.up_,
3025  solid->extrusion_.n_polyline_pts_,
3026  solid->extrusion_.point_array_,
3027  0 );
3028 #endif
3029  solid->extrusion_.contour_.clear();
3030  solid->extrusion_.contour_normals_.clear();
3031  }
3032 
3033  solid->last_vertex_ = VertexInfo( to, solid->colorTess(), solid->textureTess() );
3034 
3035  solid->contour_open_ = true;
3036 
3037  return 0;
3038  }
3039 
3040  int Solid::lineToCallback ( FT_Vector* to, Solid* solid )
3041  {
3042  VertexInfo vertex( to, solid->colorTess(), solid->textureTess() );
3043 
3044  VertexInfo normal( solid->extrusion_.normal_sign_.y_ *
3045  ( vertex.v_[Y] - solid->last_vertex_.v_[Y] ),
3046  solid->extrusion_.normal_sign_.x_ *
3047  ( vertex.v_[X] - solid->last_vertex_.v_[X] ) );
3048 
3049  solid->last_vertex_ = vertex;
3050 
3051  vertex.v_[X] *= solid->vector_scale_;
3052  vertex.v_[Y] *= solid->vector_scale_;
3053 
3054  normal.normalize();
3055 
3056  solid->extrusion_.contour_.push_back( vertex );
3057  solid->extrusion_.contour_normals_.push_back( normal );
3058 
3059  return 0;
3060  }
3061 
3062  int Solid::conicToCallback ( FT_Vector* control, FT_Vector* to, Solid* solid )
3063  {
3064  // This is crude: Step off conics with a fixed number of increments
3065 
3066  VertexInfo to_vertex( to, solid->colorTess(), solid->textureTess() );
3067  VertexInfo control_vertex( control, solid->colorTess(), solid->textureTess() );
3068 
3069  double b[2], c[2], d[2], f[2], df[2], d2f[2];
3070 
3071  b[X] = solid->last_vertex_.v_[X] - 2 * control_vertex.v_[X] +
3072  to_vertex.v_[X];
3073  b[Y] = solid->last_vertex_.v_[Y] - 2 * control_vertex.v_[Y] +
3074  to_vertex.v_[Y];
3075 
3076  c[X] = -2 * solid->last_vertex_.v_[X] + 2 * control_vertex.v_[X];
3077  c[Y] = -2 * solid->last_vertex_.v_[Y] + 2 * control_vertex.v_[Y];
3078 
3079  d[X] = solid->last_vertex_.v_[X];
3080  d[Y] = solid->last_vertex_.v_[Y];
3081 
3082  f[X] = d[X];
3083  f[Y] = d[Y];
3084  df[X] = c[X] * solid->delta_ + b[X] * solid->delta2_;
3085  df[Y] = c[Y] * solid->delta_ + b[Y] * solid->delta2_;
3086  d2f[X] = 2 * b[X] * solid->delta2_;
3087  d2f[Y] = 2 * b[Y] * solid->delta2_;
3088 
3089  for ( unsigned int i = 0; i < solid->tessellation_steps_-1; i++ ) {
3090 
3091  f[X] += df[X];
3092  f[Y] += df[Y];
3093 
3094  VertexInfo vertex( f, solid->colorTess(), solid->textureTess() );
3095 
3096  VertexInfo normal( solid->extrusion_.normal_sign_.y_ * df[Y],
3097  solid->extrusion_.normal_sign_.x_ * df[X] );
3098 
3099  vertex.v_[X] *= solid->vector_scale_;
3100  vertex.v_[Y] *= solid->vector_scale_;
3101 
3102  normal.normalize();
3103 
3104  solid->extrusion_.contour_.push_back( vertex );
3105  solid->extrusion_.contour_normals_.push_back( normal );
3106 
3107  df[X] += d2f[X];
3108  df[Y] += d2f[Y];
3109  }
3110 
3111  VertexInfo vertex( to, solid->colorTess(), solid->textureTess() );
3112 
3113  VertexInfo normal( solid->extrusion_.normal_sign_.y_ * df[Y],
3114  solid->extrusion_.normal_sign_.x_ * df[X] );
3115 
3116  vertex.v_[X] *= solid->vector_scale_;
3117  vertex.v_[Y] *= solid->vector_scale_;
3118 
3119  normal.normalize();
3120 
3121  solid->extrusion_.contour_.push_back( vertex );
3122  solid->extrusion_.contour_normals_.push_back( normal );
3123 
3124  solid->last_vertex_ = to_vertex;
3125 
3126  return 0;
3127  }
3128 
3129  int Solid::cubicToCallback ( FT_Vector* control1, FT_Vector* control2,
3130  FT_Vector* to, Solid* solid )
3131  {
3132  // This is crude: Step off cubics with a fixed number of increments
3133 
3134  VertexInfo to_vertex( to, solid->colorTess(), solid->textureTess() );
3135  VertexInfo control1_vertex( control1, solid->colorTess(), solid->textureTess() );
3136  VertexInfo control2_vertex( control2, solid->colorTess(), solid->textureTess() );
3137 
3138  double a[2], b[2], c[2], d[2], f[2], df[2], d2f[2], d3f[2];
3139 
3140  a[X] = -solid->last_vertex_.v_[X] + 3 * control1_vertex.v_[X]
3141  -3 * control2_vertex.v_[X] + to_vertex.v_[X];
3142  a[Y] = -solid->last_vertex_.v_[Y] + 3 * control1_vertex.v_[Y]
3143  -3 * control2_vertex.v_[Y] + to_vertex.v_[Y];
3144 
3145  b[X] = 3 * solid->last_vertex_.v_[X] - 6 * control1_vertex.v_[X] +
3146  3 * control2_vertex.v_[X];
3147  b[Y] = 3 * solid->last_vertex_.v_[Y] - 6 * control1_vertex.v_[Y] +
3148  3 * control2_vertex.v_[Y];
3149 
3150  c[X] = -3 * solid->last_vertex_.v_[X] + 3 * control1_vertex.v_[X];
3151  c[Y] = -3 * solid->last_vertex_.v_[Y] + 3 * control1_vertex.v_[Y];
3152 
3153  d[X] = solid->last_vertex_.v_[X];
3154  d[Y] = solid->last_vertex_.v_[Y];
3155 
3156  f[X] = d[X];
3157  f[Y] = d[Y];
3158  df[X] = c[X] * solid->delta_ + b[X] * solid->delta2_
3159  + a[X] * solid->delta3_;
3160  df[Y] = c[Y] * solid->delta_ + b[Y] * solid->delta2_
3161  + a[Y] * solid->delta3_;
3162  d2f[X] = 2 * b[X] * solid->delta2_ + 6 * a[X] * solid->delta3_;
3163  d2f[Y] = 2 * b[Y] * solid->delta2_ + 6 * a[Y] * solid->delta3_;
3164  d3f[X] = 6 * a[X] * solid->delta3_;
3165  d3f[Y] = 6 * a[Y] * solid->delta3_;
3166 
3167  for ( unsigned int i = 0; i < solid->tessellation_steps_-1; i++ ) {
3168 
3169  f[X] += df[X];
3170  f[Y] += df[Y];
3171 
3172  VertexInfo vertex( f, solid->colorTess(), solid->textureTess() );
3173 
3174  VertexInfo normal( solid->extrusion_.normal_sign_.y_ * df[Y],
3175  solid->extrusion_.normal_sign_.x_ * df[X] );
3176 
3177  vertex.v_[X] *= solid->vector_scale_;
3178  vertex.v_[Y] *= solid->vector_scale_;
3179 
3180  normal.normalize();
3181 
3182  solid->extrusion_.contour_.push_back( vertex );
3183  solid->extrusion_.contour_normals_.push_back( normal );
3184 
3185  df[X] += d2f[X];
3186  df[Y] += d2f[Y];
3187  d2f[X] += d3f[X];
3188  d2f[Y] += d3f[Y];
3189  }
3190 
3191  VertexInfo vertex( to, solid->colorTess(), solid->textureTess() );
3192 
3193  VertexInfo normal( solid->extrusion_.normal_sign_.y_ * df[Y],
3194  solid->extrusion_.normal_sign_.x_ * df[X] );
3195 
3196  vertex.v_[X] *= solid->vector_scale_;
3197  vertex.v_[Y] *= solid->vector_scale_;
3198 
3199  normal.normalize();
3200 
3201  solid->extrusion_.contour_.push_back( vertex );
3202  solid->extrusion_.contour_normals_.push_back( normal );
3203 
3204  solid->last_vertex_ = to_vertex;
3205 
3206  return 0;
3207  }
3208 #endif // OGLFT_NO_SOLID
3209 
3210  Texture::Texture ( const char* filename, float point_size, FT_UInt resolution )
3211  : Face( filename, point_size, resolution )
3212  {
3213  if ( !isValid() ) return;
3214 
3215  init();
3216  }
3217 
3218  Texture::Texture ( FT_Face face, float point_size, FT_UInt resolution )
3219  : Face( face, point_size, resolution )
3220  {
3221  init();
3222  }
3223 
3224  void Texture::init ( void )
3225  {
3226  character_rotation_.active_ = false;
3227  character_rotation_.x_ = 0;
3228  character_rotation_.y_ = 0;
3229  character_rotation_.z_ = 0;
3230 
3231  setCharSize();
3232 
3234  }
3235 
3237  {
3238  clearCaches();
3239  }
3240 
3241  // Note: Changing the character rotation also clears the display list cache.
3242 
3243  void Texture::setCharacterRotationX ( GLfloat character_rotation_x )
3244  {
3245  if ( character_rotation_x != character_rotation_.x_ ) {
3246  character_rotation_.x_ = character_rotation_x;
3247 
3248  if ( character_rotation_.x_ != 0. || character_rotation_.y_ != 0. ||
3249  character_rotation_.z_ != 0. )
3250  character_rotation_.active_ = true;
3251  else
3252  character_rotation_.active_ = false;
3253 
3254  clearCaches();
3255  }
3256  }
3257 
3258  void Texture::setCharacterRotationY ( GLfloat character_rotation_y )
3259  {
3260  if ( character_rotation_y != character_rotation_.y_ ) {
3261  character_rotation_.y_ = character_rotation_y;
3262 
3263  if ( character_rotation_.x_ != 0. || character_rotation_.y_ != 0. ||
3264  character_rotation_.z_ != 0. )
3265  character_rotation_.active_ = true;
3266  else
3267  character_rotation_.active_ = false;
3268 
3269  clearCaches();
3270  }
3271  }
3272 
3273  void Texture::setCharacterRotationZ ( GLfloat character_rotation_z )
3274  {
3275  if ( character_rotation_z != character_rotation_.z_ ) {
3276  character_rotation_.z_ = character_rotation_z;
3277 
3278  if ( character_rotation_.x_ != 0. || character_rotation_.y_ != 0. ||
3279  character_rotation_.z_ != 0. )
3280  character_rotation_.active_ = true;
3281  else
3282  character_rotation_.active_ = false;
3283 
3284  clearCaches();
3285  }
3286  }
3287 
3288  void Texture::setCharSize ( void )
3289  {
3290  for ( unsigned int f = 0; f < faces_.size(); f++ ) {
3291  FT_Error error = FT_Set_Char_Size( faces_[f].face_,
3292  (FT_F26Dot6)( point_size_ * 64 ),
3293  (FT_F26Dot6)( point_size_ * 64 ),
3294  resolution_,
3295  resolution_ );
3296  if ( error != 0 )
3297  return;
3298  }
3299 
3300  if ( rotation_reference_glyph_ != 0 )
3301  setRotationOffset();
3302  }
3303 
3304  void Texture::setRotationOffset ( void )
3305  {
3306  FT_Error error = FT_Load_Glyph( rotation_reference_face_,
3308  FT_LOAD_RENDER );
3309 
3310  if ( error != 0 )
3311  return;
3312 
3313  rotation_offset_y_ = rotation_reference_face_->glyph->bitmap.rows / 2.;
3314  }
3315 
3316  BBox Texture::measure ( unsigned char c )
3317  {
3318  BBox bbox;
3319  // For starters, just get the unscaled glyph bounding box
3320  unsigned int f;
3321  FT_UInt glyph_index = 0;
3322 
3323  for ( f = 0; f < faces_.size(); f++ ) {
3324  glyph_index = FT_Get_Char_Index( faces_[f].face_, c );
3325  if ( glyph_index != 0 ) break;
3326  }
3327 
3328  if ( glyph_index == 0 )
3329  return bbox;
3330 
3331  FT_Error error = FT_Load_Glyph( faces_[f].face_, glyph_index,
3332  FT_LOAD_DEFAULT );
3333  if ( error != 0 )
3334  return bbox;
3335 
3336  FT_Glyph glyph;
3337  error = FT_Get_Glyph( faces_[f].face_->glyph, &glyph );
3338  if ( error != 0 )
3339  return bbox;
3340 
3341  FT_BBox ft_bbox;
3342  FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_unscaled, &ft_bbox );
3343 
3344  FT_Done_Glyph( glyph );
3345 
3346  bbox = ft_bbox;
3347  bbox.advance_ = faces_[f].face_->glyph->advance;
3348 
3349  return bbox;
3350  }
3351 
3352  double Texture::height ( void ) const
3353  {
3354  if ( faces_[0].face_->height > 0 )
3355  return faces_[0].face_->height / 64.;
3356  else
3357  return faces_[0].face_->size->metrics.y_ppem;
3358  }
3359 
3360 #ifndef OGLFT_NO_QT
3361 
3362  BBox Texture::measure ( const QChar c )
3363  {
3364  BBox bbox;
3365  // For starters, just get the unscaled glyph bounding box
3366  unsigned int f;
3367  FT_UInt glyph_index = 0;
3368 
3369  for ( f = 0; f < faces_.size(); f++ ) {
3370  glyph_index = FT_Get_Char_Index( faces_[f].face_, c.unicode() );
3371  if ( glyph_index != 0 ) break;
3372  }
3373 
3374  if ( glyph_index == 0 )
3375  return bbox;
3376 
3377  FT_Error error = FT_Load_Glyph( faces_[f].face_, glyph_index,
3378  FT_LOAD_DEFAULT );
3379  if ( error != 0 )
3380  return bbox;
3381 
3382  FT_Glyph glyph;
3383  error = FT_Get_Glyph( faces_[f].face_->glyph, &glyph );
3384  if ( error != 0 )
3385  return bbox;
3386 
3387  FT_BBox ft_bbox;
3388  FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_unscaled, &ft_bbox );
3389 
3390  FT_Done_Glyph( glyph );
3391 
3392  bbox = ft_bbox;
3393  bbox.advance_ = faces_[f].face_->glyph->advance;
3394 
3395  return bbox;
3396  }
3397 #endif /* OGLFT_NO_QT */
3398  GLuint Texture::compileGlyph ( FT_Face face, FT_UInt glyph_index )
3399  {
3400  bindTexture( face, glyph_index );
3401 
3402  GLuint dlist = glGenLists( 1 );
3403  glNewList( dlist, GL_COMPILE );
3404 
3405  renderGlyph( face, glyph_index );
3406 
3407  glEndList( );
3408 
3409  return dlist;
3410  }
3411 
3412  void Texture::renderGlyph ( FT_Face face, FT_UInt glyph_index )
3413  {
3414  FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
3415 
3416  if ( error != 0 )
3417  return;
3418 
3419  TextureInfo texture_info;
3420 
3421  GTOCI texture_object = glyph_texobjs_.find( glyph_index );
3422 
3423  if ( texture_object == glyph_texobjs_.end() ) {
3424 
3425  bindTexture( face, glyph_index );
3426 
3427  texture_object = glyph_texobjs_.find( glyph_index );
3428 
3429  if ( texture_object == glyph_texobjs_.end() )
3430  return;
3431  }
3432 
3433  texture_info = texture_object->second;
3434 
3435  glBindTexture( GL_TEXTURE_2D, texture_info.texture_name_ );
3436 
3437  if ( character_rotation_.active_ ) {
3438  glPushMatrix();
3439  glTranslatef( ( texture_info.width_ / 2. +
3440  texture_info.left_bearing_ ),
3441  rotation_offset_y_, 0. );
3442 
3443  if ( character_rotation_.x_ != 0. )
3444  glRotatef( character_rotation_.x_, 1., 0., 0. );
3445 
3446  if ( character_rotation_.y_ != 0. )
3447  glRotatef( character_rotation_.y_, 0., 1., 0. );
3448 
3449  if ( character_rotation_.z_ != 0. )
3450  glRotatef( character_rotation_.z_, 0., 0., 1. );
3451 
3452  glTranslatef( -( texture_info.width_ / 2. +
3453  texture_info.left_bearing_ ),
3454  -rotation_offset_y_, 0. );
3455  }
3456 
3457  glBegin( GL_QUADS );
3458 
3459  glTexCoord2i( 0, 0 );
3460  glVertex2f( texture_info.left_bearing_, texture_info.bottom_bearing_ );
3461 
3462  glTexCoord2f( texture_info.texture_s_, 0. );
3463  glVertex2f( texture_info.left_bearing_ + texture_info.width_,
3464  texture_info.bottom_bearing_ );
3465 
3466  glTexCoord2f( texture_info.texture_s_, texture_info.texture_t_ );
3467  glVertex2f( texture_info.left_bearing_ + texture_info.width_,
3468  texture_info.bottom_bearing_ + texture_info.height_ );
3469 
3470  glTexCoord2f( 0., texture_info.texture_t_ );
3471  glVertex2f( texture_info.left_bearing_,
3472  texture_info.bottom_bearing_ + texture_info.height_ );
3473 
3474  glEnd();
3475 
3476  if ( character_rotation_.active_ ) {
3477  glPopMatrix();
3478  }
3479 
3480  // Drawing a character always advances the MODELVIEW.
3481  glTranslatef( texture_info.advance_.x / 64.,
3482  texture_info.advance_.y / 64.,
3483  0. );
3484  }
3485 
3486  void Texture::clearCaches ( void )
3487  {
3488  GDLI fgi = glyph_dlists_.begin();
3489 
3490  for ( ; fgi != glyph_dlists_.end(); ++fgi ) {
3491  glDeleteLists( fgi->second, 1 );
3492  }
3493 
3494  glyph_dlists_.clear();
3495 
3496  GTOI fti = glyph_texobjs_.begin();
3497 
3498  for ( ; fti != glyph_texobjs_.end(); ++fti ) {
3499  glDeleteTextures( 1, &fti->second.texture_name_ );
3500  }
3501 
3502  glyph_texobjs_.clear();
3503  }
3504 
3505  unsigned int Texture::nearestPowerCeil ( unsigned int a )
3506  {
3507  unsigned int b = a;
3508  unsigned int c = 1;
3509 
3510  if ( a == 0 ) return 1;
3511 
3512  // Take the log-2 of a
3513  for ( ; ; ) {
3514  if ( b == 1 )
3515  break;
3516 
3517  else if ( b == 3 ) {
3518  c *= 4;
3519  break;
3520  }
3521 
3522  b >>= 1;
3523  c *= 2;
3524  }
3525  // If it's too small, raise it another power
3526  if ( c < a ) c *= 2;
3527 
3528  return c;
3529  }
3530 
3531  MonochromeTexture::MonochromeTexture ( const char* filename, float point_size,
3532  FT_UInt resolution )
3533  : Texture( filename, point_size, resolution )
3534  {}
3535 
3536  MonochromeTexture::MonochromeTexture ( FT_Face face, float point_size,
3537  FT_UInt resolution )
3538  : Texture( face, point_size, resolution )
3539  {}
3540 
3542  {}
3543 
3544  // Round up the size of the image to a power of two, but otherwise
3545  // use the bitmap as is (i.e., don't expand it into separate
3546  // luminance and alpha components)
3547 
3548  GLubyte* MonochromeTexture::invertBitmap ( const FT_Bitmap& bitmap,
3549  int* width, int* height )
3550  {
3551  *width = nearestPowerCeil( bitmap.width );
3552  *height = nearestPowerCeil( bitmap.rows );
3553 
3554  GLubyte* inverse = new GLubyte[ ( *width + 7) / 8 * *height ];
3555  GLubyte* inverse_ptr = inverse;
3556 
3557  memset( inverse, 0, sizeof( GLubyte )*( *width + 7 ) / 8 * *height );
3558 
3559  for ( int r = 0; r < bitmap.rows; r++ ) {
3560 
3561  GLubyte* bitmap_ptr = &bitmap.buffer[bitmap.pitch * ( bitmap.rows - r - 1 )];
3562 
3563  for ( int p = 0; p < bitmap.pitch; p++ ) {
3564 
3565  *inverse_ptr++ = *bitmap_ptr++;
3566  }
3567 
3568  inverse_ptr += ( ( *width + 7 ) / 8 - bitmap.pitch );
3569  }
3570 
3571  return inverse;
3572  }
3573 
3574  // Hmm. This is the only routine which is different between the different
3575  // styles.
3576 
3577  void MonochromeTexture::bindTexture ( FT_Face face, FT_UInt glyph_index )
3578  {
3579  GTOCI texobj = glyph_texobjs_.find( glyph_index );
3580 
3581  if ( texobj != glyph_texobjs_.end() )
3582  return;
3583 
3584  // Retrieve the glyph's data.
3585 
3586  FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
3587 
3588  if ( error != 0 )
3589  return;
3590 
3591  error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_MONO );
3592 
3593  if ( error != 0 )
3594  return;
3595 
3596  TextureInfo texture_info;
3597 
3598  glGenTextures( 1, &texture_info.texture_name_ );
3599  glBindTexture( GL_TEXTURE_2D, texture_info.texture_name_ );
3600  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
3601  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
3602  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
3603  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
3604 
3605  // Texture maps have be a power of 2 in size (is 1 a power of 2?), so
3606  // pad it out while flipping it over
3607  int width, height;
3608  GLubyte* inverted_pixmap =
3609  invertBitmap( face->glyph->bitmap, &width, &height );
3610 
3611  GLfloat red_map[2] = { background_color_[R], foreground_color_[R] };
3612  GLfloat green_map[2] = { background_color_[G], foreground_color_[G] };
3613  GLfloat blue_map[2] = { background_color_[B], foreground_color_[B] };
3614  GLfloat alpha_map[2] = { background_color_[A], foreground_color_[A] };
3615 
3616  glPixelMapfv( GL_PIXEL_MAP_I_TO_R, 2, red_map );
3617  glPixelMapfv( GL_PIXEL_MAP_I_TO_G, 2, green_map );
3618  glPixelMapfv( GL_PIXEL_MAP_I_TO_B, 2, blue_map );
3619  glPixelMapfv( GL_PIXEL_MAP_I_TO_A, 2, alpha_map );
3620 
3621  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height,
3622  0, GL_COLOR_INDEX, GL_BITMAP, inverted_pixmap );
3623 
3624  // Save a good bit of the data about this glyph
3625  texture_info.left_bearing_ = face->glyph->bitmap_left;
3626  texture_info.bottom_bearing_ = -( face->glyph->bitmap.rows
3627  - face->glyph->bitmap_top );
3628  texture_info.width_ = face->glyph->bitmap.width;
3629  texture_info.height_ = face->glyph->bitmap.rows;
3630  texture_info.texture_s_ = (GLfloat)texture_info.width_ / width;
3631  texture_info.texture_t_ = (GLfloat)texture_info.height_ / height;
3632  texture_info.advance_ = face->glyph->advance;
3633 
3634  glyph_texobjs_[ glyph_index ] = texture_info;
3635 
3636  delete[] inverted_pixmap;
3637  }
3638 
3639  GrayscaleTexture::GrayscaleTexture ( const char* filename, float point_size,
3640  FT_UInt resolution )
3641  : Texture( filename, point_size, resolution )
3642  {}
3643 
3644  GrayscaleTexture::GrayscaleTexture ( FT_Face face, float point_size,
3645  FT_UInt resolution )
3646  : Texture( face, point_size, resolution )
3647  {}
3648 
3650  {}
3651 
3652  // For the grayscale style, the luminance is the grayscale FreeType value,
3653  // so this just rounds up to a power of two and inverts the pixmap
3654 
3655  GLubyte* GrayscaleTexture::invertPixmap ( const FT_Bitmap& bitmap,
3656  int* width, int* height )
3657  {
3658  *width = nearestPowerCeil( bitmap.width );
3659  *height = nearestPowerCeil( bitmap.rows );
3660 
3661  GLubyte* inverse = new GLubyte[ *width * *height ];
3662  GLubyte* inverse_ptr = inverse;
3663 
3664  for ( int r = 0; r < bitmap.rows; r++ ) {
3665 
3666  GLubyte* bitmap_ptr = &bitmap.buffer[bitmap.pitch * ( bitmap.rows - r - 1 )];
3667 
3668  for ( int p = 0; p < bitmap.width; p++ ) {
3669  *inverse_ptr++ = *bitmap_ptr++;
3670  }
3671 
3672  inverse_ptr += ( *width - bitmap.pitch );
3673  }
3674  return inverse;
3675  }
3676 
3677  // Hmm. This is the only routine which is different between the different
3678  // styles.
3679 
3680  void GrayscaleTexture::bindTexture ( FT_Face face, FT_UInt glyph_index )
3681  {
3682  GTOCI texobj = glyph_texobjs_.find( glyph_index );
3683 
3684  if ( texobj != glyph_texobjs_.end() )
3685  return;
3686 
3687  // Retrieve the glyph's data.
3688 
3689  FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
3690 
3691  if ( error != 0 )
3692  return;
3693 
3694  error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );
3695 
3696  if ( error != 0 )
3697  return;
3698 
3699  TextureInfo texture_info;
3700 
3701  glGenTextures( 1, &texture_info.texture_name_ );
3702  glBindTexture( GL_TEXTURE_2D, texture_info.texture_name_ );
3703  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
3704  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
3705  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
3706  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
3707 
3708  // Texture maps have be a power of 2 in size (is 1 a power of 2?), so
3709  // pad it out while flipping it over
3710  int width, height;
3711  GLubyte* inverted_pixmap =
3712  invertPixmap( face->glyph->bitmap, &width, &height );
3713 
3714  glPushAttrib( GL_PIXEL_MODE_BIT );
3715  glPixelTransferf( GL_RED_SCALE, foreground_color_[R] - background_color_[R] );
3716  glPixelTransferf( GL_GREEN_SCALE, foreground_color_[G]-background_color_[G] );
3717  glPixelTransferf( GL_BLUE_SCALE, foreground_color_[B]-background_color_[B] );
3718  glPixelTransferf( GL_ALPHA_SCALE, foreground_color_[A]-background_color_[A] );
3719  glPixelTransferf( GL_RED_BIAS, background_color_[R] );
3720  glPixelTransferf( GL_GREEN_BIAS, background_color_[G] );
3721  glPixelTransferf( GL_BLUE_BIAS, background_color_[B] );
3722  glPixelTransferf( GL_ALPHA_BIAS, background_color_[A] );
3723 
3724  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height,
3725  0, GL_LUMINANCE, GL_UNSIGNED_BYTE, inverted_pixmap );
3726 
3727  glPopAttrib();
3728  // Save a good bit of the data about this glyph
3729  texture_info.left_bearing_ = face->glyph->bitmap_left;
3730  texture_info.bottom_bearing_ = -( face->glyph->bitmap.rows
3731  - face->glyph->bitmap_top );
3732  texture_info.width_ = face->glyph->bitmap.width;
3733  texture_info.height_ = face->glyph->bitmap.rows;
3734  texture_info.texture_s_ = (GLfloat)texture_info.width_ / width;
3735  texture_info.texture_t_ = (GLfloat)texture_info.height_ / height;
3736  texture_info.advance_ = face->glyph->advance;
3737 
3738  glyph_texobjs_[ glyph_index ] = texture_info;
3739 
3740  delete[] inverted_pixmap;
3741  }
3742 
3743  TranslucentTexture::TranslucentTexture ( const char* filename, float point_size,
3744  FT_UInt resolution )
3745  : Texture( filename, point_size, resolution )
3746  {}
3747 
3748  TranslucentTexture::TranslucentTexture ( FT_Face face, float point_size,
3749  FT_UInt resolution )
3750  : Texture( face, point_size, resolution )
3751  {}
3752 
3754  {}
3755 
3756  // For the translucent style, the luminance is saturated and alpha value
3757  // is the translucent FreeType value
3758 
3759  GLubyte* TranslucentTexture::invertPixmap ( const FT_Bitmap& bitmap,
3760  int* width, int* height )
3761  {
3762  *width = nearestPowerCeil( bitmap.width );
3763  *height = nearestPowerCeil( bitmap.rows );
3764 
3765  GLubyte* inverse = new GLubyte[ 2 * *width * *height ];
3766  GLubyte* inverse_ptr = inverse;
3767 
3768  for ( int r = 0; r < bitmap.rows; r++ ) {
3769 
3770  GLubyte* bitmap_ptr = &bitmap.buffer[bitmap.pitch * ( bitmap.rows - r - 1 )];
3771 
3772  for ( int p = 0; p < bitmap.width; p++ ) {
3773  *inverse_ptr++ = 0xff;
3774  *inverse_ptr++ = *bitmap_ptr++;
3775  }
3776 
3777  inverse_ptr += 2 * ( *width - bitmap.pitch );
3778  }
3779  return inverse;
3780  }
3781 
3782  // Hmm. This is the only routine which is different between the different
3783  // styles.
3784 
3785  void TranslucentTexture::bindTexture ( FT_Face face, FT_UInt glyph_index )
3786  {
3787  GTOCI texobj = glyph_texobjs_.find( glyph_index );
3788 
3789  if ( texobj != glyph_texobjs_.end() )
3790  return;
3791 
3792  // Retrieve the glyph's data.
3793 
3794  FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
3795 
3796  if ( error != 0 )
3797  return;
3798 
3799  error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );
3800 
3801  if ( error != 0 )
3802  return;
3803 
3804  TextureInfo texture_info;
3805 
3806  glGenTextures( 1, &texture_info.texture_name_ );
3807  glBindTexture( GL_TEXTURE_2D, texture_info.texture_name_ );
3808  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
3809  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
3810  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
3811  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
3812 
3813  // Texture maps have be a power of 2 in size (is 1 a power of 2?), so
3814  // pad it out while flipping it over
3815  int width, height;
3816  GLubyte* inverted_pixmap =
3817  invertPixmap( face->glyph->bitmap, &width, &height );
3818 
3819  glPushAttrib( GL_PIXEL_MODE_BIT );
3820  glPixelTransferf( GL_RED_SCALE, foreground_color_[R] - background_color_[R] );
3821  glPixelTransferf( GL_GREEN_SCALE, foreground_color_[G]-background_color_[G] );
3822  glPixelTransferf( GL_BLUE_SCALE, foreground_color_[B]-background_color_[B] );
3823  glPixelTransferf( GL_ALPHA_SCALE, foreground_color_[A]-background_color_[A] );
3824  glPixelTransferf( GL_RED_BIAS, background_color_[R] );
3825  glPixelTransferf( GL_GREEN_BIAS, background_color_[G] );
3826  glPixelTransferf( GL_BLUE_BIAS, background_color_[B] );
3827  glPixelTransferf( GL_ALPHA_BIAS, background_color_[A] );
3828 
3829  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height,
3830  0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, inverted_pixmap );
3831 
3832  glPopAttrib();
3833 
3834  // Save a good bit of the data about this glyph
3835  texture_info.left_bearing_ = face->glyph->bitmap_left;
3836  texture_info.bottom_bearing_ = -( face->glyph->bitmap.rows
3837  - face->glyph->bitmap_top );
3838  texture_info.width_ = face->glyph->bitmap.width;
3839  texture_info.height_ = face->glyph->bitmap.rows;
3840  texture_info.texture_s_ = (GLfloat)texture_info.width_ / width;
3841  texture_info.texture_t_ = (GLfloat)texture_info.height_ / height;
3842  texture_info.advance_ = face->glyph->advance;
3843 
3844  glyph_texobjs_[ glyph_index ] = texture_info;
3845 
3846  delete[] inverted_pixmap;
3847  }
3848 
3849 } // close OGLFT namespace
double height(void) const
Definition: moOGLFT.cpp:2127
Baseline alignment of text (default)
Definition: moOGLFT.h:311
Render text as a filled polygons.
Definition: moOGLFT.h:1489
float x_max_
The right-most position at which "ink" appears.
Definition: moOGLFT.h:171
Monochrome(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:1555
void setForegroundColor(GLfloat red=0.0, GLfloat green=0.0, GLfloat blue=0.0, GLfloat alpha=1.0)
Definition: moOGLFT.cpp:232
BBox measure(unsigned char c)
Definition: moOGLFT.cpp:2137
void setTessellationSteps(unsigned int tessellation_steps)
Definition: moOGLFT.cpp:2034
~Solid(void)
Definition: moOGLFT.cpp:2877
var b
Definition: jquery.js:16
The Blue component of a color.
Definition: moOGLFT.h:88
DisplayLists::const_iterator DLCI
A convenience definition of an iterator for display list vectors.
Definition: moOGLFT.h:283
void setCharacterRotationX(GLfloat character_rotation_x)
Definition: moOGLFT.cpp:2050
The Z component of space.
Definition: moOGLFT.h:79
enum VerticalJustification vertical_justification_
PHIGS-like vertical positioning of text.
Definition: moOGLFT.h:381
g[c]
Definition: jquery.js:71
Face(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:65
GlyphTexObjs::iterator GTOI
Definition: moOGLFT.h:1996
float y_min_
the bottom-most position at which "ink" appears.
Definition: moOGLFT.h:170
ColorTess * color_tess_
Definition: moOGLFT.h:1235
function p(by, bw, bv)
Definition: jquery.js:28
This is the base class of the polygonal styles: outline, filled and solid.
Definition: moOGLFT.h:1078
var c
Definition: jquery.js:29
VertexInfo last_vertex_
Definition: moOGLFT.h:1211
bool contour_open_
Definition: moOGLFT.h:1231
virtual BBox measure(unsigned char c)=0
Filled(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:2502
GLfloat foreground_color_[4]
Definition: moOGLFT.h:372
bool isValid(void) const
Definition: moOGLFT.h:449
void clearCaches(void)
Definition: moOGLFT.cpp:2227
virtual void setCharSize(void)=0
virtual void clearCaches(void)=0
The Red component of a color.
Definition: moOGLFT.h:86
MonochromeTexture(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:3531
float y_max_
The top-most position at which "ink" appears.
Definition: moOGLFT.h:172
void(* GLUTessCallback)(void)
Callback from GLU tessellation routines.
Definition: moOGLFT.h:97
double depth(void) const
Definition: moOGLFT.h:1669
function a
Definition: jquery.js:41
Right justified alignment of text.
Definition: moOGLFT.h:303
The FreeType library instance.
Definition: moOGLFT.h:108
function x(bx)
Definition: jquery.js:30
f
Definition: jquery.js:71
GlyphDLists::iterator GDLI
Definition: moOGLFT.h:406
bool advance_
Does rendering text affect the MODELVIEW matrix?
Definition: moOGLFT.h:365
virtual GLuint compileGlyph(FT_Face face, FT_UInt glyph_index)=0
void setResolution(FT_UInt resolution)
Definition: moOGLFT.cpp:199
float point_size_
Nominal point size.
Definition: moOGLFT.h:359
enum GlyphCompileMode compile_mode_
Glyph display list creation mode.
Definition: moOGLFT.h:356
Left justified justification of text.
Definition: moOGLFT.h:300
double delta3_
Definition: moOGLFT.h:1097
virtual ~Raster(void)
Definition: moOGLFT.cpp:1340
FT_UInt resolution(void)
Definition: moOGLFT.h:541
FT_Face rotation_reference_face_
The rotation reference character could be in any face.
Definition: moOGLFT.h:391
std::vector< FaceData > faces_
Definition: moOGLFT.h:350
GLuint compile(const char *s)
Definition: moOGLFT.cpp:717
float dx_
Advance increment in the X direction.
Definition: moOGLFT.h:140
GLfloat rotation_offset_y_
Definition: moOGLFT.h:395
static FT_Library & instance(void)
Definition: moOGLFT.cpp:58
Raster(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:1317
struct OGLFT::Polygonal::@57 character_rotation_
Angle of rotation of characters relative to text orientation.
virtual void bindTexture(FT_Face face, FT_UInt glyph_index)=0
Descender alignment of text.
Definition: moOGLFT.h:310
BBox measure(unsigned char c)
Definition: moOGLFT.cpp:3316
double height(void) const
Definition: moOGLFT.cpp:3352
virtual ~Face(void)
Definition: moOGLFT.cpp:147
FT_UInt resolution_
Display resolution in pixels per inch.
Definition: moOGLFT.h:362
moTypes MOint moText moParamIndex moParamReference int iRow int int i int i
Definition: all_f.js:18
float dy_
Advance increment in the Y direction.
Definition: moOGLFT.h:141
bool valid_
Did a font load OK?
Definition: moOGLFT.h:353
Solid(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:2837
Compile new glyphs when seen for the first time.
Definition: moOGLFT.h:324
Library(void)
Definition: moOGLFT.cpp:36
FT_UInt rotation_reference_glyph_
Definition: moOGLFT.h:388
TextureTess * textureTess(void) const
Definition: moOGLFT.h:1355
BBox measure(unsigned char c)
Definition: moOGLFT.cpp:1362
virtual void renderGlyph(FT_Face face, FT_UInt glyph_index)=0
void setCharacterRotationY(GLfloat character_rotation_y)
Definition: moOGLFT.cpp:2065
The Alpha (or transparency) of a color.
Definition: moOGLFT.h:89
virtual ~Polygonal(void)
Definition: moOGLFT.cpp:2007
double delta2_
Definition: moOGLFT.h:1097
enum HorizontalJustification horizontal_justification_
PHIGS-like horizontal positioning of text.
Definition: moOGLFT.h:378
Polygonal(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:1958
void setCharacterRotationZ(GLfloat character_rotation_z)
Definition: moOGLFT.cpp:1345
TextureTess * texture_tess_
Definition: moOGLFT.h:1239
unsigned int tessellation_steps_
Definition: moOGLFT.h:1091
GlyphDLists::const_iterator GDLCI
Definition: moOGLFT.h:402
GLfloat background_color_[4]
Background color (what modes would use this?)
Definition: moOGLFT.h:375
GlyphTexObjs glyph_texobjs_
Cache of defined glyph texture objects.
Definition: moOGLFT.h:1999
void setDepth(double depth)
Definition: moOGLFT.cpp:2882
VertexInfoList vertices_
Definition: moOGLFT.h:1227
static const unsigned int DEFAULT_TESSELLATION_STEPS
Definition: moOGLFT.h:1110
GLfloat depth_offset_
Definition: moOGLFT.h:1503
GLfloat string_rotation_
Rotate an entire string in the Z plane.
Definition: moOGLFT.h:384
The Y component of space.
Definition: moOGLFT.h:78
function d
Definition: jquery.js:41
Advance advance_
The (total) advancement.
Definition: moOGLFT.h:173
The X component of space.
Definition: moOGLFT.h:77
virtual ~Texture(void)
Definition: moOGLFT.cpp:3236
void setCharacterRotationZ(GLfloat character_rotation_z)
Definition: moOGLFT.cpp:2080
ColorTess * colorTess(void) const
Definition: moOGLFT.h:1341
VertexInfoList::iterator VILI
A convenience definition of the iterator over the list of vertices.
Definition: moOGLFT.h:1220
void setCharacterRotationZ(GLfloat character_rotation_z)
Definition: moOGLFT.cpp:3273
virtual void setRotationOffset(void)=0
void draw(const char *s)
Definition: moOGLFT.cpp:841
GrayscaleTexture(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:3639
virtual BBox measureRaw(const char *s)
Definition: moOGLFT.cpp:422
Centered alignment of text.
Definition: moOGLFT.h:312
void setBackgroundColor(GLfloat red=1.0, GLfloat green=1.0, GLfloat blue=1.0, GLfloat alpha=0.0)
Definition: moOGLFT.cpp:213
A face (aka font) used to render text with OpenGL.
Definition: moOGLFT.h:293
Ascender justification of text.
Definition: moOGLFT.h:313
void setPointSize(float point_size)
Definition: moOGLFT.cpp:185
The Green component of a color.
Definition: moOGLFT.h:87
Grayscale(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:1684
~Library(void)
Definition: moOGLFT.cpp:47
Center justified alignment of text.
Definition: moOGLFT.h:302
bool addAuxiliaryFace(const char *filename)
Definition: moOGLFT.cpp:156
GlyphDLists glyph_dlists_
Cache of defined glyph display lists.
Definition: moOGLFT.h:409
void setCharacterRotationX(GLfloat character_rotation_x)
Definition: moOGLFT.cpp:3243
double height(void) const
Definition: moOGLFT.cpp:1354
All of OGLFT C++ objects are in this namespace.
Definition: moOGLFT.cpp:23
double vector_scale_
Definition: moOGLFT.h:1103
GLfloat character_rotation_z_
Definition: moOGLFT.h:1704
Texture(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:3210
TranslucentTexture(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:3743
virtual ~Filled(void)
Definition: moOGLFT.cpp:2536
GlyphTexObjs::const_iterator GTOCI
Definition: moOGLFT.h:1992
float x_min_
The left-most position at which "ink" appears.
Definition: moOGLFT.h:169
void setColorTess(ColorTess *color_tess)
Definition: moOGLFT.cpp:2015
struct OGLFT::Texture::@60 character_rotation_
Angle of rotation of characters relative to text orientation.
void setTextureTess(TextureTess *texture_tess)
Definition: moOGLFT.cpp:2025
Natural origin alignment of text (default)
Definition: moOGLFT.h:301
void setStringRotation(GLfloat string_rotation)
Definition: moOGLFT.cpp:335
This is the base class of the texture style.
Definition: moOGLFT.h:1950
void renderGlyph(FT_Face face, FT_UInt glyph_index)
Definition: moOGLFT.cpp:2541
unsigned int nearestPowerCeil(unsigned int a)
Definition: moOGLFT.cpp:3505
Translucent(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:1817
void setCharacterRotationReference(unsigned char c)
Definition: moOGLFT.cpp:375
Outline(const char *filename, float point_size=12, FT_UInt resolution=100)
Definition: moOGLFT.cpp:2238
FT_Outline_Funcs interface_
Callbacks for FreeType glyph decomposition into outlines.
Definition: moOGLFT.h:1106
void setCharacterRotationY(GLfloat character_rotation_y)
Definition: moOGLFT.cpp:3258
DisplayLists character_display_lists_
Definition: moOGLFT.h:413