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 | |
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 | |