Core commit. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-core / src / osd / OGLFT.cpp
CommitLineData
451ab91e 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
18 * Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22#include <iostream>
23#include <iomanip>
24#include <string.h>
25#include "OGLFT.h"
26
27int wstrlen(const wchar_t * s)
28{
29 int r = 0;
30 while (*s++) r++;
31 return r;
32}
33
34namespace OGLFT
35{
36 FT_Library ft_library;
37 bool Init_FT(void)
38 {
39 FT_Error error = FT_Init_FreeType(&ft_library);
40 if(error != 0) std::cerr << "[OGLFT] Could not initialize the FreeType library." << std::endl;
41 return (error == 0);
42 }
43 bool Uninit_FT(void)
44 {
45 FT_Error error = FT_Done_FreeType(ft_library);
46 if(error != 0) std::cerr << "[OGLFT] Could not terminate the FreeType library." << std::endl;
47 return (error == 0);
48 }
49
50 // Load a new face
51 Face::Face (const char* filename, float point_size, FT_UInt resolution)
52 : point_size_(point_size), resolution_(resolution)
53 {
54 valid_ = true;
55 FT_Face ft_face;
56 FT_Error error = FT_New_Face(ft_library, filename, 0, &ft_face);
57 if(error != 0)
58 {
59 valid_ = false;
60 return;
61 }
62
63 // As of FreeType 2.1: only a UNICODE charmap is automatically activated.
64 // If no charmap is activated automatically, just use the first one.
65 if(ft_face->charmap == 0 && ft_face->num_charmaps > 0) FT_Select_Charmap(ft_face, ft_face->charmaps[0]->encoding);
66
67 faces_.push_back(FaceData(ft_face));
68
69 init();
70 }
71
72 // Go with a face that the user has already opened.
73 Face::Face (FT_Face face, float point_size, FT_UInt resolution)
74 : point_size_(point_size), resolution_(resolution)
75 {
76 valid_ = true;
77
78 // As of FreeType 2.1: only a UNICODE charmap is automatically activated.
79 // If no charmap is activated automatically, just use the first one.
80 if(face->charmap == 0 && face->num_charmaps > 0) FT_Select_Charmap(face, face->charmaps[0]->encoding);
81
82 faces_.push_back(FaceData(face, false));
83
84 init();
85 }
86
87 // Standard initialization behavior once the font file is opened.
88 void Face::init (void)
89 {
90 // By default, each glyph is compiled into a display list the first
91 // time it is encountered
92 compile_mode_ = COMPILE;
93
94 // By default, all drawing is wrapped with push/pop matrix so that the
95 // MODELVIEW matrix is not modified. If advance_ is set, then subsequent
96 // drawings follow from the advance of the last glyph rendered.
97 advance_ = false;
98
99 // Initialize the default colors
100 foreground_color_[R] = 0.; foreground_color_[G] = 0.; foreground_color_[B] = 0.; foreground_color_[A] = 1.;
101 background_color_[R] = 1.; background_color_[G] = 1.; background_color_[B] = 1.; background_color_[A] = 0.;
102
103 // The default positioning of the text is at the origin of the first glyph
104 horizontal_justification_ = ORIGIN;
105 vertical_justification_ = BASELINE;
106
107 // By default, strings are rendered in their nominal direction
108 string_rotation_ = 0;
109
110 // setCharacterRotationReference calls the virtual function clearCaches()
111 // so it is up to a subclass to set the real default
112 rotation_reference_glyph_ = 0;
113 rotation_reference_face_ = 0;
114 rotation_offset_y_ = 0.;
115 }
116
117 Face::~Face (void)
118 {
119 for(unsigned int i=0; i<faces_.size(); i++)
120 if(faces_[i].free_on_exit_)
121 FT_Done_Face(faces_[i].face_);
122 }
123
124 // Add another Face to select characters from
125 bool Face::addAuxiliaryFace (const char* filename)
126 {
127 FT_Face ft_face;
128
129 FT_Error error = FT_New_Face(ft_library, filename, 0, &ft_face);
130
131 if(error != 0) return false;
132
133 faces_.push_back(FaceData(ft_face));
134 setCharSize();
135
136 return true;
137 }
138
139 // Add another Face to select characters from
140 bool Face::addAuxiliaryFace (FT_Face face)
141 {
142 faces_.push_back(FaceData(face, false));
143
144 setCharSize();
145
146 return true;
147 }
148
149 // Note: Changing the point size also clears the display list cache
150 void Face::setPointSize (float point_size)
151 {
152 if(point_size != point_size_)
153 {
154 point_size_ = point_size;
155 clearCaches();
156 setCharSize();
157 }
158 }
159
160 // Note: Changing the resolution also clears the display list cache
161 void Face::setResolution (FT_UInt resolution)
162 {
163 if(resolution != resolution_)
164 {
165 resolution_ = resolution;
166 clearCaches();
167 setCharSize();
168 }
169 }
170
171 // Note: Changing the background color also clears the display list cache.
172 void Face::setBackgroundColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
173 {
174 if(background_color_[R] != red||background_color_[G] != green||background_color_[B] != blue||background_color_[A] != alpha)
175 {
176 background_color_[R] = red;
177 background_color_[G] = green;
178 background_color_[B] = blue;
179 background_color_[A] = alpha;
180 }
181 }
182
183 // Note: Changing the foreground color also clears the display list cache.
184 void Face::setForegroundColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
185 {
186 if(foreground_color_[R] != red||foreground_color_[G] != green||foreground_color_[B] != blue||foreground_color_[A] != alpha)
187 {
188 foreground_color_[R] = red;
189 foreground_color_[G] = green;
190 foreground_color_[B] = blue;
191 foreground_color_[A] = alpha;
192 }
193 }
194
195 // Note: Changing the foreground color also clears the display list cache.
196 void Face::setForegroundColor (const GLfloat foreground_color[4])
197 {
198 foreground_color_[R] = foreground_color[R];
199 foreground_color_[G] = foreground_color[G];
200 foreground_color_[B] = foreground_color[B];
201 foreground_color_[A] = foreground_color[A];
202 }
203
204 // Note: Changing the background color also clears the display list cache.
205 void Face::setBackgroundColor (const GLfloat background_color[4])
206 {
207 background_color_[R] = background_color[R];
208 background_color_[G] = background_color[G];
209 background_color_[B] = background_color[B];
210 background_color_[A] = background_color[A];
211 }
212
213 // Note: Changing the string rotation angle clears the display list cache
214 void Face::setStringRotation (GLfloat string_rotation)
215 {
216 if(string_rotation != string_rotation_)
217 {
218 string_rotation_ = string_rotation;
219
220 clearCaches();
221
222 // Note that this affects ALL glyphs accessed through
223 // the Face, both the vector and the raster glyphs. Very nice!
224 if (string_rotation_ != 0)
225 {
226 float angle;
227 if (string_rotation_<0)
228 angle = 360.0f - fmod(fabs(string_rotation_), 360.f);
229 else
230 angle = fmod(string_rotation_, 360.f);
231
232 FT_Matrix rotation_matrix;
233 FT_Vector sinus;
234
235 FT_Vector_Unit(&sinus, (FT_Angle)(angle * 0x10000L));
236
237 rotation_matrix.xx = sinus.x;
238 rotation_matrix.xy = -sinus.y;
239 rotation_matrix.yx = sinus.y;
240 rotation_matrix.yy = sinus.x;
241
242 for(unsigned int i=0; i<faces_.size(); i++) FT_Set_Transform(faces_[i].face_, &rotation_matrix, 0);
243 }
244 else for(unsigned int i=0; i<faces_.size(); i++) FT_Set_Transform(faces_[i].face_, 0, 0);
245 }
246 }
247
248 // Note: Changing the rotation reference character clears the display list cache.
249 void Face::setCharacterRotationReference (unsigned char c)
250 {
251 unsigned int f;
252 FT_UInt glyph_index = 0;
253
254 for(f=0; f<faces_.size(); f++)
255 {
256 glyph_index = FT_Get_Char_Index(faces_[f].face_, c);
257 if(glyph_index != 0) break;
258 }
259
260 if(f<faces_.size() && glyph_index != rotation_reference_glyph_)
261 {
262 FT_Error error = FT_Load_Glyph(faces_[f].face_, glyph_index, FT_LOAD_DEFAULT);
263
264 if(error != 0) return;
265
266 rotation_reference_glyph_ = glyph_index;
267 rotation_reference_face_ = faces_[f].face_;
268 setRotationOffset();
269
270 clearCaches();
271 }
272 }
273
274 BBox Face::measure (const char* s)
275 {
276 BBox bbox;
277 char c;
278
279 if((c = *s++) != 0)
280 {
281 bbox = measure((unsigned char)c);
282
283 for(c = *s; c != 0; c = *++s)
284 {
285 BBox char_bbox = measure((unsigned char)c);
286 bbox += char_bbox;
287 }
288 }
289 // make sure the origin is at 0,0
290 if (bbox.x_min_ != 0)
291 {
292 bbox.x_max_ -= bbox.x_min_;
293 bbox.x_min_ = 0;
294 }
295 if (bbox.y_min_ != 0)
296 {
297 bbox.y_max_ -= bbox.y_min_;
298 bbox.y_min_ = 0;
299 }
300
301 return bbox;
302 }
303
304 BBox Face::measureRaw (const char* s)
305 {
306 BBox bbox;
307
308 for(char c = *s; c != 0; c = *++s)
309 {
310 BBox char_bbox;
311
312 unsigned int f;
313 FT_UInt glyph_index = 0;
314
315 for(f=0; f<faces_.size(); f++)
316 {
317 glyph_index = FT_Get_Char_Index(faces_[f].face_, c);
318 if(glyph_index != 0) break;
319 }
320
321 if(glyph_index == 0) continue;
322
323 FT_Error error = FT_Load_Glyph(faces_[f].face_, glyph_index, FT_LOAD_DEFAULT);
324 if(error != 0) continue;
325
326 FT_Glyph glyph;
327 error = FT_Get_Glyph(faces_[f].face_->glyph, &glyph);
328 if(error != 0) continue;
329
330 FT_BBox ft_bbox;
331 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &ft_bbox);
332
333 FT_Done_Glyph(glyph);
334
335 char_bbox = ft_bbox;
336 char_bbox.advance_ = faces_[f].face_->glyph->advance;
337
338 bbox += char_bbox;
339 }
340
341 return bbox;
342 }
343
344 BBox Face::measure (const wchar_t* s)
345 {
346 BBox bbox;
347 int i;
348
349 if(wstrlen(s) > 0)
350 {
351 bbox = measure(s[0]);
352 for(i = 1; i < wstrlen(s); i++)
353 {
354 BBox char_bbox = measure(s[i]);
355 bbox += char_bbox;
356 }
357 }
358 // make sure the origin is at 0,0
359 if (bbox.x_min_ != 0)
360 {
361 bbox.x_max_ -= bbox.x_min_;
362 bbox.x_min_ = 0;
363 }
364 if (bbox.y_min_ != 0)
365 {
366 bbox.y_max_ -= bbox.y_min_;
367 bbox.y_min_ = 0;
368 }
369 return bbox;
370 }
371
372 BBox Face::measure (const wchar_t* format, double number)
373 {
374 return measure(format, number);
375 }
376
377 BBox Face::measureRaw (const wchar_t* s)
378 {
379 BBox bbox;
380 int i;
381
382 for(i = 0; i < wstrlen(s); i++)
383 {
384 BBox char_bbox;
385
386 unsigned int f;
387 FT_UInt glyph_index = 0;
388
389 for(f=0; f<faces_.size(); f++)
390 {
391 glyph_index = FT_Get_Char_Index(faces_[f].face_, s[i]);
392 if(glyph_index != 0) break;
393 }
394
395 if(glyph_index == 0)
396 {
397 continue;
398 }
399
400 FT_Error error = FT_Load_Glyph(faces_[f].face_, glyph_index, FT_LOAD_DEFAULT);
401 if(error != 0) continue;
402
403 FT_Glyph glyph;
404 error = FT_Get_Glyph(faces_[f].face_->glyph, &glyph);
405 if(error != 0) continue;
406
407 FT_BBox ft_bbox;
408 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &ft_bbox);
409
410 FT_Done_Glyph(glyph);
411
412 char_bbox = ft_bbox;
413 char_bbox.advance_ = faces_[f].face_->glyph->advance;
414
415 bbox += char_bbox;
416 }
417
418 return bbox;
419 }
420
421 // Measure the bounding box as if the (latin1) string were not rotated
422 BBox Face::measure_nominal (const char* s)
423 {
424 if(string_rotation_ == 0.) return measure(s);
425
426 for(unsigned int f=0; f<faces_.size(); f++) FT_Set_Transform(faces_[f].face_, 0, 0);
427
428 BBox bbox = measure(s);
429
430 float angle;
431 if(string_rotation_<0.)
432 angle = 360.0f - fmod(fabs(string_rotation_), 360.f);
433 else
434 angle = fmod(string_rotation_, 360.f);
435
436 FT_Matrix rotation_matrix;
437 FT_Vector sinus;
438
439 FT_Vector_Unit(&sinus, (FT_Angle)(angle * 0x10000L));
440
441 rotation_matrix.xx = sinus.x;
442 rotation_matrix.xy = -sinus.y;
443 rotation_matrix.yx = sinus.y;
444 rotation_matrix.yy = sinus.x;
445
446 for(unsigned int f=0; f<faces_.size(); f++) FT_Set_Transform(faces_[f].face_, &rotation_matrix, 0);
447
448 return bbox;
449 }
450
451 // Measure the bounding box as if the (UNICODE) string were not rotated
452 BBox Face::measure_nominal (const wchar_t* s)
453 {
454 if(string_rotation_ == 0.)return measure(s);
455
456 for(unsigned int f=0; f<faces_.size(); f++)FT_Set_Transform(faces_[f].face_, 0, 0);
457
458 BBox bbox = measure(s);
459
460 float angle;
461 if(string_rotation_<0.0)
462 angle = 360.0f - fmod(fabs(string_rotation_), 360.f);
463 else
464 angle = fmod(string_rotation_, 360.f);
465
466 FT_Matrix rotation_matrix;
467 FT_Vector sinus;
468
469 FT_Vector_Unit(&sinus, (FT_Angle)(angle * 0x10000L));
470
471 rotation_matrix.xx = sinus.x;
472 rotation_matrix.xy = -sinus.y;
473 rotation_matrix.yx = sinus.y;
474 rotation_matrix.yy = sinus.x;
475
476 for(unsigned int f=0; f<faces_.size(); f++)FT_Set_Transform(faces_[f].face_, &rotation_matrix, 0);
477
478 return bbox;
479 }
480
481 // Compile a (latin1) character glyph into a display list and cache
482 // it for later
483
484 GLuint Face::compile (unsigned char c)
485 {
486 // See if we've done it already
487 GDLCI fgi = glyph_dlists_.find(c);
488
489 if(fgi != glyph_dlists_.end())return fgi->second;
490
491 unsigned int f;
492 FT_UInt glyph_index = 0;
493
494 for(f=0; f<faces_.size(); f++)
495 {
496 glyph_index = FT_Get_Char_Index(faces_[f].face_, c);
497 if(glyph_index != 0) break;
498 }
499
500 if(glyph_index == 0)return 0;
501
502 GLuint dlist = compileGlyph(faces_[f].face_, glyph_index);
503 glyph_dlists_[ c ] = dlist;
504
505 return dlist;
506 }
507
508
509 // Compile a (UNICODE) character glyph into a display list and cache
510 // it for later
511 GLuint Face::compile (const wchar_t c)
512 {
513 // See if we've done it already
514 GDLCI fgi = glyph_dlists_.find(c);
515
516 if(fgi != glyph_dlists_.end())return fgi->second;
517
518 unsigned int f;
519 FT_UInt glyph_index = 0;
520
521 for(f=0; f<faces_.size(); f++)
522 {
523 glyph_index = FT_Get_Char_Index(faces_[f].face_, c);
524 if(glyph_index != 0) break;
525 }
526
527 if(glyph_index == 0)return 0;
528
529 GLuint dlist = compileGlyph(faces_[f].face_, glyph_index);
530
531 glyph_dlists_[ c ] = dlist;
532
533 return dlist;
534 }
535
536 // Assume the MODELVIEW matrix is already set and draw the (latin1)
537 // string. Note: this routine now ignores almost all settings:
538 // including the position (both modelview and raster), color,
539 // justification and advance settings. Consider this to be the raw
540 // drawing routine for which you are responsible for most of the
541 // setup.
542 void Face::draw (const char* s)
543 {
544 DLCI character_display_list = character_display_lists_.begin();
545
546 for(char c = *s; c != 0; c = *++s)
547 {
548 if(character_display_list != character_display_lists_.end())
549 {
550 glCallList(*character_display_list);
551 character_display_list++;
552 }
553 draw((unsigned char)c);
554 }
555 }
556
557 // Assume the MODELVIEW matrix is already set and draw the (UNICODE)
558 // string. Note: this routine now ignores almost all settings:
559 // including the position (both modelview and raster), color,
560 // justification and advance settings. Consider this to be the raw
561 // drawing routine for which you are responsible for most of the
562 // setup.
563 void Face::draw (const wchar_t* s)
564 {
565 DLCI character_display_list = character_display_lists_.begin();
566 int i;
567
568 for(i = 0; i < wstrlen(s); i++)
569 {
570 if(character_display_list != character_display_lists_.end())
571 {
572 glCallList(*character_display_list);
573 character_display_list++;
574 }
575 draw(s[i]);
576 }
577 }
578
579 // Assume the MODELVIEW matrix is already setup and draw the
580 // (latin1) character.
581 void Face::draw (unsigned char c)
582 {
583 // See if we've done it already
584 GDLCI fgi = glyph_dlists_.find(c);
585
586 if(fgi != glyph_dlists_.end())
587 {
588 glCallList(fgi->second);
589 return;
590 }
591
592 unsigned int f;
593 FT_UInt glyph_index = 0;
594
595 for(f=0; f<faces_.size(); f++)
596 {
597 glyph_index = FT_Get_Char_Index(faces_[f].face_, c);
598 if(glyph_index != 0) break;
599 }
600
601 if(glyph_index == 0) return;
602
603 if(compile_mode_ == COMPILE)
604 {
605 GLuint dlist = compile(c);
606 glCallList(dlist);
607 }
608 else renderGlyph(faces_[f].face_, glyph_index);
609 }
610
611 // Assume the MODELVIEW matrix is already setup and draw the
612 // (UNICODE) character.
613
614 void Face::draw (const wchar_t c)
615 {
616 // See if we've done it already
617 GDLCI fgi = glyph_dlists_.find(c);
618
619 if(fgi != glyph_dlists_.end())
620 {
621 glCallList(fgi->second);
622 return;
623 }
624
625 unsigned int f;
626 FT_UInt glyph_index = 0;
627
628 for(f=0; f<faces_.size(); f++)
629 {
630 glyph_index = FT_Get_Char_Index(faces_[f].face_, c);
631 if(glyph_index != 0) break;
632 }
633
634 if(glyph_index == 0) return;
635
636 if(compile_mode_ == COMPILE)
637 {
638 GLuint dlist = compile(c);
639 glCallList(dlist);
640 }
641 else renderGlyph(faces_[f].face_, glyph_index);
642 }
643
644 // Draw the (latin1) character at the given position. The MODELVIEW
645 // matrix is modified by the glyph advance.
646 void Face::draw (GLfloat x, GLfloat y, unsigned char c)
647 {
648 glTranslatef(x, y, 0.);
649
650 glColor4f(foreground_color_[R], foreground_color_[G], foreground_color_[B], foreground_color_[A]);
651
652 glRasterPos3i(0, 0, 0);
653
654 draw(c);
655 }
656
657 // Draw the (latin1) character at the given position. The MODELVIEW
658 // matrix is modified by the glyph advance.
659 void Face::draw (GLfloat x, GLfloat y, GLfloat z, unsigned char c)
660 {
661 glTranslatef(x, y, z);
662
663 glColor4f(foreground_color_[R], foreground_color_[G], foreground_color_[B], foreground_color_[A]);
664
665 glRasterPos3i(0, 0, 0);
666
667 draw(c);
668 }
669
670 // Draw the (UNICODE) character at the given position. The MODELVIEW
671 // matrix is modified by the glyph advance.
672 void Face::draw (GLfloat x, GLfloat y, wchar_t c)
673 {
674 glTranslatef(x, y, 0.);
675
676 glColor4f(foreground_color_[R], foreground_color_[G], foreground_color_[B],
677 foreground_color_[A]);
678
679 glRasterPos3i(0, 0, 0);
680
681 draw(c);
682 }
683
684 // Draw the (UNICODE) character at the given position. The MODELVIEW
685 // matrix is modified by the glyph advance.
686 void Face::draw (GLfloat x, GLfloat y, GLfloat z, wchar_t c)
687 {
688 glTranslatef(x, y, z);
689
690 glColor4f(foreground_color_[R], foreground_color_[G], foreground_color_[B], foreground_color_[A]);
691
692 glRasterPos3i(0, 0, 0);
693
694 draw(c);
695 }
696
697
698 // Draw the (latin1) string at the given position.
699 void Face::draw (GLfloat x, GLfloat y, const char* s, float *sizebox)
700 {
701 // sizebox is xmin,ymin, xmax,ymax
702 if(!advance_) glPushMatrix();
703
704 if(horizontal_justification_ != ORIGIN || vertical_justification_ != BASELINE)
705 {
706 glPushMatrix();
707
708 GLfloat dx = 0, dy = 0;
709
710 switch (horizontal_justification_)
711 {
712 case LEFT: dx = -sizebox[0] + 1; break;
713 case CENTER: dx = -(sizebox[0] + sizebox[2])/ 2.0f; break;
714 case RIGHT: dx = -sizebox[2] - 1; break;
715 default: break;
716 }
717 switch (vertical_justification_)
718 {
719 case BOTTOM: dy = -sizebox[1] + 1; break;
720 case MIDDLE: dy = -(sizebox[1] + sizebox[3])/ 2.0f; break;
721 case TOP: dy = -sizebox[3] - 1; break;
722 default: break;
723 }
724
725 // There is probably a less expensive way to compute this
726 glRotatef(string_rotation_, 0., 0., 1.);
727 glTranslatef(dx, dy, 0);
728 glRotatef(-string_rotation_, 0., 0., 1.);
729 }
730
731 glTranslatef(x, y, 0.);
732
733 glColor4f(foreground_color_[R], foreground_color_[G], foreground_color_[B], foreground_color_[A]);
734
735 glRasterPos3i(0, 0, 0);
736
737 draw(s);
738
739 if(horizontal_justification_ != ORIGIN || vertical_justification_ != BASELINE) glPopMatrix();
740
741 if(!advance_) glPopMatrix();
742 }
743
744 // Draw the (latin1) string at the given position.
745 void Face::draw (GLfloat x, GLfloat y, GLfloat z, const char* s)
746 {
747 if(!advance_) glPushMatrix();
748
749 if(horizontal_justification_ != ORIGIN || vertical_justification_ != BASELINE)
750 {
751 glPushMatrix();
752
753 BBox bbox = measure_nominal(s);
754
755 GLfloat dx = 0, dy = 0;
756
757 switch (horizontal_justification_)
758 {
759 case LEFT: dx = -bbox.x_min_; break;
760 case CENTER: dx = -(bbox.x_min_ + bbox.x_max_)/ 2.0f; break;
761 case RIGHT: dx = -bbox.x_max_; break;
762 default: break;
763 }
764 switch (vertical_justification_)
765 {
766 case BOTTOM: dy = -bbox.y_min_; break;
767 case MIDDLE: dy = -(bbox.y_min_ + bbox.y_max_)/ 2.0f; break;
768 case TOP: dy = -bbox.y_max_; break;
769 default: break;
770 }
771
772 // There is probably a less expensive way to compute this
773 glRotatef(string_rotation_, 0., 0., 1.);
774 glTranslatef(dx, dy, 0);
775 glRotatef(-string_rotation_, 0., 0., 1.);
776 }
777
778 glTranslatef(x, y, z);
779
780 glColor4f(foreground_color_[R], foreground_color_[G], foreground_color_[B], foreground_color_[A]);
781
782 glRasterPos3i(0, 0, 0);
783
784 draw(s);
785
786 if(horizontal_justification_ != ORIGIN || vertical_justification_ != BASELINE) glPopMatrix();
787
788 if(!advance_) glPopMatrix();
789 }
790
791 // Draw the (UNICODE) string at the given position.
792 void Face::draw (GLfloat x, GLfloat y, const wchar_t* s)
793 {
794 if(!advance_)
795 glPushMatrix();
796
797 if(horizontal_justification_!=ORIGIN||vertical_justification_!=BASELINE)
798 {
799 glPushMatrix();
800
801 BBox bbox = measure_nominal(s);
802
803 GLfloat dx = 0, dy = 0;
804
805 switch (horizontal_justification_)
806 {
807 case LEFT:
808 dx = -bbox.x_min_; break;
809 case CENTER:
810 dx = -(bbox.x_min_ + bbox.x_max_)/ 2.0f; break;
811 case RIGHT:
812 dx = -bbox.x_max_; break;
813 default:
814 break;
815 }
816 switch (vertical_justification_)
817 {
818 case BOTTOM:
819 dy = -bbox.y_min_; break;
820 case MIDDLE:
821 dy = -(bbox.y_min_ + bbox.y_max_)/ 2.0f; break;
822 case TOP:
823 dy = -bbox.y_max_; break;
824 default:
825 break;
826 }
827
828 // There is probably a less expensive way to compute this
829 glRotatef(string_rotation_, 0., 0., 1.);
830 glTranslatef(dx, dy, 0);
831 glRotatef(-string_rotation_, 0., 0., 1.);
832 }
833
834 glTranslatef(x, y, 0.);
835
836 glColor4f(foreground_color_[R], foreground_color_[G], foreground_color_[B],
837 foreground_color_[A]);
838
839 glRasterPos3i(0, 0, 0);
840
841 draw(s);
842
843 if(horizontal_justification_ != ORIGIN ||
844 vertical_justification_ != BASELINE)
845 glPopMatrix();
846
847 if(!advance_)
848 glPopMatrix();
849 }
850
851 // Draw the (UNICODE) string at the given position.
852 void Face::draw (GLfloat x, GLfloat y, GLfloat z, const wchar_t* s)
853 {
854 if(!advance_) glPushMatrix();
855
856 if(horizontal_justification_!= ORIGIN||vertical_justification_!= BASELINE)
857 {
858 glPushMatrix();
859
860 // In 3D, we need to exert more care in the computation of the
861 // bounding box of the text. NOTE: Needs to be fixed up for
862 // polygonal faces, too...
863
864 BBox bbox;
865 // Code from measure_nominal, but changed to use measureRaw instead
866 if(string_rotation_ == 0.) bbox = measureRaw(s);
867 else
868 {
869 for(unsigned int f=0; f<faces_.size(); f++)
870 FT_Set_Transform(faces_[f].face_, 0, 0);
871
872 bbox = measureRaw(s);
873
874 float angle;
875 if(string_rotation_<0.0)
876 angle = 360.0f - fmod(fabs(string_rotation_), 360.f);
877 else
878 angle = fmod(string_rotation_, 360.f);
879
880 FT_Matrix rotation_matrix;
881 FT_Vector sinus;
882
883 FT_Vector_Unit(&sinus, (FT_Angle)(angle * 0x10000L));
884
885 rotation_matrix.xx = sinus.x;
886 rotation_matrix.xy = -sinus.y;
887 rotation_matrix.yx = sinus.y;
888 rotation_matrix.yy = sinus.x;
889
890 for(unsigned int f=0; f<faces_.size(); f++)
891 FT_Set_Transform(faces_[f].face_, &rotation_matrix, 0);
892 }
893
894 GLfloat dx = 0, dy = 0;
895
896 switch (horizontal_justification_)
897 {
898 case LEFT:
899 dx = bbox.x_min_; break;
900 case CENTER:
901 dx = (bbox.x_min_ + bbox.x_max_)/ 2; break;
902 case RIGHT:
903 dx = bbox.x_max_; break;
904 default:
905 break;
906 }
907 switch (vertical_justification_)
908 {
909 case BOTTOM:
910 dy = bbox.y_min_; break;
911 case MIDDLE:
912 dy = (bbox.y_min_ + bbox.y_max_)/2; break;
913 case TOP:
914 dy = bbox.y_max_; break;
915 default:
916 break;
917 }
918
919 GLint viewport[4];
920 GLdouble modelview[16], projection[16];
921
922 glGetIntegerv(GL_VIEWPORT, viewport);
923 glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
924 glGetDoublev(GL_PROJECTION_MATRIX, projection);
925
926 GLdouble x0, y0, z0;
927 gluUnProject(0, 0, 0, modelview, projection, viewport, &x0, &y0, &z0);
928
929 GLdouble dx_m, dy_m, dz_m;
930 gluUnProject(dx, dy, 0., modelview, projection, viewport,&dx_m,&dy_m,&dz_m);
931
932 glTranslated(x0-dx_m, y0-dy_m, z0-dz_m);
933 }
934
935 glTranslatef(x, y, z);
936 glColor4f(foreground_color_[R], foreground_color_[G], foreground_color_[B], foreground_color_[A]);
937 glRasterPos3i(0, 0, 0);
938 draw(s);
939
940 if(horizontal_justification_!=ORIGIN||vertical_justification_!= BASELINE)
941 glPopMatrix();
942
943 if(!advance_)
944 glPopMatrix();
945 }
946
947 Raster::Raster (const char* filename, float point_size, FT_UInt resolution)
948 : Face(filename, point_size, resolution)
949 {
950 if(!isValid()) return;
951
952 init();
953 }
954
955 Raster::Raster (FT_Face face, float point_size, FT_UInt resolution)
956 : Face(face, point_size, resolution)
957 {
958 init();
959 }
960
961 void Raster::init (void)
962 {
963 character_rotation_z_ = 0;
964 setCharSize();
965 setCharacterRotationReference('o');
966 }
967
968 Raster::~Raster (void)
969 {
970 clearCaches();
971 }
972
973 void Raster::setCharacterRotationZ (GLfloat character_rotation_z)
974 {
975 if(character_rotation_z != character_rotation_z_)
976 {
977 character_rotation_z_ = character_rotation_z;
978 clearCaches();
979 }
980 }
981
982 double Raster::height (void)const
983 {
984 if(faces_[0].face_->height > 0) return faces_[0].face_->height / 64.;
985 else return faces_[0].face_->size->metrics.y_ppem;
986 }
987
988 BBox Raster::measure (unsigned char c)
989 {
990 BBox bbox;
991
992 // For starters, just get the unscaled glyph bounding box
993 unsigned int f;
994 FT_UInt glyph_index = 0;
995
996 for(f=0; f<faces_.size(); f++)
997 {
998 glyph_index = FT_Get_Char_Index(faces_[f].face_, c);
999 if(glyph_index != 0) break;
1000 }
1001
1002 if(glyph_index == 0) return bbox;
1003
1004 FT_Error error = FT_Load_Glyph(faces_[f].face_, glyph_index, FT_LOAD_DEFAULT);
1005 if(error != 0) return bbox;
1006
1007 FT_Glyph glyph;
1008 error = FT_Get_Glyph(faces_[f].face_->glyph, &glyph);
1009 if(error != 0) return bbox;
1010
1011 FT_BBox ft_bbox;
1012 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &ft_bbox);
1013
1014 FT_Done_Glyph(glyph);
1015
1016 bbox = ft_bbox;
1017 bbox.advance_ = faces_[f].face_->glyph->advance;
1018
1019 // In order to be accurate regarding the placement of text not
1020 // aligned at the glyph's origin (CENTER/MIDDLE), the bounding box
1021 // of the raster format has to be projected back into the
1022 // view's coordinates
1023 GLint viewport[4];
1024 GLdouble modelview[16], projection[16];
1025
1026 glGetIntegerv(GL_VIEWPORT, viewport);
1027 glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
1028 glGetDoublev(GL_PROJECTION_MATRIX, projection);
1029
1030 // Well, first we have to get the Origin, since that is the basis
1031 // of the bounding box
1032 GLdouble x0, y0, z0;
1033 gluUnProject(0., 0., 0., modelview, projection, viewport, &x0, &y0, &z0);
1034
1035 GLdouble x, y, z;
1036 gluUnProject(bbox.x_min_, bbox.y_min_, 0., modelview, projection, viewport, &x, &y, &z);
1037 bbox.x_min_ = (float) (x - x0);
1038 bbox.y_min_ = (float) (y - y0);
1039
1040 gluUnProject(bbox.x_max_, bbox.y_max_, 0., modelview, projection, viewport, &x, &y, &z);
1041 bbox.x_max_ = (float) (x - x0);
1042 bbox.y_max_ = (float) (y - y0);
1043
1044 gluUnProject(bbox.advance_.dx_, bbox.advance_.dy_, 0., modelview, projection, viewport, &x, &y, &z);
1045 bbox.advance_.dx_ = (float) (x - x0);
1046 bbox.advance_.dy_ = (float) (y - y0);
1047
1048 return bbox;
1049 }
1050
1051 BBox Raster::measure (wchar_t c)
1052 {
1053 BBox bbox;
1054
1055 // For starters, just get the unscaled glyph bounding box
1056 unsigned int f;
1057 FT_UInt glyph_index = 0;
1058
1059 for(f=0; f<faces_.size(); f++)
1060 {
1061 glyph_index = FT_Get_Char_Index(faces_[f].face_, c);
1062 if(glyph_index != 0) break;
1063 }
1064
1065 if(glyph_index == 0) return bbox;
1066
1067 FT_Error error = FT_Load_Glyph(faces_[f].face_, glyph_index,
1068 FT_LOAD_DEFAULT);
1069 if(error != 0) return bbox;
1070
1071 FT_Glyph glyph;
1072 error = FT_Get_Glyph(faces_[f].face_->glyph, &glyph);
1073 if(error != 0) return bbox;
1074
1075 FT_BBox ft_bbox;
1076 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &ft_bbox);
1077
1078 FT_Done_Glyph(glyph);
1079
1080 bbox = ft_bbox;
1081 bbox.advance_ = faces_[f].face_->glyph->advance;
1082
1083 // In order to be accurate regarding the placement of text not
1084 // aligned at the glyph's origin (CENTER/MIDDLE), the bounding box
1085 // of the raster format has to be projected back into the
1086 // view's coordinates
1087 GLint viewport[4];
1088 GLdouble modelview[16], projection[16];
1089
1090 glGetIntegerv(GL_VIEWPORT, viewport);
1091 glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
1092 glGetDoublev(GL_PROJECTION_MATRIX, projection);
1093
1094 // Well, first we have to get the Origin, since that is the basis
1095 // of the bounding box
1096 GLdouble x0, y0, z0;
1097 gluUnProject(0., 0., 0., modelview, projection, viewport, &x0, &y0, &z0);
1098
1099 GLdouble x, y, z;
1100 gluUnProject(bbox.x_min_, bbox.y_min_, 0., modelview, projection, viewport, &x, &y, &z);
1101 bbox.x_min_ = (float) (x - x0);
1102 bbox.y_min_ = (float) (y - y0);
1103
1104 gluUnProject(bbox.x_max_, bbox.y_max_, 0., modelview, projection, viewport, &x, &y, &z);
1105 bbox.x_max_ = (float) (x - x0);
1106 bbox.y_max_ = (float) (y - y0);
1107
1108 gluUnProject(bbox.advance_.dx_, bbox.advance_.dy_, 0., modelview, projection, viewport, &x, &y, &z);
1109 bbox.advance_.dx_ = (float) (x - x0);
1110 bbox.advance_.dy_ = (float) (y - y0);
1111
1112 return bbox;
1113 }
1114
1115 GLuint Raster::compileGlyph (FT_Face face, FT_UInt glyph_index)
1116 {
1117 GLuint dlist = glGenLists(1);
1118 glNewList(dlist, GL_COMPILE);
1119
1120 renderGlyph(face, glyph_index);
1121
1122 glEndList();
1123
1124 return dlist;
1125 }
1126
1127 void Raster::setCharSize (void)
1128 {
1129 FT_Error error;
1130 for(unsigned int i=0; i<faces_.size(); i++)
1131 {
1132 error = FT_Set_Char_Size(faces_[i].face_,(FT_F26Dot6)(point_size_ * 64),(FT_F26Dot6)(point_size_ * 64),resolution_,resolution_);
1133 if(error != 0) return;
1134 }
1135
1136 if(rotation_reference_glyph_ != 0) setRotationOffset();
1137 }
1138
1139 void Raster::setRotationOffset (void)
1140 {
1141 FT_Error error = FT_Load_Glyph(rotation_reference_face_, rotation_reference_glyph_, FT_LOAD_RENDER);
1142
1143 if(error != 0) return;
1144
1145 rotation_offset_y_ = rotation_reference_face_->glyph->bitmap.rows / 2.0f;
1146 }
1147
1148 void Raster::clearCaches (void)
1149 {
1150 GDLI fgi = glyph_dlists_.begin();
1151
1152 for(; fgi != glyph_dlists_.end(); ++fgi)
1153 {
1154 glDeleteLists(fgi->second, 1);
1155 }
1156
1157 glyph_dlists_.clear();
1158 }
1159
1160 Monochrome::Monochrome (const char* filename, float point_size, FT_UInt resolution)
1161 : Raster(filename, point_size, resolution)
1162 {
1163 return;
1164 }
1165
1166 Monochrome::Monochrome (FT_Face face, float point_size, FT_UInt resolution)
1167 : Raster(face, point_size, resolution)
1168 {
1169 return;
1170 }
1171
1172 Monochrome::~Monochrome (void)
1173 {
1174 return;
1175 }
1176
1177 GLubyte* Monochrome::invertBitmap (const FT_Bitmap& bitmap)
1178 {
1179 // In FreeType 2.0.9, the pitch of bitmaps was rounded up to an
1180 // even number. In general, this disagrees with what we had been
1181 // using for OpenGL.
1182 int width = bitmap.width / 8 + ((bitmap.width & 7)> 0 ? 1 : 0);
1183
1184 GLubyte* inverse = new GLubyte[ bitmap.rows * width ];
1185 GLubyte* inverse_ptr = inverse;
1186
1187 for(int r=0; r<bitmap.rows; r++)
1188 {
1189 GLubyte* bitmap_ptr = &bitmap.buffer[bitmap.pitch * (bitmap.rows - r - 1)];
1190
1191 memmove(inverse_ptr, bitmap_ptr, width);
1192 inverse_ptr += width;
1193 bitmap_ptr += width;
1194 }
1195
1196 return inverse;
1197 }
1198
1199 void Monochrome::renderGlyph (FT_Face face, FT_UInt glyph_index)
1200 {
1201 // Start by retrieving the glyph's data.
1202 FT_Error error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1203
1204 if(error != 0) return;
1205
1206 FT_Glyph original_glyph;
1207 FT_Glyph glyph;
1208
1209 error = FT_Get_Glyph(face->glyph, &original_glyph);
1210
1211 if(error != 0) return;
1212
1213 error = FT_Glyph_Copy(original_glyph, &glyph);
1214
1215 FT_Done_Glyph(original_glyph);
1216
1217 if(error != 0) return;
1218
1219 // If the individual characters are rotated (as distinct from string
1220 // rotation), then apply that extra rotation here. This is equivalent
1221 // to the sequence
1222 // glTranslate(x_center,y_center);
1223 // glRotate(angle);
1224 // glTranslate(-x_center,-y_center);
1225 // which is used for the polygonal styles. The deal with the raster
1226 // styles is that you must retain the advance from the string rotation
1227 // so that the glyphs are laid out properly. So, we make a copy of
1228 // the string rotated glyph, and then rotate that and add back an
1229 // additional offset to (in effect) restore the proper origin and
1230 // advance of the glyph.
1231
1232 if(character_rotation_z_ != 0.)
1233 {
1234 FT_Matrix rotation_matrix;
1235 FT_Vector sinus;
1236
1237 FT_Vector_Unit(&sinus, (FT_Angle)(character_rotation_z_ * 0x10000L));
1238
1239 rotation_matrix.xx = sinus.x;
1240 rotation_matrix.xy = -sinus.y;
1241 rotation_matrix.yx = sinus.y;
1242 rotation_matrix.yy = sinus.x;
1243
1244 FT_Vector original_offset, rotation_offset;
1245
1246 original_offset.x = (face->glyph->metrics.width / 2 + face->glyph->metrics.horiBearingX)/ 64 * 0x10000L;
1247 original_offset.y = (FT_Pos)(rotation_offset_y_ * 0x10000L);
1248
1249 rotation_offset = original_offset;
1250
1251 FT_Vector_Rotate(&rotation_offset, (FT_Angle)(character_rotation_z_ * 0x10000L));
1252
1253 rotation_offset.x = original_offset.x - rotation_offset.x;
1254 rotation_offset.y = original_offset.y - rotation_offset.y;
1255
1256 rotation_offset.x /= 1024;
1257 rotation_offset.y /= 1024;
1258
1259 error = FT_Glyph_Transform(glyph, &rotation_matrix, &rotation_offset);
1260 }
1261
1262 error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_MONO, 0, 1);
1263
1264 if(error != 0)
1265 {
1266 FT_Done_Glyph(glyph);
1267 return;
1268 }
1269
1270 FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph) glyph;
1271
1272 // Evidently, in FreeType2, you can only get "upside-down" bitmaps and
1273 // OpenGL won't invert a bitmap with PixelZoom, so we have to invert the
1274 // glyph's bitmap ourselves.
1275
1276 GLubyte* inverted_bitmap = invertBitmap(bitmap_glyph->bitmap);
1277
1278 glBitmap(bitmap_glyph->bitmap.width, bitmap_glyph->bitmap.rows,
1279 (GLfloat) -bitmap_glyph->left,
1280 (GLfloat) (bitmap_glyph->bitmap.rows - bitmap_glyph->top),
1281 face->glyph->advance.x / 64.0f,
1282 face->glyph->advance.y / 64.0f,
1283 inverted_bitmap);
1284
1285 FT_Done_Glyph(glyph);
1286
1287 delete[] inverted_bitmap;
1288 }
1289
1290} // close OGLFT namespace
1291