mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
parent
42879225f0
commit
e13dc872e0
@ -688,7 +688,7 @@ void processCommand(const std::string &message)
|
||||
auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
|
||||
|
||||
boost::filesystem::create_directories(fullPath.substr(0, fullPath.find_last_of("/")));
|
||||
std::ofstream outFile(outPath + outName);
|
||||
std::ofstream outFile(outPath + outName, std::ofstream::binary);
|
||||
outFile.write((char*)data.first.get(), data.second);
|
||||
}
|
||||
else
|
||||
|
@ -138,49 +138,45 @@ std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineSi
|
||||
while (text.length())
|
||||
{
|
||||
ui32 lineLength = 0; //in characters or given char metric
|
||||
ui32 z = 0; //our position in text
|
||||
ui32 wordBreak = -1;
|
||||
ui32 currPos = 0; //our position in text
|
||||
bool opened = false;//if we have an unclosed brace in current line
|
||||
bool lineManuallyBroken = false;
|
||||
|
||||
while(z < text.length() && text[z] != 0x0a && lineLength < maxLineSize)
|
||||
while(currPos < text.length() && text[currPos] != 0x0a && lineLength < maxLineSize)
|
||||
{
|
||||
if (ui8(text[currPos]) <= ui8(' ')) // candidate for line break
|
||||
wordBreak = currPos;
|
||||
/* We don't count braces in string length. */
|
||||
if (text[z] == '{')
|
||||
if (text[currPos] == '{')
|
||||
opened=true;
|
||||
else if (text[z]=='}')
|
||||
else if (text[currPos]=='}')
|
||||
opened=false;
|
||||
else
|
||||
lineLength += graphics->fonts[font]->getSymbolWidth(text[z]);
|
||||
z++;
|
||||
lineLength += graphics->fonts[font]->getGlyphWidth(text.data() + currPos);
|
||||
currPos += graphics->fonts[font]->getCharacterSize(text[currPos]);
|
||||
}
|
||||
|
||||
if (z < text.length() && (text[z] != 0x0a))
|
||||
if (currPos < text.length() && (text[currPos] != 0x0a))
|
||||
{
|
||||
/* We have a long line. Try to do a nice line break, if
|
||||
* possible. We backtrack on the line until we find a
|
||||
* suitable character.
|
||||
* Note: Cyrillic symbols have indexes 220-255 so we need
|
||||
* to use ui8 for comparison
|
||||
*/
|
||||
int pos = z-1;
|
||||
while(pos > 0 && ((ui8)text[pos]) > ' ' )
|
||||
pos --;
|
||||
|
||||
if (pos > 0)
|
||||
z = pos+1;
|
||||
// We have a long line. Try to do a nice line break, if possible
|
||||
if (wordBreak != ui32(-1))
|
||||
currPos = wordBreak;
|
||||
else
|
||||
currPos--;
|
||||
}
|
||||
|
||||
if(z) //non-blank line
|
||||
if(currPos) //non-blank line
|
||||
{
|
||||
ret.push_back(text.substr(0, z));
|
||||
ret.push_back(text.substr(0, currPos));
|
||||
|
||||
if (opened)
|
||||
/* Close the brace for the current line. */
|
||||
ret.back() += '}';
|
||||
|
||||
text.erase(0, z);
|
||||
text.erase(0, currPos);
|
||||
}
|
||||
else if(text[z] == 0x0a) //blank line
|
||||
else if(text[currPos] == 0x0a) //blank line
|
||||
{
|
||||
ret.push_back(""); //add empty string, no extra actions needed
|
||||
}
|
||||
|
@ -316,6 +316,7 @@ void Graphics::loadFonts()
|
||||
|
||||
const JsonVector & bmpConf = config["bitmap"].Vector();
|
||||
const JsonNode & ttfConf = config["trueType"];
|
||||
const JsonNode & hanConf = config["bitmapHan"];
|
||||
|
||||
assert(bmpConf.size() == FONTS_NUMBER);
|
||||
|
||||
@ -323,11 +324,12 @@ void Graphics::loadFonts()
|
||||
{
|
||||
std::string filename = bmpConf[i].String();
|
||||
|
||||
if (!ttfConf[filename].isNull()) // no ttf override
|
||||
if (!hanConf[filename].isNull())
|
||||
fonts[i] = new CBitmapHanFont(hanConf[filename]);
|
||||
else if (!ttfConf[filename].isNull()) // no ttf override
|
||||
fonts[i] = new CTrueTypeFont(ttfConf[filename]);
|
||||
else
|
||||
fonts[i] = new CBitmapFont(filename);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
size_t IFont::getStringWidth(const std::string & data) const
|
||||
{
|
||||
size_t width = 0;
|
||||
|
||||
for(size_t i=0; i<data.size(); i += getCharacterSize(data[i]))
|
||||
{
|
||||
width += getGlyphWidth(data.data() + i);
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
void IFont::renderTextLeft(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const
|
||||
{
|
||||
@ -105,23 +115,12 @@ size_t CBitmapFont::getLineHeight() const
|
||||
return height;
|
||||
}
|
||||
|
||||
size_t CBitmapFont::getSymbolWidth(char data) const
|
||||
size_t CBitmapFont::getGlyphWidth(const char * data) const
|
||||
{
|
||||
const Char & ch = chars[ui8(data)];
|
||||
const Char & ch = chars[ui8(*data)];
|
||||
return ch.leftOffset + ch.width + ch.rightOffset;
|
||||
}
|
||||
|
||||
size_t CBitmapFont::getStringWidth(const std::string & data) const
|
||||
{
|
||||
size_t width = 0;
|
||||
|
||||
for(auto & ch : data)
|
||||
{
|
||||
width += getSymbolWidth(ch);
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
void CBitmapFont::renderCharacter(SDL_Surface * surface, const Char & character, const SDL_Color & color, int &posX, int &posY) const
|
||||
{
|
||||
Rect clipRect;
|
||||
@ -195,6 +194,11 @@ void CBitmapFont::renderText(SDL_Surface * surface, const std::string & data, co
|
||||
SDL_UnlockSurface(surface);
|
||||
}
|
||||
|
||||
size_t CBitmapFont::getCharacterSize(char data) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::pair<std::unique_ptr<ui8[]>, ui64> CTrueTypeFont::loadData(const JsonNode & config)
|
||||
{
|
||||
std::string filename = "Data/" + config["file"].String();
|
||||
@ -240,10 +244,10 @@ size_t CTrueTypeFont::getLineHeight() const
|
||||
return TTF_FontHeight(font.get());
|
||||
}
|
||||
|
||||
size_t CTrueTypeFont::getSymbolWidth(char data) const
|
||||
size_t CTrueTypeFont::getGlyphWidth(const char *data) const
|
||||
{
|
||||
int advance;
|
||||
TTF_GlyphMetrics(font.get(), data, nullptr, nullptr, nullptr, nullptr, &advance);
|
||||
TTF_GlyphMetrics(font.get(), *data, nullptr, nullptr, nullptr, nullptr, &advance);
|
||||
return advance;
|
||||
}
|
||||
|
||||
@ -277,3 +281,109 @@ void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data,
|
||||
SDL_FreeSurface(rendered);
|
||||
}
|
||||
}
|
||||
|
||||
size_t CTrueTypeFont::getCharacterSize(char data) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
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 SDL_Color & color, int &posX, int &posY) const
|
||||
{
|
||||
//TODO: somewhat duplicated with CBitmapFont::renderCharacter();
|
||||
Rect clipRect;
|
||||
SDL_GetClipRect(surface, &clipRect);
|
||||
|
||||
TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0);
|
||||
Uint8 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 - 1);
|
||||
|
||||
// start end end of each row, may differ from 0
|
||||
int rowBegin = std::max<int>(0, clipRect.x - posX);
|
||||
int rowEnd = std::min<int>(size, clipRect.x + clipRect.w - posX - 1);
|
||||
|
||||
//for each line in symbol
|
||||
for(int dy = lineBegin; dy <lineEnd; dy++)
|
||||
{
|
||||
Uint8 *dstLine = (Uint8*)surface->pixels;
|
||||
Uint8 *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* dstPixel = dstLine + dx*bpp;
|
||||
if (bit != 0)
|
||||
colorPutter(dstPixel, color.r, color.g, color.b);
|
||||
}
|
||||
}
|
||||
posX += size;
|
||||
}
|
||||
|
||||
void CBitmapHanFont::renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & 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 += getCharacterSize(data[i]))
|
||||
{
|
||||
if (ui8(data[i]) < 0x80)
|
||||
renderCharacter(surface, getCharacterIndex(0xa3, data[i] + 0x80), color, posX, posY);
|
||||
else
|
||||
renderCharacter(surface, getCharacterIndex(data[i], data[i+1]), color, posX, posY);
|
||||
}
|
||||
SDL_UnlockSurface(surface);
|
||||
}
|
||||
|
||||
CBitmapHanFont::CBitmapHanFont(const JsonNode &config):
|
||||
data(CResourceHandler::get()->load(ResourceID("data/" + config["name"].String(), EResType::OTHER))->readAll()),
|
||||
size(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);
|
||||
// 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 size;
|
||||
}
|
||||
|
||||
size_t CBitmapHanFont::getGlyphWidth(const char * data) const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t CBitmapHanFont::getCharacterSize(char data) const
|
||||
{
|
||||
if (ui8(data) < 0x80)
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
@ -18,6 +18,9 @@ struct SDL_Color;
|
||||
|
||||
typedef struct _TTF_Font TTF_Font;
|
||||
|
||||
class CBitmapFont;
|
||||
class CBitmapHanFont;
|
||||
|
||||
class IFont
|
||||
{
|
||||
protected:
|
||||
@ -30,10 +33,13 @@ public:
|
||||
|
||||
/// Returns height of font
|
||||
virtual size_t getLineHeight() const = 0;
|
||||
/// Returns width of a single symbol
|
||||
virtual size_t getSymbolWidth(char data) 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;
|
||||
/// Returns size (in bytes) of one char in current encoding, may be bigger than one for non-ascii
|
||||
/// TODO: move it out of this class. Separate entity for handling localization/different encodings?
|
||||
virtual size_t getCharacterSize(char data) const = 0;
|
||||
/// Return width of the string
|
||||
virtual size_t getStringWidth(const std::string & data) const = 0;
|
||||
virtual size_t getStringWidth(const std::string & data) const;
|
||||
|
||||
/**
|
||||
* @param surface - destination to print text on
|
||||
@ -77,13 +83,37 @@ class CBitmapFont : public IFont
|
||||
|
||||
void renderCharacter(SDL_Surface * surface, const Char & character, const SDL_Color & color, int &posX, int &posY) const;
|
||||
|
||||
void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const;
|
||||
void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override;
|
||||
public:
|
||||
CBitmapFont(const std::string & filename);
|
||||
|
||||
size_t getLineHeight() const;
|
||||
size_t getSymbolWidth(char data) const;
|
||||
size_t getStringWidth(const std::string & data) const;
|
||||
size_t getLineHeight() const override;
|
||||
size_t getGlyphWidth(const char * data) const override;
|
||||
size_t getCharacterSize(char data) const override;
|
||||
|
||||
friend class CBitmapHanFont;
|
||||
};
|
||||
|
||||
/// supports multi-byte characters for such languages like Chinese
|
||||
class CBitmapHanFont : public IFont
|
||||
{
|
||||
// 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 SDL_Color & color, int &posX, int &posY) const;
|
||||
void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override;
|
||||
public:
|
||||
CBitmapHanFont(const JsonNode & config);
|
||||
|
||||
size_t getLineHeight() const override;
|
||||
size_t getGlyphWidth(const char * data) const override;
|
||||
size_t getCharacterSize(char data) const override;
|
||||
};
|
||||
|
||||
class CTrueTypeFont : public IFont
|
||||
@ -97,11 +127,12 @@ class CTrueTypeFont : public IFont
|
||||
TTF_Font * loadFont(const JsonNode & config);
|
||||
int getFontStyle(const JsonNode & config);
|
||||
|
||||
void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const;
|
||||
void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override;
|
||||
public:
|
||||
CTrueTypeFont(const JsonNode & fontConfig);
|
||||
|
||||
size_t getLineHeight() const;
|
||||
size_t getSymbolWidth(char data) const;
|
||||
size_t getStringWidth(const std::string & data) const;
|
||||
size_t getLineHeight() const override;
|
||||
size_t getGlyphWidth(const char * data) const override;
|
||||
size_t getCharacterSize(char data) const override;
|
||||
size_t getStringWidth(const std::string & data) const override;
|
||||
};
|
||||
|
@ -66,8 +66,6 @@ void CDownloadManager::downloadFinished(QNetworkReply *reply)
|
||||
file.status = FileEntry::FINISHED;
|
||||
}
|
||||
|
||||
file.reply->deleteLater();
|
||||
|
||||
bool downloadComplete = true;
|
||||
for (auto & entry : currentDownloads)
|
||||
{
|
||||
@ -91,6 +89,9 @@ void CDownloadManager::downloadFinished(QNetworkReply *reply)
|
||||
|
||||
if (downloadComplete)
|
||||
emit finished(successful, failed, encounteredErrors);
|
||||
|
||||
file.reply->deleteLater();
|
||||
file.reply = nullptr;
|
||||
}
|
||||
|
||||
void CDownloadManager::downloadProgressChanged(qint64 bytesReceived, qint64 bytesTotal)
|
||||
|
@ -191,7 +191,7 @@ bool ZipArchive::extract(std::string from, std::string where, std::vector<std::s
|
||||
if (boost::algorithm::ends_with(file, "/"))
|
||||
continue;
|
||||
|
||||
std::ofstream destFile(fullName);
|
||||
std::ofstream destFile(fullName, std::ofstream::binary);
|
||||
if (!destFile.good())
|
||||
return false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user