Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-core/src/osd/OGLFT.cpp
2 views
1
/*
2
* OGLFT: A library for drawing text with OpenGL using the FreeType library
3
* Copyright (C) 2002 lignum Computing, Inc. <[email protected]>
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
27
int wstrlen(const wchar_t * s)
28
{
29
int r = 0;
30
while (*s++) r++;
31
return r;
32
}
33
34
namespace 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
1292
1293