Browse Source

Implemented terrain transition animation

Ivan Savenko 2 years ago
parent
commit
165f6a0944

+ 2 - 0
client/mapView/IMapRendererContext.h

@@ -67,6 +67,8 @@ public:
 	/// returns animation frame for terrain
 	virtual size_t terrainImageIndex(size_t groupSize) const = 0;
 
+	virtual double viewTransitionProgress() const = 0;
+
 	/// if true, rendered images will be converted to grayscale
 	virtual bool filterGrayscale() const = 0;
 

+ 15 - 0
client/mapView/MapRendererContext.cpp

@@ -139,6 +139,11 @@ size_t MapRendererBaseContext::overlayImageIndex(const int3 & coordinates) const
 	return std::numeric_limits<size_t>::max();
 }
 
+double MapRendererBaseContext::viewTransitionProgress() const
+{
+	return 0;
+}
+
 bool MapRendererBaseContext::filterGrayscale() const
 {
 	return false;
@@ -246,6 +251,16 @@ bool MapRendererAdventureContext::showBlockable() const
 	return settingShowBlockable;
 }
 
+MapRendererAdventureTransitionContext::MapRendererAdventureTransitionContext(const MapRendererContextState & viewState)
+	: MapRendererAdventureContext(viewState)
+{
+}
+
+double MapRendererAdventureTransitionContext::viewTransitionProgress() const
+{
+	return progress;
+}
+
 MapRendererAdventureFadingContext::MapRendererAdventureFadingContext(const MapRendererContextState & viewState)
 	: MapRendererAdventureContext(viewState)
 {

+ 11 - 0
client/mapView/MapRendererContext.h

@@ -47,6 +47,7 @@ public:
 	size_t terrainImageIndex(size_t groupSize) const override;
 	size_t overlayImageIndex(const int3 & coordinates) const override;
 
+	double viewTransitionProgress() const override;
 	bool filterGrayscale() const override;
 	bool showRoads() const override;
 	bool showRivers() const override;
@@ -79,6 +80,16 @@ public:
 	bool showBlockable() const override;
 };
 
+class MapRendererAdventureTransitionContext : public MapRendererAdventureContext
+{
+public:
+	double progress = 0;
+
+	explicit MapRendererAdventureTransitionContext(const MapRendererContextState & viewState);
+
+	double viewTransitionProgress() const override;
+};
+
 class MapRendererAdventureFadingContext : public MapRendererAdventureContext
 {
 public:

+ 13 - 13
client/mapView/MapViewCache.cpp

@@ -30,6 +30,7 @@ MapViewCache::MapViewCache(const std::shared_ptr<MapViewModel> & model)
 	, iconsStorage(new CAnimation("VwSymbol"))
 	, intermediate(new Canvas(Point(32, 32)))
 	, terrain(new Canvas(model->getCacheDimensionsPixels()))
+	, terrainTransition(new Canvas(model->getPixelsVisibleDimensions()))
 {
 	iconsStorage->preload();
 	for(size_t i = 0; i < iconsStorage->size(); ++i)
@@ -54,17 +55,6 @@ std::shared_ptr<IImage> MapViewCache::getOverlayImageForTile(const std::shared_p
 	return nullptr;
 }
 
-void MapViewCache::invalidate(const std::shared_ptr<IMapRendererContext> & context, const int3 & tile)
-{
-	int cacheX = (terrainChecksum.shape()[0] + tile.x) % terrainChecksum.shape()[0];
-	int cacheY = (terrainChecksum.shape()[1] + tile.y) % terrainChecksum.shape()[1];
-
-	auto & entry = terrainChecksum[cacheX][cacheY];
-
-	if(entry.tileX == tile.x && entry.tileY == tile.y)
-		entry = TileChecksum{};
-}
-
 void MapViewCache::invalidate(const std::shared_ptr<IMapRendererContext> & context, const ObjectInstanceID & object)
 {
 	for(size_t cacheY = 0; cacheY < terrainChecksum.shape()[1]; ++cacheY)
@@ -145,7 +135,7 @@ void MapViewCache::update(const std::shared_ptr<IMapRendererContext> & context)
 void MapViewCache::render(const std::shared_ptr<IMapRendererContext> & context, Canvas & target, bool fullRedraw)
 {
 	bool mapMoved = (cachedPosition != model->getMapViewCenter());
-	bool lazyUpdate = !mapMoved && !fullRedraw;
+	bool lazyUpdate = !mapMoved && !fullRedraw && context->viewTransitionProgress() == 0;
 
 	Rect dimensions = model->getTilesTotalRect();
 
@@ -164,7 +154,8 @@ void MapViewCache::render(const std::shared_ptr<IMapRendererContext> & context,
 			Rect targetRect = model->getTargetTileArea(tile);
 			target.draw(source, targetRect.topLeft());
 
-			tilesUpToDate[cacheX][cacheY] = true;
+			if (!fullRedraw)
+				tilesUpToDate[cacheX][cacheY] = true;
 		}
 	}
 
@@ -187,5 +178,14 @@ void MapViewCache::render(const std::shared_ptr<IMapRendererContext> & context,
 		}
 	}
 
+	if (context->viewTransitionProgress() != 0)
+		target.drawTransparent(*terrainTransition, Point(0,0), 1.0 - context->viewTransitionProgress());
+
 	cachedPosition = model->getMapViewCenter();
 }
+
+void MapViewCache::createTransitionSnapshot(const std::shared_ptr<IMapRendererContext> & context)
+{
+	update(context);
+	render(context, *terrainTransition, true);
+}

+ 5 - 1
client/mapView/MapViewCache.h

@@ -62,7 +62,7 @@ public:
 	explicit MapViewCache(const std::shared_ptr<MapViewModel> & model);
 	~MapViewCache();
 
-	void invalidate(const std::shared_ptr<IMapRendererContext> & context, const int3 & tile);
+	/// invalidates cache of specified object
 	void invalidate(const std::shared_ptr<IMapRendererContext> & context, const ObjectInstanceID & object);
 
 	/// updates internal terrain cache according to provided time delta
@@ -70,4 +70,8 @@ public:
 
 	/// renders updated terrain cache onto provided canvas
 	void render(const std::shared_ptr<IMapRendererContext> & context, Canvas & target, bool fullRedraw);
+
+	/// creates snapshot of current view and stores it into internal canvas
+	/// used for view transition, e.g. Dimension Door spell or teleporters (Subterra gates / Monolith)
+	void createTransitionSnapshot(const std::shared_ptr<IMapRendererContext> & context);
 };

+ 21 - 17
client/mapView/MapViewController.cpp

@@ -99,7 +99,7 @@ void MapViewController::update(uint32_t timeDelta)
 	// - teleporting ( 250 ms)
 	static const double fadeOutDuration = 500;
 	static const double fadeInDuration = 500;
-	//static const double heroTeleportDuration = 250;
+	static const double heroTeleportDuration = 250;
 
 	//FIXME: remove code duplication?
 
@@ -140,13 +140,14 @@ void MapViewController::update(uint32_t timeDelta)
 		}
 	}
 
-	//if(teleportContext)
-	//{
-	//	teleportContext->progress += timeDelta / heroTeleportDuration;
-	//	moveFocusToSelection();
-	//	if(teleportContext->progress >= 1.0)
-	//		teleportContext.reset();
-	//}
+	if(teleportContext)
+	{
+		teleportContext->progress += timeDelta / heroTeleportDuration;
+		if(teleportContext->progress >= 1.0)
+		{
+			activateAdventureContext(teleportContext->animationTime);
+		}
+	}
 
 	if(fadingOutContext)
 	{
@@ -316,9 +317,8 @@ void MapViewController::onBeforeHeroTeleported(const CGHeroInstance * obj, const
 
 	if(isEventVisible(obj, from, dest))
 	{
-		// TODO: generate view with old state
 		setViewCenter(obj->getSightCenter());
-		removeObject(obj);
+		view->createTransitionSnapshot(context);
 	}
 }
 
@@ -326,16 +326,16 @@ void MapViewController::onAfterHeroTeleported(const CGHeroInstance * obj, const
 {
 	assert(!hasOngoingAnimations());
 
+	removeObject(obj);
+	addObject(obj);
+
 	if(isEventVisible(obj, from, dest))
 	{
-		// TODO: animation
+		teleportContext = std::make_shared<MapRendererAdventureTransitionContext>(*state);
+		teleportContext->animationTime = adventureContext->animationTime;
+		adventureContext = teleportContext;
+		context = teleportContext;
 		setViewCenter(obj->getSightCenter());
-		addObject(obj);
-	}
-	else
-	{
-		removeObject(obj);
-		addObject(obj);
 	}
 }
 
@@ -395,6 +395,9 @@ bool MapViewController::hasOngoingAnimations()
 	if(fadingInContext)
 		return true;
 
+	if (teleportContext)
+		return true;
+
 	return false;
 }
 
@@ -458,6 +461,7 @@ void MapViewController::resetContext()
 	movementContext.reset();
 	fadingOutContext.reset();
 	fadingInContext.reset();
+	teleportContext.reset();
 	worldViewContext.reset();
 	spellViewContext.reset();
 	puzzleMapContext.reset();

+ 2 - 1
client/mapView/MapViewController.h

@@ -24,6 +24,7 @@ class IMapRendererContext;
 class MapRendererAdventureContext;
 class MapRendererAdventureFadingContext;
 class MapRendererAdventureMovingContext;
+class MapRendererAdventureTransitionContext;
 class MapRendererWorldViewContext;
 class MapRendererSpellViewContext;
 class MapRendererPuzzleMapContext;
@@ -41,7 +42,7 @@ class MapViewController : public IMapObjectObserver
 	// only some are present at any given moment, rest are nullptr's
 	std::shared_ptr<MapRendererAdventureContext> adventureContext;
 	std::shared_ptr<MapRendererAdventureMovingContext> movementContext;
-	//std::shared_ptr<IMapRendererContext> teleportContext;
+	std::shared_ptr<MapRendererAdventureTransitionContext> teleportContext;
 	std::shared_ptr<MapRendererAdventureFadingContext> fadingOutContext;
 	std::shared_ptr<MapRendererAdventureFadingContext> fadingInContext;
 	std::shared_ptr<MapRendererWorldViewContext> worldViewContext;

+ 5 - 0
client/render/Canvas.cpp

@@ -84,9 +84,14 @@ void Canvas::draw(const Canvas & image, const Point & pos)
 
 void Canvas::drawTransparent(const Canvas & image, const Point & pos, double transparency)
 {
+	SDL_BlendMode oldMode;
+
+	SDL_GetSurfaceBlendMode(image.surface, &oldMode);
+	SDL_SetSurfaceBlendMode(image.surface, SDL_BLENDMODE_BLEND);
 	SDL_SetSurfaceAlphaMod(image.surface, 255 * transparency);
 	CSDL_Ext::blitSurface(image.surface, image.renderArea, surface, renderArea.topLeft() + pos);
 	SDL_SetSurfaceAlphaMod(image.surface, 255);
+	SDL_SetSurfaceBlendMode(image.surface, oldMode);
 }
 
 void Canvas::drawScaled(const Canvas & image, const Point & pos, const Point & targetSize)