浏览代码

Abstracted fading into separate class;
Smoother fade animations;
Added fading when recentering hero after switching levels;

Fay 11 年之前
父节点
当前提交
5e78a3147a

+ 2 - 0
client/CPlayerInterface.cpp

@@ -276,6 +276,8 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
 
 				}
 			}
+			adventureInt->centerOn(hero, true); //actualizing screen pos
+			adventureInt->minimap.redraw();
 			adventureInt->heroList.update(hero);
 			return;	//teleport - no fancy moving animation
 					//TODO: smooth disappear / appear effect

+ 85 - 0
client/gui/CAnimation.cpp

@@ -1222,3 +1222,88 @@ void CAnimation::getAnimInfo()
             logGlobal->errorStream()<<", "<<anim->images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first;
 	}
 }
+
+
+float CFadeAnimation::initialCounter() const
+{
+	if (fadingMode == EMode::OUT)
+		return 1.0f;
+	return 0.0f;
+}
+
+void CFadeAnimation::update()
+{
+	if (!fading)
+		return;
+	
+	if (fadingMode == EMode::OUT)
+		fadingCounter -= delta;
+	else
+		fadingCounter += delta;
+		
+	if (isFinished())
+	{
+		fading = false;
+		if (shouldFreeSurface)
+		{
+			SDL_FreeSurface(fadingSurface);
+			fadingSurface = nullptr;
+		}
+	}
+}
+
+bool CFadeAnimation::isFinished() const
+{
+	if (fadingMode == EMode::OUT)
+		return fadingCounter <= 0.0f;
+	return fadingCounter >= 1.0f;
+}
+
+CFadeAnimation::CFadeAnimation()
+	: fadingSurface(nullptr),
+	  fading(false),
+	  fadingMode(EMode::NONE)
+{
+}
+
+CFadeAnimation::~CFadeAnimation()
+{
+	if (fadingSurface && shouldFreeSurface)
+		SDL_FreeSurface(fadingSurface);		
+}
+
+void CFadeAnimation::init(EMode mode, float animDelta /* = DEFAULT_DELTA */, SDL_Surface * sourceSurface /* = nullptr */, bool freeSurfaceAtEnd /* = false */)
+{
+	if (fading)
+	{
+		logGlobal->warnStream() << "Tried to init fading animation that is already running.";
+		return;
+	}		
+	if (animDelta <= 0.0f)
+	{
+		logGlobal->warnStream() << "Fade anim: delta should be positive; " << animDelta << " given.";
+		animDelta = DEFAULT_DELTA;
+	}
+	
+	if (sourceSurface)
+		fadingSurface = sourceSurface;
+	
+	delta = animDelta;
+	fadingMode = mode;
+	fadingCounter = initialCounter();
+	fading = true;
+	shouldFreeSurface = freeSurfaceAtEnd;
+}
+
+void CFadeAnimation::draw(SDL_Surface * targetSurface, const SDL_Rect * sourceRect, SDL_Rect * destRect)
+{	
+	if (!fading || !fadingSurface || fadingMode == EMode::NONE)
+	{
+		fading = false;
+		return;
+	}
+	
+	SDL_SetSurfaceAlphaMod(fadingSurface, fadingCounter * 255);
+	SDL_BlitSurface(fadingSurface, sourceRect, targetSurface, destRect);
+	SDL_SetSurfaceAlphaMod(fadingSurface, 255);
+}

+ 28 - 0
client/gui/CAnimation.h

@@ -220,3 +220,31 @@ public:
 	//total count of frames in group (including not loaded)
 	size_t size(size_t group=0) const;
 };
+
+class CFadeAnimation
+{
+public:
+	enum class EMode
+	{
+		NONE, IN, OUT
+	};
+private:
+	static constexpr float DEFAULT_DELTA = 0.05f;
+	float delta;
+	SDL_Surface * fadingSurface;
+	bool fading;
+	float fadingCounter;
+	bool shouldFreeSurface;
+	
+	float initialCounter() const;
+	bool isFinished() const;
+public:
+	EMode fadingMode;
+
+	CFadeAnimation();
+	~CFadeAnimation();
+	void init(EMode mode, float animDelta = DEFAULT_DELTA, SDL_Surface * sourceSurface = nullptr, bool freeSurfaceAtEnd = false);
+	void update();
+	void draw(SDL_Surface * targetSurface, const SDL_Rect * sourceRect, SDL_Rect * destRect);
+	bool isFading() const { return fading; }
+};

+ 105 - 61
client/mapHandler.cpp

@@ -12,6 +12,7 @@
 #include "mapHandler.h"
 
 #include "CBitmapHandler.h"
+#include "gui/CAnimation.h"
 #include "gui/SDL_Extensions.h"
 #include "CGameInfo.h"
 #include "../lib/mapObjects/CGHeroInstance.h"
@@ -185,11 +186,12 @@ void CMapHandler::prepareFOWDefs()
 	}
 }
 
-void CMapHandler::drawTerrainRectNew(SDL_Surface * targetSurface, const MapDrawingInfo * info)
+EMapAnimRedrawStatus CMapHandler::drawTerrainRectNew(SDL_Surface * targetSurface, const MapDrawingInfo * info, bool redrawOnlyAnim /* = false */)
 {
 	assert(info);
-	updateObjectsFade();
+	bool hasActiveFade = updateObjectsFade();
 	resolveBlitter(info)->blit(targetSurface, info);
+	return hasActiveFade ? EMapAnimRedrawStatus::REDRAW_REQUESTED : EMapAnimRedrawStatus::OK;
 }
 
 void CMapHandler::roadsRiverTerrainInit()
@@ -810,20 +812,21 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const Terra
 	auto & objects = tile.objects;
 	for(auto & object : objects)
 	{
-		if (object.fading == EMapObjectFadingType::OUT)
+		if (object.fadeAnimKey >= 0)
 		{
-			auto &bitmap = graphics->advmapobjGraphics[object.image]->ourImages[0].bitmap;
-			if (!parent->fadingOffscreenBitmapSurface)
-				parent->fadingOffscreenBitmapSurface = CSDL_Ext::newSurface(tileSize, tileSize, targetSurf);
-			Rect r1(object.rect);
-			r1.w = tileSize;
-			r1.h = tileSize;
-			Rect r2(realTileRect);
-			SDL_SetSurfaceAlphaMod(parent->fadingOffscreenBitmapSurface, object.fadingCounter * 255);
-			SDL_BlitSurface(bitmap, &r1, parent->fadingOffscreenBitmapSurface, nullptr);
-			SDL_BlitSurface(parent->fadingOffscreenBitmapSurface, nullptr, targetSurf, &r2);
-			SDL_SetSurfaceAlphaMod(parent->fadingOffscreenBitmapSurface, 255);
-			SDL_FillRect(parent->fadingOffscreenBitmapSurface, nullptr, 0);
+			// this object is currently fading, so skip normal drawing
+			// TODO fading heroes/boats will not be drawn correctly this way
+			
+			auto fadeIter = parent->fadeAnims.find(object.fadeAnimKey);
+			if (fadeIter != parent->fadeAnims.end())
+			{
+				Rect r1(object.rect);
+				r1.w = tileSize;
+				r1.h = tileSize;
+				Rect r2(realTileRect);
+				CFadeAnimation * fade = (*fadeIter).second.second;
+				fade->draw(targetSurf, &r1, &r2);
+			}
 			continue;
 		}
 		
@@ -1164,50 +1167,67 @@ std::pair<SDL_Surface *, bool> CMapHandler::CMapBlitter::getVisBitmap() const
 	}
 }
 
-void CMapHandler::updateObjectsFade()
+bool CMapHandler::updateObjectsFade()
 {	
-	// TODO caching fading objects indices for optimization?
-	for (size_t i=0; i<map->width; i++)
+	for (auto iter = fadeAnims.begin(); iter != fadeAnims.end(); )
 	{
-		for (size_t j=0; j<map->height; j++)
+		int3 pos = (*iter).second.first;
+		CFadeAnimation * anim = (*iter).second.second;
+		
+		anim->update();
+		if (anim->isFading())
+			++iter;
+		else
 		{
-			for (size_t k=0; k<(map->twoLevel ? 2 : 1); k++)
+			auto &objs = ttiles[pos.x][pos.y][pos.z].objects;
+			for (auto objIter = objs.begin(); objIter != objs.end(); ++objIter)
 			{
-				for(size_t x=0; x < ttiles[i][j][k].objects.size(); )
+				if ((*objIter).fadeAnimKey == (*iter).first)
 				{
-					auto &obj = ttiles[i][j][k].objects[x];
-					
-					switch (obj.fading)
-					{
-					case EMapObjectFadingType::IN:
-						obj.fadingCounter += 0.2f;
-						if (obj.fadingCounter >= 1.0f)
-						{
-							obj.fadingCounter = 1.0f;
-							obj.fading = EMapObjectFadingType::NONE;
-						}
-						++x;
-						break;
-					case EMapObjectFadingType::OUT:
-						obj.fadingCounter -= 0.2f;
-						if (obj.fadingCounter <= 0.0f)
-						{
-							obj.fadingCounter = 0.0f;
-							obj.fading = EMapObjectFadingType::NONE;
-							ttiles[i][j][k].objects.erase(ttiles[i][j][k].objects.begin() + x);
-						}
-						else
-							++x;
-						break;
-					default:
-						// not fading
-						++x;
-						break;
-					}
+					objs.erase(objIter);
+					break;
 				}
 			}
+			iter = fadeAnims.erase(iter);
 		}
 	}
+	// TODO caching fading objects indices for optimization?
+//	for (size_t i=0; i<map->width; i++)
+//	{
+//		for (size_t j=0; j<map->height; j++)
+//		{
+//			for (size_t k=0; k<(map->twoLevel ? 2 : 1); k++)
+//			{
+//				for(size_t x=0; x < ttiles[i][j][k].objects.size(); )
+//				{
+//					auto &obj = ttiles[i][j][k].objects[x];
+					
+//					if (obj.fadeAnimKey >= 0)
+//					{
+//						auto fadeAnimIter = fadeAnims.find(obj.fadeAnimKey);
+//						if (fadeAnimIter == fadeAnims.end())
+//						{
+//							obj.fadeAnimKey = -1;
+//							++x;
+//							continue;
+//						}
+						
+//						obj.fadeAnim->update();
+//						if (obj.fadeAnim->isFading())
+//						{
+//							anyObjectsStillFading = true;
+//							++x;
+//						}
+//						else if (obj.fadeAnim->fadingMode == CFadeAnimation::EMode::OUT)
+//							ttiles[i][j][k].objects.erase(ttiles[i][j][k].objects.begin() + x);
+//					}
+//					else
+//						++x;
+//				}
+//			}
+//		}
+//	}
+	return !fadeAnims.empty();
 }
 
 bool CMapHandler::printObject(const CGObjectInstance *obj, bool fadein /* = false */)
@@ -1215,7 +1235,7 @@ bool CMapHandler::printObject(const CGObjectInstance *obj, bool fadein /* = fals
 	if (!graphics->getDef(obj))
 		processDef(obj->appearance);
 
-	const SDL_Surface *bitmap = graphics->getDef(obj)->ourImages[0].bitmap;
+	SDL_Surface *bitmap = graphics->getDef(obj)->ourImages[0].bitmap;
 	const int tilesW = bitmap->w/32;
 	const int tilesH = bitmap->h/32;
 
@@ -1231,8 +1251,12 @@ bool CMapHandler::printObject(const CGObjectInstance *obj, bool fadein /* = fals
 			TerrainTileObject toAdd(obj, cr);
 			if (fadein)
 			{
-				toAdd.fading = EMapObjectFadingType::IN;
-				toAdd.fadingCounter = 0.0f;
+				auto tmp = CSDL_Ext::newSurface(bitmap->w, bitmap->h);
+				SDL_BlitSurface(bitmap, nullptr, tmp, nullptr); // can't be 8bpp for fading
+				auto anim = new CFadeAnimation();
+				anim->init(CFadeAnimation::EMode::IN, 0.05f, tmp, true);
+				fadeAnims[++fadeAnimCounter] = std::pair<int3, CFadeAnimation*>(int3(fx, fy, obj->pos.z), anim);
+				toAdd.fadeAnimKey = fadeAnimCounter;
 			}
 			
 			if((obj->pos.x + fx - tilesW+1)>=0 && (obj->pos.x + fx - tilesW+1)<ttiles.size()-frameW && (obj->pos.y + fy - tilesH+1)>=0 && (obj->pos.y + fy - tilesH+1)<ttiles[0].size()-frameH)
@@ -1272,11 +1296,15 @@ bool CMapHandler::hideObject(const CGObjectInstance *obj, bool fadeout /* = fals
 					if (ttiles[i][j][k].objects[x].obj->id == obj->id)
 					{
 						if (fadeout) // erase delayed until end of fadeout
-						{
-							ttiles[i][j][k].objects[x].fading = EMapObjectFadingType::OUT;
-							ttiles[i][j][k].objects[x].fadingCounter = 1.0f;
-							ttiles[i][j][k].objects[x].image = ttiles[i][j][k].objects[x].obj->appearance.animationFile;
-//							fadingObjectsCache.push_back(std::make_pair(int3(i, j, k), ttiles[i][j][k].objects[x].obj->ID));
+						{						
+							auto bitmap = graphics->getDef(obj)->ourImages[0].bitmap;
+							auto tmp = CSDL_Ext::newSurface(bitmap->w, bitmap->h); // TODO cache these bitmaps instead of creating new ones?
+							SDL_BlitSurface(bitmap, nullptr, tmp, nullptr); // can't be 8bpp for fading
+							
+							auto anim = new CFadeAnimation();
+							anim->init(CFadeAnimation::EMode::OUT, 0.05f, tmp, true);
+							fadeAnims[++fadeAnimCounter] = std::pair<int3, CFadeAnimation*>(int3(i, j, k), anim);
+							ttiles[i][j][k].objects[x].fadeAnimKey = fadeAnimCounter;
 						}
 						else
 							ttiles[i][j][k].objects.erase(ttiles[i][j][k].objects.begin() + x);
@@ -1410,8 +1438,8 @@ CMapHandler::~CMapHandler()
 {
 	delete graphics->FoWfullHide;
 	delete graphics->FoWpartialHide;
-	if (fadingOffscreenBitmapSurface)
-		delete fadingOffscreenBitmapSurface;
+//	if (fadingOffscreenBitmapSurface)
+//		delete fadingOffscreenBitmapSurface;
 
 	delete normalBlitter;
 	delete worldViewBlitter;
@@ -1428,6 +1456,11 @@ CMapHandler::~CMapHandler()
 		for(int j=0; j < elem.size(); ++j)
 			SDL_FreeSurface(elem[j]);
 	}
+	
+	for (auto & elem : fadeAnims)
+	{
+		delete elem.second.second;
+	}
 	terrainGraphics.clear();
 }
 
@@ -1436,10 +1469,10 @@ CMapHandler::CMapHandler()
 	frameW = frameH = 0;
 	graphics->FoWfullHide = nullptr;
 	graphics->FoWpartialHide = nullptr;
-	fadingOffscreenBitmapSurface = nullptr;
 	normalBlitter = new CMapNormalBlitter(this);
 	worldViewBlitter = new CMapWorldViewBlitter(this);
 	puzzleViewBlitter = new CMapPuzzleViewBlitter(this);
+	fadeAnimCounter = 0;
 }
 
 void CMapHandler::getTerrainDescr( const int3 &pos, std::string & out, bool terName )
@@ -1560,3 +1593,14 @@ bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObj
 	return false;
 }
 
+TerrainTileObject::TerrainTileObject(const CGObjectInstance * obj_, SDL_Rect rect_)
+	: obj(obj_),
+	  rect(rect_),
+	  fadeAnimKey(-1)
+{
+}
+
+TerrainTileObject::~TerrainTileObject()
+{
+}
+

+ 14 - 13
client/mapHandler.h

@@ -25,6 +25,7 @@ struct TerrainTile;
 struct SDL_Surface;
 struct SDL_Rect;
 class CDefEssential;
+class CFadeAnimation;
 
 enum class EWorldViewIcon
 {
@@ -57,20 +58,20 @@ enum class EMapObjectFadingType
 	OUT
 };
 
+enum class EMapAnimRedrawStatus
+{
+	OK,
+	REDRAW_REQUESTED // map blitter requests quick redraw due to current animation
+};
+
 struct TerrainTileObject
 {
 	const CGObjectInstance *obj;
 	SDL_Rect rect;
-	EMapObjectFadingType fading;
-	float fadingCounter;
-	std::string image;
+	int fadeAnimKey;
 	
-	TerrainTileObject(const CGObjectInstance *obj_, SDL_Rect rect_)
-		: obj(obj_),
-		  rect(rect_),
-		  fading(EMapObjectFadingType::NONE),
-		  fadingCounter(0.0f)
-	{}
+	TerrainTileObject(const CGObjectInstance *obj_, SDL_Rect rect_);
+	~TerrainTileObject();
 };
 
 struct TerrainTile2
@@ -308,11 +309,11 @@ class CMapHandler
 	CMapBlitter * worldViewBlitter;
 	CMapBlitter * puzzleViewBlitter;
 	
-//	std::vector<std::pair<int3, int>> fadingObjectsCache;
-	SDL_Surface * fadingOffscreenBitmapSurface;
+	std::map<int, std::pair<int3, CFadeAnimation*>> fadeAnims;
+	int fadeAnimCounter;
 
 	CMapBlitter * resolveBlitter(const MapDrawingInfo * info) const;
-	void updateObjectsFade();
+	bool updateObjectsFade();
 public:
 	PseudoV< PseudoV< PseudoV<TerrainTile2> > > ttiles; //informations about map tiles
 	int3 sizes; //map size (x = width, y = height, z = number of levels)
@@ -358,7 +359,7 @@ public:
 	void roadsRiverTerrainInit();
 	void prepareFOWDefs();
 
-	void drawTerrainRectNew(SDL_Surface * targetSurface, const MapDrawingInfo * info);
+	EMapAnimRedrawStatus drawTerrainRectNew(SDL_Surface * targetSurface, const MapDrawingInfo * info, bool redrawOnlyAnim = false);
 	void updateWater();
 	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]

+ 68 - 6
client/windows/CAdvmapInterface.cpp

@@ -18,6 +18,7 @@
 #include "../Graphics.h"
 #include "../mapHandler.h"
 
+#include "../gui/CAnimation.h"
 #include "../gui/CCursorHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/SDL_Extensions.h"
@@ -61,7 +62,10 @@ CAdvMapInt *adventureInt;
 
 
 CTerrainRect::CTerrainRect()
-	: curHoveredTile(-1,-1,-1), currentPath(nullptr)
+	: fadeSurface(nullptr), 
+	  fadeAnim(new CFadeAnimation()),
+	  curHoveredTile(-1,-1,-1), 
+	  currentPath(nullptr)
 {
 	tilesw=(ADVOPT.advmapW+31)/32;
 	tilesh=(ADVOPT.advmapH+31)/32;
@@ -73,6 +77,13 @@ CTerrainRect::CTerrainRect()
 	addUsedEvents(LCLICK | RCLICK | HOVER | MOVE);
 }
 
+CTerrainRect::~CTerrainRect()
+{
+	if (fadeSurface)
+		SDL_FreeSurface(fadeSurface);
+	delete fadeAnim;
+}
+
 void CTerrainRect::deactivate()
 {
 	CIntObject::deactivate();
@@ -272,8 +283,14 @@ void CTerrainRect::show(SDL_Surface * to)
 		info.heroAnim = adventureInt->heroAnim;
 		if (ADVOPT.smoothMove)
 			info.movement = int3(moveX, moveY, 0);
-
-		CGI->mh->drawTerrainRectNew(to, &info);
+		
+		lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info);
+		if (fadeAnim->isFading())
+		{
+			Rect r(pos);
+			fadeAnim->update();
+			fadeAnim->draw(to, nullptr, &r);
+		}
 
 		if (currentPath/* && adventureInt->position.z==currentPath->startPos().z*/) //drawing path
 		{
@@ -298,6 +315,22 @@ void CTerrainRect::showAll(SDL_Surface * to)
 	}
 }
 
+void CTerrainRect::showAnim(SDL_Surface * to)
+{	
+	if (fadeAnim->isFading())
+		show(to);
+	else if (lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED)
+	{
+		MapDrawingInfo info(adventureInt->position, &LOCPLINT->cb->getVisibilityMap(), &pos);
+		info.otherheroAnim = true;
+		info.anim = adventureInt->anim;
+		info.heroAnim = adventureInt->heroAnim;
+		if (ADVOPT.smoothMove)
+			info.movement = int3(moveX, moveY, 0);
+		lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info, true);
+	}		
+}
+
 int3 CTerrainRect::whichTileIsIt(const int & x, const int & y)
 {
 	int3 ret;
@@ -326,6 +359,22 @@ int3 CTerrainRect::tileCountOnScreen()
 	}
 }
 
+void CTerrainRect::fadeFromCurrentView()
+{
+	if (adventureInt->mode == EAdvMapMode::WORLD_VIEW)
+		return;
+	
+	if (!fadeSurface)
+		fadeSurface = CSDL_Ext::newSurface(pos.w, pos.h);
+	SDL_BlitSurface(screen, &pos, fadeSurface, nullptr);
+	fadeAnim->init(CFadeAnimation::EMode::OUT, 0.05f, fadeSurface);
+}
+
+bool CTerrainRect::needsAnimUpdate()
+{
+	return fadeAnim->isFading() || lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED;
+}
+
 void CResDataBar::clickRight(tribool down, bool previousState)
 {
 }
@@ -917,6 +966,13 @@ void CAdvMapInt::show(SDL_Surface * to)
 		updateScreen=false;
 		LOCPLINT->cingconsole->showAll(to);
 	}
+	else if (terrain.needsAnimUpdate())
+	{
+		terrain.showAnim(to);
+		for(int i=0;i<4;i++)
+			blitAt(gems[i]->ourImages[LOCPLINT->playerID.getNum()].bitmap,ADVOPT.gemX[i],ADVOPT.gemY[i],to);
+	}
+	
 	infoBar.show(to);
 	statusbar.showAll(to);
 }
@@ -928,9 +984,15 @@ void CAdvMapInt::selectionChanged()
 		select(to);
 }
 
-void CAdvMapInt::centerOn(int3 on)
+void CAdvMapInt::centerOn(int3 on, bool fadeIfZChanged /* = false */)
 {
 	bool switchedLevels = on.z != position.z;
+	
+	if (switchedLevels && fadeIfZChanged)
+	{
+		logGlobal->warnStream() << "START FADING";
+		terrain.fadeFromCurrentView();
+	}
 
 	switch (mode)
 	{
@@ -962,9 +1024,9 @@ void CAdvMapInt::centerOn(int3 on)
 		terrain.redraw();
 }
 
-void CAdvMapInt::centerOn(const CGObjectInstance *obj)
+void CAdvMapInt::centerOn(const CGObjectInstance *obj, bool fadeIfZChanged /* = false */)
 {
-	centerOn(obj->getSightCenter());
+	centerOn(obj->getSightCenter(), fadeIfZChanged);
 }
 
 void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)

+ 12 - 2
client/windows/CAdvmapInterface.h

@@ -15,6 +15,8 @@ class CGTownInstance;
 class CHeroWindow;
 class CSpell;
 class IShipyard;
+enum class EMapAnimRedrawStatus;
+class CFadeAnimation;
 
 /*****************************/
 
@@ -48,12 +50,16 @@ public:
 class CTerrainRect
 	:  public CIntObject
 {
+	SDL_Surface * fadeSurface;
+	EMapAnimRedrawStatus lastRedrawStatus;
+	CFadeAnimation * fadeAnim;
 public:
 	int tilesw, tilesh; //width and height of terrain to blit in tiles
 	int3 curHoveredTile;
 	int moveX, moveY; //shift between actual position of screen and the one we wil blit; ranges from -31 to 31 (in pixels)
 
 	CTerrainRect();
+	virtual ~CTerrainRect();
 	CGPath * currentPath;
 	void deactivate();
 	void clickLeft(tribool down, bool previousState);
@@ -62,11 +68,15 @@ public:
 	void mouseMoved (const SDL_MouseMotionEvent & sEvent);
 	void show(SDL_Surface * to);
 	void showAll(SDL_Surface * to);
+	void showAnim(SDL_Surface * to);
 	void showPath(const SDL_Rect * extRect, SDL_Surface * to);
 	int3 whichTileIsIt(const int & x, const int & y); //x,y are cursor position
 	int3 whichTileIsIt(); //uses current cursor pos
 	/// @returns number of visible tiles on screen respecting current map scaling
 	int3 tileCountOnScreen();
+	/// animates view by caching current surface and crossfading it with normal screen
+	void fadeFromCurrentView();
+	bool needsAnimUpdate();
 };
 
 /// Resources bar which shows information about how many gold, crystals,... you have
@@ -176,8 +186,8 @@ public:
 
 	void select(const CArmedInstance *sel, bool centerView = true);
 	void selectionChanged();
-	void centerOn(int3 on);
-	void centerOn(const CGObjectInstance *obj);
+	void centerOn(int3 on, bool fadeIfZChanged = false);
+	void centerOn(const CGObjectInstance *obj, bool fadeIfZChanged = false);
 	int3 verifyPos(int3 ver);
 	void handleRightClick(std::string text, tribool down);
 	void keyPressed(const SDL_KeyboardEvent & key);