瀏覽代碼

World view mode drawing: refactoring, part 2 (further merging of common functionalities; abstracted puzzle view to separate blitter);

Fay 10 年之前
父節點
當前提交
01029779d7
共有 3 個文件被更改,包括 406 次插入344 次删除
  1. 305 286
      client/mapHandler.cpp
  2. 100 57
      client/mapHandler.h
  3. 1 1
      client/windows/CAdvmapInterface.h

+ 305 - 286
client/mapHandler.cpp

@@ -188,10 +188,7 @@ void CMapHandler::prepareFOWDefs()
 void CMapHandler::drawTerrainRectNew(SDL_Surface * targetSurface, const MapDrawingInfo * info)
 {
 	assert(info);
-	if (info->scaled)
-		worldViewBlitter->blit(targetSurface, info);
-	else
-		normalBlitter->blit(targetSurface, info);
+	resolveBlitter(info)->blit(targetSurface, info);
 }
 
 void CMapHandler::roadsRiverTerrainInit()
@@ -422,147 +419,49 @@ void CMapHandler::init()
 
 }
 
-void CMapHandler::calculateWorldViewCameraPos(int targetTilesX, int targetTilesY, int3 &tile)
+CMapHandler::CMapBlitter *CMapHandler::resolveBlitter(const MapDrawingInfo * info) const
 {
-	bool outsideLeft = tile.x < 0;
-	bool outsideTop = tile.y < 0;
-	bool outsideRight = std::max(0, tile.x) + targetTilesX > sizes.x;
-	bool outsideBottom = std::max(0, tile.y) + targetTilesY > sizes.y;
-
-	if (targetTilesX > sizes.x)
-		tile.x = sizes.x / 2 - targetTilesX / 2; // center viewport if the whole map can fit into the screen at once
-	else if (outsideLeft)
-	{
-		if (outsideRight)
-			tile.x = sizes.x / 2 - targetTilesX / 2;
-		else
-			tile.x = 0;
-	}
-	else if (outsideRight)
-		tile.x = sizes.x - targetTilesX;
+	if (info->scaled)
+		return worldViewBlitter;
+	if (info->puzzleMode)
+		return puzzleViewBlitter;
 
-	if (targetTilesY > sizes.y)
-		tile.y = sizes.y / 2 - targetTilesY / 2;
-	else if (outsideTop)
-	{
-		if (outsideBottom)
-			tile.y = sizes.y / 2 - targetTilesY / 2;
-		else
-			tile.y = 0;
-	}
-	else if (outsideBottom)
-		tile.y = sizes.y - targetTilesY;
+	return normalBlitter;
 }
 
-void CMapHandler::drawScaledRotatedElement(EMapCacheType type, SDL_Surface * baseSurf, SDL_Surface * targetSurf, ui8 rotation,
-											float scale, SDL_Rect * dstRect, SDL_Rect * srcRect /*= nullptr*/)
+void CMapHandler::CMapNormalBlitter::drawElement(EMapCacheType cacheType, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Surface * targetSurf, SDL_Rect * destRect, bool alphaBlit, ui8 rotationInfo) const
 {
-	auto key = cache.genKey((intptr_t)baseSurf, rotation);
-	auto scaledSurf = cache.requestWorldViewCache(type, key);
-	if (scaledSurf) // blitting from cache
+	if (rotationInfo != 0)
 	{
-		if (srcRect)
+		if (!sourceRect)
 		{
-			dstRect->w = srcRect->w;
-			dstRect->h = srcRect->h;
+			Rect sourceRect2(0, 0, sourceSurf->w, sourceSurf->h);
+			if (alphaBlit)
+				CSDL_Ext::getBlitterWithRotationAndAlpha(targetSurf)(sourceSurf, sourceRect2, targetSurf, *destRect, rotationInfo);
+			else
+				CSDL_Ext::getBlitterWithRotation(targetSurf)(sourceSurf, sourceRect2, targetSurf, *destRect, rotationInfo);
+		}
+		else
+		{
+			if (alphaBlit)
+				CSDL_Ext::getBlitterWithRotationAndAlpha(targetSurf)(sourceSurf, *sourceRect, targetSurf, *destRect, rotationInfo);
+			else
+				CSDL_Ext::getBlitterWithRotation(targetSurf)(sourceSurf, *sourceRect, targetSurf, *destRect, rotationInfo);
 		}
-		CSDL_Ext::blitSurface(scaledSurf, srcRect, targetSurf, dstRect);
-	}
-	else // creating new
-	{
-		auto baseSurfRotated = CSDL_Ext::newSurface(baseSurf->w, baseSurf->h);
-		if (!baseSurfRotated)
-			return;
-		Rect baseRect(0, 0, baseSurf->w, baseSurf->h);
-
-		CSDL_Ext::getBlitterWithRotationAndAlpha(targetSurf)(baseSurf, baseRect, baseSurfRotated, baseRect, rotation);
-
-		SDL_Surface * scaledSurf2 = CSDL_Ext::scaleSurfaceFast(baseSurfRotated, baseSurf->w * scale, baseSurf->h * scale);
-
-		CSDL_Ext::blitSurface(scaledSurf2, srcRect, targetSurf, dstRect);
-		cache.cacheWorldViewEntry(type, key, scaledSurf2);
-	}
-}
-
-void CMapHandler::CMapNormalBlitter::drawNormalObject(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect)
-{
-	Rect dstRect(realPos.x, realPos.y, tileSize, tileSize);
-	CSDL_Ext::blit8bppAlphaTo24bpp(sourceSurf, sourceRect, targetSurf,&dstRect);
-}
-
-void CMapHandler::CMapNormalBlitter::drawHeroFlag(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving)
-{
-	CSDL_Ext::blitSurface(sourceSurf, sourceRect, targetSurf, destRect);
-}
-
-void CMapHandler::CMapNormalBlitter::drawHero(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving)
-{
-	Rect dstRect(realPos.x, realPos.y, tileSize, tileSize);
-	CSDL_Ext::blit8bppAlphaTo24bpp(sourceSurf,sourceRect,targetSurf,&dstRect);
-}
-
-void CMapHandler::CMapNormalBlitter::drawRoad(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo, const TerrainTile * tinfoUpper)
-{
-	if (tinfoUpper && tinfoUpper->roadType != ERoadType::NO_ROAD)
-	{
-		Rect source(0, tileSize / 2, tileSize, tileSize / 2);
-		Rect dest(realPos.x, realPos.y, tileSize, tileSize / 2);
-		CSDL_Ext::getBlitterWithRotationAndAlpha(targetSurf)
-				(parent->roadDefs[tinfoUpper->roadType - 1]->ourImages[tinfoUpper->roadDir].bitmap, source, targetSurf, dest, (tinfoUpper->extTileFlags >> 4) % 4);
-	}
-
-	if(tinfo.roadType != ERoadType::NO_ROAD) //print road from this tile
-	{
-		Rect source(0, 0, tileSize, tileSize);
-		Rect dest(realPos.x, realPos.y + tileSize / 2, tileSize, tileSize / 2);
-		CSDL_Ext::getBlitterWithRotationAndAlpha(targetSurf)
-				(parent->roadDefs[tinfo.roadType-1]->ourImages[tinfo.roadDir].bitmap, source, targetSurf, dest, (tinfo.extTileFlags >> 4) % 4);
 	}
-}
-
-void CMapHandler::CMapNormalBlitter::drawRiver(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo)
-{
-	Rect srcRect(0, 0, tileSize, tileSize);
-	Rect destRect(realPos.x, realPos.y, tileSize, tileSize);
-	CSDL_Ext::getBlitterWithRotationAndAlpha(targetSurf)
-			(parent->staticRiverDefs[tinfo.riverType-1]->ourImages[tinfo.riverDir].bitmap, srcRect, targetSurf, destRect, (tinfo.extTileFlags >> 2) % 4);
-}
-
-void CMapHandler::CMapNormalBlitter::drawFow(SDL_Surface * targetSurf, const MapDrawingInfo * info)
-{
-	Rect destRect(realPos.x, realPos.y, tileSize, tileSize);
-	std::pair<SDL_Surface *, bool> hide = parent->getVisBitmap(pos, *info->visibilityMap);
-	if(hide.second)
-		CSDL_Ext::blit8bppAlphaTo24bpp(hide.first, nullptr, targetSurf, &destRect);
 	else
-		CSDL_Ext::blitSurface(hide.first, nullptr, targetSurf, &destRect);
-}
-
-void CMapHandler::CMapNormalBlitter::drawFrame(SDL_Surface * targetSurf, const MapDrawingInfo * info)
-{
-	SDL_Surface * src = parent->ttiles[pos.x][pos.y][topTile.z].terbitmap;
-	assert(src);
-	Rect dstRect(realPos.x, realPos.y, tileSize, tileSize);
-	CSDL_Ext::blitSurface(src, nullptr, targetSurf, &dstRect);
-}
-
-void CMapHandler::CMapNormalBlitter::drawTileTerrain(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo, const TerrainTile2 & tile)
-{
-	Rect srcRect(0, 0, tileSize, tileSize);
-	Rect dstRect(realPos.x, realPos.y, tileSize, tileSize);
-
-	if(tile.terbitmap) //if custom terrain graphic - use it
 	{
-		CSDL_Ext::blitSurface(tile.terbitmap, &srcRect, targetSurf, &dstRect);
-	}
-	else //use default terrain graphic
-	{
-		CSDL_Ext::getBlitterWithRotation(targetSurf)(parent->terrainGraphics[tinfo.terType][tinfo.terView], srcRect, targetSurf, dstRect, tinfo.extTileFlags % 4);
+		if (alphaBlit)
+			CSDL_Ext::blit8bppAlphaTo24bpp(sourceSurf, sourceRect, targetSurf, destRect);
+		else
+			CSDL_Ext::blitSurface(sourceSurf, sourceRect, targetSurf, destRect);
 	}
 }
 
-void CMapHandler::CMapNormalBlitter::init(const MapDrawingInfo * info)
-{	// Width and height of the portion of the map to process. Units in tiles.
+void CMapHandler::CMapNormalBlitter::init(const MapDrawingInfo * drawingInfo)
+{
+	info = drawingInfo;
+	// Width and height of the portion of the map to process. Units in tiles.
 	tileCount.x = parent->tilesW;
 	tileCount.y = parent->tilesH;
 
@@ -570,6 +469,8 @@ void CMapHandler::CMapNormalBlitter::init(const MapDrawingInfo * info)
 	initPos.x = parent->offsetX + info->drawBounds->x;
 	initPos.y = parent->offsetY + info->drawBounds->y;
 
+	realTileRect = Rect(initPos.x, initPos.y, tileSize, tileSize);
+
 	// If moving, we need to add an extra column/line
 	if (info->movement.x != 0)
 	{
@@ -608,7 +509,7 @@ void CMapHandler::CMapNormalBlitter::init(const MapDrawingInfo * info)
 		tileCount.y = parent->sizes.y + parent->frameH - topTile.y;
 }
 
-SDL_Rect CMapHandler::CMapNormalBlitter::clip(SDL_Surface * targetSurf, const MapDrawingInfo * info)
+SDL_Rect CMapHandler::CMapNormalBlitter::clip(SDL_Surface * targetSurf) const
 {
 	SDL_Rect prevClip;
 	SDL_GetClipRect(targetSurf, &prevClip);
@@ -620,9 +521,90 @@ CMapHandler::CMapNormalBlitter::CMapNormalBlitter(CMapHandler * parent)
 	: CMapBlitter(parent)
 {
 	tileSize = 32;
+	halfTileSizeCeil = 16;
+	defaultTileRect = Rect(0, 0, tileSize, tileSize);
 }
 
-void CMapHandler::CMapWorldViewBlitter::drawTileOverlay(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile2 & tile)
+void CMapHandler::CMapWorldViewBlitter::calculateWorldViewCameraPos()
+{
+	bool outsideLeft = topTile.x < 0;
+	bool outsideTop = topTile.y < 0;
+	bool outsideRight = std::max(0, topTile.x) + tileCount.x > parent->sizes.x;
+	bool outsideBottom = std::max(0, topTile.y) + tileCount.y > parent->sizes.y;
+
+	if (tileCount.x > parent->sizes.x)
+		topTile.x = parent->sizes.x / 2 - tileCount.x / 2; // center viewport if the whole map can fit into the screen at once
+	else if (outsideLeft)
+	{
+		if (outsideRight)
+			topTile.x = parent->sizes.x / 2 - tileCount.x / 2;
+		else
+			topTile.x = 0;
+	}
+	else if (outsideRight)
+		topTile.x = parent->sizes.x - tileCount.x;
+
+	if (tileCount.y > parent->sizes.y)
+		topTile.y = parent->sizes.y / 2 - tileCount.y / 2;
+	else if (outsideTop)
+	{
+		if (outsideBottom)
+			topTile.y = parent->sizes.y / 2 - tileCount.y / 2;
+		else
+			topTile.y = 0;
+	}
+	else if (outsideBottom)
+		topTile.y = parent->sizes.y - tileCount.y;
+}
+
+void CMapHandler::CMapWorldViewBlitter::drawScaledRotatedElement(EMapCacheType type, SDL_Surface * baseSurf, SDL_Surface * targetSurf, ui8 rotation,
+											float scale, SDL_Rect * dstRect, SDL_Rect * srcRect /*= nullptr*/) const
+{
+	auto key = parent->cache.genKey((intptr_t)baseSurf, rotation);
+	auto scaledSurf = parent->cache.requestWorldViewCache(type, key);
+	if (scaledSurf) // blitting from cache
+	{
+		if (srcRect)
+		{
+			dstRect->w = srcRect->w;
+			dstRect->h = srcRect->h;
+		}
+		CSDL_Ext::blitSurface(scaledSurf, srcRect, targetSurf, dstRect);
+	}
+	else // creating new
+	{
+		auto baseSurfRotated = CSDL_Ext::newSurface(baseSurf->w, baseSurf->h);
+		if (!baseSurfRotated)
+			return;
+		Rect baseRect(0, 0, baseSurf->w, baseSurf->h);
+
+		CSDL_Ext::getBlitterWithRotationAndAlpha(targetSurf)(baseSurf, baseRect, baseSurfRotated, baseRect, rotation);
+
+		SDL_Surface * scaledSurf2 = CSDL_Ext::scaleSurfaceFast(baseSurfRotated, baseSurf->w * scale, baseSurf->h * scale);
+
+		CSDL_Ext::blitSurface(scaledSurf2, srcRect, targetSurf, dstRect);
+		parent->cache.cacheWorldViewEntry(type, key, scaledSurf2);
+	}
+}
+
+void CMapHandler::CMapWorldViewBlitter::drawElement(EMapCacheType cacheType, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Surface * targetSurf, SDL_Rect * destRect, bool alphaBlit, ui8 rotationInfo) const
+{
+	if (rotationInfo != 0)
+	{
+		drawScaledRotatedElement(cacheType, sourceSurf, targetSurf, rotationInfo, info->scale, destRect, sourceRect);
+	}
+	else
+	{
+		auto scaledSurf = parent->cache.requestWorldViewCacheOrCreate(cacheType, (intptr_t) sourceSurf, sourceSurf, info->scale);
+
+		if (alphaBlit)
+			CSDL_Ext::blit8bppAlphaTo24bpp(scaledSurf, sourceRect, targetSurf, destRect);
+		else
+			CSDL_Ext::blitSurface(scaledSurf, sourceRect, targetSurf, destRect);
+	}
+}
+
+void CMapHandler::CMapWorldViewBlitter::drawTileOverlay(SDL_Surface * targetSurf, const TerrainTile2 & tile) const
 {
 	auto & objects = tile.objects;
 	for(auto & object : objects)
@@ -686,97 +668,47 @@ void CMapHandler::CMapWorldViewBlitter::drawTileOverlay(SDL_Surface * targetSurf
 	}
 }
 
-void CMapHandler::CMapWorldViewBlitter::drawNormalObject(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect)
+void CMapHandler::CMapWorldViewBlitter::drawNormalObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect) const
 {
-	auto scaledSurf = parent->cache.requestWorldViewCacheOrCreate(EMapCacheType::OBJECTS, (intptr_t)sourceSurf, sourceSurf, info->scale);
-	Rect tempSrc = Rect(sourceRect->x * info->scale, sourceRect->y * info->scale, tileSize, tileSize);
-	Rect tempDst = Rect(realPos.x, realPos.y, tileSize, tileSize);
-	CSDL_Ext::blit8bppAlphaTo24bpp(scaledSurf, &tempSrc, targetSurf, &tempDst);
+	Rect scaledSourceRect(sourceRect->x * info->scale, sourceRect->y * info->scale, tileSize, tileSize);
+	CMapBlitter::drawNormalObject(targetSurf, sourceSurf, &scaledSourceRect);
 }
 
-void CMapHandler::CMapWorldViewBlitter::drawHeroFlag(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving)
+void CMapHandler::CMapWorldViewBlitter::drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const
 {
 	if (moving)
 		return;
 
-	auto scaledSurf = parent->cache.requestWorldViewCacheOrCreate(EMapCacheType::HERO_FLAGS, (intptr_t)sourceSurf, sourceSurf, info->scale);
-	CSDL_Ext::blit8bppAlphaTo24bpp(scaledSurf, nullptr, targetSurf, destRect);
+	CMapBlitter::drawHeroFlag(targetSurf, sourceSurf, sourceRect, destRect, false);
 }
 
-void CMapHandler::CMapWorldViewBlitter::drawHero(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving)
+void CMapHandler::CMapWorldViewBlitter::drawHero(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const
 {
 	if (moving)
 		return;
-	auto scaledSurf = parent->cache.requestWorldViewCacheOrCreate(EMapCacheType::HEROES, (intptr_t)sourceSurf, sourceSurf, info->scale);
-	Rect srcRect(sourceRect->x * info->scale, sourceRect->y * info->scale, sourceRect->w, sourceRect->h);
-	Rect dstRect(realPos.x, realPos.y, tileSize, tileSize);
-
-	CSDL_Ext::blit8bppAlphaTo24bpp(scaledSurf,&srcRect,targetSurf,&dstRect);
-}
-
-void CMapHandler::CMapWorldViewBlitter::drawRoad(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo, const TerrainTile * tinfoUpper)
-{
-	//Roads are shifted by 16 pixels to bottom. We have to draw both parts separately
-	if (tinfoUpper && tinfoUpper->roadType != ERoadType::NO_ROAD)
-	{
-		Rect source(0, tileSize / 2, tileSize, tileSize / 2);
-		Rect dest(realPos.x, realPos.y, tileSize, tileSize / 2);
-		auto baseSurf = parent->roadDefs[tinfoUpper->roadType - 1]->ourImages[tinfoUpper->roadDir].bitmap;
-		parent->drawScaledRotatedElement(EMapCacheType::ROADS, baseSurf, targetSurf, (tinfoUpper->extTileFlags >> 4) % 4, info->scale, &dest, &source);
-	}
-
-	if(tinfo.roadType != ERoadType::NO_ROAD) //print road from this tile
-	{
-		Rect source(0, 0, tileSize, halfTargetTileSizeHigh);
-		Rect dest(realPos.x, realPos.y + tileSize / 2, tileSize, halfTargetTileSizeHigh);
-		auto baseSurf = parent->roadDefs[tinfo.roadType-1]->ourImages[tinfo.roadDir].bitmap;
-		parent->drawScaledRotatedElement(EMapCacheType::ROADS, baseSurf, targetSurf, (tinfo.extTileFlags >> 4) % 4, info->scale, &dest, &source);
-	}
-}
-
-void CMapHandler::CMapWorldViewBlitter::drawRiver(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo)
-{
-	auto baseSurf = parent->staticRiverDefs[tinfo.riverType-1]->ourImages[tinfo.riverDir].bitmap;
-	Rect destRect(realPos.x, realPos.y, tileSize, tileSize);
-	parent->drawScaledRotatedElement(EMapCacheType::RIVERS, baseSurf, targetSurf, (tinfo.extTileFlags >> 2) % 4, info->scale, &destRect);
-}
 
-void CMapHandler::CMapWorldViewBlitter::drawFow(SDL_Surface * targetSurf, const MapDrawingInfo * info)
-{
-	Rect destRect(realPos.x, realPos.y, tileSize, tileSize);
-	std::pair<SDL_Surface *, bool> hide = parent->getVisBitmap(pos, *info->visibilityMap);
-	auto scaledSurf = parent->cache.requestWorldViewCacheOrCreate(EMapCacheType::FOW, (intptr_t)hide.first, hide.first, info->scale);
-	if(hide.second)
-		CSDL_Ext::blit8bppAlphaTo24bpp(scaledSurf, nullptr, targetSurf, &destRect);
-	else
-		CSDL_Ext::blitSurface(scaledSurf, nullptr, targetSurf, &destRect);
+	Rect scaledSourceRect(sourceRect->x * info->scale, sourceRect->y * info->scale, sourceRect->w, sourceRect->h);
+	CMapBlitter::drawHero(targetSurf, sourceSurf, &scaledSourceRect, false);
 }
 
-void CMapHandler::CMapWorldViewBlitter::drawTileTerrain(SDL_Surface * targetSurf, const MapDrawingInfo * info,
-														const TerrainTile & tinfo, const TerrainTile2 & tile)
+void CMapHandler::CMapBlitter::drawTileTerrain(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile2 & tile) const
 {
+	Rect destRect(realTileRect);
 	if(tile.terbitmap) //if custom terrain graphic - use it
-	{
-		auto scaledSurf = parent->cache.requestWorldViewCacheOrCreate(EMapCacheType::TERRAIN_CUSTOM, (intptr_t)tile.terbitmap, tile.terbitmap, info->scale);
-		Rect destRect(realPos.x, realPos.y, scaledSurf->w, scaledSurf->h);
-		CSDL_Ext::blit8bppAlphaTo24bpp(scaledSurf, nullptr, targetSurf, &destRect);
-	}
+		drawElement(EMapCacheType::TERRAIN_CUSTOM, tile.terbitmap, nullptr, targetSurf, &destRect);
 	else //use default terrain graphic
-	{
-		auto baseSurf = parent->terrainGraphics[tinfo.terType][tinfo.terView];
-		Rect destRect(realPos.x, realPos.y, tileSize, tileSize);
-		parent->drawScaledRotatedElement(EMapCacheType::TERRAIN, baseSurf, targetSurf, tinfo.extTileFlags % 4, info->scale, &destRect);
-	}
-
+		drawElement(EMapCacheType::TERRAIN, parent->terrainGraphics[tinfo.terType][tinfo.terView],
+				nullptr, targetSurf, &destRect, false, tinfo.extTileFlags % 4);
 }
 
-void CMapHandler::CMapWorldViewBlitter::init(const MapDrawingInfo * info)
+void CMapHandler::CMapWorldViewBlitter::init(const MapDrawingInfo * drawingInfo)
 {
+	info = drawingInfo;
 	parent->cache.updateWorldViewScale(info->scale);
 
 	topTile = info->topTile;
 	tileSize = (int) floorf(32.0f * info->scale);
-	halfTargetTileSizeHigh = (int)ceilf(tileSize / 2.0f);
+	halfTileSizeCeil = (int)ceilf(tileSize / 2.0f);
 
 	tileCount.x = (int) ceilf((float)info->drawBounds->w / tileSize) + 1;
 	tileCount.y = (int) ceilf((float)info->drawBounds->h / tileSize) + 1;
@@ -784,11 +716,14 @@ void CMapHandler::CMapWorldViewBlitter::init(const MapDrawingInfo * info)
 	initPos.x = parent->offsetX + info->drawBounds->x;
 	initPos.y = parent->offsetY + info->drawBounds->y;
 
-	parent->calculateWorldViewCameraPos(tileCount.x, tileCount.y, topTile);
+	realTileRect = Rect(initPos.x, initPos.y, tileSize, tileSize);
+	defaultTileRect = Rect(0, 0, tileSize, tileSize);
+
+	calculateWorldViewCameraPos();
 
 }
 
-SDL_Rect CMapHandler::CMapWorldViewBlitter::clip(SDL_Surface * targetSurf, const MapDrawingInfo * info)
+SDL_Rect CMapHandler::CMapWorldViewBlitter::clip(SDL_Surface * targetSurf) const
 {
 	SDL_Rect prevClip;
 
@@ -808,7 +743,68 @@ CMapHandler::CMapWorldViewBlitter::CMapWorldViewBlitter(CMapHandler * parent)
 {
 }
 
-void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile2 & tile)
+void CMapHandler::CMapPuzzleViewBlitter::drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const
+{
+	CMapBlitter::drawObjects(targetSurf, tile);
+
+	// grail X mark
+	if(pos.x == info->grailPos.x && pos.y == info->grailPos.y)
+	{
+		Rect destRect(realTileRect);
+		CSDL_Ext::blit8bppAlphaTo24bpp(graphics->heroMoveArrows->ourImages[0].bitmap, nullptr, targetSurf, &destRect);
+	}
+}
+
+void CMapHandler::CMapPuzzleViewBlitter::postProcessing(SDL_Surface * targetSurf) const
+{
+	CSDL_Ext::applyEffect(targetSurf, info->drawBounds, static_cast<int>(!ADVOPT.puzzleSepia));
+}
+
+bool CMapHandler::CMapPuzzleViewBlitter::canDrawObject(const CGObjectInstance * obj) const
+{
+	if (!CMapBlitter::canDrawObject(obj))
+		return false;
+
+	//don't print flaggable objects in puzzle mode
+	if (obj->isVisitable())
+		return false;
+
+	if(std::find(unblittableObjects.begin(), unblittableObjects.end(), obj->ID) != unblittableObjects.end())
+		return false;
+
+	return true;
+}
+
+CMapHandler::CMapPuzzleViewBlitter::CMapPuzzleViewBlitter(CMapHandler * parent)
+	: CMapNormalBlitter(parent)
+{
+	unblittableObjects.push_back(Obj::HOLE);
+}
+
+void CMapHandler::CMapBlitter::drawFrame(SDL_Surface * targetSurf) const
+{
+	Rect destRect(realTileRect);
+	drawElement(EMapCacheType::FRAME, parent->ttiles[pos.x][pos.y][topTile.z].terbitmap, nullptr, targetSurf, &destRect);
+}
+
+void CMapHandler::CMapBlitter::drawNormalObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect) const
+{
+	Rect destRect(realTileRect);
+	drawElement(EMapCacheType::OBJECTS, sourceSurf, sourceRect, targetSurf, &destRect, true);
+}
+
+void CMapHandler::CMapBlitter::drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const
+{
+	drawElement(EMapCacheType::HERO_FLAGS, sourceSurf, sourceRect, targetSurf, destRect, true);
+}
+
+void CMapHandler::CMapBlitter::drawHero(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const
+{
+	Rect dstRect(realTileRect);
+	drawElement(EMapCacheType::HEROES, sourceSurf, sourceRect, targetSurf, &dstRect, true);
+}
+
+void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const
 {
 	auto & objects = tile.objects;
 	for(auto & object : objects)
@@ -819,17 +815,9 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const MapDr
 		if (!graphics->getDef(obj) && !obj->appearance.animationFile.empty())
 			logGlobal->errorStream() << "Failed to load image " << obj->appearance.animationFile;
 
-		//checking if object has non-empty graphic on this tile
-		if(obj->ID != Obj::HERO && !obj->coveringAt(pos.x, pos.y))
+		if (!canDrawObject(obj))
 			continue;
 
-		static const int notBlittedInPuzzleMode[] = {Obj::HOLE};
-
-		//don't print flaggable objects in puzzle mode
-		if(info->puzzleMode && (obj->isVisitable() || std::find(notBlittedInPuzzleMode, notBlittedInPuzzleMode+1, obj->ID) != notBlittedInPuzzleMode+1)) //?
-			continue;
-
-
 		PlayerColor color = obj->tempOwner;
 
 		SDL_Rect pp = object.second;
@@ -893,17 +881,17 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const MapDr
 				size_t gg;
 				for(gg=0; gg<iv->size(); ++gg)
 				{
-					if((*iv)[gg].groupNumber==parent->getHeroFrameNum(dir, true))
+					if((*iv)[gg].groupNumber == getHeroFrameNum(dir, true))
 					{
 						tb = (*iv)[gg+info->getHeroAnim()%IMGVAL].bitmap;
 						break;
 					}
 				}
-				drawHero(targetSurf, info, tb, &pp, true);
+				drawHero(targetSurf, tb, &pp, true);
 
 				pp.y += IMGVAL * 2 - tileSize;
 				Rect destRect(realPos.x, realPos.y - tileSize / 2, tileSize, tileSize);
-				drawHeroFlag(targetSurf, info, (graphics->*flg)[color.getNum()]->ourImages[gg + info->getHeroAnim() % IMGVAL + 35].bitmap, &pp, &destRect, true);
+				drawHeroFlag(targetSurf, (graphics->*flg)[color.getNum()]->ourImages[gg + info->getHeroAnim() % IMGVAL + 35].bitmap, &pp, &destRect, true);
 
 			}
 			else //hero / boat stands still
@@ -911,13 +899,13 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const MapDr
 				size_t gg;
 				for(gg=0; gg < iv->size(); ++gg)
 				{
-					if((*iv)[gg].groupNumber==parent->getHeroFrameNum(dir, false))
+					if((*iv)[gg].groupNumber == getHeroFrameNum(dir, false))
 					{
 						tb = (*iv)[gg].bitmap;
 						break;
 					}
 				}
-				drawHero(targetSurf, info, tb, &pp, false);
+				drawHero(targetSurf, tb, &pp, false);
 
 				//printing flag
 				if(flg
@@ -928,8 +916,8 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const MapDr
 					if (dstRect.x - info->drawBounds->x > -tileSize * 2)
 					{
 						auto surf = (graphics->*flg)[color.getNum()]->ourImages
-								[parent->getHeroFrameNum(dir, false) * 8 + (info->getHeroAnim() / 4) % IMGVAL].bitmap;
-						drawHeroFlag(targetSurf, info, surf, nullptr, &dstRect, false);
+								[getHeroFrameNum(dir, false) * 8 + (info->getHeroAnim() / 4) % IMGVAL].bitmap;
+						drawHeroFlag(targetSurf, surf, nullptr, &dstRect, false);
 					}
 				}
 			}
@@ -937,21 +925,54 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const MapDr
 		else //blit normal object
 		{
 			const std::vector<Cimage> &ourImages = graphics->getDef(obj)->ourImages;
-			SDL_Surface *bitmap = ourImages[(info->anim + parent->getPhaseShift(obj)) % ourImages.size()].bitmap;
+			SDL_Surface *bitmap = ourImages[(info->anim + getPhaseShift(obj)) % ourImages.size()].bitmap;
 
 			//setting appropriate flag color
 			if(color < PlayerColor::PLAYER_LIMIT || color==PlayerColor::NEUTRAL)
 				CSDL_Ext::setPlayerColor(bitmap, color);
 
-			drawNormalObject(targetSurf, info, bitmap, &pp);
+			drawNormalObject(targetSurf, bitmap, &pp);
 		}
 	}
 }
 
-void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingInfo * const info)
+void CMapHandler::CMapBlitter::drawRoad(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile * tinfoUpper) const
+{
+	if (tinfoUpper && tinfoUpper->roadType != ERoadType::NO_ROAD)
+	{
+		Rect source(0, tileSize / 2, tileSize, tileSize / 2);
+		Rect dest(realPos.x, realPos.y, tileSize, tileSize / 2);
+		drawElement(EMapCacheType::ROADS, parent->roadDefs[tinfoUpper->roadType - 1]->ourImages[tinfoUpper->roadDir].bitmap,
+				&source, targetSurf, &dest, true, (tinfoUpper->extTileFlags >> 4) % 4);
+	}
+
+	if(tinfo.roadType != ERoadType::NO_ROAD) //print road from this tile
+	{
+		Rect source(0, 0, tileSize, halfTileSizeCeil);
+		Rect dest(realPos.x, realPos.y + tileSize / 2, tileSize, tileSize / 2);
+		drawElement(EMapCacheType::ROADS, parent->roadDefs[tinfo.roadType - 1]->ourImages[tinfo.roadDir].bitmap,
+				&source, targetSurf, &dest, true, (tinfo.extTileFlags >> 4) % 4);
+	}
+}
+
+void CMapHandler::CMapBlitter::drawRiver(SDL_Surface * targetSurf, const TerrainTile & tinfo) const
+{
+	Rect destRect(realTileRect);
+	drawElement(EMapCacheType::RIVERS, parent->staticRiverDefs[tinfo.riverType-1]->ourImages[tinfo.riverDir].bitmap,
+			nullptr, targetSurf, &destRect, true, (tinfo.extTileFlags >> 2) % 4);
+}
+
+void CMapHandler::CMapBlitter::drawFow(SDL_Surface * targetSurf) const
+{
+	Rect destRect(realTileRect);
+	std::pair<SDL_Surface *, bool> hide = getVisBitmap();
+	drawElement(EMapCacheType::FOW, hide.first, nullptr, targetSurf, &destRect, hide.second);
+}
+
+void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingInfo * info)
 {
 	init(info);
-	auto prevClip = clip(targetSurf, info);
+	auto prevClip = clip(targetSurf);
 
 	pos = int3(0, 0, topTile.z);
 
@@ -965,33 +986,22 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
 			if (pos.y < 0 || pos.y >= parent->sizes.y)
 				continue;
 
-			if (!info->puzzleMode)
-			{
-				const NeighborTilesInfo neighbors(pos, parent->sizes, *info->visibilityMap);
+			if (!canDrawCurrentTile())
+				continue;
 
-				if(neighbors.areAllHidden())
-					continue;
-			}
+			realTileRect.x = realPos.x;
+			realTileRect.y = realPos.y;
 
 			const TerrainTile2 & tile = parent->ttiles[pos.x][pos.y][pos.z];
 			const TerrainTile & tinfo = parent->map->getTile(pos);
 			const TerrainTile * tinfoUpper = pos.y > 0 ? &parent->map->getTile(int3(pos.x, pos.y - 1, pos.z)) : nullptr;
 
-			drawTileTerrain(targetSurf, info, tinfo, tile);
+			drawTileTerrain(targetSurf, tinfo, tile);
 			if (tinfo.riverType)
-				drawRiver(targetSurf, info, tinfo);
-			drawRoad(targetSurf, info, tinfo, tinfoUpper);
-
-			drawObjects(targetSurf, info, tile);
+				drawRiver(targetSurf, tinfo);
+			drawRoad(targetSurf, tinfo, tinfoUpper);
 
-			if(info->puzzleMode)
-			{
-				if(pos.x == info->grailPos.x && pos.y == info->grailPos.y)
-				{
-					Rect destRect(realPos.x, realPos.y, tileSize, tileSize);
-					CSDL_Ext::blit8bppAlphaTo24bpp(graphics->heroMoveArrows->ourImages[0].bitmap, nullptr, targetSurf, &destRect);
-				}
-			}
+			drawObjects(targetSurf, tile);
 		}
 	}
 
@@ -999,20 +1009,23 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
 	{
 		for (realPos.y = initPos.y, pos.y = topTile.y; pos.y < topTile.y + tileCount.y; pos.y++, realPos.y += tileSize)
 		{
+			realTileRect.x = realPos.x;
+			realTileRect.y = realPos.y;
+
 			if (pos.x < 0 || pos.x >= parent->sizes.x ||
 				pos.y < 0 || pos.y >= parent->sizes.y)
 			{
-				drawFrame(targetSurf, info);
+				drawFrame(targetSurf);
 			}
 			else
 			{
 				const TerrainTile2 & tile = parent->ttiles[pos.x][pos.y][pos.z];
 
-				if (!(*info->visibilityMap)[pos.x][pos.y][topTile.z] && !info->puzzleMode)
-					drawFow(targetSurf, info);
+				if (!(*info->visibilityMap)[pos.x][pos.y][topTile.z])
+					drawFow(targetSurf);
 
 				// overlay needs to be drawn over fow, because of artifacts-aura-like spells
-				drawTileOverlay(targetSurf, info, tile);
+				drawTileOverlay(targetSurf, tile);
 
 				// drawDebugVisitables()
 				if (settings["session"]["showBlock"].Bool())
@@ -1023,9 +1036,7 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
 						if (!block)
 							block = BitmapHandler::loadBitmap("blocked");
 
-						Rect sr(realPos.x, realPos.y, tileSize, tileSize);
-
-						CSDL_Ext::blitSurface(block, nullptr, targetSurf, &sr);
+						CSDL_Ext::blitSurface(block, nullptr, targetSurf, &realTileRect);
 					}
 				}
 				if (settings["session"]["showVisit"].Bool())
@@ -1036,8 +1047,7 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
 						if (!visit)
 							visit = BitmapHandler::loadBitmap("visitable");
 
-						Rect sr(realPos.x, realPos.y, tileSize, tileSize);
-						CSDL_Ext::blitSurface(visit, nullptr, targetSurf, &sr);
+						CSDL_Ext::blitSurface(visit, nullptr, targetSurf, &realTileRect);
 					}
 				}
 			}
@@ -1051,8 +1061,6 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
 		{
 			for (realPos.y = initPos.y, pos.y = topTile.y; pos.y < topTile.y + tileCount.y; pos.y++, realPos.y += tileSize)
 			{
-				SDL_Rect sr;
-
 				const int3 color(0x555555, 0x555555, 0x555555);
 
 				if (realPos.y >= info->drawBounds->y &&
@@ -1072,22 +1080,58 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
 		}
 	}
 
-	if(info->puzzleMode)
+	postProcessing(targetSurf);
+
+	SDL_SetClipRect(targetSurf, &prevClip);
+}
+
+ui8 CMapHandler::CMapBlitter::getPhaseShift(const CGObjectInstance *object) const
+{
+	auto i = parent->animationPhase.find(object);
+	if(i == parent->animationPhase.end())
 	{
-		CSDL_Ext::applyEffect(targetSurf, info->drawBounds, static_cast<int>(!ADVOPT.puzzleSepia));
+		ui8 ret = CRandomGenerator::getDefault().nextInt(254);
+		parent->animationPhase[object] = ret;
+		return ret;
 	}
 
-	SDL_SetClipRect(targetSurf, &prevClip);
+	return i->second;
 }
 
-std::pair<SDL_Surface *, bool> CMapHandler::getVisBitmap( const int3 & pos, const std::vector< std::vector< std::vector<ui8> > > & visibilityMap ) const
+bool CMapHandler::CMapBlitter::canDrawObject(const CGObjectInstance * obj) const
 {
-	const NeighborTilesInfo info(pos,sizes,visibilityMap);
+	//checking if object has non-empty graphic on this tile
+	return obj->ID == Obj::HERO || obj->coveringAt(pos.x, pos.y);
+}
+
+bool CMapHandler::CMapBlitter::canDrawCurrentTile() const
+{
+	const NeighborTilesInfo neighbors(pos, parent->sizes, *info->visibilityMap);
+	return !neighbors.areAllHidden();
+}
 
-	int retBitmapID = info.getBitmapID();// >=0 -> partial hide, <0 - full hide
+ui8 CMapHandler::CMapBlitter::getHeroFrameNum(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];
+	}
+}
+
+std::pair<SDL_Surface *, bool> CMapHandler::CMapBlitter::getVisBitmap() const
+{
+	const NeighborTilesInfo neighborInfo(pos, parent->sizes, *info->visibilityMap);
+
+	int retBitmapID = neighborInfo.getBitmapID();// >=0 -> partial hide, <0 - full hide
 	if (retBitmapID < 0)
 	{
-		retBitmapID = - hideBitmap[pos.x][pos.y][pos.z] - 1; //fully hidden
+		retBitmapID = - parent->hideBitmap[pos.x][pos.y][pos.z] - 1; //fully hidden
 	}
 
 	if (retBitmapID >= 0)
@@ -1170,20 +1214,6 @@ bool CMapHandler::removeObject(CGObjectInstance *obj)
 	return true;
 }
 
-ui8 CMapHandler::getHeroFrameNum(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];
-	}
-}
-
 void CMapHandler::validateRectTerr(SDL_Rect * val, const SDL_Rect * ext)
 {
 	if(ext)
@@ -1322,6 +1352,7 @@ CMapHandler::CMapHandler()
 	graphics->FoWpartialHide = nullptr;
 	normalBlitter = new CMapNormalBlitter(this);
 	worldViewBlitter = new CMapWorldViewBlitter(this);
+	puzzleViewBlitter = new CMapPuzzleViewBlitter(this);
 }
 
 void CMapHandler::getTerrainDescr( const int3 &pos, std::string & out, bool terName )
@@ -1344,19 +1375,6 @@ void CMapHandler::getTerrainDescr( const int3 &pos, std::string & out, bool terN
 		out = CGI->generaltexth->terrainNames[t.terType];
 }
 
-ui8 CMapHandler::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;
-}
-
 void CMapHandler::discardWorldViewCache()
 {
 	cache.discardWorldViewCache();
@@ -1454,3 +1472,4 @@ bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObj
 		return true;
 	return false;
 }
+

+ 100 - 57
client/mapHandler.h

@@ -2,6 +2,7 @@
 
 
 #include "../lib/int3.h"
+#include "gui/Geometries.h"
 #include "SDL.h"
 
 /*
@@ -134,7 +135,7 @@ class CMapHandler
 {
 	enum class EMapCacheType
 	{
-		TERRAIN, TERRAIN_CUSTOM, OBJECTS, ROADS, RIVERS, FOW, HEROES, HERO_FLAGS
+		TERRAIN, TERRAIN_CUSTOM, OBJECTS, ROADS, RIVERS, FOW, HEROES, HERO_FLAGS, FRAME
 	};
 
 	/// temporarily caches rescaled sdl surfaces for map world view redrawing
@@ -160,46 +161,81 @@ class CMapHandler
 	class CMapBlitter
 	{
 	protected:
-		CMapHandler * parent;
-		int tileSize;
-		int3 tileCount;
-		int3 topTile;
-		int3 initPos;
-		int3 pos;
-		int3 realPos;
-
-		virtual void drawTileOverlay(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile2 & tile) = 0;
-		virtual void drawNormalObject(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect) = 0;
-		virtual void drawHeroFlag(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) = 0;
-		virtual void drawHero(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) = 0;
-		void drawObjects(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile2 & tile);
-		virtual void drawRoad(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo, const TerrainTile * tinfoUpper) = 0;
-		virtual void drawRiver(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo) = 0;
-		virtual void drawFow(SDL_Surface * targetSurf, const MapDrawingInfo * info) = 0;
-		virtual void drawFrame(SDL_Surface * targetSurf, const MapDrawingInfo * info) = 0;
-		virtual void drawTileTerrain(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo, const TerrainTile2 & tile) = 0;
-		virtual void init(const MapDrawingInfo * info) = 0;
-		virtual SDL_Rect clip(SDL_Surface * targetSurf, const MapDrawingInfo * info) = 0;
+		CMapHandler * parent; // ptr to enclosing map handler; generally for legacy reasons, probably could/should be refactored out of here
+		int tileSize; // size of a tile drawn on map [in pixels]
+		int halfTileSizeCeil; // half of the tile size, rounded up
+		int3 tileCount; // number of tiles in current viewport
+		int3 topTile; // top-left tile of the viewport
+		int3 initPos; // starting drawing position [in pixels]
+		int3 pos; // current position [in tiles]
+		int3 realPos; // current position [in pixels]
+		Rect realTileRect; // default rect based on current pos: [realPos.x, realPos.y, tileSize, tileSize]
+		Rect defaultTileRect; // default rect based on 0: [0, 0, tileSize, tileSize]
+		const MapDrawingInfo * info; // data for drawing passed from outside
+
+		/// general drawing method, called internally by more specialized ones
+		virtual void drawElement(EMapCacheType cacheType, SDL_Surface * sourceSurf, SDL_Rect * sourceRect,
+								 SDL_Surface * targetSurf, SDL_Rect * destRect, bool alphaBlit = false, ui8 rotationInfo = 0u) const = 0;
+
+		// first drawing pass
+
+		/// draws terrain bitmap (or custom bitmap if applicable) on current tile
+		virtual void drawTileTerrain(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile2 & tile) const;
+		/// draws a river segment on current tile
+		virtual void drawRiver(SDL_Surface * targetSurf, const TerrainTile & tinfo) const;
+		/// draws a road segment on current tile
+		virtual void drawRoad(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile * tinfoUpper) const;
+		/// draws all objects on current tile (higher-level logic, unlike other draw*** methods)
+		virtual void drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const;
+		/// current tile: draws non-hero object with given image/position
+		virtual void drawNormalObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect) const;
+		virtual void drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const;
+		virtual void drawHero(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const;
+
+		// second drawing pass
+
+		/// current tile: draws overlay over the map, used to draw world view icons
+		virtual void drawTileOverlay(SDL_Surface * targetSurf, const TerrainTile2 & tile) const = 0;
+		/// draws fog of war on current tile
+		virtual void drawFow(SDL_Surface * targetSurf) const;
+		/// draws map border frame on current position
+		virtual void drawFrame(SDL_Surface * targetSurf) const;
+
+		// third drawing pass
+
+		/// custom post-processing, if needed (used by puzzle view)
+		virtual void postProcessing(SDL_Surface * targetSurf) const {}
+
+		// misc methods
+
+		/// initializes frame-drawing (called at the start of every redraw)
+		virtual void init(const MapDrawingInfo * drawingInfo) = 0;
+		/// calculates clip region for map viewport
+		virtual SDL_Rect clip(SDL_Surface * targetSurf) const = 0;
+
+		virtual ui8 getHeroFrameNum(ui8 dir, bool isMoving) const;
+		///returns appropriate bitmap and info if alpha blitting is necessary
+		virtual std::pair<SDL_Surface *, bool> getVisBitmap() const;
+		virtual ui8 getPhaseShift(const CGObjectInstance *object) const;
+
+		virtual bool canDrawObject(const CGObjectInstance * obj) const;
+		virtual bool canDrawCurrentTile() const;
 	public:
 		CMapBlitter(CMapHandler * p) : parent(p) {}
 		virtual ~CMapBlitter(){}
-		void blit(SDL_Surface * targetSurf, const MapDrawingInfo * const info);
+		void blit(SDL_Surface * targetSurf, const MapDrawingInfo * info);
+
 	};
 
 	class CMapNormalBlitter : public CMapBlitter
 	{
 	protected:
-		void drawTileOverlay(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile2 & tile) {}
-		void drawNormalObject(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect);
-		void drawHeroFlag(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving);
-		void drawHero(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving);
-		void drawRoad(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo, const TerrainTile * tinfoUpper);
-		void drawRiver(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo);
-		void drawFow(SDL_Surface * targetSurf, const MapDrawingInfo * info);
-		void drawFrame(SDL_Surface * targetSurf, const MapDrawingInfo * info);
-		void drawTileTerrain(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo, const TerrainTile2 & tile);
-		void init(const MapDrawingInfo * info);
-		SDL_Rect clip(SDL_Surface * targetSurf, const MapDrawingInfo * info) override;
+		void drawElement(EMapCacheType cacheType, SDL_Surface * sourceSurf, SDL_Rect * sourceRect,
+						 SDL_Surface * targetSurf, SDL_Rect * destRect, bool alphaBlit = false, ui8 rotationInfo = 0u) const override;
+
+		void drawTileOverlay(SDL_Surface * targetSurf,const TerrainTile2 & tile) const override {}
+		void init(const MapDrawingInfo * info) override;
+		SDL_Rect clip(SDL_Surface * targetSurf) const override;
 	public:
 		CMapNormalBlitter(CMapHandler * parent);
 		virtual ~CMapNormalBlitter(){}
@@ -208,36 +244,47 @@ class CMapHandler
 	class CMapWorldViewBlitter : public CMapBlitter
 	{
 	protected:
-		int halfTargetTileSizeHigh;
-
-		void drawTileOverlay(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile2 & tile);
-		void drawNormalObject(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect);
-		void drawHeroFlag(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving);
-		void drawHero(SDL_Surface * targetSurf, const MapDrawingInfo * info, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving);
-		void drawRoad(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo, const TerrainTile * tinfoUpper);
-		void drawRiver(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo);
-		void drawFow(SDL_Surface * targetSurf, const MapDrawingInfo * info);
-		void drawFrame(SDL_Surface * targetSurf, const MapDrawingInfo * info) {}
-		void drawTileTerrain(SDL_Surface * targetSurf, const MapDrawingInfo * info, const TerrainTile & tinfo, const TerrainTile2 & tile);
-		void init(const MapDrawingInfo * info);
-		SDL_Rect clip(SDL_Surface * targetSurf, const MapDrawingInfo * info) override;
+		void drawElement(EMapCacheType cacheType, SDL_Surface * sourceSurf, SDL_Rect * sourceRect,
+						 SDL_Surface * targetSurf, SDL_Rect * destRect, bool alphaBlit = false, ui8 rotationInfo = 0u) const override;
+
+		void drawTileOverlay(SDL_Surface * targetSurf, const TerrainTile2 & tile) const override;
+		void drawNormalObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect) const override;
+		void drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const override;
+		void drawHero(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const;
+		void drawFrame(SDL_Surface * targetSurf) const override {}
+		void init(const MapDrawingInfo * info) override;
+		SDL_Rect clip(SDL_Surface * targetSurf) const override;
+
+		ui8 getHeroFrameNum(ui8 dir, bool isMoving) const override { return 0u; }
+		ui8 getPhaseShift(const CGObjectInstance *object) const override { return 0u; }
+
+		void drawScaledRotatedElement(EMapCacheType type, SDL_Surface * baseSurf, SDL_Surface * targetSurf, ui8 rotation,
+									  float scale, SDL_Rect * dstRect, SDL_Rect * srcRect = nullptr) const;
+		void calculateWorldViewCameraPos();
 	public:
 		CMapWorldViewBlitter(CMapHandler * parent);
 		virtual ~CMapWorldViewBlitter(){}
 	};
 
-//	class CPuzzleViewBlitter : public CMapNormalBlitter
-//	{
-//		void drawFow(SDL_Surface * targetSurf, const MapDrawingInfo * info) {} // skipping FoW in puzzle view
-//	};
+	class CMapPuzzleViewBlitter : public CMapNormalBlitter
+	{
+		std::vector<int> unblittableObjects;
+
+		void drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const override;
+		void drawFow(SDL_Surface * targetSurf) const override {} // skipping FoW in puzzle view
+		void postProcessing(SDL_Surface * targetSurf) const override;
+		bool canDrawObject(const CGObjectInstance * obj) const override;
+		bool canDrawCurrentTile() const override { return true; }
+	public:
+		CMapPuzzleViewBlitter(CMapHandler * parent);
+	};
 
 	CMapCache cache;
 	CMapBlitter * normalBlitter;
 	CMapBlitter * worldViewBlitter;
+	CMapBlitter * puzzleViewBlitter;
 
-	void drawScaledRotatedElement(EMapCacheType type, SDL_Surface * baseSurf, SDL_Surface * targetSurf, ui8 rotation,
-								  float scale, SDL_Rect * dstRect, SDL_Rect * srcRect = nullptr);
-	void calculateWorldViewCameraPos(int targetTilesX, int targetTilesY, int3 &top_tile);
+	CMapBlitter * resolveBlitter(const MapDrawingInfo * info) const;
 public:
 	PseudoV< PseudoV< PseudoV<TerrainTile2> > > ttiles; //informations about map tiles
 	int3 sizes; //map size (x = width, y = height, z = number of levels)
@@ -271,9 +318,6 @@ public:
 	CMapHandler(); //c-tor
 	~CMapHandler(); //d-tor
 
-	std::pair<SDL_Surface *, bool> getVisBitmap(const int3 & pos, const std::vector< std::vector< std::vector<ui8> > > & visibilityMap) const; //returns appropriate bitmap and info if alpha blitting is necessary
-	ui8 getPhaseShift(const CGObjectInstance *object) const;
-
 	void getTerrainDescr(const int3 &pos, std::string & out, bool terName); //if tername == false => empty string when tile is clear
 	CGObjectInstance * createObject(int id, int subid, int3 pos, int owner=254); //creates a new object with a certain id and subid
 	bool printObject(const CGObjectInstance * obj); //puts appropriate things to ttiles, so obj will be visible on map
@@ -288,7 +332,6 @@ public:
 
 	void drawTerrainRectNew(SDL_Surface * targetSurface, const MapDrawingInfo * info);
 	void updateWater();
-	ui8 getHeroFrameNum(ui8 dir, bool isMoving) const; //terrainRect helper function
 	void validateRectTerr(SDL_Rect * val, const SDL_Rect * ext); //terrainRect helper
 	static ui8 getDir(const int3 & a, const int3 & b);  //returns direction number in range 0 - 7 (0 is left top, clockwise) [direction: form a to b]
 

+ 1 - 1
client/windows/CAdvmapInterface.h

@@ -209,7 +209,7 @@ public:
 	void updateNextHero(const CGHeroInstance *h);
 
 	/// changes current adventure map mode; used to switch between default view and world view; scale is ignored if EAdvMapMode == NORMAL
-	void changeMode(EAdvMapMode newMode, float newScale = 0.4f);
+	void changeMode(EAdvMapMode newMode, float newScale = 0.36f);
 };
 
 extern CAdvMapInt *adventureInt;