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