| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 | 
							- /*
 
-  * 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/modding/CModHandler.h"
 
- #include "../../lib/texts/TextOperations.h"
 
- #include "../../lib/texts/CGeneralTextHandler.h"
 
- #include "../../lib/texts/Languages.h"
 
- #include "../../lib/GameLibrary.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 std::string & bitmapFontName) 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
 
- 	std::string gameLanguage = LIBRARY->generaltexth->getPreferredLanguage();
 
- 	std::string gameEncoding = Languages::getLanguageOptions(gameLanguage).encoding;
 
- 	std::string fontEncoding = LIBRARY->modh->findResourceEncoding(ResourcePath("data/" + bitmapFontName, EResType::BMP_FONT));
 
- 	// player uses language with different encoding than his bitmap fonts
 
- 	// for example, Polish language with English fonts or Chinese language which can't use H3 fonts at all
 
- 	// this may result in unintended mixing of ttf and bitmap fonts, which may have a bit different look
 
- 	// so in this case prefer ttf fonts that are likely to cover target language better than H3 fonts
 
- 	if (fontEncoding != gameEncoding)
 
- 		return false;
 
- 	return true; // else - use original bitmap fonts
 
- }
 
- void FontChain::addTrueTypeFont(const JsonNode & trueTypeConfig, bool begin)
 
- {
 
- 	if(begin)
 
- 		chain.insert(chain.begin(), std::make_unique<CTrueTypeFont>(trueTypeConfig));
 
- 	else
 
- 		chain.push_back(std::make_unique<CTrueTypeFont>(trueTypeConfig));
 
- }
 
- void FontChain::addBitmapFont(const std::string & bitmapFilename)
 
- {
 
- 	if (bitmapFontsPrioritized(bitmapFilename))
 
- 		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
 
- {
 
- 	// U+FFFD - replacement character (question mark in rhombus)
 
- 	static const std::string replacementCharacter = u8"�";
 
- 	std::vector<TextChunk> chunks;
 
- 	const auto & selectFont = [this](const char * characterPtr) -> const IFont *
 
- 	{
 
- 		for(const auto & font : chain)
 
- 			if (font->canRepresentCharacter(characterPtr))
 
- 				return font.get();
 
- 		return nullptr;
 
- 	};
 
- 	for (size_t i = 0; i < data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
 
- 	{
 
- 		std::string symbol = data.substr(i, TextOperations::getUnicodeCharacterSize(data[i]));
 
- 		const IFont * currentFont = selectFont(symbol.data());
 
- 		if (currentFont == nullptr)
 
- 		{
 
- 			symbol = replacementCharacter;
 
- 			currentFont = selectFont(symbol.data());
 
- 		}
 
- 		if (currentFont == nullptr)
 
- 			continue; // Still nothing - neither desired character nor fallback can be rendered
 
- 		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;
 
- }
 
 
  |