mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Proper support for usage of multiple fonts in a chain
This commit is contained in:
		| @@ -98,6 +98,7 @@ set(vcmiclientcommon_SRCS | ||||
| 	renderSDL/CTrueTypeFont.cpp | ||||
| 	renderSDL/CursorHardware.cpp | ||||
| 	renderSDL/CursorSoftware.cpp | ||||
| 	renderSDL/FontChain.cpp | ||||
| 	renderSDL/ImageScaled.cpp | ||||
| 	renderSDL/RenderHandler.cpp | ||||
| 	renderSDL/SDLImage.cpp | ||||
| @@ -305,6 +306,7 @@ set(vcmiclientcommon_HEADERS | ||||
| 	renderSDL/CTrueTypeFont.h | ||||
| 	renderSDL/CursorHardware.h | ||||
| 	renderSDL/CursorSoftware.h | ||||
| 	renderSDL/FontChain.h | ||||
| 	renderSDL/ImageScaled.h | ||||
| 	renderSDL/RenderHandler.h | ||||
| 	renderSDL/SDLImage.h | ||||
|   | ||||
| @@ -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,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 getGlyphWidth(const char * data) const = 0; | ||||
| 	virtual size_t getGlyphWidthScaled(const char * data) const = 0; | ||||
| 	/// Return width of the string | ||||
| 	virtual size_t getStringWidth(const std::string & data) const; | ||||
| 	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 | ||||
| 	size_t getGlyphWidth(const char * data) const; | ||||
| 	/// Return width of the string | ||||
| 	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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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) | ||||
| @@ -71,48 +73,39 @@ CTrueTypeFont::CTrueTypeFont(const JsonNode & fontConfig): | ||||
| 	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 getStringWidth(std::string(data, TextOperations::getUnicodeCharacterSize(*data))); | ||||
| 	return TTF_FontHeight(font.get()); | ||||
| } | ||||
|  | ||||
| size_t CTrueTypeFont::getStringWidth(const std::string & data) const | ||||
| size_t CTrueTypeFont::getGlyphWidthScaled(const char *data) const | ||||
| { | ||||
| 	if (fallbackFont && fallbackFont->canRepresentString(data)) | ||||
| 		return fallbackFont->getStringWidth(data); | ||||
| 	return getStringWidthScaled(std::string(data, TextOperations::getUnicodeCharacterSize(*data))); | ||||
| } | ||||
|  | ||||
| bool CTrueTypeFont::canRepresentCharacter(const char * data) const | ||||
| { | ||||
| 	return TTF_GlyphIsProvided32(font.get(), TextOperations::getUnicodeCodepoint(data, TextOperations::getUnicodeCharacterSize(*data))); | ||||
| } | ||||
|  | ||||
| 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)) | ||||
| 	{ | ||||
| 		fallbackFont->renderText(surface, data, color, pos); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow | ||||
| 	{ | ||||
| 		if (outline) | ||||
|   | ||||
| @@ -21,7 +21,6 @@ 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; | ||||
| @@ -35,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; | ||||
| }; | ||||
|   | ||||
							
								
								
									
										117
									
								
								client/renderSDL/FontChain.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								client/renderSDL/FontChain.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| /* | ||||
|  * 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; | ||||
| } | ||||
|  | ||||
| void FontChain::addTrueTypeFont(const JsonNode & trueTypeConfig) | ||||
| { | ||||
| 	chain.push_back(std::make_unique<CTrueTypeFont>(trueTypeConfig)); | ||||
| } | ||||
|  | ||||
| void FontChain::addBitmapFont(const std::string & bitmapFilename) | ||||
| { | ||||
| 	if (settings["video"]["scalableFonts"].Bool()) | ||||
| 		chain.push_back(std::make_unique<CBitmapFont>(bitmapFilename)); | ||||
| 	else | ||||
| 		chain.insert(chain.begin(), 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; | ||||
| } | ||||
							
								
								
									
										42
									
								
								client/renderSDL/FontChain.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								client/renderSDL/FontChain.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| /* | ||||
|  * 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; | ||||
| 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; | ||||
| }; | ||||
| @@ -12,8 +12,7 @@ | ||||
|  | ||||
| #include "SDLImage.h" | ||||
| #include "ImageScaled.h" | ||||
| #include "CBitmapFont.h" | ||||
| #include "CTrueTypeFont.h" | ||||
| #include "FontChain.h" | ||||
|  | ||||
| #include "../gui/CGuiHandler.h" | ||||
|  | ||||
| @@ -22,8 +21,6 @@ | ||||
| #include "../render/Colors.h" | ||||
| #include "../render/ColorFilter.h" | ||||
| #include "../render/IScreenHandler.h" | ||||
|  | ||||
| #include "../../lib/CConfigHandler.h" | ||||
| #include "../../lib/json/JsonUtils.h" | ||||
| #include "../../lib/filesystem/Filesystem.h" | ||||
| #include "../../lib/VCMIDirs.h" | ||||
| @@ -345,18 +342,23 @@ std::shared_ptr<const IFont> RenderHandler::loadFont(EFonts font) | ||||
| 		return fonts.at(font); | ||||
|  | ||||
| 	const int8_t index = static_cast<int8_t>(font); | ||||
| 	const JsonNode config(JsonPath::builtin("config/fonts.json")); | ||||
| 	const JsonVector & bmpConf = config["bitmap"].Vector(); | ||||
| 	const JsonNode   & ttfConf = config["trueType"]; | ||||
| 	auto configList = CResourceHandler::get()->getResourcesWithName(JsonPath::builtin("config/fonts.json")); | ||||
| 	std::shared_ptr<FontChain> loadedFont = std::make_shared<FontChain>(); | ||||
| 	std::string bitmapPath; | ||||
|  | ||||
| 	std::string filename = bmpConf[index].String(); | ||||
| 	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"]; | ||||
|  | ||||
| 	std::shared_ptr<const IFont> loadedFont; | ||||
|  | ||||
| 	if(ttfConf[filename].isNull() || settings["video"]["scalableFonts"].Bool() == false) | ||||
| 		loadedFont = std::make_shared<CBitmapFont>(filename); | ||||
| 	else | ||||
| 		loadedFont = std::make_shared<CTrueTypeFont>(ttfConf[filename]); | ||||
| 		bitmapPath = bmpConf[index].String(); | ||||
| 		loadedFont->addTrueTypeFont(ttfConf[bitmapPath]); | ||||
| 	} | ||||
| 	loadedFont->addBitmapFont(bitmapPath); | ||||
|  | ||||
| 	fonts[font] = loadedFont; | ||||
| 	return loadedFont; | ||||
|   | ||||
| @@ -167,6 +167,7 @@ | ||||
| 				"targetfps", | ||||
| 				"vsync", | ||||
| 				"scalableFonts", | ||||
| 				"fontScalingFactor", | ||||
| 				"upscalingFilter", | ||||
| 				"fontUpscalingFilter", | ||||
| 				"downscalingFilter" | ||||
| @@ -237,6 +238,10 @@ | ||||
| 					"type" : "boolean", | ||||
| 					"default" : false | ||||
| 				}, | ||||
| 				"fontScalingFactor" : { | ||||
| 					"type" : "number", | ||||
| 					"default" : 1 | ||||
| 				}, | ||||
| 				"fontUpscalingFilter" : { | ||||
| 					"type" : "string", | ||||
| 					"enum" : [ "nearest", "bilinear", "xbrz" ], | ||||
|   | ||||
		Reference in New Issue
	
	Block a user