mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	| @@ -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; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user