libmoldeo (Moldeo 1.0 Core)  1.0
libmoldeo is the group of objects and functions that executes the basic operations of Moldeo 1.0 Platform.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
moOGLFT.cpp
Go to the documentation of this file.
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 
394  rotation_reference_face_ = faces_[f].face_;
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
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
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
This is the base class of the polygonal styles: outline, filled and solid.
Definition: moOGLFT.h:1078
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
Right justified alignment of text.
Definition: moOGLFT.h:303
The FreeType library instance.
Definition: moOGLFT.h:108
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
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
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