فهرست منبع

Implement proper font handling

sapier 9 سال پیش
والد
کامیت
dceb9f7d60
91فایلهای تغییر یافته به همراه902 افزوده شده و 194 حذف شده
  1. BIN
      fonts/fontdejavusansmono.png
  2. BIN
      fonts/fontlucida.png
  3. 100 0
      fonts/liberation_sans_14.xml
  4. BIN
      fonts/liberation_sans_14_img.png
  5. BIN
      fonts/lucida_sans_10.xml
  6. BIN
      fonts/lucida_sans_100.png
  7. BIN
      fonts/lucida_sans_11.xml
  8. BIN
      fonts/lucida_sans_110.png
  9. BIN
      fonts/lucida_sans_12.xml
  10. BIN
      fonts/lucida_sans_120.png
  11. BIN
      fonts/lucida_sans_14.xml
  12. BIN
      fonts/lucida_sans_140.png
  13. BIN
      fonts/lucida_sans_16.xml
  14. BIN
      fonts/lucida_sans_160.png
  15. BIN
      fonts/lucida_sans_18.xml
  16. BIN
      fonts/lucida_sans_180.png
  17. BIN
      fonts/lucida_sans_20.xml
  18. BIN
      fonts/lucida_sans_200.png
  19. BIN
      fonts/lucida_sans_22.xml
  20. BIN
      fonts/lucida_sans_220.png
  21. BIN
      fonts/lucida_sans_24.xml
  22. BIN
      fonts/lucida_sans_240.png
  23. BIN
      fonts/lucida_sans_26.xml
  24. BIN
      fonts/lucida_sans_260.png
  25. BIN
      fonts/lucida_sans_28.xml
  26. BIN
      fonts/lucida_sans_280.png
  27. BIN
      fonts/lucida_sans_36.xml
  28. BIN
      fonts/lucida_sans_360.png
  29. BIN
      fonts/lucida_sans_4.xml
  30. BIN
      fonts/lucida_sans_40.png
  31. BIN
      fonts/lucida_sans_48.xml
  32. BIN
      fonts/lucida_sans_480.png
  33. BIN
      fonts/lucida_sans_56.xml
  34. BIN
      fonts/lucida_sans_560.png
  35. BIN
      fonts/lucida_sans_6.xml
  36. BIN
      fonts/lucida_sans_60.png
  37. BIN
      fonts/lucida_sans_8.xml
  38. BIN
      fonts/lucida_sans_80.png
  39. BIN
      fonts/lucida_sans_9.xml
  40. BIN
      fonts/lucida_sans_90.png
  41. BIN
      fonts/mono_dejavu_sans_10.xml
  42. BIN
      fonts/mono_dejavu_sans_100.png
  43. BIN
      fonts/mono_dejavu_sans_11.xml
  44. BIN
      fonts/mono_dejavu_sans_110.png
  45. BIN
      fonts/mono_dejavu_sans_12.xml
  46. BIN
      fonts/mono_dejavu_sans_120.png
  47. BIN
      fonts/mono_dejavu_sans_14.xml
  48. BIN
      fonts/mono_dejavu_sans_140.png
  49. BIN
      fonts/mono_dejavu_sans_16.xml
  50. BIN
      fonts/mono_dejavu_sans_160.png
  51. BIN
      fonts/mono_dejavu_sans_18.xml
  52. BIN
      fonts/mono_dejavu_sans_180.png
  53. BIN
      fonts/mono_dejavu_sans_20.xml
  54. BIN
      fonts/mono_dejavu_sans_200.png
  55. BIN
      fonts/mono_dejavu_sans_22.xml
  56. BIN
      fonts/mono_dejavu_sans_220.png
  57. BIN
      fonts/mono_dejavu_sans_24.xml
  58. BIN
      fonts/mono_dejavu_sans_240.png
  59. BIN
      fonts/mono_dejavu_sans_26.xml
  60. BIN
      fonts/mono_dejavu_sans_260.png
  61. BIN
      fonts/mono_dejavu_sans_28.xml
  62. BIN
      fonts/mono_dejavu_sans_280.png
  63. BIN
      fonts/mono_dejavu_sans_4.xml
  64. BIN
      fonts/mono_dejavu_sans_40.png
  65. BIN
      fonts/mono_dejavu_sans_6.xml
  66. BIN
      fonts/mono_dejavu_sans_60.png
  67. BIN
      fonts/mono_dejavu_sans_8.xml
  68. BIN
      fonts/mono_dejavu_sans_80.png
  69. BIN
      fonts/mono_dejavu_sans_9.xml
  70. BIN
      fonts/mono_dejavu_sans_90.png
  71. 2 0
      minetest.conf.example
  72. 1 0
      src/CMakeLists.txt
  73. 3 3
      src/client.cpp
  74. 2 1
      src/constants.h
  75. 18 19
      src/defaultsettings.cpp
  76. 0 6
      src/defaultsettings.h
  77. 29 23
      src/drawscene.cpp
  78. 2 2
      src/drawscene.h
  79. 463 0
      src/fontengine.cpp
  80. 140 0
      src/fontengine.h
  81. 27 39
      src/game.cpp
  82. 0 1
      src/game.h
  83. 5 22
      src/guiChatConsole.cpp
  84. 40 9
      src/guiEngine.cpp
  85. 3 0
      src/guiEngine.h
  86. 29 13
      src/guiFormSpecMenu.cpp
  87. 0 1
      src/guiFormSpecMenu.h
  88. 7 44
      src/main.cpp
  89. 1 10
      src/porting.cpp
  90. 24 0
      src/settings.cpp
  91. 6 1
      src/settings.h

BIN
fonts/fontdejavusansmono.png


BIN
fonts/fontlucida.png


+ 100 - 0
fonts/liberation_sans_14.xml

@@ -0,0 +1,100 @@
+<?xml version="1.0"?>
+<font type="bitmap">
+
+	<Texture index="0" filename="liberation_sans_14_img.png" hasAlpha="true" />
+
+<c c="!" r="0, 0, 6, 18" />
+<c c="&quot;" r="6, 0, 15, 9" />
+<c c="#" r="15, 0, 30, 18" />
+<c c="$" r="30, 0, 43, 20" />
+<c c="%" r="43, 0, 62, 18" />
+<c c="&amp;" r="62, 0, 78, 18" />
+<c c="'" r="78, 0, 84, 9" />
+<c c="(" r="84, 0, 93, 22" />
+<c c=")" r="93, 0, 103, 22" />
+<c c="*" r="103, 0, 114, 12" />
+<c c="+" r="114, 0, 127, 16" />
+<c c="," r="127, 0, 133, 20" />
+<c c="-" r="133, 0, 141, 13" />
+<c c="." r="141, 0, 147, 18" />
+<c c="/" r="147, 0, 156, 18" />
+<c c="0" r="156, 0, 169, 18" />
+<c c="1" r="169, 0, 181, 18" />
+<c c="2" r="181, 0, 195, 18" />
+<c c="3" r="195, 0, 208, 18" />
+<c c="4" r="208, 0, 222, 18" />
+<c c="5" r="222, 0, 235, 18" />
+<c c="6" r="235, 0, 248, 18" />
+<c c="7" r="248, 0, 261, 18" />
+<c c="8" r="261, 0, 274, 18" />
+<c c="9" r="274, 0, 287, 18" />
+<c c=":" r="287, 0, 293, 18" />
+<c c=";" r="293, 0, 299, 20" />
+<c c="&lt;" r="299, 0, 312, 16" />
+<c c="=" r="312, 0, 325, 15" />
+<c c="&gt;" r="325, 0, 338, 16" />
+<c c="?" r="338, 0, 351, 18" />
+<c c="@" r="351, 0, 370, 21" />
+<c c="A" r="370, 0, 386, 18" />
+<c c="B" r="386, 0, 400, 18" />
+<c c="C" r="400, 0, 415, 18" />
+<c c="D" r="415, 0, 430, 18" />
+<c c="E" r="430, 0, 444, 18" />
+<c c="F" r="444, 0, 457, 18" />
+<c c="G" r="457, 0, 473, 18" />
+<c c="H" r="473, 0, 487, 18" />
+<c c="I" r="487, 0, 493, 18" />
+<c c="J" r="493, 0, 506, 18" />
+<c c="K" r="0, 22, 15, 40" />
+<c c="L" r="15, 22, 27, 40" />
+<c c="M" r="27, 22, 43, 40" />
+<c c="N" r="43, 22, 57, 40" />
+<c c="O" r="57, 22, 73, 40" />
+<c c="P" r="73, 22, 87, 40" />
+<c c="Q" r="87, 22, 103, 44" />
+<c c="R" r="103, 22, 118, 40" />
+<c c="S" r="118, 22, 133, 40" />
+<c c="T" r="133, 22, 147, 40" />
+<c c="U" r="147, 22, 161, 40" />
+<c c="V" r="161, 22, 177, 40" />
+<c c="W" r="177, 22, 199, 40" />
+<c c="X" r="199, 22, 216, 40" />
+<c c="Y" r="216, 22, 232, 40" />
+<c c="Z" r="232, 22, 247, 40" />
+<c c="[" r="247, 22, 255, 44" />
+<c c="\" r="255, 22, 264, 40" />
+<c c="]" r="264, 22, 272, 44" />
+<c c="^" r="272, 22, 283, 34" />
+<c c="_" r="283, 22, 298, 44" />
+<c c="`" r="298, 22, 306, 29" />
+<c c="a" r="306, 22, 319, 40" />
+<c c="b" r="319, 22, 333, 40" />
+<c c="c" r="333, 22, 345, 40" />
+<c c="d" r="345, 22, 358, 40" />
+<c c="e" r="358, 22, 371, 40" />
+<c c="f" r="371, 22, 381, 40" />
+<c c="g" r="381, 22, 394, 44" />
+<c c="h" r="394, 22, 406, 40" />
+<c c="i" r="406, 22, 412, 40" />
+<c c="j" r="412, 22, 420, 44" />
+<c c="k" r="420, 22, 432, 40" />
+<c c="l" r="432, 22, 438, 40" />
+<c c="m" r="438, 22, 456, 40" />
+<c c="n" r="456, 22, 468, 40" />
+<c c="o" r="468, 22, 481, 40" />
+<c c="p" r="481, 22, 495, 44" />
+<c c="q" r="495, 22, 508, 44" />
+<c c="r" r="0, 44, 10, 62" />
+<c c="s" r="10, 44, 22, 62" />
+<c c="t" r="22, 44, 31, 62" />
+<c c="u" r="31, 44, 43, 62" />
+<c c="v" r="43, 44, 56, 62" />
+<c c="w" r="56, 44, 73, 62" />
+<c c="x" r="73, 44, 86, 62" />
+<c c="y" r="86, 44, 99, 66" />
+<c c="z" r="99, 44, 111, 62" />
+<c c="{" r="111, 44, 121, 66" />
+<c c="|" r="121, 44, 127, 66" />
+<c c="}" r="127, 44, 137, 66" />
+<c c="~" r="137, 44, 150, 57" />
+</font>

BIN
fonts/liberation_sans_14_img.png


BIN
fonts/lucida_sans_10.xml


BIN
fonts/lucida_sans_100.png


BIN
fonts/lucida_sans_11.xml


BIN
fonts/lucida_sans_110.png


BIN
fonts/lucida_sans_12.xml


BIN
fonts/lucida_sans_120.png


BIN
fonts/lucida_sans_14.xml


BIN
fonts/lucida_sans_140.png


BIN
fonts/lucida_sans_16.xml


BIN
fonts/lucida_sans_160.png


BIN
fonts/lucida_sans_18.xml


BIN
fonts/lucida_sans_180.png


BIN
fonts/lucida_sans_20.xml


BIN
fonts/lucida_sans_200.png


BIN
fonts/lucida_sans_22.xml


BIN
fonts/lucida_sans_220.png


BIN
fonts/lucida_sans_24.xml


BIN
fonts/lucida_sans_240.png


BIN
fonts/lucida_sans_26.xml


BIN
fonts/lucida_sans_260.png


BIN
fonts/lucida_sans_28.xml


BIN
fonts/lucida_sans_280.png


BIN
fonts/lucida_sans_36.xml


BIN
fonts/lucida_sans_360.png


BIN
fonts/lucida_sans_4.xml


BIN
fonts/lucida_sans_40.png


BIN
fonts/lucida_sans_48.xml


BIN
fonts/lucida_sans_480.png


BIN
fonts/lucida_sans_56.xml


BIN
fonts/lucida_sans_560.png


BIN
fonts/lucida_sans_6.xml


BIN
fonts/lucida_sans_60.png


BIN
fonts/lucida_sans_8.xml


BIN
fonts/lucida_sans_80.png


BIN
fonts/lucida_sans_9.xml


BIN
fonts/lucida_sans_90.png


BIN
fonts/mono_dejavu_sans_10.xml


BIN
fonts/mono_dejavu_sans_100.png


BIN
fonts/mono_dejavu_sans_11.xml


BIN
fonts/mono_dejavu_sans_110.png


BIN
fonts/mono_dejavu_sans_12.xml


BIN
fonts/mono_dejavu_sans_120.png


BIN
fonts/mono_dejavu_sans_14.xml


BIN
fonts/mono_dejavu_sans_140.png


BIN
fonts/mono_dejavu_sans_16.xml


BIN
fonts/mono_dejavu_sans_160.png


BIN
fonts/mono_dejavu_sans_18.xml


BIN
fonts/mono_dejavu_sans_180.png


BIN
fonts/mono_dejavu_sans_20.xml


BIN
fonts/mono_dejavu_sans_200.png


BIN
fonts/mono_dejavu_sans_22.xml


BIN
fonts/mono_dejavu_sans_220.png


BIN
fonts/mono_dejavu_sans_24.xml


BIN
fonts/mono_dejavu_sans_240.png


BIN
fonts/mono_dejavu_sans_26.xml


BIN
fonts/mono_dejavu_sans_260.png


BIN
fonts/mono_dejavu_sans_28.xml


BIN
fonts/mono_dejavu_sans_280.png


BIN
fonts/mono_dejavu_sans_4.xml


BIN
fonts/mono_dejavu_sans_40.png


BIN
fonts/mono_dejavu_sans_6.xml


BIN
fonts/mono_dejavu_sans_60.png


BIN
fonts/mono_dejavu_sans_8.xml


BIN
fonts/mono_dejavu_sans_80.png


BIN
fonts/mono_dejavu_sans_9.xml


BIN
fonts/mono_dejavu_sans_90.png


+ 2 - 0
minetest.conf.example

@@ -215,6 +215,8 @@
 #directional_colored_fog = true
 #tooltip_show_delay = 400
 # Delay showing tooltips, in miliseconds
+#screen_dpi = 72
+# adjust dpi configuration to your screen (PC/MAC only) e.g. for 4k screens
 
 # Default timeout for cURL, in milliseconds
 # Only has an effect if compiled with cURL

+ 1 - 0
src/CMakeLists.txt

@@ -453,6 +453,7 @@ set(minetest_SRCS
 	convert_json.cpp
 	drawscene.cpp
 	filecache.cpp
+	fontengine.cpp
 	game.cpp
 	guiChatConsole.cpp
 	guiEngine.cpp

+ 3 - 3
src/client.cpp

@@ -2726,7 +2726,7 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
 	{
 		verbosestream<<"Updating item textures and meshes"<<std::endl;
 		wchar_t* text = wgettext("Item textures...");
-		draw_load_screen(text, device, guienv, font, 0, 0);
+		draw_load_screen(text, device, guienv, 0, 0);
 		std::set<std::string> names = m_itemdef->getAll();
 		size_t size = names.size();
 		size_t count = 0;
@@ -2739,7 +2739,7 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
 			count++;
 			percent = count*100/size;
 			if (count%50 == 0) // only update every 50 item
-				draw_load_screen(text, device, guienv, font, 0, percent);
+				draw_load_screen(text, device, guienv, 0, percent);
 		}
 		delete[] text;
 	}
@@ -2775,7 +2775,7 @@ void Client::makeScreenshot(IrrlichtDevice *device)
 	irr::video::IVideoDriver *driver = device->getVideoDriver();
 	irr::video::IImage* const raw_image = driver->createScreenShot();
 	if (raw_image) {
-		irr::video::IImage* const image = driver->createImage(video::ECF_R8G8B8, 
+		irr::video::IImage* const image = driver->createImage(video::ECF_R8G8B8,
 			raw_image->getDimension());
 
 		if (image) {

+ 2 - 1
src/constants.h

@@ -98,7 +98,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
  *    GUI related things
  */
 #define LEGACY_SCALING                                     (2./3.)
-#define DEFAULT_FONT_SIZE                  (13.0 / LEGACY_SCALING)
+#define TTF_DEFAULT_FONT_SIZE              (13.0 / LEGACY_SCALING)
+#define DEFAULT_FONT_SIZE                                     (14)
 #define DEFAULT_IMGSIZE                                     (48.0)
 #define DEFAULT_XSPACING                    ((15.0 + (1.0 / 3.0)))
 #define DEFAULT_YSPACING                                     (9.0)

+ 18 - 19
src/defaultsettings.cpp

@@ -187,10 +187,23 @@ void set_default_settings(Settings *settings)
 
 	settings->setDefault("fallback_font_shadow", "1");
 	settings->setDefault("fallback_font_shadow_alpha", "128");
+
+	std::stringstream fontsize;
+	fontsize << TTF_DEFAULT_FONT_SIZE;
+
+	settings->setDefault("font_size", fontsize.str());
+	settings->setDefault("mono_font_size", fontsize.str());
+	settings->setDefault("fallback_font_size", fontsize.str());
 #else
-	settings->setDefault("freetype", "false");
-	settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "fontlucida.png"));
-	settings->setDefault("mono_font_path", porting::getDataPath("fonts" DIR_DELIM "fontdejavusansmono.png"));
+ 	settings->setDefault("freetype", "false");
+	settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "lucida_sans"));
+	settings->setDefault("mono_font_path", porting::getDataPath("fonts" DIR_DELIM "mono_dejavu_sans"));
+
+	std::stringstream fontsize;
+	fontsize << DEFAULT_FONT_SIZE;
+
+	settings->setDefault("font_size", fontsize.str());
+	settings->setDefault("mono_font_size", fontsize.str());
 #endif
 
 	// Server stuff
@@ -317,22 +330,8 @@ void set_default_settings(Settings *settings)
 		settings->setDefault("gui_scaling", "0.7");
 	}
 	settings->setDefault("curl_verify_cert","false");
-#endif
-}
-
-void late_init_default_settings(Settings* settings)
-{
-#ifndef SERVER
-	std::stringstream fontsize;
-	fontsize << floor(
-			DEFAULT_FONT_SIZE *
-			porting::getDisplayDensity() *
-			settings->getFloat("gui_scaling")
-			);
-
-	settings->setDefault("font_size", fontsize.str());
-	settings->setDefault("mono_font_size", fontsize.str());
-	settings->setDefault("fallback_font_size", fontsize.str());
+#else
+	settings->setDefault("screen_dpi", "72");
 #endif
 }
 

+ 0 - 6
src/defaultsettings.h

@@ -28,12 +28,6 @@ class Settings;
  */
 void set_default_settings(Settings *settings);
 
-/**
- * initialize default values which require knowledge about gui
- * @param settings pointer to settings
- */
-void late_init_default_settings(Settings* settings);
-
 /**
  * override a default settings by settings from another settings element
  * @param settings target settings pointer

+ 29 - 23
src/drawscene.cpp

@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "clouds.h"
 #include "clientmap.h"
 #include "util/timetaker.h"
+#include "fontengine.h"
 
 typedef enum {
 	LEFT = -1,
@@ -500,21 +501,18 @@ void draw_scene(video::IVideoDriver* driver, scene::ISceneManager* smgr,
 	Text will be removed when the screen is drawn the next time.
 	Additionally, a progressbar can be drawn when percent is set between 0 and 100.
 */
-/*gui::IGUIStaticText **/
 void draw_load_screen(const std::wstring &text, IrrlichtDevice* device,
-		gui::IGUIEnvironment* guienv, gui::IGUIFont* font, float dtime,
-		int percent, bool clouds )
+		gui::IGUIEnvironment* guienv, float dtime, int percent, bool clouds )
 {
-	video::IVideoDriver* driver = device->getVideoDriver();
-	v2u32 screensize = driver->getScreenSize();
-	const wchar_t *loadingtext = text.c_str();
-	core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
-	core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
-	core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
-	core::rect<s32> textrect(center - textsize/2, center + textsize/2);
+	video::IVideoDriver* driver    = device->getVideoDriver();
+	v2u32 screensize               = porting::getWindowSize();
+
+	v2s32 textsize(glb_fontengine->getTextWidth(text), glb_fontengine->getLineHeight());
+	v2s32 center(screensize.X / 2, screensize.Y / 2);
+	core::rect<s32> textrect(center - textsize / 2, center + textsize / 2);
 
 	gui::IGUIStaticText *guitext = guienv->addStaticText(
-			loadingtext, textrect, false, false);
+			text.c_str(), textrect, false, false);
 	guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
 
 	bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
@@ -522,25 +520,33 @@ void draw_load_screen(const std::wstring &text, IrrlichtDevice* device,
 	{
 		g_menuclouds->step(dtime*3);
 		g_menuclouds->render();
-		driver->beginScene(true, true, video::SColor(255,140,186,250));
+		driver->beginScene(true, true, video::SColor(255, 140, 186, 250));
 		g_menucloudsmgr->drawAll();
 	}
 	else
-		driver->beginScene(true, true, video::SColor(255,0,0,0));
+		driver->beginScene(true, true, video::SColor(255, 0, 0, 0));
 
-	if (percent >= 0 && percent <= 100) // draw progress bar
+	// draw progress bar
+	if ((percent >= 0) && (percent <= 100))
 	{
-		core::vector2d<s32> barsize(256,32);
-		core::rect<s32> barrect(center-barsize/2, center+barsize/2);
-		driver->draw2DRectangle(video::SColor(255,255,255,255),barrect, NULL); // border
-		driver->draw2DRectangle(video::SColor(255,64,64,64), core::rect<s32> (
-				barrect.UpperLeftCorner+1,
+		v2s32 barsize(
+				// 342 is (approximately) 256/0.75 to keep bar on same size as
+				// before with default settings
+				342 * porting::getDisplayDensity() *
+				g_settings->getFloat("gui_scaling"),
+				glb_fontengine->getTextHeight() * 2);
+
+		core::rect<s32> barrect(center - barsize / 2, center + barsize / 2);
+		driver->draw2DRectangle(video::SColor(255, 255, 255, 255),barrect, NULL); // border
+		driver->draw2DRectangle(video::SColor(255, 64, 64, 64), core::rect<s32> (
+				barrect.UpperLeftCorner + 1,
 				barrect.LowerRightCorner-1), NULL); // black inside the bar
-		driver->draw2DRectangle(video::SColor(255,128,128,128), core::rect<s32> (
-				barrect.UpperLeftCorner+1,
+		driver->draw2DRectangle(video::SColor(255, 128, 128, 128), core::rect<s32> (
+				barrect.UpperLeftCorner + 1,
 				core::vector2d<s32>(
-					barrect.LowerRightCorner.X-(barsize.X-1)+percent*(barsize.X-2)/100,
-					barrect.LowerRightCorner.Y-1)), NULL); // the actual progress
+						barrect.LowerRightCorner.X -
+						(barsize.X - 1) + percent * (barsize.X - 2) / 100,
+						barrect.LowerRightCorner.Y - 1)), NULL); // the actual progress
 	}
 	guienv->drawAll();
 	driver->endScene();

+ 2 - 2
src/drawscene.h

@@ -26,8 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 
 void draw_load_screen(const std::wstring &text, IrrlichtDevice* device,
-		gui::IGUIEnvironment* guienv, gui::IGUIFont* font, float dtime=0,
-		int percent=0, bool clouds=true);
+		gui::IGUIEnvironment* guienv, float dtime=0, int percent=0,
+		bool clouds=true);
 
 void draw_scene(video::IVideoDriver* driver, scene::ISceneManager* smgr,
 		Camera& camera, Client& client, LocalPlayer* player, Hud& hud,

+ 463 - 0
src/fontengine.cpp

@@ -0,0 +1,463 @@
+/*
+Minetest
+Copyright (C) 2010-2014 sapier <sapier at gmx dot net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "fontengine.h"
+#include "log.h"
+#include "main.h"
+#include "config.h"
+#include "porting.h"
+#include "constants.h"
+#include "filesys.h"
+
+#if USE_FREETYPE
+#include "gettext.h"
+#include "xCGUITTFont.h"
+#endif
+
+/** maximum size distance for getting a "similar" font size */
+#define MAX_FONT_SIZE_OFFSET 10
+
+/** reference to access font engine, has to be initialized by main */
+FontEngine* glb_fontengine = NULL;
+
+/** callback to be used on change of font size setting */
+static void font_setting_changed(const std::string) {
+	glb_fontengine->readSettings();
+}
+
+/******************************************************************************/
+FontEngine::FontEngine(Settings* main_settings, gui::IGUIEnvironment* env) :
+	m_settings(main_settings),
+	m_env(env),
+	m_font_cache(),
+	m_default_size(),
+	m_currentMode(FM_Standard),
+	m_lastMode(),
+	m_lastSize(0),
+	m_lastFont(NULL)
+{
+
+	for ( unsigned int i = 0; i < FM_MaxMode; i++) {
+		m_default_size[i] = (FontMode) FONT_SIZE_UNSPECIFIED;
+	}
+
+	assert(m_settings != NULL);
+	assert(m_env != NULL);
+	assert(m_env->getSkin() != NULL);
+
+	m_currentMode = FM_Simple;
+
+#if USE_FREETYPE
+	if (g_settings->getBool("freetype")) {
+		m_default_size[FM_Standard] = m_settings->getU16("font_size");
+		m_default_size[FM_Fallback] = m_settings->getU16("fallback_font_size");
+		m_default_size[FM_Mono]     = m_settings->getU16("mono_font_size");
+
+		if (is_yes(gettext("needs_fallback_font"))) {
+			m_currentMode = FM_Fallback;
+		}
+		else {
+			m_currentMode = FM_Standard;
+		}
+	}
+
+	// having freetype but not using it is quite a strange case so we need to do
+	// special handling for it
+	if (m_currentMode == FM_Simple) {
+		std::stringstream fontsize;
+		fontsize << DEFAULT_FONT_SIZE;
+		m_settings->setDefault("font_size", fontsize.str());
+		m_settings->setDefault("mono_font_size", fontsize.str());
+	}
+#endif
+
+	m_default_size[FM_Simple]       = m_settings->getU16("font_size");
+	m_default_size[FM_SimpleMono]   = m_settings->getU16("mono_font_size");
+
+	updateSkin();
+
+	if (m_currentMode == FM_Standard) {
+		m_settings->registerChangedCallback("font_size", font_setting_changed);
+		m_settings->registerChangedCallback("font_path", font_setting_changed);
+		m_settings->registerChangedCallback("font_shadow", font_setting_changed);
+		m_settings->registerChangedCallback("font_shadow_alpha", font_setting_changed);
+	}
+	else if (m_currentMode == FM_Fallback) {
+		m_settings->registerChangedCallback("fallback_font_size", font_setting_changed);
+		m_settings->registerChangedCallback("fallback_font_path", font_setting_changed);
+		m_settings->registerChangedCallback("fallback_font_shadow", font_setting_changed);
+		m_settings->registerChangedCallback("fallback_font_shadow_alpha", font_setting_changed);
+	}
+
+	m_settings->registerChangedCallback("mono_font_path", font_setting_changed);
+	m_settings->registerChangedCallback("mono_font_size", font_setting_changed);
+	m_settings->registerChangedCallback("screen_dpi", font_setting_changed);
+	m_settings->registerChangedCallback("gui_scaling", font_setting_changed);
+}
+
+/******************************************************************************/
+FontEngine::~FontEngine()
+{
+	cleanCache();
+}
+
+/******************************************************************************/
+void FontEngine::cleanCache()
+{
+	for ( unsigned int i = 0; i < FM_MaxMode; i++) {
+
+		for (std::map<unsigned int, irr::gui::IGUIFont*>::iterator iter
+				= m_font_cache[i].begin();
+				iter != m_font_cache[i].end(); iter++) {
+			iter->second->drop();
+			iter->second = NULL;
+		}
+		m_font_cache[i].clear();
+	}
+}
+
+/******************************************************************************/
+irr::gui::IGUIFont* FontEngine::getFont(unsigned int font_size, FontMode mode)
+{
+	if (mode == FM_Unspecified) {
+		mode = m_currentMode;
+	}
+	else if ((mode == FM_Mono) && (m_currentMode == FM_Simple)) {
+		mode = FM_SimpleMono;
+	}
+
+	if (font_size == FONT_SIZE_UNSPECIFIED) {
+		font_size = m_default_size[mode];
+	}
+
+	if ((font_size == m_lastSize) && (mode == m_lastMode)) {
+		return m_lastFont;
+	}
+
+	if (m_font_cache[mode].find(font_size) == m_font_cache[mode].end()) {
+		initFont(font_size, mode);
+	}
+
+	if (m_font_cache[mode].find(font_size) == m_font_cache[mode].end()) {
+		return NULL;
+	}
+
+	m_lastSize = font_size;
+	m_lastMode = mode;
+	m_lastFont = m_font_cache[mode][font_size];
+
+	return m_font_cache[mode][font_size];
+}
+
+/******************************************************************************/
+unsigned int FontEngine::getTextHeight(unsigned int font_size, FontMode mode)
+{
+	irr::gui::IGUIFont* font = getFont(font_size, mode);
+
+	// use current skin font as fallback
+	if (font == NULL) {
+		font = m_env->getSkin()->getFont();
+	}
+	assert(font != NULL);
+
+	return font->getDimension(L"Some unimportant example String").Height;
+}
+
+/******************************************************************************/
+unsigned int FontEngine::getTextWidth(const std::wstring& text,
+		unsigned int font_size, FontMode mode)
+{
+	irr::gui::IGUIFont* font = getFont(font_size, mode);
+
+	// use current skin font as fallback
+	if (font == NULL) {
+		font = m_env->getSkin()->getFont();
+	}
+	assert(font != NULL);
+
+	return font->getDimension(text.c_str()).Width;
+}
+
+
+/** get line height for a specific font (including empty room between lines) */
+unsigned int FontEngine::getLineHeight(unsigned int font_size, FontMode mode)
+{
+	irr::gui::IGUIFont* font = getFont(font_size, mode);
+
+	// use current skin font as fallback
+	if (font == NULL) {
+		font = m_env->getSkin()->getFont();
+	}
+	assert(font != NULL);
+
+	return font->getDimension(L"Some unimportant example String").Height
+			+ font->getKerningHeight();
+}
+
+/******************************************************************************/
+unsigned int FontEngine::getDefaultFontSize()
+{
+	return m_default_size[m_currentMode];
+}
+
+/******************************************************************************/
+void FontEngine::readSettings()
+{
+#if USE_FREETYPE
+	if (g_settings->getBool("freetype")) {
+		m_default_size[FM_Standard] = m_settings->getU16("font_size");
+		m_default_size[FM_Fallback] = m_settings->getU16("fallback_font_size");
+		m_default_size[FM_Mono]     = m_settings->getU16("mono_font_size");
+
+		if (is_yes(gettext("needs_fallback_font"))) {
+			m_currentMode = FM_Fallback;
+		}
+		else {
+			m_currentMode = FM_Standard;
+		}
+	}
+#endif
+	m_default_size[FM_Simple]       = m_settings->getU16("font_size");
+	m_default_size[FM_SimpleMono]   = m_settings->getU16("mono_font_size");
+
+	cleanCache();
+	updateFontCache();
+	updateSkin();
+}
+
+/******************************************************************************/
+void FontEngine::updateSkin()
+{
+	gui::IGUIFont *font = getFont();
+
+	if (font)
+		m_env->getSkin()->setFont(font);
+	else
+		errorstream << "FontEngine: Default font file: " <<
+				"\n\t\"" << m_settings->get("font_path") << "\"" <<
+				"\n\trequired for current screen configuration was not found" <<
+				" or was invalid file format." <<
+				"\n\tUsing irrlicht default font." << std::endl;
+
+	// If we did fail to create a font our own make irrlicht find a default one
+	font = m_env->getSkin()->getFont();
+	assert(font);
+
+	u32 text_height = font->getDimension(L"Hello, world!").Height;
+	infostream << "text_height=" << text_height << std::endl;
+}
+
+/******************************************************************************/
+void FontEngine::updateFontCache()
+{
+	/* the only font to be initialized is default one,
+	 * all others are re-initialized on demand */
+	initFont(m_default_size[m_currentMode], m_currentMode);
+
+	/* reset font quick access */
+	m_lastMode = FM_Unspecified;
+	m_lastSize = 0;
+	m_lastFont = NULL;
+}
+
+/******************************************************************************/
+void FontEngine::initFont(unsigned int basesize, FontMode mode)
+{
+
+	std::string font_config_prefix;
+
+	if (mode == FM_Unspecified) {
+		mode = m_currentMode;
+	}
+
+	switch (mode) {
+
+		case FM_Standard:
+			font_config_prefix = "";
+			break;
+
+		case FM_Fallback:
+			font_config_prefix = "fallback_";
+			break;
+
+		case FM_Mono:
+			font_config_prefix = "mono_";
+			if (m_currentMode == FM_Simple)
+				mode = FM_SimpleMono;
+			break;
+
+		case FM_Simple: /* Fallthrough */
+		case FM_SimpleMono: /* Fallthrough */
+		default:
+			font_config_prefix = "";
+
+	}
+
+	if (m_font_cache[mode].find(basesize) != m_font_cache[mode].end())
+		return;
+
+	if ((mode == FM_Simple) || (mode == FM_SimpleMono)) {
+		initSimpleFont(basesize, mode);
+		return;
+	}
+#if USE_FREETYPE
+	else {
+		if (! is_yes(m_settings->get("freetype"))) {
+			return;
+		}
+		unsigned int size = floor(
+				porting::getDisplayDensity() *
+				m_settings->getFloat("gui_scaling") *
+				basesize);
+		u32 font_shadow       = 0;
+		u32 font_shadow_alpha = 0;
+
+		try {
+			font_shadow =
+					g_settings->getU16(font_config_prefix + "font_shadow");
+		} catch (SettingNotFoundException&) {}
+		try {
+			font_shadow_alpha =
+					g_settings->getU16(font_config_prefix + "font_shadow_alpha");
+		} catch (SettingNotFoundException&) {}
+
+		std::string font_path = g_settings->get(font_config_prefix + "font_path");
+
+		if (font_path.substr(font_path.length() -4) != ".ttf") {
+			errorstream << "FontEngine: \"" << font_path
+					<< "\" doesn't seem to be a ttf File." << std::endl;
+			return;
+		}
+
+		irr::gui::IGUIFont* font = gui::CGUITTFont::createTTFont(m_env,
+				font_path.c_str(), size, true, true, font_shadow,
+				font_shadow_alpha);
+
+		if (font != NULL) {
+			font->grab();
+			m_font_cache[mode][basesize] = font;
+		}
+		else {
+			errorstream << "FontEngine: failed to load freetype font: "
+					<< font_path << std::endl;
+		}
+	}
+#endif
+}
+
+/** initialize a font without freetype */
+void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode)
+{
+	assert((mode == FM_Simple) || (mode == FM_SimpleMono));
+
+	std::string font_path = "";
+	if (mode == FM_Simple) {
+		font_path = m_settings->get("font_path");
+	} else {
+		font_path = m_settings->get("mono_font_path");
+	}
+	std::string basename = font_path;
+	std::string ending = font_path.substr(font_path.length() -4);
+
+	if (ending == ".ttf") {
+		errorstream << "FontEngine: Not trying to open \"" << font_path
+				<< "\" which seems to be a truetype font." << std::endl;
+		return;
+	}
+
+	if ((ending == ".xml") || ( ending == ".png")) {
+		basename = font_path.substr(0,font_path.length()-4);
+	}
+
+	if (basesize == FONT_SIZE_UNSPECIFIED)
+		basesize = DEFAULT_FONT_SIZE;
+
+	unsigned int size = floor(
+			porting::getDisplayDensity() *
+			m_settings->getFloat("gui_scaling") *
+			basesize);
+
+	irr::gui::IGUIFont* font = NULL;
+
+	for(unsigned int offset = 0; offset < MAX_FONT_SIZE_OFFSET; offset++) {
+
+		// try opening positive offset
+		std::stringstream fontsize_plus_png;
+		fontsize_plus_png << basename << "_" << (size + offset) << ".png";
+
+		if (fs::PathExists(fontsize_plus_png.str())) {
+			font = m_env->getFont(fontsize_plus_png.str().c_str());
+
+			if (font) {
+				verbosestream << "FontEngine: found font: " << fontsize_plus_png.str() << std::endl;
+				break;
+			}
+		}
+
+		std::stringstream fontsize_plus_xml;
+		fontsize_plus_xml << basename << "_" << (size + offset) << ".xml";
+
+		if (fs::PathExists(fontsize_plus_xml.str())) {
+			font = m_env->getFont(fontsize_plus_xml.str().c_str());
+
+			if (font) {
+				verbosestream << "FontEngine: found font: " << fontsize_plus_xml.str() << std::endl;
+				break;
+			}
+		}
+
+		// try negative offset
+		std::stringstream fontsize_minus_png;
+		fontsize_minus_png << basename << "_" << (size - offset) << ".png";
+
+		if (fs::PathExists(fontsize_minus_png.str())) {
+			font = m_env->getFont(fontsize_minus_png.str().c_str());
+
+			if (font) {
+				verbosestream << "FontEngine: found font: " << fontsize_minus_png.str() << std::endl;
+				break;
+			}
+		}
+
+		std::stringstream fontsize_minus_xml;
+		fontsize_minus_xml << basename << "_" << (size - offset) << ".xml";
+
+		if (fs::PathExists(fontsize_minus_xml.str())) {
+			font = m_env->getFont(fontsize_minus_xml.str().c_str());
+
+			if (font) {
+				verbosestream << "FontEngine: found font: " << fontsize_minus_xml.str() << std::endl;
+				break;
+			}
+		}
+	}
+
+	// try name direct
+	if (font == NULL) {
+		if (fs::PathExists(font_path)) {
+			font = m_env->getFont(font_path.c_str());
+			if (font)
+				verbosestream << "FontEngine: found font: " << font_path << std::endl;
+		}
+	}
+
+	if (font != NULL) {
+		font->grab();
+		m_font_cache[mode][basesize] = font;
+	}
+}

+ 140 - 0
src/fontengine.h

@@ -0,0 +1,140 @@
+/*
+Minetest
+Copyright (C) 2010-2014 sapier <sapier at gmx dot net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef __FONTENGINE_H__
+#define __FONTENGINE_H__
+
+#include <map>
+#include <vector>
+#include "IGUIFont.h"
+#include "IGUISkin.h"
+#include "IGUIEnvironment.h"
+#include "settings.h"
+
+#define FONT_SIZE_UNSPECIFIED 0xFFFFFFFF
+
+enum FontMode {
+	FM_Standard = 0,
+	FM_Mono,
+	FM_Fallback,
+	FM_Simple,
+	FM_SimpleMono,
+	FM_MaxMode,
+	FM_Unspecified
+};
+
+class FontEngine
+{
+public:
+
+	FontEngine(Settings* main_settings, gui::IGUIEnvironment* env);
+
+	~FontEngine();
+
+	/** get Font */
+	irr::gui::IGUIFont* getFont(unsigned int font_size=FONT_SIZE_UNSPECIFIED,
+			FontMode mode=FM_Unspecified);
+
+	/** get text height for a specific font */
+	unsigned int getTextHeight(unsigned int font_size=FONT_SIZE_UNSPECIFIED,
+			FontMode mode=FM_Unspecified);
+
+	/** get text width if a text for a specific font */
+	unsigned int getTextWidth(const std::string& text,
+			unsigned int font_size=FONT_SIZE_UNSPECIFIED,
+			FontMode mode=FM_Unspecified)
+	{
+		return getTextWidth(narrow_to_wide(text));
+	}
+
+	/** get text width if a text for a specific font */
+	unsigned int getTextWidth(const std::wstring& text,
+			unsigned int font_size=FONT_SIZE_UNSPECIFIED,
+			FontMode mode=FM_Unspecified);
+
+	/** get line height for a specific font (including empty room between lines) */
+	unsigned int getLineHeight(unsigned int font_size=FONT_SIZE_UNSPECIFIED,
+			FontMode mode=FM_Unspecified);
+
+	/** get default font size */
+	unsigned int getDefaultFontSize();
+
+	/** initialize font engine */
+	void initialize(Settings* main_settings, gui::IGUIEnvironment* env);
+
+	/** update internal parameters from settings */
+	void readSettings();
+
+private:
+	/** disable copy constructor */
+	FontEngine() :
+		m_settings(NULL),
+		m_env(NULL),
+		m_font_cache(),
+		m_default_size(),
+		m_currentMode(FM_Standard),
+		m_lastMode(),
+		m_lastSize(0),
+		m_lastFont(NULL)
+	{};
+
+	/** update content of font cache in case of a setting change made it invalid */
+	void updateFontCache();
+
+	/** initialize a new font */
+	void initFont(unsigned int basesize, FontMode mode=FM_Unspecified);
+
+	/** initialize a font without freetype */
+	void initSimpleFont(unsigned int basesize, FontMode mode);
+
+	/** update current minetest skin with font changes */
+	void updateSkin();
+
+	/** clean cache */
+	void cleanCache();
+
+	/** pointer to settings for registering callbacks or reading config */
+	Settings* m_settings;
+
+	/** pointer to irrlicht gui environment */
+	gui::IGUIEnvironment* m_env;
+
+	/** internal storage for caching fonts of different size */
+	std::map<unsigned int, irr::gui::IGUIFont*> m_font_cache[FM_MaxMode];
+
+	/** default font size to use */
+	unsigned int m_default_size[FM_MaxMode];
+
+	/** current font engine mode */
+	FontMode m_currentMode;
+
+	/** font mode of last request */
+	FontMode m_lastMode;
+
+	/** size of last request */
+	unsigned int m_lastSize;
+
+	/** last font returned */
+	irr::gui::IGUIFont* m_lastFont;
+
+};
+
+/** interface to access main font engine*/
+extern FontEngine* glb_fontengine;
+
+#endif

+ 27 - 39
src/game.cpp

@@ -70,6 +70,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/pointedthing.h"
 #include "drawscene.h"
 #include "content_cao.h"
+#include "fontengine.h"
 
 #ifdef HAVE_TOUCHSCREENGUI
 #include "touchscreengui.h"
@@ -437,9 +438,8 @@ PointedThing getPointedThing(Client *client, v3f player_position,
 
 /* Profiler display */
 
-void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
-		gui::IGUIFont *font, u32 text_height, u32 show_profiler,
-		u32 show_profiler_max)
+void update_profiler_gui(gui::IGUIStaticText *guitext_profiler, FontEngine *fe,
+		u32 show_profiler, u32 show_profiler_max)
 {
 	if (show_profiler == 0) {
 		guitext_profiler->setVisible(false);
@@ -451,14 +451,14 @@ void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
 		guitext_profiler->setText(text.c_str());
 		guitext_profiler->setVisible(true);
 
-		s32 w = font->getDimension(text.c_str()).Width;
+		s32 w = fe->getTextWidth(text.c_str());
 
 		if (w < 400)
 			w = 400;
 
-		core::rect<s32> rect(6, 4 + (text_height + 5) * 2, 12 + w,
-				     8 + (text_height + 5) * 2 +
-				     font->getDimension(text.c_str()).Height);
+		core::rect<s32> rect(6, 4 + (fe->getTextHeight() + 5) * 2, 12 + w,
+				     8 + (fe->getTextHeight() + 5) * 2 +
+				     fe->getTextHeight());
 		guitext_profiler->setRelativePosition(rect);
 		guitext_profiler->setVisible(true);
 	}
@@ -1136,8 +1136,7 @@ static void show_pause_menu(GUIFormSpecMenu **cur_formspec,
 /******************************************************************************/
 static void updateChat(Client &client, f32 dtime, bool show_debug,
 		const v2u32 &screensize, bool show_chat, u32 show_profiler,
-		ChatBackend &chat_backend, gui::IGUIStaticText *guitext_chat,
-		gui::IGUIFont *font)
+		ChatBackend &chat_backend, gui::IGUIStaticText *guitext_chat)
 {
 	// Add chat log output for errors to be shown in chat
 	static LogOutputBuffer chat_log_error_buf(LMT_ERROR);
@@ -1160,9 +1159,7 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
 	// Display all messages in a static text element
 	unsigned int recent_chat_count = chat_backend.getRecentBuffer().getLineCount();
 	std::wstring recent_chat       = chat_backend.getRecentChat();
-
-	// TODO replace by fontengine fcts
-	unsigned int line_height       = font->getDimension(L"Ay").Height + font->getKerningHeight();
+	unsigned int line_height       = glb_fontengine->getLineHeight();
 
 	guitext_chat->setText(recent_chat.c_str());
 
@@ -1173,7 +1170,7 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
 		chat_y += line_height;
 
 	// first pass to calculate height of text to be set
-	s32 width = std::min(font->getDimension(recent_chat.c_str()).Width + 10,
+	s32 width = std::min(glb_fontengine->getTextWidth(recent_chat) + 10,
 			     porting::getWindowSize().X - 20);
 	core::rect<s32> rect(10, chat_y, width, chat_y + porting::getWindowSize().Y);
 	guitext_chat->setRelativePosition(rect);
@@ -1402,7 +1399,6 @@ public:
 			bool random_input,
 			InputHandler *input,
 			IrrlichtDevice *device,
-			gui::IGUIFont *font,
 			const std::string &map_dir,
 			const std::string &playername,
 			const std::string &password,
@@ -1522,8 +1518,6 @@ private:
 	Client *client;
 	Server *server;
 
-	gui::IGUIFont *font;
-
 	IWritableTextureSource *texture_src;
 	IWritableShaderSource *shader_src;
 
@@ -1558,7 +1552,6 @@ private:
 	IrrlichtDevice *device;
 	video::IVideoDriver *driver;
 	scene::ISceneManager *smgr;
-	u32 text_height;
 	bool *kill;
 	std::wstring *error_message;
 	IGameDef *gamedef;                     // Convenience (same as *client)
@@ -1592,7 +1585,6 @@ private:
 Game::Game() :
 	client(NULL),
 	server(NULL),
-	font(NULL),
 	texture_src(NULL),
 	shader_src(NULL),
 	itemdef_manager(NULL),
@@ -1648,7 +1640,6 @@ bool Game::startup(bool *kill,
 		bool random_input,
 		InputHandler *input,
 		IrrlichtDevice *device,
-		gui::IGUIFont *font,
 		const std::string &map_dir,
 		const std::string &playername,
 		const std::string &password,
@@ -1661,7 +1652,6 @@ bool Game::startup(bool *kill,
 {
 	// "cache"
 	this->device        = device;
-	this->font          = font;
 	this->kill          = kill;
 	this->error_message = error_message;
 	this->random_input  = random_input;
@@ -1671,7 +1661,6 @@ bool Game::startup(bool *kill,
 
 	driver              = device->getVideoDriver();
 	smgr                = device->getSceneManager();
-	text_height         = font->getDimension(L"Random test string").Height;
 
 	if (!init(map_dir, address, port, gamespec))
 		return false;
@@ -1934,7 +1923,7 @@ bool Game::createClient(const std::string &playername,
 	}
 
 	// Update cached textures, meshes and materials
-	client->afterContentReceived(device, font);
+	client->afterContentReceived(device, glb_fontengine->getFont());
 
 	/* Camera
 	 */
@@ -1992,8 +1981,8 @@ bool Game::createClient(const std::string &playername,
 	player->hurt_tilt_timer = 0;
 	player->hurt_tilt_strength = 0;
 
-	hud = new Hud(driver, smgr, guienv, font, text_height, gamedef,
-			player, local_inventory);
+	hud = new Hud(driver, smgr, guienv, glb_fontengine->getFont(),
+			glb_fontengine->getTextHeight(), gamedef, player, local_inventory);
 
 	if (!hud) {
 		*error_message = L"Memory error: could not create HUD";
@@ -2022,7 +2011,7 @@ bool Game::initGui(std::wstring *error_message)
 	// Object infos are shown in this
 	guitext_info = guienv->addStaticText(
 			L"",
-			core::rect<s32>(0, 0, 400, text_height * 5 + 5) + v2s32(100, 200),
+			core::rect<s32>(0, 0, 400, glb_fontengine->getTextHeight() * 5 + 5) + v2s32(100, 200),
 			false, true, guiroot);
 
 	// Status text (displays info when showing and hiding GUI stuff, etc.)
@@ -2224,12 +2213,12 @@ bool Game::getServerContent(bool *aborted)
 		if (!client->itemdefReceived()) {
 			wchar_t *text = wgettext("Item definitions...");
 			progress = 0;
-			draw_load_screen(text, device, guienv, font, dtime, progress);
+			draw_load_screen(text, device, guienv, dtime, progress);
 			delete[] text;
 		} else if (!client->nodedefReceived()) {
 			wchar_t *text = wgettext("Node definitions...");
 			progress = 25;
-			draw_load_screen(text, device, guienv, font, dtime, progress);
+			draw_load_screen(text, device, guienv, dtime, progress);
 			delete[] text;
 		} else {
 			std::stringstream message;
@@ -2251,7 +2240,7 @@ bool Game::getServerContent(bool *aborted)
 
 			progress = 50 + client->mediaReceiveProgress() * 50 + 0.5;
 			draw_load_screen(narrow_to_wide(message.str().c_str()), device,
-					guienv, font, dtime, progress);
+					guienv, dtime, progress);
 		}
 	}
 
@@ -2353,7 +2342,7 @@ void Game::updateProfilers(const GameRunData &run_data, const RunStats &stats,
 			g_profiler->print(infostream);
 		}
 
-		update_profiler_gui(guitext_profiler, font, text_height,
+		update_profiler_gui(guitext_profiler, glb_fontengine,
 				run_data.profiler_current_page, run_data.profiler_max_page);
 
 		g_profiler->clear();
@@ -2764,8 +2753,8 @@ void Game::toggleProfiler(float *statustext_time, u32 *profiler_current_page,
 	*profiler_current_page = (*profiler_current_page + 1) % (profiler_max_page + 1);
 
 	// FIXME: This updates the profiler with incomplete values
-	update_profiler_gui(guitext_profiler, font, text_height,
-			    *profiler_current_page, profiler_max_page);
+	update_profiler_gui(guitext_profiler, glb_fontengine, *profiler_current_page,
+			profiler_max_page);
 
 	if (*profiler_current_page != 0) {
 		std::wstringstream sstr;
@@ -3805,7 +3794,7 @@ void Game::updateFrame(std::vector<aabb3f> &highlight_boxes,
 
 	updateChat(*client, dtime, flags.show_debug, screensize,
 			flags.show_chat, runData->profiler_current_page,
-			*chat_backend, guitext_chat, font);
+			*chat_backend, guitext_chat);
 
 	/*
 		Inventory
@@ -3883,7 +3872,7 @@ void Game::updateFrame(std::vector<aabb3f> &highlight_boxes,
 		Profiler graph
 	*/
 	if (flags.show_profiler_graph)
-		graph->draw(10, screensize.Y - 10, driver, font);
+		graph->draw(10, screensize.Y - 10, driver, glb_fontengine->getFont());
 
 	/*
 		Damage flash
@@ -3966,7 +3955,7 @@ void Game::updateGui(float *statustext_time, const RunStats& stats,
 	if (guitext->isVisible()) {
 		core::rect<s32> rect(
 				5,              5,
-				screensize.X,   5 + text_height
+				screensize.X,   5 + glb_fontengine->getTextHeight()
 		);
 		guitext->setRelativePosition(rect);
 	}
@@ -3984,8 +3973,8 @@ void Game::updateGui(float *statustext_time, const RunStats& stats,
 		guitext2->setVisible(true);
 
 		core::rect<s32> rect(
-				5,             5 + text_height,
-				screensize.X,  5 + text_height * 2
+				5,             5 + glb_fontengine->getTextHeight(),
+				screensize.X,  5 + glb_fontengine->getTextHeight() * 2
 		);
 		guitext2->setRelativePosition(rect);
 	} else {
@@ -4096,7 +4085,7 @@ void Game::showOverlayMessage(const char *msg, float dtime,
 		int percent, bool draw_clouds)
 {
 	wchar_t *text = wgettext(msg);
-	draw_load_screen(text, device, guienv, font, dtime, percent, draw_clouds);
+	draw_load_screen(text, device, guienv, dtime, percent, draw_clouds);
 	delete[] text;
 }
 
@@ -4136,7 +4125,6 @@ void the_game(bool *kill,
 		bool random_input,
 		InputHandler *input,
 		IrrlichtDevice *device,
-		gui::IGUIFont *font,
 
 		const std::string &map_dir,
 		const std::string &playername,
@@ -4159,7 +4147,7 @@ void the_game(bool *kill,
 
 	try {
 
-		if (game.startup(kill, random_input, input, device, font, map_dir,
+		if (game.startup(kill, random_input, input, device, map_dir,
 					playername, password, &server_address, port,
 					&error_message, &chat_backend, gamespec,
 					simple_singleplayer_mode)) {

+ 0 - 1
src/game.h

@@ -140,7 +140,6 @@ void the_game(bool *kill,
 		bool random_input,
 		InputHandler *input,
 		IrrlichtDevice *device,
-		gui::IGUIFont *font,
 		const std::string &map_dir,
 		const std::string &playername,
 		const std::string &password,

+ 5 - 22
src/guiChatConsole.cpp

@@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "main.h"  // for g_settings
 #include "porting.h"
 #include "tile.h"
-#include "IGUIFont.h"
+#include "fontengine.h"
 #include <string>
 
 #include "gettext.h"
@@ -92,23 +92,11 @@ GUIChatConsole::GUIChatConsole(
 		m_background_color.setBlue(255);
 	}
 
-	// load the font
-	// FIXME should a custom texture_path be searched too?
-	std::string font_name = g_settings->get("mono_font_path");
-	#if USE_FREETYPE
-	m_use_freetype = g_settings->getBool("freetype");
-	if (m_use_freetype) {
-		u16 font_size = g_settings->getU16("mono_font_size");
-		m_font = gui::CGUITTFont::createTTFont(env, font_name.c_str(), font_size);
-	} else {
-		m_font = env->getFont(font_name.c_str());
-	}
-	#else
-	m_font = env->getFont(font_name.c_str());
-	#endif
+	m_font = glb_fontengine->getFont(FONT_SIZE_UNSPECIFIED, FM_Mono);
+
 	if (m_font == NULL)
 	{
-		dstream << "Unable to load font: " << font_name << std::endl;
+		errorstream << "GUIChatConsole: Unable to load mono font ";
 	}
 	else
 	{
@@ -124,12 +112,7 @@ GUIChatConsole::GUIChatConsole(
 }
 
 GUIChatConsole::~GUIChatConsole()
-{
-#if USE_FREETYPE
-	if (m_use_freetype)
-		m_font->drop();
-#endif
-}
+{}
 
 void GUIChatConsole::openConsole(f32 height)
 {

+ 40 - 9
src/guiEngine.cpp

@@ -35,6 +35,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "clouds.h"
 #include "httpfetch.h"
 #include "log.h"
+#include "fontengine.h"
+
 #ifdef __ANDROID__
 #include "tile.h"
 #include <GLES/gl.h>
@@ -169,12 +171,14 @@ GUIEngine::GUIEngine(	irr::IrrlichtDevice* dev,
 		m_sound_manager = &dummySoundManager;
 
 	//create topleft header
-	core::rect<s32> rect(0, 0, 500, 20);
+	std::wstring t = narrow_to_wide(std::string("Minetest ") +
+			minetest_version_hash);
+
+	core::rect<s32> rect(0, 0, glb_fontengine->getTextWidth(t), glb_fontengine->getTextHeight());
 	rect += v2s32(4, 0);
-	std::string t = std::string("Minetest ") + minetest_version_hash;
 
 	m_irr_toplefttext =
-		m_device->getGUIEnvironment()->addStaticText(narrow_to_wide(t).c_str(),
+		m_device->getGUIEnvironment()->addStaticText(t.c_str(),
 		rect,false,true,0,-1);
 
 	//create formspecsource
@@ -256,7 +260,16 @@ void GUIEngine::run()
 
 	cloudInit();
 
-	while(m_device->run() && (!m_startgame) && (!m_kill)) {
+	unsigned int text_height = glb_fontengine->getTextHeight();
+
+	while(m_device->run() && (!m_startgame) && (!m_kill))
+	{
+		//check if we need to update the "upper left corner"-text
+		if (text_height != glb_fontengine->getTextHeight()) {
+			updateTopLeftTextSize();
+			text_height = glb_fontengine->getTextHeight();
+		}
+
 		driver->beginScene(true, true, video::SColor(255,140,186,250));
 
 		if (m_clouds_enabled)
@@ -558,14 +571,32 @@ bool GUIEngine::downloadFile(std::string url, std::string target)
 /******************************************************************************/
 void GUIEngine::setTopleftText(std::string append)
 {
-	std::string toset = std::string("Minetest ") + minetest_version_hash;
+	std::wstring toset = narrow_to_wide( std::string("Minetest ") +
+			minetest_version_hash);
 
-	if (append != "") {
-		toset += " / ";
-		toset += append;
+	if (append != "")
+	{
+		toset += L" / ";
+		toset += narrow_to_wide(append);
 	}
 
-	m_irr_toplefttext->setText(narrow_to_wide(toset).c_str());
+	m_irr_toplefttext->setText(toset.c_str());
+
+	updateTopLeftTextSize();
+}
+
+/******************************************************************************/
+void GUIEngine::updateTopLeftTextSize()
+{
+	std::wstring text = m_irr_toplefttext->getText();
+
+	core::rect<s32> rect(0, 0, glb_fontengine->getTextWidth(text), glb_fontengine->getTextHeight());
+		rect += v2s32(4, 0);
+
+	m_irr_toplefttext->remove();
+	m_irr_toplefttext =
+		m_device->getGUIEnvironment()->addStaticText(text.c_str(),
+		rect,false,true,0,-1);
 }
 
 /******************************************************************************/

+ 3 - 0
src/guiEngine.h

@@ -188,6 +188,9 @@ private:
 	/** handler to limit frame rate within main menu */
 	void limitFrameRate();
 
+	/** update size of topleftext element */
+	void updateTopLeftTextSize();
+
 	/** device to draw at */
 	irr::IrrlichtDevice*     m_device;
 	/** parent gui element */

+ 29 - 13
src/guiFormSpecMenu.cpp

@@ -89,7 +89,6 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
 	m_lock(false),
 	m_form_src(fsrc),
 	m_text_dst(tdst),
-	m_font(dev->getGUIEnvironment()->getSkin()->getFont()),
 	m_formspec_version(0)
 #ifdef __ANDROID__
 	,m_JavaDialogFieldName(L"")
@@ -107,9 +106,6 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
 	m_doubleclickdetect[1].pos = v2s32(0, 0);
 
 	m_tooltip_show_delay = (u32)g_settings->getS32("tooltip_show_delay");
-
-	m_btn_height = g_settings->getS32("font_size") +2;
-	assert(m_btn_height > 0);
 }
 
 GUIFormSpecMenu::~GUIFormSpecMenu()
@@ -437,9 +433,14 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data,std::string element)
 
 		std::wstring wlabel = narrow_to_wide(label.c_str());
 
+		gui::IGUIFont *font = NULL;
+		gui::IGUISkin* skin = Environment->getSkin();
+		if (skin)
+			font = skin->getFont();
+
 		core::rect<s32> rect = core::rect<s32>(
 				pos.X, pos.Y + ((imgsize.Y/2) - m_btn_height),
-				pos.X + m_font->getDimension(wlabel.c_str()).Width + 25, // text size + size of checkbox
+				pos.X + font->getDimension(wlabel.c_str()).Width + 25, // text size + size of checkbox
 				pos.Y + ((imgsize.Y/2) + m_btn_height));
 
 		FieldSpec spec(
@@ -1248,9 +1249,14 @@ void GUIFormSpecMenu::parseLabel(parserData* data,std::string element)
 
 		std::wstring wlabel = narrow_to_wide(text.c_str());
 
+		gui::IGUIFont *font = NULL;
+				gui::IGUISkin* skin = Environment->getSkin();
+				if (skin)
+					font = skin->getFont();
+
 		core::rect<s32> rect = core::rect<s32>(
 				pos.X, pos.Y+((imgsize.Y/2) - m_btn_height),
-				pos.X + m_font->getDimension(wlabel.c_str()).Width,
+				pos.X + font->getDimension(wlabel.c_str()).Width,
 				pos.Y+((imgsize.Y/2) + m_btn_height));
 
 		FieldSpec spec(
@@ -1282,12 +1288,18 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element)
 		pos.X += stof(v_pos[0]) * (float)spacing.X;
 		pos.Y += stof(v_pos[1]) * (float)spacing.Y;
 
+		gui::IGUIFont *font = NULL;
+				gui::IGUISkin* skin = Environment->getSkin();
+				if (skin)
+					font = skin->getFont();
+
 		core::rect<s32> rect = core::rect<s32>(
 				pos.X, pos.Y+((imgsize.Y/2)- m_btn_height),
 				pos.X+15, pos.Y +
-					(m_font->getKerningHeight() +
-					m_font->getDimension(text.c_str()).Height)
-					* (text.length()+1));
+					(font->getKerningHeight() +
+					font->getDimension(text.c_str()).Height)
+					* (text.length()+1)
+					+((imgsize.Y/2)- m_btn_height));
 		//actually text.length() would be correct but adding +1 avoids to break all mods
 
 		if(data->bp_set != 2)
@@ -1837,6 +1849,14 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
 		return;
 	}
 
+	gui::IGUIFont *font = NULL;
+			gui::IGUISkin* skin = Environment->getSkin();
+			if (skin)
+				font = skin->getFont();
+
+	m_btn_height = font->getDimension(L"Some unimportant test String").Height;
+	assert(m_btn_height > 0);
+
 	parserData mydata;
 
 	//preserve tables
@@ -2048,7 +2068,6 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
 {
 	video::IVideoDriver* driver = Environment->getVideoDriver();
 
-	// Get font
 	gui::IGUIFont *font = NULL;
 	gui::IGUISkin* skin = Environment->getSkin();
 	if (skin)
@@ -2194,9 +2213,6 @@ void GUIFormSpecMenu::drawMenu()
 
 	updateSelectedItem();
 
-	gui::IGUISkin* skin = Environment->getSkin();
-	if (!skin)
-		return;
 	video::IVideoDriver* driver = Environment->getVideoDriver();
 
 	v2u32 screenSize = driver->getScreenSize();

+ 0 - 1
src/guiFormSpecMenu.h

@@ -345,7 +345,6 @@ protected:
 private:
 	IFormSource      *m_form_src;
 	TextDest         *m_text_dst;
-	gui::IGUIFont    *m_font;
 	unsigned int      m_formspec_version;
 
 	typedef struct {

+ 7 - 44
src/main.cpp

@@ -69,9 +69,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "profiler.h"
 #include "log.h"
 #include "mods.h"
-#if USE_FREETYPE
-#include "xCGUITTFont.h"
-#endif
 #include "util/string.h"
 #include "subgame.h"
 #include "quicktune.h"
@@ -80,6 +77,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "guiEngine.h"
 #include "mapsector.h"
 #include "player.h"
+#include "fontengine.h"
 
 #include "database-sqlite3.h"
 #ifdef USE_LEVELDB
@@ -1571,13 +1569,11 @@ ClientLauncher::~ClientLauncher()
 	if (input)
 		delete input;
 
+	if (glb_fontengine)
+		delete glb_fontengine;
+
 	if (device)
 		device->drop();
-
-#if USE_FREETYPE
-	if (use_freetype && font != NULL)
-		font->drop();
-#endif
 }
 
 bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
@@ -1593,8 +1589,6 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
 		return false;
 	}
 
-	late_init_default_settings(g_settings);
-
 	// Speed tests (done after irrlicht is loaded to get timer)
 	if (cmd_args.getFlag("speedtests")) {
 		dstream << "Running speed tests" << std::endl;
@@ -1630,45 +1624,15 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
 
 	guienv = device->getGUIEnvironment();
 	skin = guienv->getSkin();
-	std::string font_path = g_settings->get("font_path");
-
-#if USE_FREETYPE
-
-	if (use_freetype) {
-		std::string fallback;
-		if (is_yes(gettext("needs_fallback_font")))
-			fallback = "fallback_";
-		u16 font_size = g_settings->getU16(fallback + "font_size");
-		font_path = g_settings->get(fallback + "font_path");
-		u32 font_shadow = g_settings->getU16(fallback + "font_shadow");
-		u32 font_shadow_alpha = g_settings->getU16(fallback + "font_shadow_alpha");
-		font = gui::CGUITTFont::createTTFont(guienv,
-				font_path.c_str(), font_size, true, true,
-				font_shadow, font_shadow_alpha);
-	} else {
-		font = guienv->getFont(font_path.c_str());
-	}
-#else
-	font = guienv->getFont(font_path.c_str());
-#endif
-	if (font)
-		skin->setFont(font);
-	else
-		errorstream << "WARNING: Font file was not found. Using default font."
-		            << std::endl;
-
-	font = skin->getFont(); // If font was not found, this will get us one
-	assert(font);
-
-	u32 text_height = font->getDimension(L"Hello, world!").Height;
-	infostream << "text_height=" << text_height << std::endl;
-
 	skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255));
 	skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255, 0, 0, 0));
 	skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255, 0, 0, 0));
 	skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255, 70, 100, 50));
 	skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255, 255, 255, 255));
 
+	glb_fontengine = new FontEngine(g_settings, guienv);
+	assert(glb_fontengine != NULL);
+
 #if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
 	// Irrlicht 1.8 input colours
 	skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128));
@@ -1764,7 +1728,6 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
 				random_input,
 				input,
 				device,
-				font,
 				worldspec.path,
 				current_playername,
 				current_password,

+ 1 - 10
src/porting.cpp

@@ -553,16 +553,7 @@ v2u32 getWindowSize() {
 #ifndef __ANDROID__
 
 float getDisplayDensity() {
-	float gui_scaling = g_settings->getFloat("gui_scaling");
-	// using Y here feels like a bug, this needs to be discussed later!
-	if (getWindowSize().Y <= 800) {
-		return (2.0/3.0) * gui_scaling;
-	}
-	if (getWindowSize().Y <= 1280) {
-		return 1.0 * gui_scaling;
-	}
-
-	return (4.0/3.0) * gui_scaling;
+	return g_settings->getFloat("screen_dpi")/96.0;
 }
 
 v2u32 getDisplaySize() {

+ 24 - 0
src/settings.cpp

@@ -620,6 +620,13 @@ void Settings::update(const Settings &other)
 }
 
 
+void Settings::registerChangedCallback(std::string name,
+		setting_changed_callback cbf)
+{
+	m_callbacks[name].push_back(cbf);
+}
+
+
 inline bool Settings::parseConfigObject(std::istream &is,
 		std::string &name, std::string &value)
 {
@@ -701,3 +708,20 @@ void Settings::clearNoLock()
 	m_defaults.clear();
 }
 
+void Settings::doCallbacks(const std::string name)
+{
+	std::vector<setting_changed_callback> tempvector;
+	{
+		JMutexAutoLock lock(m_mutex);
+		if (m_callbacks.find(name) != m_callbacks.end())
+		{
+			tempvector = m_callbacks[name];
+		}
+	}
+
+	for (std::vector<setting_changed_callback>::iterator iter = tempvector.begin();
+			iter != tempvector.end(); iter ++)
+	{
+		(*iter)(name);
+	}
+}

+ 6 - 1
src/settings.h

@@ -45,6 +45,9 @@ struct ValueSpec
 	const char *help;
 };
 
+/** function type to register a changed callback */
+typedef void (*setting_changed_callback)(const std::string);
+
 
 class Settings
 {
@@ -139,7 +142,7 @@ public:
 	void clear();
 	void updateValue(const Settings &other, const std::string &name);
 	void update(const Settings &other);
-
+	void registerChangedCallback(std::string name, setting_changed_callback cbf);
 
 private:
 	/***********************
@@ -166,9 +169,11 @@ private:
 	void updateNoLock(const Settings &other);
 	void clearNoLock();
 
+	void doCallbacks(std::string name);
 
 	std::map<std::string, std::string> m_settings;
 	std::map<std::string, std::string> m_defaults;
+	std::map<std::string, std::vector<setting_changed_callback> > m_callbacks;
 	// All methods that access m_settings/m_defaults directly should lock this.
 	mutable JMutex m_mutex;
 };