1 // ==============================================================
2 // This file is part of the MegaGlest Shared Library (www.megaglest.org)
3 //
4 // Copyright (C) 2011 Mark Vejvoda and others
5 //
6 // You can redistribute this code and/or modify it under
7 // the terms of the GNU General Public License as published
8 // by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version
10 // ==============================================================
11
12 #ifdef USE_FTGL
13
14 //#include "gettext.h"
15
16 #include "font_textFTGL.h"
17
18 #include "opengl.h"
19 #include <stdexcept>
20 #include <sys/stat.h>
21 #include <FTGL/ftgl.h>
22
23 #include "platform_common.h"
24 #include "util.h"
25
26 using namespace std;
27 using namespace Shared::Util;
28 using namespace Shared::PlatformCommon;
29
30 namespace Shared { namespace Graphics { namespace Gl {
31
32
33 string TextFTGL::langHeightText = "yW";
34 int TextFTGL::faceResolution = 72;
35
36 //====================================================================
TextFTGL(FontTextHandlerType type)37 TextFTGL::TextFTGL(FontTextHandlerType type) : Text(type) {
38
39 //throw megaglest_runtime_error("FTGL!");
40 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",0);
41 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/arphic/uming.ttc",0); // Chinese
42 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/arphic/ukai.ttc",0); // Chinese
43 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/ttf-sil-doulos/DoulosSILR.ttf",0); // Russian / Cyrillic
44 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/ttf-sil-charis/CharisSILR.ttf",0); // Russian / Cyrillic
45 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-R.ttf",0); // Russian / Cyrillic
46 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/takao/TakaoPGothic.ttf",0); // Japanese
47 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/ttf-sil-scheherazade/ScheherazadeRegOT.ttf",0); // Arabic
48 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/linux-libertine/LinLibertine_Re.ttf",0); // Hebrew
49 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/unifont/unifont.ttf",0); // Czech?
50 //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Regular.ttf",0); // Czech?
51
52
53 fontFile = findFont();
54 //ftFont = new FTBufferFont(fontFile);
55 //ftFont = new FTGLPixmapFont(fontFile);
56 //ftFont = new FTGLExtrdFont(fontFile);
57 //ftFont = new FTGLPolygonFont("/usr/share/fonts/truetype/arphic/uming.ttc");
58
59 //ftFont = new FTGLPixmapFont("/usr/share/fonts/truetype/arphic/uming.ttc");
60 if(type == ftht_2D) {
61 ftFont = new FTGLPixmapFont(fontFile);
62 if(SystemFlags::VERBOSE_MODE_ENABLED) printf("2D font [%s]\n",fontFile);
63 }
64 else if(type == ftht_3D) {
65 ftFont = new FTGLTextureFont(fontFile);
66 if(SystemFlags::VERBOSE_MODE_ENABLED) printf("3D font [%s]\n",fontFile);
67 }
68 else {
69 throw megaglest_runtime_error("font render type not set to a known value!");
70 }
71
72 if(ftFont->Error()) {
73 string fontFileName = (fontFile != NULL ? fontFile : "n/a");
74 printf("FTGL: error loading font: %s\n", fontFileName.c_str());
75 delete ftFont; ftFont = NULL;
76 if(fontFile != NULL) free((void*)fontFile);
77 fontFile = NULL;
78 throw megaglest_runtime_error(string("FTGL: error loading font: ") + fontFileName);
79 }
80 free((void*)fontFile);
81 fontFile = NULL;
82
83 const unsigned int defSize = 24;
84 ftFont->FaceSize(defSize,TextFTGL::faceResolution);
85
86 GLenum error = glGetError();
87 if(error != GL_NO_ERROR) {
88 printf("\n[%s::%s] Line %d Error = %d [%s] for size = %u res = %d\n",__FILE__,__FUNCTION__,__LINE__,error,gluErrorString(error),defSize,TextFTGL::faceResolution);
89 fflush(stdout);
90 }
91
92 if(ftFont->Error()) {
93 char szBuf[8096]="";
94 snprintf(szBuf,8096,"FTGL: error setting face size, #%d",ftFont->Error());
95 throw megaglest_runtime_error(szBuf);
96 }
97 //ftFont->UseDisplayList(false);
98 //ftFont->CharMap(ft_encoding_gb2312);
99 //ftFont->CharMap(ft_encoding_big5);
100 if(ftFont->CharMap(ft_encoding_unicode) == false) {
101 throw megaglest_runtime_error("FTGL: error setting encoding");
102 }
103
104 if(ftFont->Error()) {
105 char szBuf[8096]="";
106 snprintf(szBuf,8096,"FTGL: error setting encoding, #%d",ftFont->Error());
107 throw megaglest_runtime_error(szBuf);
108 }
109 }
110
~TextFTGL()111 TextFTGL::~TextFTGL() {
112 cleanupFont();
113 }
114
cleanupFont()115 void TextFTGL::cleanupFont() {
116 delete ftFont;
117 ftFont = NULL;
118
119 if(fontFile) {
120 free((void*)fontFile);
121 }
122 fontFile = NULL;
123 }
124
init(string fontName,string fontFamilyName,int fontSize)125 void TextFTGL::init(string fontName, string fontFamilyName, int fontSize) {
126 cleanupFont();
127 fontFile = findFont(fontName.c_str(),fontFamilyName.c_str());
128
129 //ftFont = new FTBufferFont(fontFile);
130 //ftFont = new FTGLPixmapFont(fontFile);
131 //ftFont = new FTGLExtrdFont(fontFile);
132 //ftFont = new FTGLPolygonFont("/usr/share/fonts/truetype/arphic/uming.ttc");
133 //ftFont = new FTGLPixmapFont("/usr/share/fonts/truetype/arphic/uming.ttc");
134
135 if(type == ftht_2D) {
136 ftFont = new FTGLPixmapFont(fontFile);
137 //printf("2D font [%s]\n",fontFile);
138 }
139 else if(type == ftht_3D) {
140 ftFont = new FTGLTextureFont(fontFile);
141
142 //ftFont = new FTBufferFont(fontFile);
143 //ftFont = new FTGLExtrdFont(fontFile);
144 //ftFont = new FTGLPolygonFont("/usr/share/fonts/truetype/arphic/uming.ttc");
145
146 //printf("3D font [%s]\n",fontFile);
147 }
148 else {
149 throw megaglest_runtime_error("font render type not set to a known value!");
150 }
151
152 if(ftFont->Error()) {
153 printf("FTGL: error loading font: %s\n", fontFile);
154 delete ftFont; ftFont = NULL;
155 if(fontFile) {
156 free((void*)fontFile);
157 }
158 fontFile = NULL;
159 throw megaglest_runtime_error("FTGL: error loading font");
160 }
161 free((void*)fontFile);
162 fontFile = NULL;
163
164 if(fontSize <= 0) {
165 fontSize = 24;
166 }
167 ftFont->FaceSize(fontSize,TextFTGL::faceResolution);
168
169 GLenum error = glGetError();
170 if(error != GL_NO_ERROR) {
171 printf("\n[%s::%s] Line %d Error = %d [%s] for size = %d res = %d\n",__FILE__,__FUNCTION__,__LINE__,error,gluErrorString(error),fontSize,TextFTGL::faceResolution);
172 fflush(stdout);
173 }
174
175 if(ftFont->Error()) {
176 char szBuf[8096]="";
177 snprintf(szBuf,8096,"FTGL: error setting face size, #%d",ftFont->Error());
178 throw megaglest_runtime_error(szBuf);
179 }
180
181 //ftFont->UseDisplayList(false);
182 //ftFont->CharMap(ft_encoding_gb2312);
183 //ftFont->CharMap(ft_encoding_big5);
184 if(ftFont->CharMap(ft_encoding_unicode) == false) {
185 throw megaglest_runtime_error("FTGL: error setting encoding");
186 }
187 if(ftFont->Error()) {
188 char szBuf[8096]="";
189 snprintf(szBuf,8096,"FTGL: error setting encoding, #%d",ftFont->Error());
190 throw megaglest_runtime_error(szBuf);
191 }
192
193 // Create a string containing common characters
194 // and preload the chars without rendering them.
195 string preloadText = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-=!@#$%^&*()_+:\"{}[]/?.,<>\\';";
196 ftFont->Advance(preloadText.c_str());
197
198 error = glGetError();
199 if(error != GL_NO_ERROR) {
200 printf("\n[%s::%s] Line %d Error = %d [%s] for text [%s]\n",__FILE__,__FUNCTION__,__LINE__,error,gluErrorString(error),preloadText.c_str());
201 fflush(stdout);
202 }
203
204 if(ftFont->Error()) {
205 char szBuf[8096]="";
206 snprintf(szBuf,8096,"FTGL: error advancing(a), #%d",ftFont->Error());
207 throw megaglest_runtime_error(szBuf);
208 }
209 }
210
SetFaceSize(int value)211 void TextFTGL::SetFaceSize(int value) {
212 ftFont->FaceSize(value,TextFTGL::faceResolution);
213
214 GLenum error = glGetError();
215 if(error != GL_NO_ERROR) {
216 printf("\n[%s::%s] Line %d Error = %d [%s] for facesize = %d\n",__FILE__,__FUNCTION__,__LINE__,error,gluErrorString(error),value);
217 fflush(stdout);
218 }
219
220 if(ftFont->Error()) {
221 char szBuf[8096]="";
222 snprintf(szBuf,8096,"FTGL: error setting face size, #%d",ftFont->Error());
223 throw megaglest_runtime_error(szBuf);
224 }
225 }
226
GetFaceSize()227 int TextFTGL::GetFaceSize() {
228 return ftFont->FaceSize();
229 }
230
Render(const char * str,const int len)231 void TextFTGL::Render(const char* str, const int len) {
232 //printf("Render TextFTGL\n");
233
234 /*
235 FTGL renders the whole string when len == 0
236 but we don't want any text rendered then.
237 */
238 if(len != 0) {
239 //printf("FTGL Render [%s] facesize = %d\n",str,ftFont->FaceSize());
240 assertGl();
241
242 ftFont->Render(str, len);
243 //assertGl();
244 GLenum error = glGetError();
245 if(error != GL_NO_ERROR) {
246 printf("\n[%s::%s] Line %d Error = %d [%s] for text [%s]\n",__FILE__,__FUNCTION__,__LINE__,error,gluErrorString(error),str);
247 fflush(stdout);
248 }
249
250 if(ftFont->Error()) {
251 char szBuf[8096]="";
252 snprintf(szBuf,8096,"FTGL: error trying to render, #%d",ftFont->Error());
253 throw megaglest_runtime_error(szBuf);
254 }
255 }
256 }
257
Advance(const char * str,const int len)258 float TextFTGL::Advance(const char* str, const int len) {
259 float result = ftFont->Advance(str, len);
260
261 GLenum error = glGetError();
262 if(error != GL_NO_ERROR) {
263 printf("\n[%s::%s] Line %d Error = %d [%s] for text [%s]\n",__FILE__,__FUNCTION__,__LINE__,error,gluErrorString(error),str);
264 fflush(stdout);
265 }
266
267 if(ftFont->Error()) {
268 char szBuf[8096]="";
269 snprintf(szBuf,8096,"FTGL: error trying to advance(b), #%d",ftFont->Error());
270 throw megaglest_runtime_error(szBuf);
271 }
272 return result;
273
274 //FTBBox box = ftFont->BBox(str);
275 //float urx = box.Upper().X();
276 //float llx = box.Lower().X();
277 //float llx, lly, llz, urx, ury, urz;
278 //ftFont->BBox(str, llx, lly, llz, urx, ury, urz);
279
280 //Short_t halign = fTextAlign/10;
281 //Short_t valign = fTextAlign - 10*halign;
282 //Float_t dx = 0, dy = 0;
283 // switch (halign) {
284 // case 1 : dx = 0 ; break;
285 // case 2 : dx = -urx/2; break;
286 // case 3 : dx = -urx ; break;
287 // }
288 // switch (valign) {
289 // case 1 : dy = 0 ; break;
290 // case 2 : dy = -ury/2; break;
291 // case 3 : dy = -ury ; break;
292 // }
293
294 //printf("For str [%s] advance = %f, urx = %f, llx = %f\n",str, ftFont->Advance(str, len),urx,llx);
295 //return urx;
296 }
297
LineHeight(const char * str,const int len)298 float TextFTGL::LineHeight(const char* str, const int len) {
299 //FTBBox box = ftFont->BBox(str);
300 //printf("String [%s] lineheight = %f upper_y = %f lower_y = %f\n",str,ftFont->LineHeight(),box.Upper().Y(),box.Lower().Y());
301
302
303 //printf("ftFont->Ascender():%f ftFont->Descender()*-1 = %f ftFont->LineHeight() = %f\n",ftFont->Ascender(),ftFont->Descender()*-1 , ftFont->LineHeight());
304 //return ftFont->Ascender() + ftFont->Descender()*-1 - ftFont->LineHeight();
305 //return ftFont->LineHeight();
306
307 //static float result = -1000;
308 float result = -1000;
309 if(result == -1000) {
310 FTBBox box = ftFont->BBox(TextFTGL::langHeightText.c_str());
311
312 GLenum error = glGetError();
313 if(error != GL_NO_ERROR) {
314 printf("\n[%s::%s] Line %d Error = %d [%s] for text [%s]\n",__FILE__,__FUNCTION__,__LINE__,error,gluErrorString(error),str);
315 fflush(stdout);
316 }
317
318 result = box.Upper().Yf()- box.Lower().Yf();
319 if(result == 0) {
320 result = ftFont->LineHeight();
321
322 GLenum error = glGetError();
323 if(error != GL_NO_ERROR) {
324 printf("\n[%s::%s] Line %d Error = %d [%s] for text [%s]\n",__FILE__,__FUNCTION__,__LINE__,error,gluErrorString(error),str);
325 fflush(stdout);
326 }
327 }
328 //printf("ftFont->BBox(''yW'')%f\n",result);
329 }
330 // else {
331 // FTBBox box = ftFont->BBox(TextFTGL::langHeightText.c_str());
332 //
333 // GLenum error = glGetError();
334 // if(error != GL_NO_ERROR) {
335 // printf("\n[%s::%s] Line %d Error = %d [%s] for text [%s]\n",__FILE__,__FUNCTION__,__LINE__,error,gluErrorString(error),str);
336 // fflush(stdout);
337 // }
338 //
339 // int newresult = box.Upper().Y()- box.Lower().Y();
340 // if(newresult == 0) {
341 // newresult = ftFont->LineHeight();
342 //
343 // GLenum error = glGetError();
344 // if(error != GL_NO_ERROR) {
345 // printf("\n[%s::%s] Line %d Error = %d [%s] for text [%s]\n",__FILE__,__FUNCTION__,__LINE__,error,gluErrorString(error),str);
346 // fflush(stdout);
347 // }
348 // }
349 //
350 // printf("Height for [%s] result [%d] [%d]\n",str,result,newresult);
351 // }
352 if(ftFont->Error()) {
353 char szBuf[8096]="";
354 snprintf(szBuf,8096,"FTGL: error trying to get lineheight, #%d",ftFont->Error());
355 throw megaglest_runtime_error(szBuf);
356 }
357
358 return result;
359 // printf("For str [%s] LineHeight = %f, result = %f\n",str, ftFont->LineHeight(),result);
360 // return result;
361
362 //float urx = box.Upper().X();
363 //float llx = box.Lower().X();
364 //float llx, lly, llz, urx, ury, urz;
365 //ftFont->BBox(str, llx, lly, llz, urx, ury, urz);
366 //return ury - lly;
367
368 //Short_t halign = fTextAlign/10;
369 //Short_t valign = fTextAlign - 10*halign;
370 //Float_t dx = 0, dy = 0;
371 // switch (halign) {
372 // case 1 : dx = 0 ; break;
373 // case 2 : dx = -urx/2; break;
374 // case 3 : dx = -urx ; break;
375 // }
376 // switch (valign) {
377 // case 1 : dy = 0 ; break;
378 // case 2 : dy = -ury/2; break;
379 // case 3 : dy = -ury ; break;
380 // }
381
382 //printf("For str [%s] advance = %f, urx = %f, llx = %f\n",str, ftFont->Advance(str, len),urx,llx);
383 //return urx;
384
385 }
386
LineHeight(const wchar_t * str,const int len)387 float TextFTGL::LineHeight(const wchar_t* str, const int len) {
388 static float result = -1000;
389 if(result == -1000) {
390 FTBBox box = ftFont->BBox(TextFTGL::langHeightText.c_str());
391 result = box.Upper().Yf()- box.Lower().Yf();
392 if(result == 0) {
393 result = ftFont->LineHeight();
394 }
395 //printf("ftFont->BBox(''yW'')%f\n",result);
396 }
397 if(ftFont->Error()) {
398 char szBuf[8096]="";
399 snprintf(szBuf,8096,"FTGL: error trying to get lineheight, #%d",ftFont->Error());
400 throw megaglest_runtime_error(szBuf);
401 }
402
403 return result;
404 }
405
Render(const wchar_t * str,const int len)406 void TextFTGL::Render(const wchar_t* str, const int len) {
407 /*
408 FTGL renders the whole string when len == 0
409 but we don't want any text rendered then.
410 */
411 if(len != 0) {
412 ftFont->Render(str, len);
413
414 if(ftFont->Error()) {
415 char szBuf[8096]="";
416 snprintf(szBuf,8096,"FTGL: error trying to render, #%d",ftFont->Error());
417 throw megaglest_runtime_error(szBuf);
418 }
419 }
420 }
421
Advance(const wchar_t * str,const int len)422 float TextFTGL::Advance(const wchar_t* str, const int len) {
423 float result = ftFont->Advance(str, len);
424 if(ftFont->Error()) {
425 char szBuf[8096]="";
426 snprintf(szBuf,8096,"FTGL: error trying to advance(c), #%d",ftFont->Error());
427 throw megaglest_runtime_error(szBuf);
428 }
429
430 return result;
431 }
432
433 }}}//end namespace
434
435 #endif // USE_FTGL
436