1 /*
2 	Tool for creating Irrlicht bitmap+vector fonts,
3 	started by Gaz Davidson in December 2006
4 
5 	Due to my laziness and Microsoft's unintuitive API, surrogate pairs and
6 	nonspacing diacritical marks are not supported!
7 
8 	Linux bitmap font support added by Neil Burlock Oct 2008
9 	Note: Xft/Freetype2 is used to render the fonts under X11.  Anti-aliasing
10 	is controlled by the system and cannot be overriden by an application,
11 	so fonts that are rendered will be aliased or anti-aliased depending
12 	on the system that they are created on.
13 
14 */
15 
16 
17 #include <irrlicht.h>
18 #include <iostream>
19 
20 #include "CFontTool.h"
21 #include "CVectorFontTool.h"
22 #include "ITexture.h"
23 
24 using namespace irr;
25 using namespace gui;
26 
27 #pragma comment(lib, "Irrlicht.lib")
28 
29 const s32 texturesizes[] = {128, 256, 512, 1024, 2048, 4096, 0};
30 
31 const wchar_t *fileformats[]		 =  { L"bmp", L"ppm", 0 };  // bitmap font formats
32 const wchar_t *alphafileformats[]  =  { L"png", L"tga", 0 };  // bitmap font formats which support alpha channels
33 const wchar_t *vectorfileformats[] =  { L"xml", L"bin", 0 };  // file formats for vector fonts
34 
35 const wchar_t *warntext = L"Legal Notice\n"
36 					L"------------\n\n"
37 					L"When making bitmap and vector fonts, you should consider the potential legal "
38 					L"issues with redistributing the fonts with your software; this tool basically "
39 					L"copies font data and some authors might not like this!\n"
40 					L"If you purchased fonts or they came with an application or your OS, you'll have"
41 					L"to check the license to see what restrictions are placed on making derivative works.\n\n"
42 					L"PD and the OFL\n"
43 					L"--------------\n\n"
44 					L"You'll find lots of fonts on the web listed as Public Domain, you can do what you like "
45 					L"with these.\n"
46 					L"Many fonts are released under the Open Font License, which is a 'viral' open source "
47 					L"license like the GPL. It's worth reading the license here: http://scripts.sil.org/OFL\n"
48 					L"The most important restrictions are- you must include the original font's license, you "
49 					L"can't stop your users from using or distributing the font, the font must have a "
50 					L"different name the original.\n\n"
51 					L"Some free fonts can be found here- www.openfontlibrary.org\n"
52 					L"http://savannah.nongnu.org/projects/freefont/";
53 
54 const wchar_t *helptext = L"This tool creates bitmap fonts for the Irrlicht Engine\n\n"
55 
56 					L"First select a character encoding from the list, then choose the font, "
57 					L"size, and whether you'd like bold, italic, antialiasing and an alpha channel. "
58 					L"In Windows, antialiasing will be ignored for small fonts\n\n"
59 
60 					L"Then select a texture width and height. If the output exceeds this then more than "
61 					L"one image will be created. You can use the scrollbar at the top of the screen to "
62 					L"preview them. Most modern graphics cards will support up to 2048x2048, "
63 					L"keep in mind that more images means worse performance when drawing text!\n\n"
64 
65 					L"If you want a vector font rather than a bitmap font, check the vector box. "
66 					L"Vector fonts are stored in system memory while bitmap fonts are in video ram\n\n"
67 
68 					L"Click create to preview your font, this may take lots of time and memory "
69 					L"when making a font with a lot of characters, please be patient!\n\n"
70 
71 					L"Now you're ready to give your font a name, select a format and click save.\n\n"
72 					L"To load your font in Irrlicht, simply use env->getFont(\"Myfont.xml\");\n\n"
73 
74 					L"That's all, have fun :-)";
75 
76 #ifdef _IRR_WINDOWS_
77 					const wchar_t *completeText = L"Font created";
78 #else
79 					const wchar_t *completeText = L"Font created\n\n"
80 							L"Please note that anti-aliasing under X11 is controlled by the system "
81 							L"configuration, so if your system is set to use anti-aliasing, then so "
82 							L"will any fonts you create with FontTool";
83 #endif
84 
85 enum MYGUI
86 {
87 	MYGUI_CHARSET  = 100,
88 	MYGUI_FONTNAME,
89 	MYGUI_SIZE,
90 	MYGUI_TEXWIDTH,
91 	MYGUI_TEXHEIGHT,
92 	MYGUI_BOLD,
93 	MYGUI_ITALIC,
94 	MYGUI_ANTIALIAS,
95 	MYGUI_ALPHA,
96 	MYGUI_VECTOR,
97 	MYGUI_FILENAME,
98 	MYGUI_FORMAT,
99 	MYGUI_CREATE,
100 	MYGUI_SAVE,
101 	MYGUI_IMAGE,
102 	MYGUI_CURRENTIMAGE,
103 	MYGUI_HELPBUTTON
104 };
105 
106 
107 // event reciever
108 class MyEventReceiver : public IEventReceiver
109 {
110 public:
111 
MyEventReceiver(IrrlichtDevice * device,CFontTool * & fonttool,CVectorFontTool * & vectool)112 	MyEventReceiver(IrrlichtDevice* device, CFontTool*& fonttool, CVectorFontTool* &vectool) :
113 		Device(device), FontTool(fonttool), VecTool(vectool)
114 	{
115 		device->setEventReceiver(this);
116 	}
117 
OnEvent(const SEvent & event)118 	virtual bool OnEvent(const SEvent &event)
119 	{
120 		if (event.EventType == EET_GUI_EVENT)
121 		{
122 			s32 id = event.GUIEvent.Caller->getID();
123 			IGUIEnvironment* env = Device->getGUIEnvironment();
124 
125 			switch(event.GUIEvent.EventType)
126 			{
127 			case EGET_SCROLL_BAR_CHANGED:
128 				if (id == MYGUI_CURRENTIMAGE)
129 				{
130 					IGUIImage* img = (IGUIImage*)env->getRootGUIElement()->getElementFromId(MYGUI_IMAGE,true);
131 					s32 i = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
132 					img->setImage(FontTool->currentTextures[i]);
133 
134 					return true;
135 				}
136 				break;
137 			case EGET_COMBO_BOX_CHANGED:
138 				if (id == MYGUI_CHARSET)
139 				{
140 					IGUIComboBox* cbo = (IGUIComboBox*)event.GUIEvent.Caller;
141 					FontTool->selectCharSet(cbo->getSelected());
142 					// rebuild font list
143 					cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FONTNAME,true);
144 					cbo->clear();
145 					for (u32 i=0; i < FontTool->FontNames.size(); ++i)
146 						cbo->addItem(FontTool->FontNames[i].c_str());
147 					return true;
148 				}
149 				break;
150 			case EGET_CHECKBOX_CHANGED:
151 				if (id == MYGUI_VECTOR)
152 				{
153 					IGUICheckBox* chk = (IGUICheckBox*)event.GUIEvent.Caller;
154 
155 					IGUIComboBox *cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FORMAT,true);
156 					cbo->clear();
157 
158 					if (chk->isChecked() && VecTool)
159 					{
160 						// vector formats
161 						for (s32 i=0; fileformats[i] != 0; ++i)
162 							cbo->addItem( core::stringw(vectorfileformats[i]).c_str());
163 
164 					}
165 					else
166 					{
167 
168 						// bitmap formats
169 						if (!FontTool->UseAlphaChannel)
170 						{
171 							// add non-alpha formats
172 							for (s32 i=0; fileformats[i] != 0; ++i)
173 								cbo->addItem( core::stringw(fileformats[i]).c_str());
174 						}
175 						// add formats which support alpha
176 						for (s32 i=0; alphafileformats[i] != 0; ++i)
177 							cbo->addItem( core::stringw(alphafileformats[i]).c_str());
178 					}
179 
180 				}
181 				break;
182 
183 			case EGET_BUTTON_CLICKED:
184 
185 				if (id == MYGUI_CREATE)
186 				{
187 					// create the font with the params
188 					IGUIComboBox* cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_CHARSET, true);
189 					int charset = cbo->getSelected();
190 
191 					cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FONTNAME,true);
192 					int fontname = cbo->getSelected();
193 
194 					cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_SIZE,true);
195 					int fontsize = cbo->getSelected();
196 
197 					cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_TEXWIDTH,true);
198 					int texwidth = cbo->getSelected();
199 
200 					cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_TEXHEIGHT,true);
201 					int texheight = cbo->getSelected();
202 
203 					IGUICheckBox* chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_BOLD,true);
204 					bool bold = chk->isChecked();
205 					chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_ITALIC,true);
206 					bool italic = chk->isChecked();
207 
208 					chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_ALPHA,true);
209 					bool alpha = chk->isChecked();
210 
211 					chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_ANTIALIAS,true);
212 					bool aa = chk->isChecked();
213 
214 					// vector fonts disabled
215 					//chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_VECTOR,true);
216 					bool vec = false;//chk->isChecked();
217 
218 					FontTool->makeBitmapFont(fontname, charset, FontTool->FontSizes[fontsize], texturesizes[texwidth], texturesizes[texheight], bold, italic, aa, alpha);
219 
220 					IGUIScrollBar* scrl = (IGUIScrollBar*)env->getRootGUIElement()->getElementFromId(MYGUI_CURRENTIMAGE,true);
221 					scrl->setMax(FontTool->currentTextures.size() == 0 ? 0 : FontTool->currentTextures.size()-1);
222 
223 					if (FontTool->currentTextures.size() > 0)
224 					{
225 						IGUIImage* img = (IGUIImage*)env->getRootGUIElement()->getElementFromId(MYGUI_IMAGE,true);
226 						img->setImage(FontTool->currentTextures[0]);
227 						scrl->setPos(0);
228 					}
229 
230 					// make sure users pick a file format that supports alpha channel
231 					cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FORMAT,true);
232 					cbo->clear();
233 
234 					if (vec)
235 					{
236 						// add vector formats
237 						for (s32 i=0; fileformats[i] != 0; ++i)
238 							cbo->addItem( core::stringw(vectorfileformats[i]).c_str());
239 					}
240 					else
241 					{
242 						if (!alpha)
243 						{
244 							// add non-alpha formats
245 							for (s32 i=0; fileformats[i] != 0; ++i)
246 								cbo->addItem( core::stringw(fileformats[i]).c_str());
247 						}
248 						// add formats which support alpha
249 						for (s32 i=0; alphafileformats[i] != 0; ++i)
250 							cbo->addItem( core::stringw(alphafileformats[i]).c_str());
251 					}
252 					if (VecTool)
253 					{
254 						delete VecTool;
255 						VecTool = 0;
256 					}
257 					if (vec)
258 					{
259 						VecTool = new CVectorFontTool(FontTool);
260 					}
261 
262 					/* Message box letting the user know the process is complete */
263 					env->addMessageBox(L"Create", completeText);
264 
265 					return true;
266 				}
267 
268 				if (id == MYGUI_SAVE)
269 				{
270 					IGUIEditBox *edt  = (IGUIEditBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FILENAME,true);
271 					core::stringc name = edt->getText();
272 
273 					IGUIComboBox *fmt  = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FORMAT,true);
274 					core::stringc format = fmt->getItem(fmt->getSelected());
275 
276 					// vector fonts disabled
277 					IGUICheckBox *chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_VECTOR,true);
278 					bool vec = false; // chk->isChecked();
279 
280 					if (vec && VecTool)
281 						VecTool->saveVectorFont(name.c_str(), format.c_str());
282 					else
283 						FontTool->saveBitmapFont(name.c_str(), format.c_str());
284 
285 					return true;
286 				}
287 
288 				if (id == MYGUI_HELPBUTTON)
289 				{
290 					env->addMessageBox(L"Irrlicht Unicode Font Tool", helptext);
291 					return true;
292 				}
293 
294 				break;
295 			}
296 		}
297 
298 		return false;
299 	}
300 
301 	IrrlichtDevice*	 Device;
302 	CFontTool*       FontTool;
303 	CVectorFontTool* VecTool;
304 
305 };
306 
createGUI(IrrlichtDevice * device,CFontTool * fc)307 void createGUI(IrrlichtDevice* device, CFontTool* fc)
308 {
309 	gui::IGUIEnvironment *env = device->getGUIEnvironment();
310 
311 	// change transparency of skin
312 	for (s32 i=0; i<gui::EGDC_COUNT ; ++i)
313 	{
314 		video::SColor col = env->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
315 		col.setAlpha(255);
316 		env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col);
317 	}
318 
319 	IGUIWindow *win = env->addWindow( core::rect<s32>(10,10,200,500), false, L"Font Creator");
320 	win->getCloseButton()->setVisible(false);
321 
322 	s32 xs=10,xp=xs, yp=30, h=20;
323 
324 	env->addStaticText(L"Charset", core::rect<s32>(xp,yp,50,yp+h),false,false, win);
325 
326 	xp+=60;
327 
328 	// charset combo
329 	gui::IGUIComboBox* cbo = env->addComboBox( core::rect<s32>(xp,yp,180,yp+h),win, MYGUI_CHARSET);
330 	for (u32 i=0; i < fc->CharSets.size(); ++i)
331 		cbo->addItem(fc->CharSets[i].c_str());
332 
333 	yp += (s32)(h*1.5f);
334 	xp = xs;
335 
336 	env->addStaticText(L"Font", core::rect<s32>(xp,yp,50,yp+h),false,false, win);
337 
338 	xp+=60;
339 
340 	// font name combo
341 	cbo = env->addComboBox( core::rect<s32>(xp,yp,180,yp+h),win, MYGUI_FONTNAME);
342 	for (u32 i=0; i < fc->FontNames.size(); ++i)
343 		cbo->addItem(fc->FontNames[i].c_str());
344 
345 	yp += (s32)(h*1.5f);
346 	xp = xs;
347 
348 	env->addStaticText(L"Size", core::rect<s32>(xp,yp,50,yp+h),false,false, win);
349 
350 	xp += 60;
351 
352 	// font size combo
353 	cbo = env->addComboBox( core::rect<s32>(xp,yp,xp+50,yp+h),win, MYGUI_SIZE);
354 	for (s32 i=0; fc->FontSizes[i] != 0; ++i)
355 		cbo->addItem( ((core::stringw(fc->FontSizes[i])) + L"px").c_str());
356 
357 	xp = xs;
358 	yp += (s32)(h*1.5f);
359 
360 	// bold checkbox
361 	env->addCheckBox(false, core::rect<s32>(xp,yp,xp+50,yp+h),win, MYGUI_BOLD, L"Bold");
362 
363 	xp += 45;
364 
365 	// italic checkbox
366 	env->addCheckBox(false, core::rect<s32>(xp,yp,xp+50,yp+h),win, MYGUI_ITALIC, L"Italic");
367 
368 	xp += 45;
369 
370 	// AA checkbox
371 	env->addCheckBox(false, core::rect<s32>(xp,yp,xp+50,yp+h),win, MYGUI_ANTIALIAS, L"AA");
372 
373 	xp +=40;
374 
375 	// Alpha checkbox
376 	env->addCheckBox(false, core::rect<s32>(xp,yp,xp+50,yp+h),win, MYGUI_ALPHA, L"Alpha");
377 
378 	xp = xs;
379 	yp += (s32)(h*1.5f);
380 
381 	/*
382 	// vector fonts can't be loaded yet
383 	env->addCheckBox(false, core::rect<s32>(xp,yp,xp+200,yp+h),win, MYGUI_VECTOR, L"Vector Font");
384 	*/
385 
386 	yp += (s32)(h*1.5f);
387 
388 	env->addStaticText(L"Max Width:", core::rect<s32>(xp,yp,50,yp+h),false,false, win);
389 
390 	xp += 60;
391 
392 	// texture widths
393 	cbo = env->addComboBox( core::rect<s32>(xp,yp,xp+70,yp+h),win, MYGUI_TEXWIDTH);
394 	for (s32 i=0; texturesizes[i] != 0; ++i)
395 		cbo->addItem( ((core::stringw(texturesizes[i])) + L" wide").c_str());
396 
397 	xp=xs;
398 	yp += (s32)(h*1.5f);
399 
400 	env->addStaticText(L"Max Height:", core::rect<s32>(xp,yp,60,yp+h),false,false, win);
401 
402 	xp += 60;
403 
404 	// texture height
405 	cbo = env->addComboBox( core::rect<s32>(xp,yp,xp+70,yp+h),win, MYGUI_TEXHEIGHT);
406 	for (s32 i=0; texturesizes[i] != 0; ++i)
407 		cbo->addItem( ((core::stringw(texturesizes[i])) + L" tall").c_str());
408 
409 	// file name
410 	xp = xs;
411 	yp += (s32)(h*1.5f);
412 	env->addStaticText(L"Filename", core::rect<s32>(xp,yp,60,yp+h),false,false, win);
413 	xp += 60;
414 	env->addEditBox(L"myfont",core::rect<s32>(xp,yp,xp+70,yp+h), true, win, MYGUI_FILENAME);
415 
416 	// file format
417 	xp = xs;
418 	yp += (s32)(h*1.5f);
419 	env->addStaticText(L"File Format", core::rect<s32>(xp,yp,60,yp+h),false,false, win);
420 	xp += 60;
421 
422 	cbo = env->addComboBox( core::rect<s32>(xp,yp,xp+70,yp+h),win, MYGUI_FORMAT);
423 	for (s32 i=0; fileformats[i] != 0; ++i)
424 		cbo->addItem( core::stringw(fileformats[i]).c_str());
425 	for (s32 i=0; alphafileformats[i] != 0; ++i)
426 		cbo->addItem( core::stringw(alphafileformats[i]).c_str());
427 
428 	xp = xs;
429 	yp += h*2;
430 
431 	// create button
432 	env->addButton( core::rect<s32>(xp,yp,xp+50,yp+h),win, MYGUI_CREATE, L"Create");
433 
434 	xp += 60;
435 
436 	// save button
437 	env->addButton( core::rect<s32>(xp,yp,xp+50,yp+h),win, MYGUI_SAVE, L"Save");
438 
439 	xp += 60;
440 
441 	// help button
442 	env->addButton( core::rect<s32>(xp,yp,xp+50,yp+h),win, MYGUI_HELPBUTTON, L"Help");
443 
444 	// font image
445 	gui::IGUIImage *img = env->addImage(0, core::position2d<s32>(0,0), true,0, MYGUI_IMAGE);
446 	img->setRelativePosition(core::rect<s32>(0,20,800,600));
447 
448 	// font scrollbar
449 	IGUIScrollBar *scrl= env->addScrollBar(true,core::rect<s32>(0,0,800,20),0, MYGUI_CURRENTIMAGE);
450 	scrl->setMax(0);
451 	scrl->setSmallStep(1);
452 
453 	yp += h*3;
454 
455 	env->getRootGUIElement()->bringToFront(win);
456 	win->setRelativePosition( core::rect<s32>(10,10,200,yp));
457 }
458 
main()459 int main()
460 {
461 	IrrlichtDevice* device =createDevice(video::EDT_OPENGL, core::dimension2du(800, 600));
462 	video::IVideoDriver* driver = device->getVideoDriver();
463 	scene::ISceneManager* smgr = device->getSceneManager();
464 	gui::IGUIEnvironment *env = device->getGUIEnvironment();
465 
466 	// create font tool
467 	CFontTool *fc = new CFontTool(device);
468 	CVectorFontTool *vc = 0;
469 
470 	IEventReceiver *events = new MyEventReceiver(device,fc,vc);
471 
472 	createGUI(device, fc);
473 
474 	while(device->run())
475 	{
476 		if (device->isWindowActive())
477 		{
478 
479 			driver->beginScene(true, true, video::SColor(0,200,200,200));
480 			smgr->drawAll();
481 			env->drawAll();
482 			driver->endScene();
483 		}
484 	}
485 
486 	// drop the font tool and resources
487 	fc->drop();
488 
489 	device->drop();
490 
491 	return 0;
492 }
493 
494