Sfoglia il codice sorgente

Moved path rendering to new map renderer

Ivan Savenko 2 anni fa
parent
commit
21a48e4f0d

+ 91 - 1
client/adventureMap/MapRenderer.cpp

@@ -26,6 +26,7 @@
 #include "../../lib/TerrainHandler.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
 #include "../../lib/mapping/CMap.h"
+#include "../../lib/CPathfinder.h"
 
 struct NeighborTilesInfo
 {
@@ -534,10 +535,98 @@ void MapRendererDebugGrid::renderTile(const IMapRendererContext & context, Canva
 	}
 }
 
+MapRendererPath::MapRendererPath()
+	: pathNodes(new CAnimation("ADAG"))
+{
+	pathNodes->preload();
+}
+
+void MapRendererPath::renderImage(Canvas & target, bool reachableToday, size_t imageIndex)
+{
+	const static size_t unreachableTodayOffset = 25;
+
+	if(reachableToday)
+		target.draw(pathNodes->getImage(imageIndex), Point(0, 0));
+	else
+		target.draw(pathNodes->getImage(imageIndex + unreachableTodayOffset), Point(0, 0));
+}
+
+void MapRendererPath::renderImageCross(Canvas & target, bool reachableToday, const int3 & curr)
+{
+	renderImage(target, reachableToday, 0);
+}
+
+void MapRendererPath::renderImageArrow(Canvas & target, bool reachableToday, const int3 & curr, const int3 & prev, const int3 & next)
+{
+	// Vector directions
+	//  0   1   2
+	//      |
+	//  3 - 4 - 5
+	//      |
+	//  6   7   8
+	//For example:
+	//  |
+	//  +->
+	// is (directionToArrowIndex[7][5])
+	//
+	const static size_t directionToArrowIndex[9][9] = {
+		{16, 17, 18, 7,  0, 19, 6,  5,  0 },
+		{8,  9,  18, 7,  0, 19, 6,  0,  20},
+		{8,  1,  10, 7,  0, 19, 0,  21, 20},
+		{24, 17, 18, 15, 0, 0,  6,  5,  4 },
+		{0,  0,  0,  0,  0, 0,  0,  0,  0 },
+		{8,  1,  2,  0,  0, 11, 22, 21, 20},
+		{24, 17, 0,  23, 0, 3,  14, 5,  4 },
+		{24, 0,  2,  23, 0, 3,  22, 13, 4 },
+		{0,  1,  2,  23, 0, 3,  22, 21, 12}
+	};
+
+	size_t enterDirection = (curr.x - next.x + 1) + 3 * (curr.y - next.y + 1);
+	size_t leaveDirection = (prev.x - curr.x + 1) + 3 * (prev.y - curr.y + 1);
+	size_t imageIndex = directionToArrowIndex[enterDirection][leaveDirection];
+
+	renderImage(target, reachableToday, imageIndex);
+}
+
+void MapRendererPath::renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates)
+{
+	const auto & functor = [&](const CGPathNode & node)
+	{
+		return node.coord == coordinates;
+	};
+
+	const auto * path = context.currentPath();
+	if(!path)
+		return;
+
+	const auto & iter = boost::range::find_if(path->nodes, functor);
+
+	if(iter == path->nodes.end())
+		return;
+
+	bool reachableToday = iter->turns == 0;
+	if(iter == path->nodes.begin())
+		renderImageCross(target, reachableToday, iter->coord);
+
+	auto next = iter + 1;
+	auto prev = iter - 1;
+
+	// start of path - currentl hero location
+	if(next == path->nodes.end())
+		return;
+
+	bool pathContinuous = iter->coord.areNeighbours(next->coord) && iter->coord.areNeighbours(prev->coord);
+	bool embarking = iter->action == CGPathNode::EMBARK || iter->action == CGPathNode::DISEMBARK;
+
+	if(pathContinuous && !embarking)
+		renderImageArrow(target, reachableToday, iter->coord, prev->coord, next->coord);
+	else
+		renderImageCross(target, reachableToday, iter->coord);
+}
+
 MapRenderer::MapRenderer(const IMapRendererContext & context)
 	: rendererObjects(context)
 {
-
 }
 
 void MapRenderer::renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates)
@@ -560,6 +649,7 @@ void MapRenderer::renderTile(const IMapRendererContext & context, Canvas & targe
 		rendererRiver.renderTile(context, target, coordinates);
 		rendererRoad.renderTile(context, target, coordinates);
 		rendererObjects.renderTile(context, target, coordinates);
+		rendererPath.renderTile(context, target, coordinates);
 
 		if (!context.isVisible(coordinates))
 			rendererFow.renderTile(context, target, coordinates);

+ 14 - 0
client/adventureMap/MapRenderer.h

@@ -113,6 +113,19 @@ public:
 	void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
 };
 
+class MapRendererPath
+{
+	std::unique_ptr<CAnimation> pathNodes;
+
+	void renderImage(Canvas & target, bool reachableToday, size_t imageIndex);
+	void renderImageCross(Canvas & target, bool reachableToday, const int3 & curr);
+	void renderImageArrow(Canvas & target, bool reachableToday, const int3 & curr, const int3 & prev, const int3 & next);
+public:
+	MapRendererPath();
+	void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
+};
+
+
 class MapRendererDebugGrid
 {
 public:
@@ -127,6 +140,7 @@ class MapRenderer
 	MapRendererBorder rendererBorder;
 	MapRendererFow rendererFow;
 	MapRendererObjects rendererObjects;
+	MapRendererPath rendererPath;
 	MapRendererDebugGrid rendererDebugGrid;
 
 public:

+ 19 - 2
client/adventureMap/MapRendererContext.h

@@ -18,6 +18,7 @@ class Point;
 class ObjectInstanceID;
 class CGObjectInstance;
 struct TerrainTile;
+struct CGPath;
 
 VCMI_LIB_NAMESPACE_END
 
@@ -26,22 +27,38 @@ class IMapRendererContext
 public:
 	virtual ~IMapRendererContext() = default;
 
-	using VisibilityMap = std::shared_ptr<const boost::multi_array<ui8, 3>>;
 	using ObjectsVector = std::vector< ConstTransitivePtr<CGObjectInstance> >;
 
+	/// returns dimensions of current map
 	virtual int3 getMapSize() const = 0;
+
+	/// returns true if chosen coordinates exist on map
 	virtual bool isInMap(const int3 & coordinates) const = 0;
+
+	/// returns tile by selected coordinates. Coordinates MUST be valid
 	virtual const TerrainTile & getMapTile(const int3 & coordinates) const = 0;
 
+	/// returns vector of all objects present on current map
 	virtual ObjectsVector getAllObjects() const = 0;
+
+	/// returns specific object by ID, or nullptr if not found
 	virtual const CGObjectInstance * getObject( ObjectInstanceID objectID ) const = 0;
 
+	/// returns path of currently active hero, or nullptr if none
+	virtual const CGPath * currentPath() const = 0;
+
+	/// returns true if specified tile is visible in current context
 	virtual bool isVisible(const int3 & coordinates) const = 0;
-	virtual VisibilityMap getVisibilityMap() const = 0;
 
+	/// returns how long should each frame of animation be visible, in milliseconds
 	virtual uint32_t getAnimationPeriod() const = 0;
+
+	/// returns total animation time since creation of this context
 	virtual uint32_t getAnimationTime() const = 0;
+
+	/// returns size of ouput tile, in pixels. 32x32 for "standard" map, may be smaller for world view mode
 	virtual Point tileSize() const = 0;
 
+	/// if true, map grid should be visible on map
 	virtual bool showGrid() const = 0;
 };

+ 11 - 2
client/adventureMap/MapView.cpp

@@ -13,6 +13,7 @@
 
 #include "MapRenderer.h"
 #include "mapHandler.h"
+#include "CAdvMapInt.h"
 
 #include "../CGameInfo.h"
 #include "../CMusicHandler.h"
@@ -266,9 +267,17 @@ bool MapRendererContext::isVisible(const int3 & coordinates) const
 	return LOCPLINT->cb->isVisible(coordinates) || settings["session"]["spectate"].Bool();
 }
 
-MapRendererContext::VisibilityMap MapRendererContext::getVisibilityMap() const
+const CGPath * MapRendererContext::currentPath() const
 {
-	return LOCPLINT->cb->getVisibilityMap();
+	const auto * hero = adventureInt->curHero();
+
+	if(!hero)
+		return nullptr;
+
+	if(!LOCPLINT->paths.hasPath(hero))
+		return nullptr;
+
+	return &LOCPLINT->paths.getPath(hero);
 }
 
 uint32_t MapRendererContext::getAnimationPeriod() const

+ 2 - 1
client/adventureMap/MapView.h

@@ -30,8 +30,9 @@ public:
 	ObjectsVector getAllObjects() const override;
 	const CGObjectInstance * getObject(ObjectInstanceID objectID) const override;
 
+	const CGPath * currentPath() const override;
+
 	bool isVisible(const int3 & coordinates) const override;
-	VisibilityMap getVisibilityMap() const override;
 
 	uint32_t getAnimationPeriod() const override;
 	uint32_t getAnimationTime() const override;