Переглянути джерело

Merge pull request #4664 from IvanSavenko/ttf_fonts

Integrate true type fonts into VCMI
Ivan Savenko 1 рік тому
батько
коміт
bee2e7200c
42 змінених файлів з 977 додано та 772 видалено
  1. 1 1
      .github/workflows/github.yml
  2. BIN
      Mods/vcmi/Data/NotoSans-Medium.ttf
  3. BIN
      Mods/vcmi/Data/NotoSerif-Black.ttf
  4. BIN
      Mods/vcmi/Data/NotoSerif-Bold.ttf
  5. BIN
      Mods/vcmi/Data/NotoSerif-Medium.ttf
  6. 2 2
      client/CMakeLists.txt
  7. 4 2
      client/battle/BattleInterfaceClasses.cpp
  8. 4 1
      client/battle/BattleOverlayLogVisualizer.cpp
  9. 2 2
      client/battle/BattleStacksController.cpp
  10. 2 1
      client/gui/CGuiHandler.cpp
  11. 4 2
      client/gui/InterfaceObjectConfigurable.cpp
  12. 6 3
      client/lobby/CSelectionBase.cpp
  13. 6 3
      client/lobby/OptionsTab.cpp
  14. 6 2
      client/mapView/MapOverlayLogVisualizer.cpp
  15. 2 2
      client/mapView/MapViewCache.cpp
  16. 13 8
      client/render/Canvas.cpp
  17. 1 1
      client/render/Canvas.h
  18. 10 2
      client/render/EFont.h
  19. 0 34
      client/render/Graphics.cpp
  20. 2 22
      client/render/Graphics.h
  21. 21 1
      client/render/IFont.cpp
  22. 19 5
      client/render/IFont.h
  23. 5 0
      client/render/IRenderHandler.h
  24. 30 28
      client/renderSDL/CBitmapFont.cpp
  25. 7 5
      client/renderSDL/CBitmapFont.h
  26. 0 127
      client/renderSDL/CBitmapHanFont.cpp
  27. 0 40
      client/renderSDL/CBitmapHanFont.h
  28. 37 27
      client/renderSDL/CTrueTypeFont.cpp
  29. 7 4
      client/renderSDL/CTrueTypeFont.h
  30. 136 0
      client/renderSDL/FontChain.cpp
  31. 43 0
      client/renderSDL/FontChain.h
  32. 30 1
      client/renderSDL/RenderHandler.cpp
  33. 4 0
      client/renderSDL/RenderHandler.h
  34. 4 1
      client/widgets/CComponent.cpp
  35. 3 1
      client/widgets/CTextInput.cpp
  36. 25 16
      client/widgets/TextControls.cpp
  37. 5 3
      client/windows/CMessage.cpp
  38. 15 14
      config/fonts.json
  39. 11 0
      config/schemas/settings.json
  40. 33 21
      launcher/settingsView/csettingsview_moc.cpp
  41. 7 1
      launcher/settingsView/csettingsview_moc.h
  42. 470 389
      launcher/settingsView/csettingsview_moc.ui

+ 1 - 1
.github/workflows/github.yml

@@ -352,7 +352,7 @@ jobs:
           run: |
             find . -path ./.git -prune -o -path ./AI/FuzzyLite -prune -o -path ./test/googletest \
             -o -path ./osx  -prune -o -type f \
-            -not -name '*.png' -and -not -name '*.vcxproj*' -and -not -name '*.props' -and -not -name '*.wav' -and -not -name '*.webm' -and -not -name '*.ico' -and -not -name '*.bat' -print0 | \
+            -not -name '*.png' -and -not -name '*.ttf' -and -not -name '*.wav' -and -not -name '*.webm' -and -not -name '*.ico' -and -not -name '*.bat' -print0 | \
             { ! xargs -0 grep -l -z -P '\r\n'; }
 
         - name: Validate JSON

BIN
Mods/vcmi/Data/NotoSans-Medium.ttf


BIN
Mods/vcmi/Data/NotoSerif-Black.ttf


BIN
Mods/vcmi/Data/NotoSerif-Bold.ttf


BIN
Mods/vcmi/Data/NotoSerif-Medium.ttf


+ 2 - 2
client/CMakeLists.txt

@@ -95,10 +95,10 @@ set(vcmiclientcommon_SRCS
 	render/ImageLocator.cpp
 
 	renderSDL/CBitmapFont.cpp
-	renderSDL/CBitmapHanFont.cpp
 	renderSDL/CTrueTypeFont.cpp
 	renderSDL/CursorHardware.cpp
 	renderSDL/CursorSoftware.cpp
+	renderSDL/FontChain.cpp
 	renderSDL/ImageScaled.cpp
 	renderSDL/RenderHandler.cpp
 	renderSDL/SDLImage.cpp
@@ -303,10 +303,10 @@ set(vcmiclientcommon_HEADERS
 	render/IScreenHandler.h
 
 	renderSDL/CBitmapFont.h
-	renderSDL/CBitmapHanFont.h
 	renderSDL/CTrueTypeFont.h
 	renderSDL/CursorHardware.h
 	renderSDL/CursorSoftware.h
+	renderSDL/FontChain.h
 	renderSDL/ImageScaled.h
 	renderSDL/RenderHandler.h
 	renderSDL/SDLImage.h

+ 4 - 2
client/battle/BattleInterfaceClasses.cpp

@@ -112,9 +112,10 @@ std::vector<std::string> BattleConsole::splitText(const std::string &text)
 
 	boost::split(lines, text, boost::is_any_of("\n"));
 
+	const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
 	for(const auto & line : lines)
 	{
-		if (graphics->fonts[FONT_SMALL]->getStringWidth(text) < pos.w)
+		if (font->getStringWidth(text) < pos.w)
 		{
 			output.push_back(line);
 		}
@@ -1098,7 +1099,8 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn, std::
 		if(currentTurn && !owner->embedded)
 		{
 			std::string tmp = std::to_string(*currentTurn);
-			int len = graphics->fonts[FONT_SMALL]->getStringWidth(tmp);
+			const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
+			int len = font->getStringWidth(tmp);
 			roundRect->pos.w = len + 6;
 			round->setText(tmp);
 		}

+ 4 - 1
client/battle/BattleOverlayLogVisualizer.cpp

@@ -17,7 +17,9 @@
 #include "../render/Colors.h"
 #include "../render/EFont.h"
 #include "../render/IFont.h"
+#include "../render/IRenderHandler.h"
 #include "../gui/TextAlignment.h"
+#include "../gui/CGuiHandler.h"
 #include "../render/Graphics.h"
 
 BattleOverlayLogVisualizer::BattleOverlayLogVisualizer(
@@ -30,7 +32,8 @@ BattleOverlayLogVisualizer::BattleOverlayLogVisualizer(
 void BattleOverlayLogVisualizer::drawText(BattleHex hex, int lineNumber, const std::string & text)
 {
 	Point offset = owner.fieldController->hexPositionLocal(hex).topLeft() + Point(20, 20);
-	int h = graphics->fonts[EFonts::FONT_TINY]->getLineHeight();
+	const auto & font = GH.renderHandler().loadFont(FONT_TINY);
+	int h = font->getLineHeight();
 
 	offset.y += h * lineNumber;
 

+ 2 - 2
client/battle/BattleStacksController.cpp

@@ -318,10 +318,10 @@ void BattleStacksController::showStackAmountBox(Canvas & canvas, const CStack *
 			boxPosition = owner.fieldController->hexPositionLocal(frontPos).center() + Point(-8, -14);
 	}
 
-	Point textPosition = Point(amountBG->dimensions().x/2 + boxPosition.x, boxPosition.y + graphics->fonts[EFonts::FONT_TINY]->getLineHeight() - 6);
+	Point textPosition = Point(amountBG->dimensions().x/2 + boxPosition.x, boxPosition.y + amountBG->dimensions().y/2);
 
 	canvas.draw(amountBG, boxPosition);
-	canvas.drawText(textPosition, EFonts::FONT_TINY, Colors::WHITE, ETextAlignment::TOPCENTER, TextOperations::formatMetric(stack->getCount(), 4));
+	canvas.drawText(textPosition, EFonts::FONT_TINY, Colors::WHITE, ETextAlignment::CENTER, TextOperations::formatMetric(stack->getCount(), 4));
 }
 
 void BattleStacksController::showStack(Canvas & canvas, const CStack * stack)

+ 2 - 1
client/gui/CGuiHandler.cpp

@@ -192,7 +192,8 @@ void CGuiHandler::drawFPSCounter()
 
 	std::string fps = std::to_string(framerate().getFramerate())+" FPS";
 
-	graphics->fonts[FONT_SMALL]->renderTextLeft(screen, fps, Colors::WHITE, Point(8 * scaling, screen->h-22 * scaling));
+	const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
+	font->renderTextLeft(screen, fps, Colors::WHITE, Point(8 * scaling, screen->h-22 * scaling));
 }
 
 bool CGuiHandler::amIGuiThread()

+ 4 - 2
client/gui/InterfaceObjectConfigurable.cpp

@@ -19,6 +19,7 @@
 #include "../gui/Shortcut.h"
 #include "../render/Graphics.h"
 #include "../render/IFont.h"
+#include "../render/IRenderHandler.h"
 #include "../widgets/CComponent.h"
 #include "../widgets/ComboBox.h"
 #include "../widgets/Buttons.h"
@@ -284,7 +285,7 @@ EFonts InterfaceObjectConfigurable::readFont(const JsonNode & config) const
 			return EFonts::FONT_CALLI;
 	}
 	logGlobal->debug("Unknown font attribute");
-	return EFonts::FONT_TIMES;
+	return EFonts::FONT_MEDIUM;
 }
 
 std::pair<std::string, std::string> InterfaceObjectConfigurable::readHintText(const JsonNode & config) const
@@ -357,8 +358,9 @@ std::shared_ptr<CMultiLineLabel> InterfaceObjectConfigurable::buildMultiLineLabe
 	auto color = readColor(config["color"]);
 	auto text = readText(config["text"]);
 	Rect rect = readRect(config["rect"]);
+	const auto & fontPtr = GH.renderHandler().loadFont(font);
 	if(!config["adoptHeight"].isNull() && config["adoptHeight"].Bool())
-		rect.h = graphics->fonts[font]->getLineHeight() * 2;
+		rect.h = fontPtr->getLineHeight() * 2;
 	return std::make_shared<CMultiLineLabel>(rect, font, alignment, color, text);
 }
 

+ 6 - 3
client/lobby/CSelectionBase.cpp

@@ -256,15 +256,17 @@ void InfoCard::changeSelection()
 	if(!showChat)
 		labelGroupPlayers->disable();
 
+	const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
+
 	for(const auto & p : CSH->playerNames)
 	{
 		int slotsUsed = labelGroupPlayers->currentSize();
 		Point labelPosition;
 
 		if(slotsUsed < 4)
-			labelPosition = Point(24, 285 + slotsUsed * graphics->fonts[FONT_SMALL]->getLineHeight()); // left column
+			labelPosition = Point(24, 285 + slotsUsed * font->getLineHeight()); // left column
 		else
-			labelPosition = Point(193, 285 + (slotsUsed - 4) * graphics->fonts[FONT_SMALL]->getLineHeight()); // right column
+			labelPosition = Point(193, 285 + (slotsUsed - 4) * font->getLineHeight()); // right column
 
 		labelGroupPlayers->add(labelPosition.x, labelPosition.y, p.second.name);
 	}
@@ -358,7 +360,8 @@ CChatBox::CChatBox(const Rect & rect)
 	pos += rect.topLeft();
 	setRedrawParent(true);
 
-	const int height = static_cast<int>(graphics->fonts[FONT_SMALL]->getLineHeight());
+	const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
+	const int height = font->getLineHeight();
 	Rect textInputArea(1, rect.h - height, rect.w - 1, height);
 	Rect chatHistoryArea(3, 1, rect.w - 3, rect.h - height - 1);
 	inputBackground = std::make_shared<TransparentFilledRectangle>(textInputArea, ColorRGBA(0,0,0,192));

+ 6 - 3
client/lobby/OptionsTab.cpp

@@ -19,6 +19,7 @@
 #include "../gui/WindowHandler.h"
 #include "../render/Graphics.h"
 #include "../render/IFont.h"
+#include "../render/IRenderHandler.h"
 #include "../media/ISoundPlayer.h"
 #include "../widgets/CComponent.h"
 #include "../widgets/ComboBox.h"
@@ -1034,12 +1035,14 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con
 		labelPlayerNameEdit = std::make_shared<CTextInput>(Rect(6, 3, 95, 15), EFonts::FONT_SMALL, ETextAlignment::CENTER, false);
 		labelPlayerNameEdit->setText(name);
 	}
-	labelWhoCanPlay = std::make_shared<CMultiLineLabel>(Rect(6, 23, 45, (int)graphics->fonts[EFonts::FONT_TINY]->getLineHeight()*2), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->arraytxt[206 + whoCanPlay]);
+	const auto & font = GH.renderHandler().loadFont(FONT_SMALL);
+
+	labelWhoCanPlay = std::make_shared<CMultiLineLabel>(Rect(6, 23, 45, font->getLineHeight()*2), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->arraytxt[206 + whoCanPlay]);
 
 	auto hasHandicap = [this](){ return s->handicap.startBonus.empty() && s->handicap.percentIncome == 100 && s->handicap.percentGrowth == 100; };
 	std::string labelHandicapText = hasHandicap() ? CGI->generaltexth->arraytxt[210] : MetaString::createFromTextID("vcmi.lobby.handicap").toString();
-	labelHandicap = std::make_shared<CMultiLineLabel>(Rect(57, 24, 47, (int)graphics->fonts[EFonts::FONT_TINY]->getLineHeight()*2), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, labelHandicapText);
-	handicap = std::make_shared<LRClickableArea>(Rect(56, 24, 49, (int)graphics->fonts[EFonts::FONT_TINY]->getLineHeight()*2), [](){
+	labelHandicap = std::make_shared<CMultiLineLabel>(Rect(57, 24, 47, font->getLineHeight()*2), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, labelHandicapText);
+	handicap = std::make_shared<LRClickableArea>(Rect(56, 24, 49, font->getLineHeight()*2), [](){
 		if(!CSH->isHost())
 			return;
 		

+ 6 - 2
client/mapView/MapOverlayLogVisualizer.cpp

@@ -17,8 +17,10 @@
 #include "../render/Colors.h"
 #include "../render/EFont.h"
 #include "../render/IFont.h"
+#include "../render/IRenderHandler.h"
 #include "../render/Graphics.h"
 #include "../gui/TextAlignment.h"
+#include "../gui/CGuiHandler.h"
 
 
 MapOverlayLogVisualizer::MapOverlayLogVisualizer(Canvas & target, std::shared_ptr<MapViewModel> model)
@@ -78,8 +80,10 @@ void MapOverlayLogVisualizer::drawText(
 
 	if(viewPort.isInside(pStart))
 	{
-		int w = graphics->fonts[EFonts::FONT_TINY]->getStringWidth(text);
-		int h = graphics->fonts[EFonts::FONT_TINY]->getLineHeight();
+		const auto & font = GH.renderHandler().loadFont(FONT_TINY);
+
+		int w = font->getStringWidth(text);
+		int h = font->getLineHeight();
 
 		pStart.y += h * lineNumber;
 

+ 2 - 2
client/mapView/MapViewCache.cpp

@@ -188,6 +188,8 @@ void MapViewCache::render(const std::shared_ptr<IMapRendererContext> & context,
 
 	if(context->showTextOverlay())
 	{
+		const auto & font = GH.renderHandler().loadFont(FONT_TINY);
+
 		for(int y = dimensions.top(); y < dimensions.bottom(); ++y)
 		{
 			for(int x = dimensions.left(); x < dimensions.right(); ++x)
@@ -204,8 +206,6 @@ void MapViewCache::render(const std::shared_ptr<IMapRendererContext> & context,
 					else
 						position.y -= targetRect.h / 4;
 
-					const auto font = graphics->fonts[EFonts::FONT_TINY];
-
 					Point dimensions(font->getStringWidth(overlay), font->getLineHeight());
 					Rect textRect = Rect(position - dimensions / 2, dimensions).resize(2);
 

+ 13 - 8
client/render/Canvas.cpp

@@ -11,6 +11,7 @@
 #include "Canvas.h"
 
 #include "../gui/CGuiHandler.h"
+#include "../render/IRenderHandler.h"
 #include "../render/IScreenHandler.h"
 #include "../renderSDL/SDL_Extensions.h"
 #include "Colors.h"
@@ -169,23 +170,27 @@ void Canvas::drawBorderDashed(const Rect & target, const ColorRGBA & color)
 
 void Canvas::drawText(const Point & position, const EFonts & font, const ColorRGBA & colorDest, ETextAlignment alignment, const std::string & text )
 {
+	const auto & fontPtr = GH.renderHandler().loadFont(font);
+
 	switch (alignment)
 	{
-	case ETextAlignment::TOPLEFT:      return graphics->fonts[font]->renderTextLeft  (surface, text, colorDest, transformPos(position));
-	case ETextAlignment::TOPCENTER:    return graphics->fonts[font]->renderTextCenter(surface, text, colorDest, transformPos(position));
-	case ETextAlignment::CENTER:       return graphics->fonts[font]->renderTextCenter(surface, text, colorDest, transformPos(position));
-	case ETextAlignment::BOTTOMRIGHT:  return graphics->fonts[font]->renderTextRight (surface, text, colorDest, transformPos(position));
+	case ETextAlignment::TOPLEFT:      return fontPtr->renderTextLeft  (surface, text, colorDest, transformPos(position));
+	case ETextAlignment::TOPCENTER:    return fontPtr->renderTextCenter(surface, text, colorDest, transformPos(position));
+	case ETextAlignment::CENTER:       return fontPtr->renderTextCenter(surface, text, colorDest, transformPos(position));
+	case ETextAlignment::BOTTOMRIGHT:  return fontPtr->renderTextRight (surface, text, colorDest, transformPos(position));
 	}
 }
 
 void Canvas::drawText(const Point & position, const EFonts & font, const ColorRGBA & colorDest, ETextAlignment alignment, const std::vector<std::string> & text )
 {
+	const auto & fontPtr = GH.renderHandler().loadFont(font);
+
 	switch (alignment)
 	{
-	case ETextAlignment::TOPLEFT:      return graphics->fonts[font]->renderTextLinesLeft  (surface, text, colorDest, transformPos(position));
-	case ETextAlignment::TOPCENTER:    return graphics->fonts[font]->renderTextLinesCenter(surface, text, colorDest, transformPos(position));
-	case ETextAlignment::CENTER:       return graphics->fonts[font]->renderTextLinesCenter(surface, text, colorDest, transformPos(position));
-	case ETextAlignment::BOTTOMRIGHT:  return graphics->fonts[font]->renderTextLinesRight (surface, text, colorDest, transformPos(position));
+	case ETextAlignment::TOPLEFT:      return fontPtr->renderTextLinesLeft  (surface, text, colorDest, transformPos(position));
+	case ETextAlignment::TOPCENTER:    return fontPtr->renderTextLinesCenter(surface, text, colorDest, transformPos(position));
+	case ETextAlignment::CENTER:       return fontPtr->renderTextLinesCenter(surface, text, colorDest, transformPos(position));
+	case ETextAlignment::BOTTOMRIGHT:  return fontPtr->renderTextLinesRight (surface, text, colorDest, transformPos(position));
 	}
 }
 

+ 1 - 1
client/render/Canvas.h

@@ -15,7 +15,7 @@
 
 struct SDL_Surface;
 class IImage;
-enum EFonts : int;
+enum EFonts : int8_t;
 
 enum class CanvasScalingPolicy
 {

+ 10 - 2
client/render/EFont.h

@@ -9,7 +9,15 @@
  */
 #pragma once
 
-enum EFonts : int
+enum EFonts : int8_t
 {
-	FONT_BIG, FONT_CALLI, FONT_CREDITS, FONT_HIGH_SCORE, FONT_MEDIUM, FONT_SMALL, FONT_TIMES, FONT_TINY, FONT_VERD
+	FONT_BIG,
+	FONT_CALLI,
+	FONT_CREDITS,
+	FONT_HIGH_SCORE,
+	FONT_MEDIUM,
+	FONT_SMALL,
+	FONT_TIMES,
+	FONT_TINY,
+	FONT_VERD
 };

+ 0 - 34
client/render/Graphics.cpp

@@ -19,25 +19,15 @@
 #include <vcmi/spells/Service.h>
 
 #include "../renderSDL/SDL_Extensions.h"
-#include "../renderSDL/CBitmapFont.h"
-#include "../renderSDL/CBitmapHanFont.h"
-#include "../renderSDL/CTrueTypeFont.h"
 #include "../render/CAnimation.h"
 #include "../render/IImage.h"
-#include "../render/IRenderHandler.h"
-#include "../gui/CGuiHandler.h"
 
 #include "../lib/filesystem/Filesystem.h"
 #include "../lib/filesystem/CBinaryReader.h"
 #include "../../lib/json/JsonNode.h"
 #include "../lib/modding/CModHandler.h"
 #include "../lib/modding/ModScope.h"
-#include "CGameInfo.h"
 #include "../lib/VCMI_Lib.h"
-#include "../CCallback.h"
-#include "../lib/texts/CGeneralTextHandler.h"
-#include "../lib/vcmi_endian.h"
-#include "../lib/CStopWatch.h"
 #include "../lib/CHeroHandler.h"
 
 #include <SDL_surface.h>
@@ -127,7 +117,6 @@ void Graphics::initializeBattleGraphics()
 }
 Graphics::Graphics()
 {
-	loadFonts();
 	loadPaletteAndColors();
 	initializeBattleGraphics();
 	loadErmuToPicture();
@@ -166,29 +155,6 @@ void Graphics::setPlayerFlagColor(SDL_Palette * targetPalette, PlayerColor playe
 	}
 }
 
-void Graphics::loadFonts()
-{
-	const JsonNode config(JsonPath::builtin("config/fonts.json"));
-
-	const JsonVector & bmpConf = config["bitmap"].Vector();
-	const JsonNode   & ttfConf = config["trueType"];
-	const JsonNode   & hanConf = config["bitmapHan"];
-
-	assert(bmpConf.size() == FONTS_NUMBER);
-
-	for (size_t i=0; i<FONTS_NUMBER; i++)
-	{
-		std::string filename = bmpConf[i].String();
-
-		if (!hanConf[filename].isNull())
-			fonts[i] = std::make_shared<CBitmapHanFont>(hanConf[filename]);
-		else if (!ttfConf[filename].isNull()) // no ttf override
-			fonts[i] = std::make_shared<CTrueTypeFont>(ttfConf[filename]);
-		else
-			fonts[i] = std::make_shared<CBitmapFont>(filename);
-	}
-}
-
 void Graphics::loadErmuToPicture()
 {
 	//loading ERMU to picture

+ 2 - 22
client/render/Graphics.h

@@ -9,26 +9,11 @@
  */
 #pragma once
 
-#include "../lib/GameConstants.h"
+#include "../lib/constants/NumericConstants.h"
+#include "../lib/constants/EntityIdentifiers.h"
 #include "../lib/Color.h"
-#include "../lib/filesystem/ResourcePath.h"
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-class CGHeroInstance;
-class CGTownInstance;
-class CHeroClass;
-struct InfoAboutHero;
-struct InfoAboutTown;
-class CGObjectInstance;
-class ObjectTemplate;
-class EntityService;
-class JsonNode;
-
-VCMI_LIB_NAMESPACE_END
 
 struct SDL_Palette;
-class IFont;
 
 /// Handles fonts, hero images, town images, various graphics
 class Graphics
@@ -36,13 +21,8 @@ class Graphics
 	void initializeBattleGraphics();
 	void loadPaletteAndColors();
 	void loadErmuToPicture();
-	void loadFonts();
 
 public:
-	//Fonts
-	static const int FONTS_NUMBER = 9;
-	std::array< std::shared_ptr<IFont>, FONTS_NUMBER> fonts;
-
 	using PlayerPalette = std::array<ColorRGBA, 32>;
 
 	//various graphics

+ 21 - 1
client/render/IFont.cpp

@@ -23,13 +23,33 @@ int IFont::getScalingFactor() const
 	return GH.screenHandler().getScalingFactor();
 }
 
+size_t IFont::getLineHeight() const
+{
+	return getLineHeightScaled() / getScalingFactor();
+}
+
+size_t IFont::getGlyphWidth(const char * data) const
+{
+	return getGlyphWidthScaled(data) / getScalingFactor();
+}
+
 size_t IFont::getStringWidth(const std::string & data) const
+{
+	return getStringWidthScaled(data) / getScalingFactor();
+}
+
+size_t IFont::getFontAscent() const
+{
+	return getFontAscentScaled() / getScalingFactor();
+}
+
+size_t IFont::getStringWidthScaled(const std::string & data) const
 {
 	size_t width = 0;
 
 	for(size_t i=0; i<data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
 	{
-		width += getGlyphWidth(data.data() + i);
+		width += getGlyphWidthScaled(data.data() + i);
 	}
 	return width;
 }

+ 19 - 5
client/render/IFont.h

@@ -19,8 +19,6 @@ struct SDL_Surface;
 class IFont : boost::noncopyable
 {
 protected:
-	/// Internal function to render font, see renderTextLeft
-	virtual void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const = 0;
 
 	int getScalingFactor() const;
 
@@ -29,11 +27,27 @@ public:
 	{}
 
 	/// Returns height of font
-	virtual size_t getLineHeight() const = 0;
+	virtual size_t getLineHeightScaled() const = 0;
+	/// Returns width, in pixels of a character glyph. Pointer must contain at least characterSize valid bytes
+	virtual size_t getGlyphWidthScaled(const char * data) const = 0;
+	/// Return width of the string
+	virtual size_t getStringWidthScaled(const std::string & data) const;
+	/// Returns distance from top of the font glyphs to baseline
+	virtual size_t getFontAscentScaled() const = 0;
+
+	/// Returns height of font
+	size_t getLineHeight() const;
 	/// Returns width, in pixels of a character glyph. Pointer must contain at least characterSize valid bytes
-	virtual size_t getGlyphWidth(const char * data) const = 0;
+	size_t getGlyphWidth(const char * data) const;
 	/// Return width of the string
-	virtual size_t getStringWidth(const std::string & data) const;
+	size_t getStringWidth(const std::string & data) const;
+	/// Returns distance from top of the font glyphs to baseline
+	size_t getFontAscent() const;
+
+	/// Internal function to render font, see renderTextLeft
+	virtual void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const = 0;
+
+	virtual bool canRepresentCharacter(const char * data) const	= 0;
 
 	/**
 	 * @param surface - destination to print text on

+ 5 - 0
client/render/IRenderHandler.h

@@ -17,9 +17,11 @@ VCMI_LIB_NAMESPACE_END
 
 struct SDL_Surface;
 
+class IFont;
 class IImage;
 class CAnimation;
 enum class EImageBlitMode : uint8_t;
+enum EFonts : int8_t;
 
 class IRenderHandler : public boost::noncopyable
 {
@@ -40,4 +42,7 @@ public:
 
 	/// Loads animation using given path
 	virtual std::shared_ptr<CAnimation> loadAnimation(const AnimationPath & path, EImageBlitMode mode) = 0;
+
+	/// Returns font with specified identifer
+	virtual std::shared_ptr<const IFont> loadFont(EFonts font) = 0;
 };

+ 30 - 28
client/renderSDL/CBitmapFont.cpp

@@ -96,21 +96,14 @@ static AtlasLayout doAtlasPacking(const std::map<int, Point> & images)
 	}
 }
 
-void CBitmapFont::loadModFont(const std::string & modName, const ResourcePath & resource, std::unordered_map<CodePoint, EntryFNT> & loadedChars)
+void CBitmapFont::loadFont(const ResourcePath & resource, std::unordered_map<CodePoint, EntryFNT> & loadedChars)
 {
-	if (!CResourceHandler::get(modName)->existsResource(resource))
-	{
-		logGlobal->error("Failed to load font %s from mod %s", resource.getName(), modName);
-		return;
-	}
-
-	auto data = CResourceHandler::get(modName)->load(resource)->readAll();
-	std::string modLanguage = CGI->modh->getModLanguage(modName);
+	auto data = CResourceHandler::get()->load(resource)->readAll();
+	std::string modName = VLC->modh->findResourceOrigin(resource);
+	std::string modLanguage = VLC->modh->getModLanguage(modName);
 	std::string modEncoding = Languages::getLanguageOptions(modLanguage).encoding;
 
-	uint32_t dataHeight = data.first[5];
-
-	maxHeight = std::max(maxHeight, dataHeight);
+	height = data.first[5];
 
 	constexpr size_t symbolsInFile = 0x100;
 	constexpr size_t baseIndex = 32;
@@ -126,10 +119,10 @@ void CBitmapFont::loadModFont(const std::string & modName, const ResourcePath &
 		symbol.leftOffset =  read_le_u32(data.first.get() + baseIndex + charIndex * 12 + 0);
 		symbol.width =       read_le_u32(data.first.get() + baseIndex + charIndex * 12 + 4);
 		symbol.rightOffset = read_le_u32(data.first.get() + baseIndex + charIndex * 12 + 8);
-		symbol.height = dataHeight;
+		symbol.height = height;
 
 		uint32_t pixelDataOffset = read_le_u32(data.first.get() + offsetIndex + charIndex * 4);
-		uint32_t pixelsCount = dataHeight * symbol.width;
+		uint32_t pixelsCount = height * symbol.width;
 
 		symbol.pixels.resize(pixelsCount);
 
@@ -139,21 +132,27 @@ void CBitmapFont::loadModFont(const std::string & modName, const ResourcePath &
 
 		loadedChars[codepoint] = symbol;
 	}
+
+	// Try to use symbol 'L' to detect font 'ascent' - number of pixels above text baseline
+	const auto & symbolL = loadedChars['L'];
+	uint32_t lastNonEmptyRow = 0;
+	for (uint32_t row = 0; row < symbolL.height; ++row)
+	{
+		for (uint32_t col = 0; col < symbolL.width; ++col)
+			if (symbolL.pixels.at(row * symbolL.width + col) == 255)
+				lastNonEmptyRow = std::max(lastNonEmptyRow, row);
+	}
+
+	ascent = lastNonEmptyRow + 1;
 }
 
 CBitmapFont::CBitmapFont(const std::string & filename):
-	maxHeight(0)
+	height(0)
 {
 	ResourcePath resource("data/" + filename, EResType::BMP_FONT);
 
 	std::unordered_map<CodePoint, EntryFNT> loadedChars;
-	loadModFont("core", resource, loadedChars);
-
-	for(const auto & modName : VLC->modh->getActiveMods())
-	{
-		if (CResourceHandler::get(modName)->existsResource(resource))
-			loadModFont(modName, resource, loadedChars);
-	}
+	loadFont(resource, loadedChars);
 
 	std::map<int, Point> atlasSymbol;
 	for (auto const & symbol : loadedChars)
@@ -213,8 +212,6 @@ CBitmapFont::CBitmapFont(const std::string & filename):
 		SDL_FreeSurface(atlasImage);
 		atlasImage = scaledSurface;
 	}
-
-	IMG_SavePNG(atlasImage, ("/home/ivan/font_" + filename).c_str());
 }
 
 CBitmapFont::~CBitmapFont()
@@ -222,12 +219,12 @@ CBitmapFont::~CBitmapFont()
 	SDL_FreeSurface(atlasImage);
 }
 
-size_t CBitmapFont::getLineHeight() const
+size_t CBitmapFont::getLineHeightScaled() const
 {
-	return maxHeight;
+	return height * getScalingFactor();
 }
 
-size_t CBitmapFont::getGlyphWidth(const char * data) const
+size_t CBitmapFont::getGlyphWidthScaled(const char * data) const
 {
 	CodePoint localChar = TextOperations::getUnicodeCodepoint(data, 4);
 
@@ -236,7 +233,12 @@ size_t CBitmapFont::getGlyphWidth(const char * data) const
 	if (iter == chars.end())
 		return 0;
 
-	return iter->second.leftOffset + iter->second.positionInAtlas.w + iter->second.rightOffset;
+	return (iter->second.leftOffset + iter->second.positionInAtlas.w + iter->second.rightOffset) * getScalingFactor();
+}
+
+size_t CBitmapFont::getFontAscentScaled() const
+{
+	return ascent * getScalingFactor();
 }
 
 bool CBitmapFont::canRepresentCharacter(const char *data) const

+ 7 - 5
client/renderSDL/CBitmapFont.h

@@ -40,9 +40,10 @@ class CBitmapFont final : public IFont
 	};
 
 	std::unordered_map<CodePoint, BitmapChar> chars;
-	uint32_t maxHeight;
+	uint32_t height;
+	uint32_t ascent;
 
-	void loadModFont(const std::string & modName, const ResourcePath & resource, std::unordered_map<CodePoint, EntryFNT> & loadedChars);
+	void loadFont(const ResourcePath & resource, std::unordered_map<CodePoint, EntryFNT> & loadedChars);
 
 	void renderCharacter(SDL_Surface * surface, const BitmapChar & character, const ColorRGBA & color, int &posX, int &posY) const;
 	void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const override;
@@ -50,11 +51,12 @@ public:
 	explicit CBitmapFont(const std::string & filename);
 	~CBitmapFont();
 
-	size_t getLineHeight() const override;
-	size_t getGlyphWidth(const char * data) const override;
+	size_t getFontAscentScaled() const override;
+	size_t getLineHeightScaled() const override;
+	size_t getGlyphWidthScaled(const char * data) const override;
 
 	/// returns true if this font contains provided utf-8 character
-	bool canRepresentCharacter(const char * data) const;
+	bool canRepresentCharacter(const char * data) const override;
 	bool canRepresentString(const std::string & data) const;
 
 	friend class CBitmapHanFont;

+ 0 - 127
client/renderSDL/CBitmapHanFont.cpp

@@ -1,127 +0,0 @@
-/*
- * CBitmapHanFont.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#include "StdInc.h"
-#include "CBitmapHanFont.h"
-
-#include "CBitmapFont.h"
-#include "SDL_Extensions.h"
-
-#include "../../lib/filesystem/Filesystem.h"
-#include "../../lib/json/JsonNode.h"
-#include "../../lib/Rect.h"
-#include "../../lib/texts/TextOperations.h"
-
-#include <SDL_surface.h>
-
-size_t CBitmapHanFont::getCharacterDataOffset(size_t index) const
-{
-	size_t rowSize  = (size + 7) / 8; // 1 bit per pixel, rounded up
-	size_t charSize = rowSize * size; // glyph contains "size" rows
-	return index * charSize;
-}
-
-size_t CBitmapHanFont::getCharacterIndex(ui8 first, ui8 second) const
-{
-	if (second > 0x7f )
-		second--;
-
-	return (first - 0x81) * (12*16 - 2) + (second - 0x40);
-}
-
-void CBitmapHanFont::renderCharacter(SDL_Surface * surface, int characterIndex, const ColorRGBA & color, int &posX, int &posY) const
-{
-	//TODO: somewhat duplicated with CBitmapFont::renderCharacter();
-	Rect clipRect;
-	CSDL_Ext::getClipRect(surface, clipRect);
-
-	CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface);
-	uint8_t bpp = surface->format->BytesPerPixel;
-
-	// start of line, may differ from 0 due to end of surface or clipped surface
-	int lineBegin = std::max<int>(0, clipRect.y - posY);
-	int lineEnd   = std::min((int)size, clipRect.y + clipRect.h - posY);
-
-	// start end end of each row, may differ from 0
-	int rowBegin = std::max<int>(0, clipRect.x - posX);
-	int rowEnd   = std::min<int>((int)size, clipRect.x + clipRect.w - posX);
-
-	//for each line in symbol
-	for(int dy = lineBegin; dy <lineEnd; dy++)
-	{
-		uint8_t *dstLine = (uint8_t*)surface->pixels;
-		uint8_t *source = data.first.get() + getCharacterDataOffset(characterIndex);
-
-		// shift source\destination pixels to current position
-		dstLine += (posY+dy) * surface->pitch + posX * bpp;
-		source += ((size + 7) / 8) * dy;
-
-		//for each column in line
-		for(int dx = rowBegin; dx < rowEnd; dx++)
-		{
-			// select current bit in bitmap
-			int bit = (source[dx / 8] << (dx % 8)) & 0x80;
-
-			uint8_t* dstPixel = dstLine + dx*bpp;
-			if (bit != 0)
-				colorPutter(dstPixel, color.r, color.g, color.b);
-		}
-	}
-	posX += (int)size + 1;
-}
-
-void CBitmapHanFont::renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const
-{
-	int posX = pos.x;
-	int posY = pos.y;
-
-	SDL_LockSurface(surface);
-
-	for(size_t i=0; i<data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
-	{
-		std::string localChar = TextOperations::fromUnicode(data.substr(i, TextOperations::getUnicodeCharacterSize(data[i])), "GBK");
-
-		if (localChar.size() == 1)
-			fallback->renderCharacter(surface, fallback->chars[ui8(localChar[0])], color, posX, posY);
-
-		if (localChar.size() == 2)
-			renderCharacter(surface, (int)getCharacterIndex(localChar[0], localChar[1]), color, posX, posY);
-	}
-	SDL_UnlockSurface(surface);
-}
-
-CBitmapHanFont::CBitmapHanFont(const JsonNode &config):
-	fallback(new CBitmapFont(config["fallback"].String())),
-	data(CResourceHandler::get()->load(ResourcePath("data/" + config["name"].String(), EResType::OTHER))->readAll()),
-	size((size_t)config["size"].Float())
-{
-	// basic tests to make sure that fonts are OK
-	// 1) fonts must contain 190 "sections", 126 symbols each.
-	assert(getCharacterIndex(0xfe, 0xff) == 190*126);
-	// 2) ensure that font size is correct - enough to fit all possible symbols
-	assert(getCharacterDataOffset(getCharacterIndex(0xfe, 0xff)) == data.second);
-}
-
-size_t CBitmapHanFont::getLineHeight() const
-{
-	return std::max(size + 1, fallback->getLineHeight());
-}
-
-size_t CBitmapHanFont::getGlyphWidth(const char * data) const
-{
-	std::string localChar = TextOperations::fromUnicode(std::string(data, TextOperations::getUnicodeCharacterSize(data[0])), "GBK");
-
-	if (localChar.size() == 1)
-		return fallback->getGlyphWidth(data);
-
-	if (localChar.size() == 2)
-		return size + 1;
-
-	return 0;
-}

+ 0 - 40
client/renderSDL/CBitmapHanFont.h

@@ -1,40 +0,0 @@
-/*
- * CBitmapHanFont.h, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#pragma once
-
-#include "../render/IFont.h"
-
-VCMI_LIB_NAMESPACE_BEGIN
-class JsonNode;
-VCMI_LIB_NAMESPACE_END
-
-class CBitmapFont;
-
-/// supports multi-byte characters for such languages like Chinese
-class CBitmapHanFont final : public IFont
-{
-	std::unique_ptr<CBitmapFont> fallback;
-	// data, directly copied from file
-	const std::pair<std::unique_ptr<ui8[]>, ui64> data;
-
-	// size of the font. Not available in file but needed for proper rendering
-	const size_t size;
-
-	size_t getCharacterDataOffset(size_t index) const;
-	size_t getCharacterIndex(ui8 first, ui8 second) const;
-
-	void renderCharacter(SDL_Surface * surface, int characterIndex, const ColorRGBA & color, int &posX, int &posY) const;
-	void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const override;
-public:
-	CBitmapHanFont(const JsonNode & config);
-
-	size_t getLineHeight() const override;
-	size_t getGlyphWidth(const char * data) const override;
-};

+ 37 - 27
client/renderSDL/CTrueTypeFont.cpp

@@ -15,6 +15,7 @@
 #include "../render/Colors.h"
 #include "../renderSDL/SDL_Extensions.h"
 
+#include "../../lib/CConfigHandler.h"
 #include "../../lib/json/JsonNode.h"
 #include "../../lib/filesystem/Filesystem.h"
 #include "../../lib/texts/TextOperations.h"
@@ -29,12 +30,13 @@ std::pair<std::unique_ptr<ui8[]>, ui64> CTrueTypeFont::loadData(const JsonNode &
 
 int CTrueTypeFont::getPointSize(const JsonNode & config) const
 {
+	float fontScale = settings["video"]["fontScalingFactor"].Float();
 	int scalingFactor = getScalingFactor();
 
 	if (config.isNumber())
-		return config.Integer() * scalingFactor;
+		return std::round(config.Integer() * scalingFactor * fontScale);
 	else
-		return config[scalingFactor-1].Integer();
+		return std::round(config[scalingFactor-1].Integer() * fontScale);
 }
 
 TTF_Font * CTrueTypeFont::loadFont(const JsonNode &config)
@@ -62,57 +64,65 @@ int CTrueTypeFont::getFontStyle(const JsonNode &config) const
 CTrueTypeFont::CTrueTypeFont(const JsonNode & fontConfig):
 	data(loadData(fontConfig)),
 	font(loadFont(fontConfig), TTF_CloseFont),
-	dropShadow(fontConfig["blend"].Bool()),
-	blended(fontConfig["blend"].Bool())
+	dropShadow(!fontConfig["noShadow"].Bool()),
+	outline(fontConfig["outline"].Bool()),
+	blended(true)
 {
 	assert(font);
 
 	TTF_SetFontStyle(font.get(), getFontStyle(fontConfig));
+	TTF_SetFontHinting(font.get(),TTF_HINTING_MONO);
 
-	std::string fallbackName = fontConfig["fallback"].String();
-
-	if (!fallbackName.empty())
-		fallbackFont = std::make_unique<CBitmapFont>(fallbackName);
 }
 
 CTrueTypeFont::~CTrueTypeFont() = default;
 
-size_t CTrueTypeFont::getLineHeight() const
+size_t CTrueTypeFont::getFontAscentScaled() const
 {
-	if (fallbackFont)
-		return fallbackFont->getLineHeight();
-
-	return TTF_FontHeight(font.get()) / getScalingFactor();
+	return TTF_FontAscent(font.get());
 }
 
-size_t CTrueTypeFont::getGlyphWidth(const char *data) const
+size_t CTrueTypeFont::getLineHeightScaled() const
 {
-	if (fallbackFont && fallbackFont->canRepresentCharacter(data))
-		return fallbackFont->getGlyphWidth(data);
+	return TTF_FontHeight(font.get());
+}
 
-	return getStringWidth(std::string(data, TextOperations::getUnicodeCharacterSize(*data)));
+size_t CTrueTypeFont::getGlyphWidthScaled(const char *data) const
+{
+	return getStringWidthScaled(std::string(data, TextOperations::getUnicodeCharacterSize(*data)));
 }
 
-size_t CTrueTypeFont::getStringWidth(const std::string & data) const
+bool CTrueTypeFont::canRepresentCharacter(const char * data) const
 {
-	if (fallbackFont && fallbackFont->canRepresentString(data))
-		return fallbackFont->getStringWidth(data);
+	uint32_t codepoint = TextOperations::getUnicodeCodepoint(data, TextOperations::getUnicodeCharacterSize(*data));
+#if SDL_TTF_VERSION_ATLEAST(2, 0, 18)
+	return TTF_GlyphIsProvided32(font.get(), codepoint);
+#elif SDL_TTF_VERSION_ATLEAST(2, 0, 12)
+	if (codepoint <= 0xffff)
+		return TTF_GlyphIsProvided(font.get(), codepoint);
+	return true;
+#else
+	return true;
+#endif
+}
 
+size_t CTrueTypeFont::getStringWidthScaled(const std::string & data) const
+{
 	int width;
 	TTF_SizeUTF8(font.get(), data.c_str(), &width, nullptr);
-	return width / getScalingFactor();
+	return width;
 }
 
 void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const
 {
-	if (fallbackFont && fallbackFont->canRepresentString(data))
+	if (color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow
 	{
-		fallbackFont->renderText(surface, data, color, pos);
-		return;
-	}
+		if (outline)
+			renderText(surface, data, Colors::BLACK, pos - Point(1,1) * getScalingFactor());
 
-	if (dropShadow && color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow
-		renderText(surface, data, Colors::BLACK, pos + Point(1,1) * getScalingFactor());
+		if (dropShadow || outline)
+			renderText(surface, data, Colors::BLACK, pos + Point(1,1) * getScalingFactor());
+	}
 
 	if (!data.empty())
 	{

+ 7 - 4
client/renderSDL/CTrueTypeFont.h

@@ -21,11 +21,11 @@ using TTF_Font = struct _TTF_Font;
 
 class CTrueTypeFont final : public IFont
 {
-	std::unique_ptr<CBitmapFont> fallbackFont;
 	const std::pair<std::unique_ptr<ui8[]>, ui64> data;
 
 	const std::unique_ptr<TTF_Font, void (*)(TTF_Font*)> font;
 	const bool blended;
+	const bool outline;
 	const bool dropShadow;
 
 	std::pair<std::unique_ptr<ui8[]>, ui64> loadData(const JsonNode & config);
@@ -34,11 +34,14 @@ class CTrueTypeFont final : public IFont
 	int getFontStyle(const JsonNode & config) const;
 
 	void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const override;
+	size_t getFontAscentScaled() const override;
 public:
 	CTrueTypeFont(const JsonNode & fontConfig);
 	~CTrueTypeFont();
 
-	size_t getLineHeight() const override;
-	size_t getGlyphWidth(const char * data) const override;
-	size_t getStringWidth(const std::string & data) const override;
+	bool canRepresentCharacter(const char * data) const override;
+
+	size_t getLineHeightScaled() const override;
+	size_t getGlyphWidthScaled(const char * data) const override;
+	size_t getStringWidthScaled(const std::string & data) const override;
 };

+ 136 - 0
client/renderSDL/FontChain.cpp

@@ -0,0 +1,136 @@
+/*
+ * FontChain.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "FontChain.h"
+
+#include "CTrueTypeFont.h"
+#include "CBitmapFont.h"
+
+#include "../../lib/CConfigHandler.h"
+#include "../../lib/texts/TextOperations.h"
+
+void FontChain::renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const
+{
+	auto chunks = splitTextToChunks(data);
+	int maxAscent = getFontAscentScaled();
+	Point currentPos = pos;
+	for (auto const & chunk : chunks)
+	{
+		Point chunkPos = currentPos;
+		int currAscent = chunk.font->getFontAscentScaled();
+		chunkPos.y += maxAscent - currAscent;
+		chunk.font->renderText(surface, chunk.text, color, chunkPos);
+		currentPos.x += chunk.font->getStringWidthScaled(chunk.text);
+	}
+}
+
+size_t FontChain::getFontAscentScaled() const
+{
+	size_t maxHeight = 0;
+	for(const auto & font : chain)
+		maxHeight = std::max(maxHeight, font->getFontAscentScaled());
+	return maxHeight;
+}
+
+bool FontChain::bitmapFontsPrioritized() const
+{
+	const std::string & fontType = settings["video"]["fontsType"].String();
+	if (fontType == "original")
+		return true;
+	if (fontType == "scalable")
+		return false;
+
+	// else - autoselection.
+
+	if (getScalingFactor() != 1)
+		return false; // If xbrz in use ttf/scalable fonts are preferred
+
+	if (!vstd::isAlmostEqual(1.0, settings["video"]["fontScalingFactor"].Float()))
+		return false; // If player requested non-100% scaling - use scalable fonts
+
+	return true; // else - use original bitmap fonts
+}
+
+void FontChain::addTrueTypeFont(const JsonNode & trueTypeConfig)
+{
+	chain.insert(chain.begin(), std::make_unique<CTrueTypeFont>(trueTypeConfig));
+}
+
+void FontChain::addBitmapFont(const std::string & bitmapFilename)
+{
+	if (bitmapFontsPrioritized())
+		chain.insert(chain.begin(), std::make_unique<CBitmapFont>(bitmapFilename));
+	else
+		chain.push_back(std::make_unique<CBitmapFont>(bitmapFilename));
+}
+
+bool FontChain::canRepresentCharacter(const char * data) const
+{
+	for(const auto & font : chain)
+		if (font->canRepresentCharacter(data))
+			return true;
+	return false;
+}
+
+size_t FontChain::getLineHeightScaled() const
+{
+	size_t maxHeight = 0;
+	for(const auto & font : chain)
+		maxHeight = std::max(maxHeight, font->getLineHeightScaled());
+	return maxHeight;
+}
+
+size_t FontChain::getGlyphWidthScaled(const char * data) const
+{
+	for(const auto & font : chain)
+		if (font->canRepresentCharacter(data))
+			return font->getGlyphWidthScaled(data);
+	return 0;
+}
+
+std::vector<FontChain::TextChunk> FontChain::splitTextToChunks(const std::string & data) const
+{
+	std::vector<TextChunk> chunks;
+
+	for (size_t i = 0; i < data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
+	{
+		const IFont * currentFont = nullptr;
+		for(const auto & font : chain)
+		{
+			if (font->canRepresentCharacter(data.data() + i))
+			{
+				currentFont = font.get();
+				break;
+			}
+		}
+
+		if (currentFont == nullptr)
+			continue; // not representable
+
+		std::string symbol = data.substr(i, TextOperations::getUnicodeCharacterSize(data[i]));
+
+		if (chunks.empty() || chunks.back().font != currentFont)
+			chunks.push_back({currentFont, symbol});
+		else
+			chunks.back().text += symbol;
+	}
+
+	return chunks;
+}
+
+size_t FontChain::getStringWidthScaled(const std::string & data) const
+{
+	size_t result = 0;
+	auto chunks = splitTextToChunks(data);
+	for (auto const & chunk : chunks)
+		result += chunk.font->getStringWidthScaled(chunk.text);
+
+	return result;
+}

+ 43 - 0
client/renderSDL/FontChain.h

@@ -0,0 +1,43 @@
+/*
+ * FontChain.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "../render/IFont.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+class JsonNode;
+VCMI_LIB_NAMESPACE_END
+
+class FontChain final : public IFont
+{
+	struct TextChunk
+	{
+		const IFont * font;
+		std::string text;
+	};
+
+	std::vector<TextChunk> splitTextToChunks(const std::string & data) const;
+
+	std::vector<std::unique_ptr<IFont>> chain;
+
+	void renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const override;
+	size_t getFontAscentScaled() const override;
+	bool bitmapFontsPrioritized() const;
+public:
+	FontChain() = default;
+
+	void addTrueTypeFont(const JsonNode & trueTypeConfig);
+	void addBitmapFont(const std::string & bitmapFilename);
+
+	size_t getLineHeightScaled() const override;
+	size_t getGlyphWidthScaled(const char * data) const override;
+	size_t getStringWidthScaled(const std::string & data) const override;
+	bool canRepresentCharacter(const char * data) const override;
+};

+ 30 - 1
client/renderSDL/RenderHandler.cpp

@@ -12,6 +12,7 @@
 
 #include "SDLImage.h"
 #include "ImageScaled.h"
+#include "FontChain.h"
 
 #include "../gui/CGuiHandler.h"
 
@@ -20,7 +21,6 @@
 #include "../render/Colors.h"
 #include "../render/ColorFilter.h"
 #include "../render/IScreenHandler.h"
-
 #include "../../lib/json/JsonUtils.h"
 #include "../../lib/filesystem/Filesystem.h"
 #include "../../lib/VCMIDirs.h"
@@ -335,3 +335,32 @@ void RenderHandler::onLibraryLoadingFinished(const Services * services)
 	addImageListEntries(services->spells());
 	addImageListEntries(services->skills());
 }
+
+std::shared_ptr<const IFont> RenderHandler::loadFont(EFonts font)
+{
+	if (fonts.count(font))
+		return fonts.at(font);
+
+	const int8_t index = static_cast<int8_t>(font);
+	auto configList = CResourceHandler::get()->getResourcesWithName(JsonPath::builtin("config/fonts.json"));
+	std::shared_ptr<FontChain> loadedFont = std::make_shared<FontChain>();
+	std::string bitmapPath;
+
+	for(auto & loader : configList)
+	{
+		auto stream = loader->load(JsonPath::builtin("config/fonts.json"));
+		std::unique_ptr<ui8[]> textData(new ui8[stream->getSize()]);
+		stream->read(textData.get(), stream->getSize());
+		const JsonNode config(reinterpret_cast<const std::byte*>(textData.get()), stream->getSize(), "config/fonts.json");
+		const JsonVector & bmpConf = config["bitmap"].Vector();
+		const JsonNode   & ttfConf = config["trueType"];
+
+		bitmapPath = bmpConf[index].String();
+		if (!ttfConf[bitmapPath].isNull())
+			loadedFont->addTrueTypeFont(ttfConf[bitmapPath]);
+	}
+	loadedFont->addBitmapFont(bitmapPath);
+
+	fonts[font] = loadedFont;
+	return loadedFont;
+}

+ 4 - 0
client/renderSDL/RenderHandler.h

@@ -26,6 +26,7 @@ class RenderHandler : public IRenderHandler
 	std::map<AnimationPath, std::shared_ptr<CDefFile>> animationFiles;
 	std::map<AnimationPath, AnimationLayoutMap> animationLayouts;
 	std::map<ImageLocator, std::shared_ptr<ISharedImage>> imageFiles;
+	std::map<EFonts, std::shared_ptr<const IFont>> fonts;
 
 	std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
 	AnimationLayoutMap & getAnimationLayout(const AnimationPath & path);
@@ -59,4 +60,7 @@ public:
 	std::shared_ptr<CAnimation> loadAnimation(const AnimationPath & path, EImageBlitMode mode) override;
 
 	std::shared_ptr<IImage> createImage(SDL_Surface * source) override;
+
+	/// Returns font with specified identifer
+	std::shared_ptr<const IFont> loadFont(EFonts font) override;
 };

+ 4 - 1
client/widgets/CComponent.cpp

@@ -21,6 +21,7 @@
 #include "../gui/Shortcut.h"
 #include "../render/Canvas.h"
 #include "../render/IFont.h"
+#include "../render/IRenderHandler.h"
 #include "../render/Graphics.h"
 #include "../windows/CMessage.h"
 #include "../windows/InfoWindows.h"
@@ -95,9 +96,11 @@ void CComponent::init(ComponentType Type, ComponentSubType Subtype, std::optiona
 		max = 80;
 
 	std::vector<std::string> textLines = CMessage::breakText(getSubtitle(), std::max<int>(max, pos.w), font);
+	const auto & fontPtr = GH.renderHandler().loadFont(font);
+	const int height = static_cast<int>(fontPtr->getLineHeight());
+
 	for(auto & line : textLines)
 	{
-		int height = static_cast<int>(graphics->fonts[font]->getLineHeight());
 		auto label = std::make_shared<CLabel>(pos.w/2, pos.h + height/2, font, ETextAlignment::CENTER, Colors::WHITE, line);
 
 		pos.h += height;

+ 3 - 1
client/widgets/CTextInput.cpp

@@ -17,6 +17,7 @@
 #include "../gui/Shortcut.h"
 #include "../render/Graphics.h"
 #include "../render/IFont.h"
+#include "../render/IRenderHandler.h"
 
 #include "../../lib/texts/TextOperations.h"
 
@@ -190,8 +191,9 @@ void CTextInput::updateLabel()
 	std::string visibleText = getVisibleText();
 
 	label->alignment = originalAlignment;
+	const auto & font = GH.renderHandler().loadFont(label->font);
 
-	while (graphics->fonts[label->font]->getStringWidth(visibleText) > pos.w)
+	while (font->getStringWidth(visibleText) > pos.w)
 	{
 		label->alignment = ETextAlignment::CENTERRIGHT;
 		visibleText = visibleText.substr(TextOperations::getUnicodeCharacterSize(visibleText[0]));

+ 25 - 16
client/widgets/TextControls.cpp

@@ -22,6 +22,7 @@
 #include "../render/Canvas.h"
 #include "../render/Graphics.h"
 #include "../render/IFont.h"
+#include "../render/IRenderHandler.h"
 
 #include "../../lib/texts/TextOperations.h"
 
@@ -56,8 +57,9 @@ CLabel::CLabel(int x, int y, EFonts Font, ETextAlignment Align, const ColorRGBA
 
 	if(alignment == ETextAlignment::TOPLEFT) // causes issues for MIDDLE
 	{
-		pos.w = (int)graphics->fonts[font]->getStringWidth(visibleText().c_str());
-		pos.h = (int)graphics->fonts[font]->getLineHeight();
+		const auto & fontPtr = GH.renderHandler().loadFont(font);
+		pos.w = fontPtr->getStringWidth(visibleText().c_str());
+		pos.h = fontPtr->getLineHeight();
 	}
 }
 
@@ -114,8 +116,12 @@ void CLabel::setMaxWidth(int width)
 void CLabel::trimText()
 {
 	if(maxWidth > 0)
-		while ((int)graphics->fonts[font]->getStringWidth(visibleText().c_str()) > maxWidth)
+	{
+		const auto & fontPtr = GH.renderHandler().loadFont(font);
+
+		while (fontPtr->getStringWidth(visibleText().c_str()) > maxWidth)
 			TextOperations::trimRightUnicode(text);
+	}
 }
 
 void CLabel::setColor(const ColorRGBA & Color)
@@ -132,7 +138,8 @@ void CLabel::setColor(const ColorRGBA & Color)
 
 size_t CLabel::getWidth()
 {
-	return graphics->fonts[font]->getStringWidth(visibleText());
+	const auto & fontPtr = GH.renderHandler().loadFont(font);
+	return fontPtr->getStringWidth(visibleText());
 }
 
 CMultiLineLabel::CMultiLineLabel(Rect position, EFonts Font, ETextAlignment Align, const ColorRGBA & Color, const std::string & Text) :
@@ -171,7 +178,7 @@ void CMultiLineLabel::setText(const std::string & Txt)
 
 void CTextContainer::blitLine(Canvas & to, Rect destRect, std::string what)
 {
-	const auto f = graphics->fonts[font];
+	const auto f = GH.renderHandler().loadFont(font);
 	Point where = destRect.topLeft();
 	const std::string delimiters = "{}";
 	auto delimitersCount = std::count_if(what.cbegin(), what.cend(), [&delimiters](char c)
@@ -264,7 +271,7 @@ void CMultiLineLabel::showAll(Canvas & to)
 {
 	CIntObject::showAll(to);
 
-	const auto f = graphics->fonts[font];
+	const auto & fontPtr = GH.renderHandler().loadFont(font);
 
 	// calculate which lines should be visible
 	int totalLines = static_cast<int>(lines.size());
@@ -274,17 +281,17 @@ void CMultiLineLabel::showAll(Canvas & to)
 	if(beginLine < 0)
 		beginLine = 0;
 	else
-		beginLine /= (int)f->getLineHeight();
+		beginLine /= fontPtr->getLineHeight();
 
 	if(endLine < 0)
 		endLine = 0;
 	else
-		endLine /= (int)f->getLineHeight();
+		endLine /= fontPtr->getLineHeight();
 	endLine++;
 
 	// and where they should be displayed
-	Point lineStart = getTextLocation().topLeft() - visibleSize + Point(0, beginLine * (int)f->getLineHeight());
-	Point lineSize = Point(getTextLocation().w, (int)f->getLineHeight());
+	Point lineStart = getTextLocation().topLeft() - visibleSize + Point(0, beginLine * fontPtr->getLineHeight());
+	Point lineSize = Point(getTextLocation().w, fontPtr->getLineHeight());
 
 	CSDL_Ext::CClipRectGuard guard(to.getInternalSurface(), getTextLocation()); // to properly trim text that is too big to fit
 
@@ -293,7 +300,7 @@ void CMultiLineLabel::showAll(Canvas & to)
 		if(!lines[i].empty()) //non-empty line
 			blitLine(to, Rect(lineStart, lineSize), lines[i]);
 
-		lineStart.y += (int)f->getLineHeight();
+		lineStart.y += fontPtr->getLineHeight();
 	}
 }
 
@@ -301,15 +308,15 @@ void CMultiLineLabel::splitText(const std::string & Txt, bool redrawAfter)
 {
 	lines.clear();
 
-	const auto f = graphics->fonts[font];
-	int lineHeight = static_cast<int>(f->getLineHeight());
+	const auto & fontPtr = GH.renderHandler().loadFont(font);
+	int lineHeight = static_cast<int>(fontPtr->getLineHeight());
 
 	lines = CMessage::breakText(Txt, pos.w, font);
 
 	textSize.y = lineHeight * (int)lines.size();
 	textSize.x = 0;
 	for(const std::string & line : lines)
-		vstd::amax(textSize.x, f->getStringWidth(line.c_str()));
+		vstd::amax(textSize.x, fontPtr->getStringWidth(line.c_str()));
 	if(redrawAfter)
 		redraw();
 }
@@ -322,7 +329,8 @@ Rect CMultiLineLabel::getTextLocation()
 	if(pos.h <= textSize.y)
 		return pos;
 
-	Point textSize(pos.w, (int)graphics->fonts[font]->getLineHeight() * (int)lines.size());
+	const auto & fontPtr = GH.renderHandler().loadFont(font);
+	Point textSize(pos.w, fontPtr->getLineHeight() * (int)lines.size());
 	Point textOffset(pos.w - textSize.x, pos.h - textSize.y);
 
 	switch(alignment)
@@ -421,11 +429,12 @@ void CTextBox::setText(const std::string & text)
 		label->pos.w = pos.w - 16;
 		assert(label->pos.w > 0);
 		label->setText(text);
+		const auto & fontPtr = GH.renderHandler().loadFont(label->font);
 
 		OBJECT_CONSTRUCTION;
 		slider = std::make_shared<CSlider>(Point(pos.w - 16, 0), pos.h, std::bind(&CTextBox::sliderMoved, this, _1),
 			label->pos.h, label->textSize.y, 0, Orientation::VERTICAL, CSlider::EStyle(sliderStyle));
-		slider->setScrollStep((int)graphics->fonts[label->font]->getLineHeight());
+		slider->setScrollStep(fontPtr->getLineHeight());
 		slider->setPanningStep(1);
 		slider->setScrollBounds(pos - slider->pos.topLeft());
 	}

+ 5 - 3
client/windows/CMessage.cpp

@@ -70,6 +70,8 @@ std::vector<std::string> CMessage::breakText(std::string text, size_t maxLineWid
 
 	boost::algorithm::trim_right_if(text, boost::algorithm::is_any_of(std::string(" ")));
 
+	const auto & fontPtr = GH.renderHandler().loadFont(font);
+
 	// each iteration generates one output line
 	while(text.length())
 	{
@@ -83,7 +85,7 @@ std::vector<std::string> CMessage::breakText(std::string text, size_t maxLineWid
 		std::string printableString;
 
 		// loops till line is full or end of text reached
-		while(currPos < text.length() && text[currPos] != 0x0a && graphics->fonts[font]->getStringWidth(printableString) <= maxLineWidth)
+		while(currPos < text.length() && text[currPos] != 0x0a && fontPtr->getStringWidth(printableString) <= maxLineWidth)
 		{
 			symbolSize = TextOperations::getUnicodeCharacterSize(text[currPos]);
 
@@ -193,9 +195,9 @@ std::string CMessage::guessHeader(const std::string & msg)
 
 int CMessage::guessHeight(const std::string & txt, int width, EFonts font)
 {
-	const auto f = graphics->fonts[font];
+	const auto & fontPtr = GH.renderHandler().loadFont(font);
 	const auto lines = CMessage::breakText(txt, width, font);
-	size_t lineHeight = f->getLineHeight();
+	size_t lineHeight = fontPtr->getLineHeight();
 	return lineHeight * lines.size();
 }
 

+ 15 - 14
config/fonts.json

@@ -5,12 +5,12 @@
 	"bitmap" :
 	[
 		"BIGFONT",  // Mostly used for window titles
-		"CALLI10R", // Unused in VCMI
-		"CREDITS",  // Used for credits menu
-		"HISCORE",  // Unused in VCMI
+		"CALLI10R", // Only in World View menu
+		"CREDITS",  // Only in Credits menu
+		"HISCORE",  // Only in High Scores menu
 		"MEDFONT",  // Some titles
 		"SMALFONT", // Most of the messages
-		"TIMES08R", // Used to display amounts on creature card 
+		"TIMES08R", // Unused in VCMI
 		"TINY",     // Some text
 		"VERD10B"   // Unused in VCMI
 	],
@@ -25,17 +25,18 @@
 	// b) list of scaling factors for each scaling mode, e.g. [ 10, 16, 22, 26]. In this case game will select point size according to xBRZ scaling factor
 	//    so unscaled mode will use 10px, xbrz2 will use 16px, and xbrz3 will use 22
 	// "style" - italic and\or bold, indicates font style
-	// "blend" - if set to true, font will be antialiased
+	// "outline" - if set, black shadow will be generated around entire text (instead of only bottom-right side)
+	// "noShadow" - if set, this font will not drop any shadow
 	"trueType":
 	{
-		//"BIGFONT"  : { "file" : "LiberationSerif-Bold.ttf", "size" : 22, "blend" : true},
-		//"CALLI10R" : { "file" : "Georgia.ttf",       "size" : 10},
-		//"CREDITS"  : { "file" : "LiberationSerif-Bold.ttf", "size" : 28},
-		//"HISCORE"  : { "file" : "Georgia.ttf",       "size" : 13},
-		//"MEDFONT"  : { "file" : "LiberationSerif-Bold.ttf", "size" : 16}, // breaks messages (from map events)
-		//"SMALFONT" : { "file" : "LiberationSerif-Regular.ttf",       "size" : 13, "blend" : true},
-		//"TIMES08R" : { "file" : "LiberationSerif-Regular.ttf", "size" :  11, "blend" : true},
-		//"TINY"     : { "file" : "LiberationSerif-Regular.ttf",       "size" : 11, "blend" : true},
-		//"VERD10B"  : { "file" : "Georgia.ttf",       "size" : 13}
+		"BIGFONT"  : { "file" : "NotoSerif-Bold.ttf",   "size" : [ 19, 39, 58, 78] },
+		"CALLI10R" : { "file" : "NotoSerif-Bold.ttf",   "size" : [ 12, 24, 36, 48] }, // TODO: find better matching font? This is likely non-free 'Callisto MT' font
+		"CREDITS"  : { "file" : "NotoSerif-Black.ttf",  "size" : [ 22, 44, 66, 88], "outline" : true },
+		"HISCORE"  : { "file" : "NotoSerif-Black.ttf",  "size" : [ 18, 36, 54, 72], "outline" : true },
+		"MEDFONT"  : { "file" : "NotoSerif-Bold.ttf",   "size" : [ 15, 31, 46, 62] },
+		"SMALFONT" : { "file" : "NotoSerif-Medium.ttf", "size" : [ 12, 24, 36, 48] },
+		"TIMES08R" : { "file" : "NotoSerif-Medium.ttf", "size" : [  8, 16, 24, 32] },
+		"TINY"     : { "file" : "NotoSans-Medium.ttf",  "size" : [  9, 19, 28, 38], "noShadow" : true }, // The only H3 font without shadow
+		"VERD10B"  : { "file" : "NotoSans-Medium.ttf",  "size" : [ 13, 26, 39, 52] }
 	}
 }

+ 11 - 0
config/schemas/settings.json

@@ -166,6 +166,8 @@
 				"showfps",
 				"targetfps",
 				"vsync",
+				"fontsType",
+				"fontScalingFactor",
 				"upscalingFilter",
 				"fontUpscalingFilter",
 				"downscalingFilter"
@@ -232,6 +234,15 @@
 					"type" : "boolean",
 					"default" : true
 				},
+				"fontsType" : {
+					"type" : "string",
+					"enum" : [ "auto", "original", "scalable" ],
+					"default" : "auto"
+				},
+				"fontScalingFactor" : {
+					"type" : "number",
+					"default" : 1
+				},
 				"fontUpscalingFilter" : {
 					"type" : "string",
 					"enum" : [ "nearest", "bilinear", "xbrz" ],

+ 33 - 21
launcher/settingsView/csettingsview_moc.cpp

@@ -174,17 +174,13 @@ void CSettingsView::loadSettings()
 	ui->sliderControllerSticksAcceleration->setValue(settings["input"]["controllerAxisScale"].Float() * 100);
 	ui->lineEditGameLobbyHost->setText(QString::fromStdString(settings["lobby"]["hostname"].String()));
 	ui->spinBoxNetworkPortLobby->setValue(settings["lobby"]["port"].Integer());
-	
-	auto mainWindow = getMainWindow();
-	if(mainWindow)
-	{
-		bool fontModAvailable = mainWindow->getModView()->isModInstalled("vcmi-extras.truetypefonts");
-		if(!fontModAvailable)
-		{
-			ui->labelTtfFont->hide();
-			ui->buttonTtfFont->hide();
-		}
-	}
+
+	if (settings["video"]["fontsType"].String() == "auto")
+		ui->buttonFontAuto->setChecked(true);
+	else if (settings["video"]["fontsType"].String() == "original")
+		ui->buttonFontOriginal->setChecked(true);
+	else
+		ui->buttonFontScalable->setChecked(true);
 
 	loadToggleButtonSettings();
 }
@@ -210,9 +206,9 @@ void CSettingsView::loadToggleButtonSettings()
 	int cursorTypeIndex = vstd::find_pos(cursorTypesList, cursorType);
 	setCheckbuttonState(ui->buttonCursorType, cursorTypeIndex);
 
-	auto mainWindow = getMainWindow();
-	if(mainWindow)
-		setCheckbuttonState(ui->buttonTtfFont, mainWindow->getModView()->isModEnabled("vcmi-extras.truetypefonts"));
+	int fontScalingPercentage = settings["video"]["fontScalingFactor"].Float() * 100;
+	ui->sliderScalingFont->setValue(fontScalingPercentage / 5);
+
 }
 
 void CSettingsView::fillValidResolutions()
@@ -770,12 +766,28 @@ void CSettingsView::on_sliderControllerSticksSensitivity_valueChanged(int value)
 	node->Integer() = value;
 }
 
-void CSettingsView::on_buttonTtfFont_toggled(bool value)
+void CSettingsView::on_sliderScalingFont_valueChanged(int value)
 {
-	auto mainWindow = getMainWindow();
-	if(value)
-		mainWindow->getModView()->enableModByName("vcmi-extras.truetypefonts");
-	else
-		mainWindow->getModView()->disableModByName("vcmi-extras.truetypefonts");
-	updateCheckbuttonText(ui->buttonTtfFont);
+	int actualValuePercentage = value * 5;
+	ui->labelScalingFontValue->setText(QString("%1%").arg(actualValuePercentage));
+	Settings node = settings.write["video"]["fontScalingFactor"];
+	node->Float() = actualValuePercentage / 100.0;
+}
+
+void CSettingsView::on_buttonFontAuto_clicked(bool checked)
+{
+	Settings node = settings.write["video"]["fontsType"];
+	node->String() = "auto";
+}
+
+void CSettingsView::on_buttonFontScalable_clicked(bool checked)
+{
+	Settings node = settings.write["video"]["fontsType"];
+	node->String() = "scalable";
+}
+
+void CSettingsView::on_buttonFontOriginal_clicked(bool checked)
+{
+	Settings node = settings.write["video"]["fontsType"];
+	node->String() = "original";
 }

+ 7 - 1
launcher/settingsView/csettingsview_moc.h

@@ -88,7 +88,13 @@ private slots:
 
 	void on_sliderControllerSticksSensitivity_valueChanged(int value);
 
-	void on_buttonTtfFont_toggled(bool value);
+	//void on_buttonTtfFont_toggled(bool value);
+
+	void on_sliderScalingFont_valueChanged(int value);
+
+	void on_buttonFontAuto_clicked(bool checked);
+	void on_buttonFontScalable_clicked(bool checked);
+	void on_buttonFontOriginal_clicked(bool checked);
 
 private:
 	Ui::CSettingsView * ui;

Різницю між файлами не показано, бо вона завелика
+ 470 - 389
launcher/settingsView/csettingsview_moc.ui


Деякі файли не було показано, через те що забагато файлів було змінено