mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Implement smart invalidation for objects
This commit is contained in:
		| @@ -4,13 +4,10 @@ | ||||
| // | ||||
| //  Created by nordsoft on 29.08.2022. | ||||
| // | ||||
|  | ||||
| #include "BitmapHandler.h" | ||||
|  | ||||
| #include "StdInc.h" | ||||
| #include "BitmapHandler.h" | ||||
|  | ||||
| #include "../lib/filesystem/Filesystem.h" | ||||
| #include "BitmapHandler.h" | ||||
|  | ||||
| #include <QBitmap> | ||||
| #include <QImage> | ||||
| @@ -21,152 +18,152 @@ namespace BitmapHandler | ||||
| 	QImage loadH3PCX(ui8 * data, size_t size); | ||||
| 	 | ||||
| 	QImage loadBitmapFromDir(std::string path, std::string fname, bool setKey=true); | ||||
| } | ||||
|  | ||||
| bool isPCX(const ui8 *header)//check whether file can be PCX according to header | ||||
| { | ||||
| 	ui32 fSize  = read_le_u32(header + 0); | ||||
| 	ui32 width  = read_le_u32(header + 4); | ||||
| 	ui32 height = read_le_u32(header + 8); | ||||
| 	return fSize == width*height || fSize == width*height*3; | ||||
| } | ||||
|  | ||||
| enum Epcxformat | ||||
| { | ||||
| 	PCX8B, | ||||
| 	PCX24B | ||||
| }; | ||||
|  | ||||
| QImage BitmapHandler::loadH3PCX(ui8 * pcx, size_t size) | ||||
| { | ||||
| 	//SDL_Surface * ret; | ||||
| 	 | ||||
| 	Epcxformat format; | ||||
| 	int it=0; | ||||
| 	 | ||||
| 	ui32 fSize = read_le_u32(pcx + it); it+=4; | ||||
| 	ui32 width = read_le_u32(pcx + it); it+=4; | ||||
| 	ui32 height = read_le_u32(pcx + it); it+=4; | ||||
| 	 | ||||
| 	if (fSize==width*height*3) | ||||
| 		format=PCX24B; | ||||
| 	else if (fSize==width*height) | ||||
| 		format=PCX8B; | ||||
| 	else | ||||
| 		return QImage(); | ||||
| 	 | ||||
| 	QSize qsize(width, height); | ||||
| 	 | ||||
| 	if (format==PCX8B) | ||||
| 	bool isPCX(const ui8 *header)//check whether file can be PCX according to header | ||||
| 	{ | ||||
| 		it = 0xC; | ||||
| 		//auto bitmap = QBitmap::fromData(qsize, pcx + it); | ||||
| 		QImage image(pcx + it, width, height, QImage::Format_Indexed8); | ||||
| 		ui32 fSize  = read_le_u32(header + 0); | ||||
| 		ui32 width  = read_le_u32(header + 4); | ||||
| 		ui32 height = read_le_u32(header + 8); | ||||
| 		return fSize == width*height || fSize == width*height*3; | ||||
| 	} | ||||
|  | ||||
| 	enum Epcxformat | ||||
| 	{ | ||||
| 		PCX8B, | ||||
| 		PCX24B | ||||
| 	}; | ||||
|  | ||||
| 	QImage loadH3PCX(ui8 * pcx, size_t size) | ||||
| 	{ | ||||
| 		//SDL_Surface * ret; | ||||
| 		 | ||||
| 		//palette - last 256*3 bytes | ||||
| 		QVector<QRgb> colorTable; | ||||
| 		it = (int)size-256*3; | ||||
| 		for (int i=0;i<256;i++) | ||||
| 		Epcxformat format; | ||||
| 		int it=0; | ||||
| 		 | ||||
| 		ui32 fSize = read_le_u32(pcx + it); it+=4; | ||||
| 		ui32 width = read_le_u32(pcx + it); it+=4; | ||||
| 		ui32 height = read_le_u32(pcx + it); it+=4; | ||||
| 		 | ||||
| 		if (fSize==width*height*3) | ||||
| 			format=PCX24B; | ||||
| 		else if (fSize==width*height) | ||||
| 			format=PCX8B; | ||||
| 		else | ||||
| 			return QImage(); | ||||
| 		 | ||||
| 		QSize qsize(width, height); | ||||
| 		 | ||||
| 		if (format==PCX8B) | ||||
| 		{ | ||||
| 			char bytes[3]; | ||||
| 			bytes[0] = pcx[it++]; | ||||
| 			bytes[1] = pcx[it++]; | ||||
| 			bytes[2] = pcx[it++]; | ||||
| 			colorTable.append(qRgb(bytes[0], bytes[1], bytes[2])); | ||||
| 		} | ||||
| 		image.setColorTable(colorTable); | ||||
| 		return image; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		QImage image(pcx + it, width, height, QImage::Format_RGB32); | ||||
| 		return image; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| QImage BitmapHandler::loadBitmapFromDir(std::string path, std::string fname, bool setKey) | ||||
| { | ||||
| 	if(!fname.size()) | ||||
| 	{ | ||||
| 		logGlobal->warn("Call to loadBitmap with void fname!"); | ||||
| 		return QImage(); | ||||
| 	} | ||||
| 	if (!CResourceHandler::get()->existsResource(ResourceID(path + fname, EResType::IMAGE))) | ||||
| 	{ | ||||
| 		return QImage(); | ||||
| 	} | ||||
| 	 | ||||
| 	auto fullpath = CResourceHandler::get()->getResourceName(ResourceID(path + fname, EResType::IMAGE)); | ||||
| 	auto readFile = CResourceHandler::get()->load(ResourceID(path + fname, EResType::IMAGE))->readAll(); | ||||
| 	 | ||||
| 	if (isPCX(readFile.first.get())) | ||||
| 	{//H3-style PCX | ||||
| 		auto image = loadH3PCX(readFile.first.get(), readFile.second); | ||||
| 		if(!image.isNull()) | ||||
| 		{ | ||||
| 			if(image.bitPlaneCount() == 1 && setKey) | ||||
| 			it = 0xC; | ||||
| 			//auto bitmap = QBitmap::fromData(qsize, pcx + it); | ||||
| 			QImage image(pcx + it, width, height, QImage::Format_Indexed8); | ||||
| 			 | ||||
| 			//palette - last 256*3 bytes | ||||
| 			QVector<QRgb> colorTable; | ||||
| 			it = (int)size-256*3; | ||||
| 			for (int i=0;i<256;i++) | ||||
| 			{ | ||||
| 				QVector<QRgb> colorTable = image.colorTable(); | ||||
| 				colorTable[0] = qRgba(255, 255, 255, 0); | ||||
| 				image.setColorTable(colorTable); | ||||
| 				char bytes[3]; | ||||
| 				bytes[0] = pcx[it++]; | ||||
| 				bytes[1] = pcx[it++]; | ||||
| 				bytes[2] = pcx[it++]; | ||||
| 				colorTable.append(qRgb(bytes[0], bytes[1], bytes[2])); | ||||
| 			} | ||||
| 			image.setColorTable(colorTable); | ||||
| 			return image; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			logGlobal->error("Failed to open %s as H3 PCX!", fname); | ||||
| 		} | ||||
| 		return image; | ||||
| 	} | ||||
| 	else | ||||
| 	{ //loading via SDL_Image | ||||
| 		QImage image(QString::fromStdString(fullpath->make_preferred().string())); | ||||
| 		if(!image.isNull()) | ||||
| 		{ | ||||
| 			if(image.bitPlaneCount() == 1) | ||||
| 			{ | ||||
| 				//set correct value for alpha\unused channel | ||||
| 				QVector<QRgb> colorTable = image.colorTable(); | ||||
| 				for(auto & c : colorTable) | ||||
| 					c = qRgb(qRed(c), qGreen(c), qBlue(c)); | ||||
| 				image.setColorTable(colorTable); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			logGlobal->error("Failed to open %s via QImage", fname); | ||||
| 			QImage image(pcx + it, width, height, QImage::Format_RGB32); | ||||
| 			return image; | ||||
| 		} | ||||
| 	} | ||||
| 	return QImage(); | ||||
| 	// When modifying anything here please check two use cases: | ||||
| 	// 1) Vampire mansion in Necropolis (not 1st color is transparent) | ||||
| 	// 2) Battle background when fighting on grass/dirt, topmost sky part (NO transparent color) | ||||
| 	// 3) New objects that may use 24-bit images for icons (e.g. witchking arts) | ||||
| 	/*if (ret->format->palette) | ||||
| 	{ | ||||
| 		CSDL_Ext::setDefaultColorKeyPresize(ret); | ||||
| 	} | ||||
| 	else if (ret->format->Amask) | ||||
| 	{ | ||||
| 		SDL_SetSurfaceBlendMode(ret, SDL_BLENDMODE_BLEND); | ||||
| 	} | ||||
| 	else // always set | ||||
| 	{ | ||||
| 		CSDL_Ext::setDefaultColorKey(ret); | ||||
| 	} | ||||
| 	return ret;*/ | ||||
| } | ||||
|  | ||||
| QImage BitmapHandler::loadBitmap(std::string fname, bool setKey) | ||||
| { | ||||
| 	QImage image = loadBitmapFromDir("DATA/", fname, setKey); | ||||
| 	if(image.isNull()) | ||||
| 	QImage loadBitmapFromDir(std::string path, std::string fname, bool setKey) | ||||
| 	{ | ||||
| 		image = loadBitmapFromDir("SPRITES/", fname, setKey); | ||||
| 		if(!fname.size()) | ||||
| 		{ | ||||
| 			logGlobal->warn("Call to loadBitmap with void fname!"); | ||||
| 			return QImage(); | ||||
| 		} | ||||
| 		if (!CResourceHandler::get()->existsResource(ResourceID(path + fname, EResType::IMAGE))) | ||||
| 		{ | ||||
| 			return QImage(); | ||||
| 		} | ||||
| 		 | ||||
| 		auto fullpath = CResourceHandler::get()->getResourceName(ResourceID(path + fname, EResType::IMAGE)); | ||||
| 		auto readFile = CResourceHandler::get()->load(ResourceID(path + fname, EResType::IMAGE))->readAll(); | ||||
| 		 | ||||
| 		if (isPCX(readFile.first.get())) | ||||
| 		{//H3-style PCX | ||||
| 			auto image = BitmapHandler::loadH3PCX(readFile.first.get(), readFile.second); | ||||
| 			if(!image.isNull()) | ||||
| 			{ | ||||
| 				if(image.bitPlaneCount() == 1 && setKey) | ||||
| 				{ | ||||
| 					QVector<QRgb> colorTable = image.colorTable(); | ||||
| 					colorTable[0] = qRgba(255, 255, 255, 0); | ||||
| 					image.setColorTable(colorTable); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				logGlobal->error("Failed to open %s as H3 PCX!", fname); | ||||
| 			} | ||||
| 			return image; | ||||
| 		} | ||||
| 		else | ||||
| 		{ //loading via SDL_Image | ||||
| 			QImage image(QString::fromStdString(fullpath->make_preferred().string())); | ||||
| 			if(!image.isNull()) | ||||
| 			{ | ||||
| 				if(image.bitPlaneCount() == 1) | ||||
| 				{ | ||||
| 					//set correct value for alpha\unused channel | ||||
| 					QVector<QRgb> colorTable = image.colorTable(); | ||||
| 					for(auto & c : colorTable) | ||||
| 						c = qRgb(qRed(c), qGreen(c), qBlue(c)); | ||||
| 					image.setColorTable(colorTable); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				logGlobal->error("Failed to open %s via QImage", fname); | ||||
| 				return image; | ||||
| 			} | ||||
| 		} | ||||
| 		return QImage(); | ||||
| 		// When modifying anything here please check two use cases: | ||||
| 		// 1) Vampire mansion in Necropolis (not 1st color is transparent) | ||||
| 		// 2) Battle background when fighting on grass/dirt, topmost sky part (NO transparent color) | ||||
| 		// 3) New objects that may use 24-bit images for icons (e.g. witchking arts) | ||||
| 		/*if (ret->format->palette) | ||||
| 		{ | ||||
| 			CSDL_Ext::setDefaultColorKeyPresize(ret); | ||||
| 		} | ||||
| 		else if (ret->format->Amask) | ||||
| 		{ | ||||
| 			SDL_SetSurfaceBlendMode(ret, SDL_BLENDMODE_BLEND); | ||||
| 		} | ||||
| 		else // always set | ||||
| 		{ | ||||
| 			CSDL_Ext::setDefaultColorKey(ret); | ||||
| 		} | ||||
| 		return ret;*/ | ||||
| 	} | ||||
|  | ||||
| 	QImage loadBitmap(std::string fname, bool setKey) | ||||
| 	{ | ||||
| 		QImage image = loadBitmapFromDir("DATA/", fname, setKey); | ||||
| 		if(image.isNull()) | ||||
| 		{ | ||||
| 			logGlobal->error("Error: Failed to find file %s", fname); | ||||
| 			image = loadBitmapFromDir("SPRITES/", fname, setKey); | ||||
| 			if(image.isNull()) | ||||
| 			{ | ||||
| 				logGlobal->error("Error: Failed to find file %s", fname); | ||||
| 			} | ||||
| 		} | ||||
| 		return image; | ||||
| 	} | ||||
| 	return image; | ||||
| } | ||||
|   | ||||
| @@ -10,6 +10,8 @@ | ||||
| #define read_le_u16(p) (* reinterpret_cast<const ui16 *>(p)) | ||||
| #define read_le_u32(p) (* reinterpret_cast<const ui32 *>(p)) | ||||
|  | ||||
| #include <QImage> | ||||
|  | ||||
| namespace BitmapHandler | ||||
| { | ||||
| 	//Load file from /DATA or /SPRITES | ||||
|   | ||||
| @@ -4,9 +4,10 @@ | ||||
| #include "../lib/spells/CSpellHandler.h" | ||||
| #include "../lib/CRandomGenerator.h" | ||||
| #include "../lib/mapObjects/CObjectClassesHandler.h" | ||||
| #include "../lib/mapping/CMap.h" | ||||
|  | ||||
| //===============IMPLEMENT OBJECT INITIALIZATION FUNCTIONS================ | ||||
| Initializer::Initializer(CGObjectInstance * o) | ||||
| Initializer::Initializer(CMap * m, CGObjectInstance * o) : map(m) | ||||
| { | ||||
| ///IMPORTANT! initialize order should be from base objects to derived objects | ||||
| 	INIT_OBJ_TYPE(CGResource); | ||||
| @@ -16,14 +17,14 @@ Initializer::Initializer(CGObjectInstance * o) | ||||
| 	INIT_OBJ_TYPE(CGTownInstance); | ||||
| } | ||||
|  | ||||
| void initialize(CArmedInstance * o) | ||||
| void Initializer::initialize(CArmedInstance * o) | ||||
| { | ||||
| 	if(!o) return; | ||||
| 	 | ||||
| 	o->tempOwner = PlayerColor::NEUTRAL; | ||||
| } | ||||
|  | ||||
| void initialize(CGTownInstance * o) | ||||
| void Initializer::initialize(CGTownInstance * o) | ||||
| { | ||||
| 	if(!o) return; | ||||
|  | ||||
| @@ -37,7 +38,7 @@ void initialize(CGTownInstance * o) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void initialize(CGArtifact * o) | ||||
| void Initializer::initialize(CGArtifact * o) | ||||
| { | ||||
| 	if(!o) return; | ||||
| 	 | ||||
| @@ -46,7 +47,7 @@ void initialize(CGArtifact * o) | ||||
| 		std::vector<SpellID> out; | ||||
| 		for(auto spell : VLC->spellh->objects) //spellh size appears to be greater (?) | ||||
| 		{ | ||||
| 			if(/*map.isAllowedSpell(spell->id) && spell->level == i + 1*/ true) | ||||
| 			//if(map->isAllowedSpell(spell->id)) | ||||
| 			{ | ||||
| 				out.push_back(spell->id); | ||||
| 			} | ||||
| @@ -56,7 +57,7 @@ void initialize(CGArtifact * o) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void initialize(CGMine * o) | ||||
| void Initializer::initialize(CGMine * o) | ||||
| { | ||||
| 	if(!o) return; | ||||
| 	 | ||||
| @@ -64,7 +65,7 @@ void initialize(CGMine * o) | ||||
| 	o->producedQuantity = o->defaultResProduction(); | ||||
| } | ||||
|  | ||||
| void initialize(CGResource * o) | ||||
| void Initializer::initialize(CGResource * o) | ||||
| { | ||||
| 	if(!o) return; | ||||
| 	 | ||||
|   | ||||
| @@ -18,12 +18,23 @@ void setProperty(x*, const QString &, const QVariant &); | ||||
| #define UPDATE_OBJ_PROPERTIES(x) updateProperties(dynamic_cast<x*>(obj)) | ||||
| #define SET_PROPERTIES(x) setProperty(dynamic_cast<x*>(obj), key, value) | ||||
|  | ||||
| //===============DECLARE MAP OBJECTS====================================== | ||||
| DECLARE_OBJ_TYPE(CArmedInstance); | ||||
| DECLARE_OBJ_TYPE(CGTownInstance); | ||||
| DECLARE_OBJ_TYPE(CGArtifact); | ||||
| DECLARE_OBJ_TYPE(CGMine); | ||||
| DECLARE_OBJ_TYPE(CGResource); | ||||
|  | ||||
| class Initializer | ||||
| { | ||||
| public: | ||||
| 	//===============DECLARE MAP OBJECTS====================================== | ||||
| 	DECLARE_OBJ_TYPE(CArmedInstance); | ||||
| 	DECLARE_OBJ_TYPE(CGTownInstance); | ||||
| 	DECLARE_OBJ_TYPE(CGArtifact); | ||||
| 	DECLARE_OBJ_TYPE(CGMine); | ||||
| 	DECLARE_OBJ_TYPE(CGResource); | ||||
| 	 | ||||
| 	 | ||||
| 	Initializer(CMap *, CGObjectInstance *); | ||||
|  | ||||
| private: | ||||
| 	CMap * map; | ||||
| }; | ||||
|  | ||||
| class Inspector | ||||
| { | ||||
| @@ -90,11 +101,7 @@ protected: | ||||
| }; | ||||
|  | ||||
|  | ||||
| class Initializer | ||||
| { | ||||
| public: | ||||
| 	Initializer(CGObjectInstance *); | ||||
| }; | ||||
|  | ||||
|  | ||||
| class PlayerColorDelegate : public QStyledItemDelegate | ||||
| { | ||||
|   | ||||
| @@ -88,7 +88,9 @@ void MapController::sceneForceUpdate(int level) | ||||
|  | ||||
| void MapController::resetMapHandler() | ||||
| { | ||||
| 	_mapHandler.reset(new MapHandler(_map.get())); | ||||
| 	if(!_mapHandler) | ||||
| 		_mapHandler.reset(new MapHandler()); | ||||
| 	_mapHandler->reset(map()); | ||||
| 	_scenes[0]->initialize(*this); | ||||
| 	_scenes[1]->initialize(*this); | ||||
| 	_miniscenes[0]->initialize(*this); | ||||
| @@ -121,11 +123,13 @@ void MapController::commitObjectErase(int level) | ||||
| 	for(auto * obj : _scenes[level]->selectionObjectsView.getSelection()) | ||||
| 	{ | ||||
| 		_map->getEditManager()->removeObject(obj); | ||||
| 		//invalidate tiles under object | ||||
| 		_mapHandler->invalidate(_mapHandler->geTilesUnderObject(obj)); | ||||
| 		delete obj; | ||||
| 	} | ||||
| 	_scenes[level]->selectionObjectsView.clear(); | ||||
| 	resetMapHandler(); | ||||
| 	_scenes[level]->updateViews(); | ||||
| 	_scenes[level]->objectsView.draw(); | ||||
| 	_scenes[level]->selectionObjectsView.draw(); | ||||
| 	 | ||||
| 	_miniscenes[level]->updateViews(); | ||||
| 	main->mapChanged(); | ||||
| @@ -176,8 +180,14 @@ void MapController::commitObstacleFill(int level) | ||||
| 		sel.second.placeObstacles(_map.get(), CRandomGenerator::getDefault()); | ||||
| 	} | ||||
|  | ||||
| 	resetMapHandler(); | ||||
| 	_scenes[level]->updateViews(); | ||||
| 	for(auto & t : selection) | ||||
| 	{ | ||||
| 		_mapHandler->invalidate(t.x, t.y, t.z); | ||||
| 	} | ||||
| 	 | ||||
| 	_scenes[level]->selectionTerrainView.clear(); | ||||
| 	_scenes[level]->selectionTerrainView.draw(); | ||||
| 	_scenes[level]->objectsView.draw(); | ||||
| 	 | ||||
| 	_miniscenes[level]->updateViews(); | ||||
| 	main->mapChanged(); | ||||
| @@ -185,7 +195,8 @@ void MapController::commitObstacleFill(int level) | ||||
|  | ||||
| void MapController::commitObjectChange(int level) | ||||
| { | ||||
| 	resetMapHandler(); | ||||
| 	//for(auto * o : _scenes[level]->selectionObjectsView.getSelection()) | ||||
| 		//_mapHandler->invalidate(o); | ||||
| 	_scenes[level]->objectsView.draw(); | ||||
| 	_scenes[level]->selectionObjectsView.draw(); | ||||
| 	 | ||||
| @@ -219,16 +230,18 @@ void MapController::commitObjectShiftOrCreate(int level) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			auto prevPositions = _mapHandler->geTilesUnderObject(obj); | ||||
| 			_map->getEditManager()->moveObject(obj, pos); | ||||
| 			_mapHandler->invalidate(prevPositions); | ||||
| 			_mapHandler->invalidate(obj); | ||||
| 		} | ||||
| 	} | ||||
| 		 | ||||
| 	_scenes[level]->selectionObjectsView.newObject = nullptr; | ||||
| 	_scenes[level]->selectionObjectsView.shift = QPoint(0, 0); | ||||
| 	_scenes[level]->selectionObjectsView.selectionMode = 0; | ||||
| 	 | ||||
| 	resetMapHandler(); | ||||
| 	_scenes[level]->updateViews(); | ||||
| 	_scenes[level]->objectsView.draw(); | ||||
| 	_scenes[level]->selectionObjectsView.draw(); | ||||
| 	 | ||||
| 	_miniscenes[level]->updateViews(); | ||||
| 	main->mapChanged(); | ||||
| @@ -239,9 +252,10 @@ void MapController::commitObjectCreate(int level) | ||||
| 	auto * newObj = _scenes[level]->selectionObjectsView.newObject; | ||||
| 	if(!newObj) | ||||
| 		return; | ||||
| 	Initializer init(newObj); | ||||
| 	Initializer init(map(), newObj); | ||||
| 	 | ||||
| 	_map->getEditManager()->insertObject(newObj); | ||||
| 	_mapHandler->invalidate(newObj); | ||||
| 	main->mapChanged(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -13,26 +13,37 @@ | ||||
|  | ||||
| const int tileSize = 32; | ||||
|  | ||||
| static bool objectBlitOrderSorter(const TerrainTileObject & a, const TerrainTileObject & b) | ||||
| static bool objectBlitOrderSorter(const TileObject & a, const TileObject & b) | ||||
| { | ||||
| 	return MapHandler::compareObjectBlitOrder(a.obj, b.obj); | ||||
| } | ||||
|  | ||||
| MapHandler::MapHandler(const CMap * Map): | ||||
| 	map(Map) | ||||
| int MapHandler::index(int x, int y, int z) const | ||||
| { | ||||
| 	init(); | ||||
| 	return z * (sizes.x * sizes.y) + y * sizes.x + x; | ||||
| } | ||||
|  | ||||
| void MapHandler::init() | ||||
| int MapHandler::index(const int3 & p) const | ||||
| { | ||||
| 	return index(p.x, p.y, p.z); | ||||
| } | ||||
|  | ||||
| MapHandler::MapHandler() | ||||
| { | ||||
| 	initTerrainGraphics(); | ||||
| 	logGlobal->info("\tPreparing terrain, roads, rivers, borders"); | ||||
| } | ||||
|  | ||||
| void MapHandler::reset(const CMap * Map) | ||||
| { | ||||
| 	ttiles.clear(); | ||||
| 	map = Map; | ||||
| 	 | ||||
| 	//sizes of terrain | ||||
| 	sizes.x = map->width; | ||||
| 	sizes.y = map->height; | ||||
| 	sizes.z = map->twoLevel ? 2 : 1; | ||||
| 	 | ||||
| 	initTerrainGraphics(); | ||||
| 	logGlobal->info("\tPreparing terrain, roads, rivers, borders"); | ||||
| 	initObjectRects(); | ||||
| 	logGlobal->info("\tMaking object rects"); | ||||
| } | ||||
| @@ -78,22 +89,17 @@ void MapHandler::initTerrainGraphics() | ||||
| 	loadFlipped(terrainAnimations, terrainImages, terrainFiles); | ||||
| 	loadFlipped(roadAnimations, roadImages, ROAD_FILES); | ||||
| 	loadFlipped(riverAnimations, riverImages, RIVER_FILES); | ||||
| 	 | ||||
| 	ttiles.resize(sizes.x * sizes.y * sizes.z); | ||||
| } | ||||
|  | ||||
| void MapHandler::drawTerrainTile(QPainter & painter, int x, int y, int z) | ||||
| { | ||||
| 	auto & tinfo = map->getTile(int3(x, y, z)); | ||||
| 	//Rect destRect(realTileRect); | ||||
| 	 | ||||
| 	ui8 rotation = tinfo.extTileFlags % 4; | ||||
| 	 | ||||
| 	if(terrainImages.at(tinfo.terType).size() <= tinfo.terView) | ||||
| 		return; | ||||
| 	 | ||||
| 	bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3); | ||||
| 	 | ||||
| 	painter.drawImage(x * tileSize, y * tileSize, terrainImages.at(tinfo.terType)[tinfo.terView]->mirrored(hflip, vflip)); | ||||
| } | ||||
|  | ||||
| @@ -102,24 +108,11 @@ void MapHandler::drawRoad(QPainter & painter, int x, int y, int z) | ||||
| 	auto & tinfo = map->getTile(int3(x, y, z)); | ||||
| 	auto * tinfoUpper = map->isInTheMap(int3(x, y - 1, z)) ? &map->getTile(int3(x, y - 1, z)) : nullptr; | ||||
|  | ||||
| 	/*if(tinfoUpper && tinfoUpper->roadType != ROAD_NAMES[0]) | ||||
| 	{ | ||||
| 		ui8 rotation = (tinfoUpper->extTileFlags >> 4) % 4; | ||||
|  | ||||
| 		bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3); | ||||
|  | ||||
| 		if(roadImages.at(tinfoUpper->roadType).size() > tinfoUpper->roadDir) | ||||
| 		{ | ||||
| 			painter.drawImage(x * tileSize, y * tileSize, roadImages.at(tinfoUpper->roadType)[tinfoUpper->roadDir]->mirrored(hflip, vflip)); | ||||
| 		} | ||||
| 	}*/ | ||||
|  | ||||
| 	if(tinfo.roadType != ROAD_NAMES[0]) //print road from this tile | ||||
| 	{ | ||||
| 		ui8 rotation = (tinfo.extTileFlags >> 4) % 4; | ||||
|  | ||||
| 		bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3); | ||||
|  | ||||
| 		if(roadImages.at(tinfo.roadType).size() > tinfo.roadDir) | ||||
| 		{ | ||||
| 			painter.drawImage(x * tileSize, y * tileSize, roadImages.at(tinfo.roadType)[tinfo.roadDir]->mirrored(hflip, vflip)); | ||||
| @@ -138,7 +131,6 @@ void MapHandler::drawRiver(QPainter & painter, int x, int y, int z) | ||||
| 		return; | ||||
|  | ||||
| 	ui8 rotation = (tinfo.extTileFlags >> 2) % 4; | ||||
|  | ||||
| 	bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3); | ||||
|  | ||||
| 	painter.drawImage(x * tileSize, y * tileSize, riverImages.at(tinfo.riverType)[tinfo.riverDir]->mirrored(hflip, vflip)); | ||||
| @@ -162,6 +154,8 @@ void setPlayerColor(QImage * sur, PlayerColor player) | ||||
|  | ||||
| void MapHandler::initObjectRects() | ||||
| { | ||||
| 	ttiles.resize(sizes.x * sizes.y * sizes.z); | ||||
| 	 | ||||
| 	//initializing objects / rects | ||||
| 	for(const CGObjectInstance * elem : map->objects) | ||||
| 	{ | ||||
| @@ -184,16 +178,17 @@ void MapHandler::initObjectRects() | ||||
| 			continue; | ||||
| 		 | ||||
| 		auto image = animation->getImage(0,0); | ||||
| 		bool real = true; | ||||
| 		for(int fx=0; fx < obj->getWidth(); ++fx) | ||||
| 		{ | ||||
| 			for(int fy=0; fy < obj->getHeight(); ++fy) | ||||
| 			{ | ||||
| 				int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z); | ||||
| 				QRect cr(image->width() - fx * 32 - 32, image->height() - fy * 32 - 32, image->width(), image->height()); | ||||
| 				TerrainTileObject toAdd(obj, cr, real/*obj->visitableAt(currTile.x, currTile.y)*/); | ||||
| 				real = false; | ||||
| 				QRect cr(image->width() - fx * tileSize - tileSize, | ||||
| 						 image->height() - fy * tileSize - tileSize, | ||||
| 						 image->width(), | ||||
| 						 image->height()); | ||||
| 				 | ||||
| 				TileObject toAdd(obj, cr); | ||||
| 				 | ||||
| 				if( map->isInTheMap(currTile) && // within map | ||||
| 				   cr.x() + cr.width() > 0 &&           // image has data on this tile | ||||
| @@ -201,7 +196,7 @@ void MapHandler::initObjectRects() | ||||
| 				   obj->coveringAt(currTile.x, currTile.y) // object is visible here | ||||
| 				   ) | ||||
| 				{ | ||||
| 					ttiles[currTile.z * (sizes.x * sizes.y) + currTile.y * sizes.x + currTile.x].objects.push_back(toAdd); | ||||
| 					ttiles[index(currTile)].push_back(toAdd); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @@ -209,7 +204,7 @@ void MapHandler::initObjectRects() | ||||
| 	 | ||||
| 	for(auto & tt : ttiles) | ||||
| 	{ | ||||
| 		stable_sort(tt.objects.begin(), tt.objects.end(), objectBlitOrderSorter); | ||||
| 		stable_sort(tt.begin(), tt.end(), objectBlitOrderSorter); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -239,125 +234,24 @@ bool MapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObje | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| TerrainTileObject::TerrainTileObject(CGObjectInstance * obj_, QRect rect_, bool real_) | ||||
| TileObject::TileObject(CGObjectInstance * obj_, QRect rect_) | ||||
| : obj(obj_), | ||||
| rect(rect_), | ||||
| real(real_) | ||||
| rect(rect_) | ||||
| { | ||||
| } | ||||
|  | ||||
| TerrainTileObject::~TerrainTileObject() | ||||
| TileObject::~TileObject() | ||||
| { | ||||
| } | ||||
|  | ||||
| ui8 MapHandler::getHeroFrameGroup(ui8 dir, bool isMoving) const | ||||
| { | ||||
| 	if(isMoving) | ||||
| 	{ | ||||
| 		static const ui8 frame [] = {0xff, 10, 5, 6, 7, 8, 9, 12, 11}; | ||||
| 		return frame[dir]; | ||||
| 	} | ||||
| 	else //if(isMoving) | ||||
| 	{ | ||||
| 		static const ui8 frame [] = {0xff, 13, 0, 1, 2, 3, 4, 15, 14}; | ||||
| 		return frame[dir]; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ui8 MapHandler::getPhaseShift(const CGObjectInstance *object) const | ||||
| { | ||||
| 	auto i = animationPhase.find(object); | ||||
| 	if(i == animationPhase.end()) | ||||
| 	{ | ||||
| 		ui8 ret = CRandomGenerator::getDefault().nextInt(254); | ||||
| 		animationPhase[object] = ret; | ||||
| 		return ret; | ||||
| 	} | ||||
| 	 | ||||
| 	return i->second; | ||||
| } | ||||
|  | ||||
| MapHandler::AnimBitmapHolder MapHandler::findHeroBitmap(const CGHeroInstance * hero, int anim) const | ||||
| { | ||||
| 	if(hero && hero->moveDir && hero->type) //it's hero or boat | ||||
| 	{ | ||||
| 		if(hero->tempOwner >= PlayerColor::PLAYER_LIMIT) //Neutral hero? | ||||
| 		{ | ||||
| 			logGlobal->error("A neutral hero (%s) at %s. Should not happen!", hero->name, hero->pos.toString()); | ||||
| 			return MapHandler::AnimBitmapHolder(); | ||||
| 		} | ||||
| 		 | ||||
| 		//pick graphics of hero (or boat if hero is sailing) | ||||
| 		std::shared_ptr<Animation> animation; | ||||
| 		if (hero->boat) | ||||
| 			animation = graphics->boatAnimations[hero->boat->subID]; | ||||
| 		else | ||||
| 			animation = graphics->heroAnimations[hero->appearance.animationFile]; | ||||
| 		 | ||||
| 		bool moving = !hero->isStanding; | ||||
| 		int group = getHeroFrameGroup(hero->moveDir, moving); | ||||
| 		 | ||||
| 		if(animation->size(group) > 0) | ||||
| 		{ | ||||
| 			int frame = anim % animation->size(group); | ||||
| 			auto heroImage = animation->getImage(frame, group); | ||||
| 			 | ||||
| 			//get flag overlay only if we have main image | ||||
| 			auto flagImage = findFlagBitmap(hero, anim, &hero->tempOwner, group); | ||||
| 			 | ||||
| 			return MapHandler::AnimBitmapHolder(heroImage, flagImage); | ||||
| 		} | ||||
| 	} | ||||
| 	return MapHandler::AnimBitmapHolder(); | ||||
| } | ||||
|  | ||||
| MapHandler::AnimBitmapHolder MapHandler::findBoatBitmap(const CGBoat * boat, int anim) const | ||||
| { | ||||
| 	auto animation = graphics->boatAnimations.at(boat->subID); | ||||
| 	int group = getHeroFrameGroup(boat->direction, false); | ||||
| 	if(animation->size(group) > 0) | ||||
| 		return MapHandler::AnimBitmapHolder(animation->getImage(anim % animation->size(group), group)); | ||||
| 	else | ||||
| 		return MapHandler::AnimBitmapHolder(); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<QImage> MapHandler::findFlagBitmap(const CGHeroInstance * hero, int anim, const PlayerColor * color, int group) const | ||||
| { | ||||
| 	if(!hero) | ||||
| 	if(!hero || hero->boat) | ||||
| 		return std::shared_ptr<QImage>(); | ||||
| 	 | ||||
| 	if(hero->boat) | ||||
| 		return findBoatFlagBitmap(hero->boat, anim, color, group, hero->moveDir); | ||||
| 	return findHeroFlagBitmap(hero, anim, color, group); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<QImage> MapHandler::findHeroFlagBitmap(const CGHeroInstance * hero, int anim, const PlayerColor * color, int group) const | ||||
| { | ||||
| 	return findFlagBitmapInternal(graphics->heroFlagAnimations.at(color->getNum()), anim, group, hero->moveDir, !hero->isStanding); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<QImage> MapHandler::findBoatFlagBitmap(const CGBoat * boat, int anim, const PlayerColor * color, int group, ui8 dir) const | ||||
| { | ||||
| 	int boatType = boat->subID; | ||||
| 	if(boatType < 0 || boatType >= graphics->boatFlagAnimations.size()) | ||||
| 	{ | ||||
| 		logGlobal->error("Not supported boat subtype: %d", boat->subID); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	 | ||||
| 	const auto & subtypeFlags = graphics->boatFlagAnimations.at(boatType); | ||||
| 	 | ||||
| 	int colorIndex = color->getNum(); | ||||
| 	 | ||||
| 	if(colorIndex < 0 || colorIndex >= subtypeFlags.size()) | ||||
| 	{ | ||||
| 		logGlobal->error("Invalid player color %d", colorIndex); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	 | ||||
| 	return findFlagBitmapInternal(subtypeFlags.at(colorIndex), anim, group, dir, false); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<QImage> MapHandler::findFlagBitmapInternal(std::shared_ptr<Animation> animation, int anim, int group, ui8 dir, bool moving) const | ||||
| { | ||||
| 	size_t groupSize = animation->size(group); | ||||
| @@ -370,16 +264,11 @@ std::shared_ptr<QImage> MapHandler::findFlagBitmapInternal(std::shared_ptr<Anima | ||||
| 		return animation->getImage((anim / 4) % groupSize, group); | ||||
| } | ||||
|  | ||||
|  | ||||
| MapHandler::AnimBitmapHolder MapHandler::findObjectBitmap(const CGObjectInstance * obj, int anim) const | ||||
| { | ||||
| 	if (!obj) | ||||
| 	if(!obj || obj->ID == Obj::HERO || obj->ID == Obj::BOAT) | ||||
| 		return MapHandler::AnimBitmapHolder(); | ||||
| 	if (obj->ID == Obj::HERO) | ||||
| 		return findHeroBitmap(static_cast<const CGHeroInstance*>(obj), anim); | ||||
| 	if (obj->ID == Obj::BOAT) | ||||
| 		return findBoatBitmap(static_cast<const CGBoat*>(obj), anim); | ||||
| 	 | ||||
|  | ||||
| 	// normal object | ||||
| 	std::shared_ptr<Animation> animation = graphics->getAnimation(obj); | ||||
| 	size_t groupSize = animation->size(); | ||||
| @@ -387,7 +276,7 @@ MapHandler::AnimBitmapHolder MapHandler::findObjectBitmap(const CGObjectInstance | ||||
| 		return MapHandler::AnimBitmapHolder(); | ||||
| 	 | ||||
| 	animation->playerColored(obj->tempOwner); | ||||
| 	auto bitmap = animation->getImage((anim + getPhaseShift(obj)) % groupSize); | ||||
| 	auto bitmap = animation->getImage(anim % groupSize); | ||||
| 	if(!bitmap) | ||||
| 		return MapHandler::AnimBitmapHolder(); | ||||
|  | ||||
| @@ -396,9 +285,9 @@ MapHandler::AnimBitmapHolder MapHandler::findObjectBitmap(const CGObjectInstance | ||||
| 	return MapHandler::AnimBitmapHolder(bitmap); | ||||
| } | ||||
|  | ||||
| std::vector<TerrainTileObject> & MapHandler::getObjects(int x, int y, int z) | ||||
| std::vector<TileObject> & MapHandler::getObjects(int x, int y, int z) | ||||
| { | ||||
| 	return ttiles[z * (sizes.x * sizes.y) + y * sizes.x + x].objects; | ||||
| 	return ttiles[index(x, y, z)]; | ||||
| } | ||||
|  | ||||
| void MapHandler::drawObjects(QPainter & painter, int x, int y, int z) | ||||
| @@ -418,33 +307,19 @@ void MapHandler::drawObjects(QPainter & painter, int x, int y, int z) | ||||
| 		if (objData.objBitmap) | ||||
| 		{ | ||||
| 			auto pos = obj->getPosition(); | ||||
| 			QRect srcRect(object.rect.x() + pos.x * 32, object.rect.y() + pos.y * 32, tileSize, tileSize); | ||||
|  | ||||
| 			painter.drawImage(QPoint(x * 32, y * 32), *objData.objBitmap, object.rect); | ||||
| 			//painter.drawImage(pos.x * 32 - object.rect.x(), pos.y * 32 - object.rect.y(), *objData.objBitmap); | ||||
| 			//drawObject(targetSurf, objData.objBitmap, &srcRect, objData.isMoving); | ||||
| 			painter.drawImage(QPoint(x * tileSize, y * tileSize), *objData.objBitmap, object.rect); | ||||
| 			if(objData.flagBitmap) | ||||
| 			{ | ||||
| 				/*if (objData.isMoving) | ||||
| 				{ | ||||
| 					srcRect.y += FRAMES_PER_MOVE_ANIM_GROUP * 2 - tileSize; | ||||
| 					Rect dstRect(realPos.x, realPos.y - tileSize / 2, tileSize, tileSize); | ||||
| 					drawHeroFlag(targetSurf, objData.flagBitmap, &srcRect, &dstRect, true); | ||||
| 				}*/ | ||||
| 				if (obj->pos.x == pos.x && obj->pos.y == pos.y) | ||||
| 				{ | ||||
| 					//Rect dstRect(realPos.x - 2 * tileSize, realPos.y - tileSize, 3 * tileSize, 2 * tileSize); | ||||
| 					painter.drawImage(QPoint(x * 32, y * 32), *objData.flagBitmap, object.rect); | ||||
| 					//drawHeroFlag(targetSurf, objData.flagBitmap, nullptr, &dstRect, false); | ||||
| 				} | ||||
| 					painter.drawImage(QPoint(x * tileSize, y * tileSize), *objData.flagBitmap, object.rect); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void MapHandler::drawObject(QPainter & painter, const TerrainTileObject & object) | ||||
| void MapHandler::drawObject(QPainter & painter, const TileObject & object) | ||||
| { | ||||
| 	//if(object.visi) | ||||
| 	const CGObjectInstance * obj = object.obj; | ||||
| 	if (!obj) | ||||
| 	{ | ||||
| @@ -458,24 +333,13 @@ void MapHandler::drawObject(QPainter & painter, const TerrainTileObject & object | ||||
| 	if (objData.objBitmap) | ||||
| 	{ | ||||
| 		auto pos = obj->getPosition(); | ||||
| 		QRect srcRect(object.rect.x() + pos.x * 32, object.rect.y() + pos.y * 32, tileSize, tileSize); | ||||
|  | ||||
| 		painter.drawImage(pos.x * 32 - object.rect.x(), pos.y * 32 - object.rect.y(), *objData.objBitmap); | ||||
| 		//drawObject(targetSurf, objData.objBitmap, &srcRect, objData.isMoving); | ||||
| 		painter.drawImage(pos.x * tileSize - object.rect.x(), pos.y * tileSize - object.rect.y(), *objData.objBitmap); | ||||
| 		if (objData.flagBitmap) | ||||
| 		{ | ||||
| 			/*if (objData.isMoving) | ||||
| 			{ | ||||
| 				srcRect.y += FRAMES_PER_MOVE_ANIM_GROUP * 2 - tileSize; | ||||
| 				Rect dstRect(realPos.x, realPos.y - tileSize / 2, tileSize, tileSize); | ||||
| 				drawHeroFlag(targetSurf, objData.flagBitmap, &srcRect, &dstRect, true); | ||||
| 			} | ||||
| 			else */ | ||||
| 			if (obj->pos.x == pos.x && obj->pos.y == pos.y) | ||||
| 			{ | ||||
| 				//Rect dstRect(realPos.x - 2 * tileSize, realPos.y - tileSize, 3 * tileSize, 2 * tileSize); | ||||
| 				//drawHeroFlag(targetSurf, objData.flagBitmap, nullptr, &dstRect, false); | ||||
| 				painter.drawImage(pos.x * 32 - object.rect.x(), pos.y * 32 - object.rect.y(), *objData.flagBitmap); | ||||
| 				painter.drawImage(pos.x * tileSize - object.rect.x(), pos.y * tileSize - object.rect.y(), *objData.flagBitmap); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -538,3 +402,102 @@ void MapHandler::drawMinimapTile(QPainter & painter, int x, int y, int z) | ||||
| 	painter.setPen(getTileColor(x, y, z)); | ||||
| 	painter.drawPoint(x, y); | ||||
| } | ||||
|  | ||||
| void MapHandler::invalidate(int x, int y, int z) | ||||
| { | ||||
| 	auto & objects = getObjects(x, y, z); | ||||
| 	 | ||||
| 	for(auto obj = objects.begin(); obj != objects.end();) | ||||
| 	{ | ||||
| 		//object was removed | ||||
| 		if(std::find(map->objects.begin(), map->objects.end(), obj->obj) == map->objects.end()) | ||||
| 		{ | ||||
| 			obj = objects.erase(obj); | ||||
| 			continue; | ||||
| 		} | ||||
| 			 | ||||
| 		//object was moved | ||||
| 		auto & pos = obj->obj->pos; | ||||
| 		if(pos.z != z || pos.x < x || pos.y < y || pos.x - obj->obj->getWidth() >= x || pos.y - obj->obj->getHeight() >= y) | ||||
| 		{ | ||||
| 			obj = objects.erase(obj); | ||||
| 			continue; | ||||
| 		} | ||||
| 		 | ||||
| 		++obj; | ||||
| 		//invalidate(obj->obj); | ||||
| 	} | ||||
| 	 | ||||
| 	stable_sort(objects.begin(), objects.end(), objectBlitOrderSorter); | ||||
| } | ||||
|  | ||||
| void MapHandler::invalidate(CGObjectInstance * obj) | ||||
| { | ||||
| 	std::shared_ptr<Animation> animation = graphics->getAnimation(obj); | ||||
| 		 | ||||
| 	//no animation at all or empty animation | ||||
| 	if(!animation || animation->size(0) == 0) | ||||
| 		return; | ||||
| 		 | ||||
| 	auto image = animation->getImage(0,0); | ||||
| 	for(int fx=0; fx < obj->getWidth(); ++fx) | ||||
| 	{ | ||||
| 		for(int fy=0; fy < obj->getHeight(); ++fy) | ||||
| 		{ | ||||
| 			//object presented on the tile | ||||
| 			int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z); | ||||
| 			QRect cr(image->width() - fx * tileSize - tileSize, image->height() - fy * tileSize - tileSize, image->width(), image->height()); | ||||
| 			 | ||||
| 			if( map->isInTheMap(currTile) && // within map | ||||
| 			   cr.x() + cr.width() > 0 &&           // image has data on this tile | ||||
| 			   cr.y() + cr.height() > 0 && | ||||
| 			   obj->coveringAt(currTile.x, currTile.y) // object is visible here | ||||
| 			   ) | ||||
| 			{ | ||||
| 				auto & objects = ttiles[index(currTile)]; | ||||
| 				bool found = false; | ||||
| 				for(auto & o : objects) | ||||
| 				{ | ||||
| 					if(o.obj == obj) | ||||
| 					{ | ||||
| 						o.rect = cr; | ||||
| 						found = true; | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				if(!found) | ||||
| 					objects.emplace_back(obj, cr); | ||||
| 				 | ||||
| 				stable_sort(objects.begin(), objects.end(), objectBlitOrderSorter); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::vector<int3> MapHandler::geTilesUnderObject(CGObjectInstance * obj) const | ||||
| { | ||||
| 	std::vector<int3> result; | ||||
| 	for(int fx=0; fx < obj->getWidth(); ++fx) | ||||
| 	{ | ||||
| 		for(int fy=0; fy < obj->getHeight(); ++fy) | ||||
| 		{ | ||||
| 			//object presented on the tile | ||||
| 			int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z); | ||||
| 			if(map->isInTheMap(currTile) && // within map | ||||
| 			   obj->coveringAt(currTile.x, currTile.y) // object is visible here | ||||
| 			   ) | ||||
| 			{ | ||||
| 				result.push_back(currTile); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| void MapHandler::invalidate(const std::vector<int3> & tiles) | ||||
| { | ||||
| 	for(auto & currTile : tiles) | ||||
| 	{ | ||||
| 		invalidate(currTile.x, currTile.y, currTile.z); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -13,20 +13,16 @@ class CGObjectInstance; | ||||
| class CGBoat; | ||||
| class PlayerColor; | ||||
|  | ||||
| struct TerrainTileObject | ||||
| struct TileObject | ||||
| { | ||||
| 	CGObjectInstance *obj; | ||||
| 	QRect rect; | ||||
| 	bool real; | ||||
| 	 | ||||
| 	TerrainTileObject(CGObjectInstance *obj_, QRect rect_, bool visitablePos = false); | ||||
| 	~TerrainTileObject(); | ||||
| 	TileObject(CGObjectInstance *obj_, QRect rect_); | ||||
| 	~TileObject(); | ||||
| }; | ||||
|  | ||||
| struct TerrainTile2 | ||||
| { | ||||
| 	std::vector<TerrainTileObject> objects; //pointers to objects being on this tile with rects to be easier to blit this tile on screen | ||||
| }; | ||||
| using TileObjects = std::vector<TileObject>; //pointers to objects being on this tile with rects to be easier to blit this tile on screen | ||||
|  | ||||
| class MapHandler | ||||
| { | ||||
| @@ -44,21 +40,30 @@ public: | ||||
| 	 | ||||
| private: | ||||
| 	 | ||||
| 	ui8 getHeroFrameGroup(ui8 dir, bool isMoving) const; | ||||
| 	ui8 getPhaseShift(const CGObjectInstance *object) const; | ||||
| 	 | ||||
| 	// internal helper methods to choose correct bitmap(s) for object; called internally by findObjectBitmap | ||||
| 	AnimBitmapHolder findHeroBitmap(const CGHeroInstance * hero, int anim) const; | ||||
| 	AnimBitmapHolder findBoatBitmap(const CGBoat * hero, int anim) const; | ||||
| 	std::shared_ptr<QImage> findFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int group) const; | ||||
| 	std::shared_ptr<QImage> findHeroFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int group) const; | ||||
| 	std::shared_ptr<QImage> findBoatFlagBitmap(const CGBoat * obj, int anim, const PlayerColor * color, int group, ui8 dir) const; | ||||
| 	int index(int x, int y, int z) const; | ||||
| 	int index(const int3 &) const; | ||||
| 		 | ||||
| 	std::shared_ptr<QImage> findFlagBitmapInternal(std::shared_ptr<Animation> animation, int anim, int group, ui8 dir, bool moving) const; | ||||
| 	 | ||||
| public: | ||||
| 	 | ||||
| 	std::shared_ptr<QImage> findFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int group) const; | ||||
| 	AnimBitmapHolder findObjectBitmap(const CGObjectInstance * obj, int anim) const; | ||||
| 	 | ||||
| 	//FIXME: unique_ptr should be enough, but fails to compile in MSVS 2013 | ||||
| 	typedef std::map<std::string, std::shared_ptr<Animation>> TFlippedAnimations; //[type, rotation] | ||||
| 	typedef std::map<std::string, std::vector<std::shared_ptr<QImage>>> TFlippedCache;//[type, view type, rotation] | ||||
| 	 | ||||
| 	TFlippedAnimations terrainAnimations;//[terrain type, rotation] | ||||
| 	TFlippedCache terrainImages;//[terrain type, view type, rotation] | ||||
| 	 | ||||
| 	TFlippedAnimations roadAnimations;//[road type, rotation] | ||||
| 	TFlippedCache roadImages;//[road type, view type, rotation] | ||||
| 	 | ||||
| 	TFlippedAnimations riverAnimations;//[river type, rotation] | ||||
| 	TFlippedCache riverImages;//[river type, view type, rotation] | ||||
| 	 | ||||
| 	std::vector<TileObjects> ttiles; //informations about map tiles | ||||
| 	int3 sizes; //map size (x = width, y = height, z = number of levels) | ||||
| 	const CMap * map; | ||||
| 		 | ||||
| 	enum class EMapCacheType : char | ||||
| 	{ | ||||
| 		TERRAIN, OBJECTS, ROADS, RIVERS, FOW, HEROES, HERO_FLAGS, FRAME, AFTER_LAST | ||||
| @@ -66,59 +71,34 @@ public: | ||||
| 	 | ||||
| 	void initObjectRects(); | ||||
| 	void initTerrainGraphics(); | ||||
| 	QRgb getTileColor(int x, int y, int z); | ||||
| 		 | ||||
| public: | ||||
| 	MapHandler(); | ||||
| 	~MapHandler() = default; | ||||
| 	 | ||||
| 	void reset(const CMap * Map); | ||||
|  | ||||
| 	std::vector<TerrainTile2> ttiles; //informations about map tiles | ||||
| 	int3 sizes; //map size (x = width, y = height, z = number of levels) | ||||
| 	const CMap * map; | ||||
|  | ||||
| 	//terrain graphics | ||||
|  | ||||
| 	//FIXME: unique_ptr should be enough, but fails to compile in MSVS 2013 | ||||
| 	typedef std::map<std::string, std::shared_ptr<Animation>> TFlippedAnimations; //[type, rotation] | ||||
| 	typedef std::map<std::string, std::vector<std::shared_ptr<QImage>>> TFlippedCache;//[type, view type, rotation] | ||||
|  | ||||
| 	TFlippedAnimations terrainAnimations;//[terrain type, rotation] | ||||
| 	TFlippedCache terrainImages;//[terrain type, view type, rotation] | ||||
|  | ||||
| 	TFlippedAnimations roadAnimations;//[road type, rotation] | ||||
| 	TFlippedCache roadImages;//[road type, view type, rotation] | ||||
|  | ||||
| 	TFlippedAnimations riverAnimations;//[river type, rotation] | ||||
| 	TFlippedCache riverImages;//[river type, view type, rotation] | ||||
| 	void updateWater(); | ||||
| 	 | ||||
| 	void drawTerrainTile(QPainter & painter, int x, int y, int z); | ||||
| 	/// draws a river segment on current tile | ||||
| 	void drawRiver(QPainter & painter, int x, int y, int z); | ||||
| 	/// draws a road segment on current tile | ||||
| 	void drawRoad(QPainter & painter, int x, int y, int z); | ||||
| 	 | ||||
| 	void invalidate(int x, int y, int z); //invalidates all objects in particular tile | ||||
| 	void invalidate(CGObjectInstance *); //invalidates object rects | ||||
| 	void invalidate(const std::vector<int3> &); //invalidates all tiles | ||||
| 	std::vector<int3> geTilesUnderObject(CGObjectInstance *) const; | ||||
| 	 | ||||
| 	/// draws all objects on current tile (higher-level logic, unlike other draw*** methods) | ||||
| 	void drawObjects(QPainter & painter, int x, int y, int z); | ||||
| 	void drawObject(QPainter & painter, const TerrainTileObject & object); | ||||
| 	void drawObject(QPainter & painter, const TileObject & object); | ||||
| 	void drawObjectAt(QPainter & painter, const CGObjectInstance * object, int x, int y); | ||||
| 	std::vector<TerrainTileObject> & getObjects(int x, int y, int z); | ||||
| 	//void drawObject(SDL_Surface * targetSurf, std::shared_ptr<IImage> source, SDL_Rect * sourceRect, bool moving) const; | ||||
| 	//void drawHeroFlag(SDL_Surface * targetSurf, std::shared_ptr<IImage> source, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const; | ||||
| 	QRgb getTileColor(int x, int y, int z); | ||||
| 	std::vector<TileObject> & getObjects(int x, int y, int z); | ||||
| 	 | ||||
| 	void drawMinimapTile(QPainter & painter, int x, int y, int z); | ||||
| 	 | ||||
| 	mutable std::map<const CGObjectInstance*, ui8> animationPhase; | ||||
|  | ||||
| 	MapHandler(const CMap * Map); | ||||
| 	~MapHandler() = default; | ||||
| 	 | ||||
| 	void init(); | ||||
|  | ||||
| 	//void getTerrainDescr(const int3 & pos, std::string & out, bool isRMB) const; // isRMB = whether Right Mouse Button is clicked | ||||
| 	//bool printObject(const CGObjectInstance * obj, bool fadein = false); //puts appropriate things to tiles, so obj will be visible on map | ||||
| 	//bool hideObject(const CGObjectInstance * obj, bool fadeout = false); //removes appropriate things from ttiles, so obj will be no longer visible on map (but still will exist) | ||||
| 	//bool hasObjectHole(const int3 & pos) const; // Checks if TerrainTile2 tile has a pit remained after digging. | ||||
|  | ||||
| 	//EMapAnimRedrawStatus drawTerrainRectNew(SDL_Surface * targetSurface, const MapDrawingInfo * info, bool redrawOnlyAnim = false); | ||||
| 	void updateWater(); | ||||
| 	/// determines if the map is ready to handle new hero movement (not available during fading animations) | ||||
| 	//bool canStartHeroMovement(); | ||||
|  | ||||
| 	//void discardWorldViewCache(); | ||||
|  | ||||
| 	static bool compareObjectBlitOrder(const CGObjectInstance * a, const CGObjectInstance * b); | ||||
| }; | ||||
|   | ||||
| @@ -319,7 +319,6 @@ void ObjectsLayer::setDirty(int x, int y) | ||||
|  | ||||
| void ObjectsLayer::setDirty(const CGObjectInstance * object) | ||||
| { | ||||
| 	dirty.insert(object); | ||||
| } | ||||
|  | ||||
| SelectionObjectsLayer::SelectionObjectsLayer(MapSceneBase * s): AbstractLayer(s), newObject(nullptr) | ||||
|   | ||||
| @@ -98,7 +98,8 @@ public: | ||||
| 	void setDirty(const CGObjectInstance * object); | ||||
| 	 | ||||
| private: | ||||
| 	std::set<const CGObjectInstance *> dirty; | ||||
| 	std::set<const CGObjectInstance *> objDirty; | ||||
| 	std::set<int3> dirty; | ||||
| }; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -88,6 +88,13 @@ void WindowNewMap::on_okButtong_clicked() | ||||
| 	std::unique_ptr<CMap> nmap; | ||||
| 	if(ui->randomMapCheck->isChecked()) | ||||
| 	{ | ||||
| 		//verify map template | ||||
| 		if(mapGenOptions.getPossibleTemplates().empty()) | ||||
| 		{ | ||||
| 			QMessageBox::warning(this, "No template", "No template for parameters scecified. Random map cannot be generated."); | ||||
| 			return; | ||||
| 		} | ||||
| 		 | ||||
| 		CMapGenerator generator(mapGenOptions); | ||||
| 		//TODO: fix water and roads | ||||
| 		generator.disableModificator("RoadPlacer"); | ||||
| @@ -96,9 +103,16 @@ void WindowNewMap::on_okButtong_clicked() | ||||
| 		auto progressBarWnd = new GeneratorProgress(generator, this); | ||||
| 		progressBarWnd->show(); | ||||
| 	 | ||||
| 		auto f = std::async(std::launch::async, &CMapGenerator::generate, &generator); | ||||
| 		progressBarWnd->update(); | ||||
| 		nmap = f.get(); | ||||
| 		try | ||||
| 		{ | ||||
| 			auto f = std::async(std::launch::async, &CMapGenerator::generate, &generator); | ||||
| 			progressBarWnd->update(); | ||||
| 			nmap = f.get(); | ||||
| 		} | ||||
| 		catch(const std::exception & e) | ||||
| 		{ | ||||
| 			QMessageBox::critical(this, "RMG failure", e.what()); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{		 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user