mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-19 00:17:56 +02:00
@ -688,7 +688,7 @@ void processCommand(const std::string &message)
|
|||||||
auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
|
auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
|
||||||
|
|
||||||
boost::filesystem::create_directories(fullPath.substr(0, fullPath.find_last_of("/")));
|
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);
|
outFile.write((char*)data.first.get(), data.second);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -138,49 +138,45 @@ std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineSi
|
|||||||
while (text.length())
|
while (text.length())
|
||||||
{
|
{
|
||||||
ui32 lineLength = 0; //in characters or given char metric
|
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 opened = false;//if we have an unclosed brace in current line
|
||||||
bool lineManuallyBroken = false;
|
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. */
|
/* We don't count braces in string length. */
|
||||||
if (text[z] == '{')
|
if (text[currPos] == '{')
|
||||||
opened=true;
|
opened=true;
|
||||||
else if (text[z]=='}')
|
else if (text[currPos]=='}')
|
||||||
opened=false;
|
opened=false;
|
||||||
else
|
else
|
||||||
lineLength += graphics->fonts[font]->getSymbolWidth(text[z]);
|
lineLength += graphics->fonts[font]->getGlyphWidth(text.data() + currPos);
|
||||||
z++;
|
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
|
// We have a long line. Try to do a nice line break, if possible
|
||||||
* possible. We backtrack on the line until we find a
|
if (wordBreak != ui32(-1))
|
||||||
* suitable character.
|
currPos = wordBreak;
|
||||||
* Note: Cyrillic symbols have indexes 220-255 so we need
|
else
|
||||||
* to use ui8 for comparison
|
currPos--;
|
||||||
*/
|
|
||||||
int pos = z-1;
|
|
||||||
while(pos > 0 && ((ui8)text[pos]) > ' ' )
|
|
||||||
pos --;
|
|
||||||
|
|
||||||
if (pos > 0)
|
|
||||||
z = pos+1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
if (opened)
|
||||||
/* Close the brace for the current line. */
|
/* Close the brace for the current line. */
|
||||||
ret.back() += '}';
|
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
|
ret.push_back(""); //add empty string, no extra actions needed
|
||||||
}
|
}
|
||||||
|
@ -316,6 +316,7 @@ void Graphics::loadFonts()
|
|||||||
|
|
||||||
const JsonVector & bmpConf = config["bitmap"].Vector();
|
const JsonVector & bmpConf = config["bitmap"].Vector();
|
||||||
const JsonNode & ttfConf = config["trueType"];
|
const JsonNode & ttfConf = config["trueType"];
|
||||||
|
const JsonNode & hanConf = config["bitmapHan"];
|
||||||
|
|
||||||
assert(bmpConf.size() == FONTS_NUMBER);
|
assert(bmpConf.size() == FONTS_NUMBER);
|
||||||
|
|
||||||
@ -323,11 +324,12 @@ void Graphics::loadFonts()
|
|||||||
{
|
{
|
||||||
std::string filename = bmpConf[i].String();
|
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]);
|
fonts[i] = new CTrueTypeFont(ttfConf[filename]);
|
||||||
else
|
else
|
||||||
fonts[i] = new CBitmapFont(filename);
|
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
|
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;
|
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;
|
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
|
void CBitmapFont::renderCharacter(SDL_Surface * surface, const Char & character, const SDL_Color & color, int &posX, int &posY) const
|
||||||
{
|
{
|
||||||
Rect clipRect;
|
Rect clipRect;
|
||||||
@ -195,6 +194,11 @@ void CBitmapFont::renderText(SDL_Surface * surface, const std::string & data, co
|
|||||||
SDL_UnlockSurface(surface);
|
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::pair<std::unique_ptr<ui8[]>, ui64> CTrueTypeFont::loadData(const JsonNode & config)
|
||||||
{
|
{
|
||||||
std::string filename = "Data/" + config["file"].String();
|
std::string filename = "Data/" + config["file"].String();
|
||||||
@ -240,10 +244,10 @@ size_t CTrueTypeFont::getLineHeight() const
|
|||||||
return TTF_FontHeight(font.get());
|
return TTF_FontHeight(font.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t CTrueTypeFont::getSymbolWidth(char data) const
|
size_t CTrueTypeFont::getGlyphWidth(const char *data) const
|
||||||
{
|
{
|
||||||
int advance;
|
int advance;
|
||||||
TTF_GlyphMetrics(font.get(), data, nullptr, nullptr, nullptr, nullptr, &advance);
|
TTF_GlyphMetrics(font.get(), *data, nullptr, nullptr, nullptr, nullptr, &advance);
|
||||||
return advance;
|
return advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,3 +281,109 @@ void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data,
|
|||||||
SDL_FreeSurface(rendered);
|
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;
|
typedef struct _TTF_Font TTF_Font;
|
||||||
|
|
||||||
|
class CBitmapFont;
|
||||||
|
class CBitmapHanFont;
|
||||||
|
|
||||||
class IFont
|
class IFont
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -30,10 +33,13 @@ public:
|
|||||||
|
|
||||||
/// Returns height of font
|
/// Returns height of font
|
||||||
virtual size_t getLineHeight() const = 0;
|
virtual size_t getLineHeight() const = 0;
|
||||||
/// Returns width of a single symbol
|
/// Returns width, in pixels of a character glyph. Pointer must contain at least characterSize valid bytes
|
||||||
virtual size_t getSymbolWidth(char data) const = 0;
|
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
|
/// 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
|
* @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 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:
|
public:
|
||||||
CBitmapFont(const std::string & filename);
|
CBitmapFont(const std::string & filename);
|
||||||
|
|
||||||
size_t getLineHeight() const;
|
size_t getLineHeight() const override;
|
||||||
size_t getSymbolWidth(char data) const;
|
size_t getGlyphWidth(const char * data) const override;
|
||||||
size_t getStringWidth(const std::string & data) const;
|
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
|
class CTrueTypeFont : public IFont
|
||||||
@ -97,11 +127,12 @@ class CTrueTypeFont : public IFont
|
|||||||
TTF_Font * loadFont(const JsonNode & config);
|
TTF_Font * loadFont(const JsonNode & config);
|
||||||
int getFontStyle(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:
|
public:
|
||||||
CTrueTypeFont(const JsonNode & fontConfig);
|
CTrueTypeFont(const JsonNode & fontConfig);
|
||||||
|
|
||||||
size_t getLineHeight() const;
|
size_t getLineHeight() const override;
|
||||||
size_t getSymbolWidth(char data) const;
|
size_t getGlyphWidth(const char * data) const override;
|
||||||
size_t getStringWidth(const std::string & data) const;
|
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.status = FileEntry::FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.reply->deleteLater();
|
|
||||||
|
|
||||||
bool downloadComplete = true;
|
bool downloadComplete = true;
|
||||||
for (auto & entry : currentDownloads)
|
for (auto & entry : currentDownloads)
|
||||||
{
|
{
|
||||||
@ -91,6 +89,9 @@ void CDownloadManager::downloadFinished(QNetworkReply *reply)
|
|||||||
|
|
||||||
if (downloadComplete)
|
if (downloadComplete)
|
||||||
emit finished(successful, failed, encounteredErrors);
|
emit finished(successful, failed, encounteredErrors);
|
||||||
|
|
||||||
|
file.reply->deleteLater();
|
||||||
|
file.reply = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDownloadManager::downloadProgressChanged(qint64 bytesReceived, qint64 bytesTotal)
|
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, "/"))
|
if (boost::algorithm::ends_with(file, "/"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::ofstream destFile(fullName);
|
std::ofstream destFile(fullName, std::ofstream::binary);
|
||||||
if (!destFile.good())
|
if (!destFile.good())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user