1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
/*
* 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 "../CGameInfo.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"
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 = CGI->generaltexth->getPreferredLanguage();
std::string gameEncoding = Languages::getLanguageOptions(gameLanguage).encoding;
std::string fontEncoding = CGI->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)
{
chain.insert(chain.begin(), 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;
}
|