瀏覽代碼

Cleaned up code of Minimap

Ivan Savenko 2 年之前
父節點
當前提交
d0f57fed6f

+ 56 - 146
client/adventureMap/CMinimap.cpp

@@ -19,6 +19,7 @@
 #include "../gui/CGuiHandler.h"
 #include "../render/Colors.h"
 #include "../renderSDL/SDL_PixelAccess.h"
+#include "../windows/InfoWindows.h"
 
 #include "../../CCallback.h"
 #include "../../lib/CGeneralTextHandler.h"
@@ -26,159 +27,65 @@
 #include "../../lib/mapObjects/CGHeroInstance.h"
 #include "../../lib/mapping/CMapDefines.h"
 
-#include <SDL_surface.h>
-
-const SDL_Color & CMinimapInstance::getTileColor(const int3 & pos)
+ColorRGBA CMinimapInstance::getTileColor(const int3 & pos) const
 {
 	const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false);
 
 	// if tile is not visible it will be black on minimap
 	if(!tile)
-		return Colors::BLACK;
+		return CSDL_Ext::fromSDL(Colors::BLACK);
 
 	// if object at tile is owned - it will be colored as its owner
 	for (const CGObjectInstance *obj : tile->blockingObjects)
 	{
-		//heroes will be blitted later
-		switch (obj->ID)
-		{
-			case Obj::HERO:
-			case Obj::PRISON:
-				continue;
-		}
-
 		PlayerColor player = obj->getOwner();
 		if(player == PlayerColor::NEUTRAL)
-			return *graphics->neutralColor;
-		else
+			return CSDL_Ext::fromSDL(*graphics->neutralColor);
+
 		if (player < PlayerColor::PLAYER_LIMIT)
-			return graphics->playerColors[player.getNum()];
+			return CSDL_Ext::fromSDL(graphics->playerColors[player.getNum()]);
 	}
 
-	// else - use terrain color (blocked version or normal)
-	const auto & colorPair = parent->colors.find(tile->terType->getId())->second;
 	if (tile->blocked && (!tile->visitable))
-		return colorPair.second;
+		return tile->terType->minimapBlocked;
 	else
-		return colorPair.first;
-}
-void CMinimapInstance::tileToPixels (const int3 &tile, int &x, int &y, int toX, int toY)
-{
-	int3 mapSizes = LOCPLINT->cb->getMapSize();
-
-	double stepX = double(pos.w) / mapSizes.x;
-	double stepY = double(pos.h) / mapSizes.y;
-
-	x = static_cast<int>(toX + stepX * tile.x);
-	y = static_cast<int>(toY + stepY * tile.y);
-}
-
-void CMinimapInstance::blitTileWithColor(const SDL_Color &color, const int3 &tile, SDL_Surface *to, int toX, int toY)
-{
-	//coordinates of rectangle on minimap representing this tile
-	// begin - first to blit, end - first NOT to blit
-	int xBegin, yBegin, xEnd, yEnd;
-	tileToPixels (tile, xBegin, yBegin, toX, toY);
-	tileToPixels (int3 (tile.x + 1, tile.y + 1, tile.z), xEnd, yEnd, toX, toY);
-
-	for (int y=yBegin; y<yEnd; y++)
-	{
-		uint8_t *ptr = (uint8_t*)to->pixels + y * to->pitch + xBegin * minimap->format->BytesPerPixel;
-
-		for (int x=xBegin; x<xEnd; x++)
-			ColorPutter<4, 1>::PutColor(ptr, color);
-	}
+		return tile->terType->minimapUnblocked;
 }
 
 void CMinimapInstance::refreshTile(const int3 &tile)
 {
-	blitTileWithColor(getTileColor(int3(tile.x, tile.y, level)), tile, minimap, 0, 0);
+	if (level == tile.z)
+		minimap->drawPoint(Point(tile.x, tile.y), getTileColor(tile));
 }
 
-void CMinimapInstance::drawScaled(int level)
+void CMinimapInstance::redrawMinimap()
 {
 	int3 mapSizes = LOCPLINT->cb->getMapSize();
 
-	//size of one map tile on our minimap
-	double stepX = double(pos.w) / mapSizes.x;
-	double stepY = double(pos.h) / mapSizes.y;
-
-	double currY = 0;
-	for (int y=0; y<mapSizes.y; y++, currY += stepY)
-	{
-		double currX = 0;
-		for (int x=0; x<mapSizes.x; x++, currX += stepX)
-		{
-			const SDL_Color &color = getTileColor(int3(x,y,level));
-
-			//coordinates of rectangle on minimap representing this tile
-			// begin - first to blit, end - first NOT to blit
-			int xBegin = static_cast<int>(currX);
-			int yBegin = static_cast<int>(currY);
-			int xEnd = static_cast<int>(currX + stepX);
-			int yEnd = static_cast<int>(currY + stepY);
-
-			for (int y=yBegin; y<yEnd; y++)
-			{
-				uint8_t *ptr = (uint8_t*)minimap->pixels + y * minimap->pitch + xBegin * minimap->format->BytesPerPixel;
-
-				for (int x=xBegin; x<xEnd; x++)
-					ColorPutter<4, 1>::PutColor(ptr, color);
-			}
-		}
-	}
+	for (int y = 0; y < mapSizes.y; ++y)
+		for (int x = 0; x < mapSizes.x; ++x)
+			minimap->drawPoint(Point(x, y), getTileColor(int3(x, y, level)));
 }
 
 CMinimapInstance::CMinimapInstance(CMinimap *Parent, int Level):
 	parent(Parent),
-	minimap(CSDL_Ext::createSurfaceWithBpp<4>(parent->pos.w, parent->pos.h)),
+	minimap(new Canvas(Point(LOCPLINT->cb->getMapSize().x, LOCPLINT->cb->getMapSize().y))),
 	level(Level)
 {
 	pos.w = parent->pos.w;
 	pos.h = parent->pos.h;
-	drawScaled(level);
-}
-
-CMinimapInstance::~CMinimapInstance()
-{
-	SDL_FreeSurface(minimap);
+	redrawMinimap();
 }
 
 void CMinimapInstance::showAll(SDL_Surface * to)
 {
-	blitAtLoc(minimap, 0, 0, to);
-
-	//draw heroes
-	std::vector <const CGHeroInstance *> heroes = LOCPLINT->cb->getHeroesInfo(false); //TODO: do we really need separate function for drawing heroes?
-	for(auto & hero : heroes)
-	{
-		int3 position = hero->visitablePos();
-		if(position.z == level)
-		{
-			const SDL_Color & color = graphics->playerColors[hero->getOwner().getNum()];
-			blitTileWithColor(color, position, to, pos.x, pos.y);
-		}
-	}
-}
-
-std::map<TerrainId, std::pair<SDL_Color, SDL_Color> > CMinimap::loadColors()
-{
-	std::map<TerrainId, std::pair<SDL_Color, SDL_Color> > ret;
-
-	for(const auto & terrain : CGI->terrainTypeHandler->objects)
-	{
-		SDL_Color normal = CSDL_Ext::toSDL(terrain->minimapUnblocked);
-		SDL_Color blocked = CSDL_Ext::toSDL(terrain->minimapBlocked);
-
-		ret[terrain->getId()] = std::make_pair(normal, blocked);
-	}
-	return ret;
+	Canvas target(to);
+	target.draw(*minimap, pos.topLeft(), pos.dimensions());
 }
 
 CMinimap::CMinimap(const Rect & position)
 	: CIntObject(LCLICK | RCLICK | HOVER | MOVE, position.topLeft()),
-	level(0),
-	colors(loadColors())
+	level(0)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 	pos.w = position.w;
@@ -188,21 +95,36 @@ CMinimap::CMinimap(const Rect & position)
 	aiShield->disable();
 }
 
-int3 CMinimap::translateMousePosition()
+int3 CMinimap::pixelToTile(const Point & cursorPos) const
 {
 	// 0 = top-left corner, 1 = bottom-right corner
-	double dx = double(GH.getCursorPosition().x - pos.x) / pos.w;
-	double dy = double(GH.getCursorPosition().y - pos.y) / pos.h;
+	double dx = static_cast<double>(cursorPos.x) / pos.w;
+	double dy = static_cast<double>(cursorPos.y) / pos.h;
+
+	int3 mapSizes = LOCPLINT->cb->getMapSize();
+
+	int tileX(std::round(mapSizes.x * dx));
+	int tileY(std::round(mapSizes.y * dy));
+
+	return int3(tileX, tileY, level);
+}
 
+Point CMinimap::tileToPixels(const int3 &tile) const
+{
 	int3 mapSizes = LOCPLINT->cb->getMapSize();
 
-	int3 tile ((si32)(mapSizes.x * dx), (si32)(mapSizes.y * dy), level);
-	return tile;
+	double stepX = static_cast<double>(pos.w) / mapSizes.x;
+	double stepY = static_cast<double>(pos.h) / mapSizes.y;
+
+	int x = static_cast<int>(stepX * tile.x);
+	int y = static_cast<int>(stepY * tile.y);
+
+	return Point(x,y);
 }
 
 void CMinimap::moveAdvMapSelection()
 {
-	int3 newLocation = translateMousePosition();
+	int3 newLocation = pixelToTile(GH.getCursorPosition() - pos.topLeft());
 	adventureInt->centerOn(newLocation);
 
 	if (!(adventureInt->active & GENERAL))
@@ -219,7 +141,8 @@ void CMinimap::clickLeft(tribool down, bool previousState)
 
 void CMinimap::clickRight(tribool down, bool previousState)
 {
-	adventureInt->handleRightClick(CGI->generaltexth->zelp[291].second, down);
+	if (down)
+		CRClickPopup::createAndPush(CGI->generaltexth->zelp[291].second);
 }
 
 void CMinimap::hover(bool on)
@@ -241,33 +164,22 @@ void CMinimap::showAll(SDL_Surface * to)
 	CIntObject::showAll(to);
 	if(minimap)
 	{
+		Canvas target(to);
+
 		int3 mapSizes = LOCPLINT->cb->getMapSize();
 		int3 tileCountOnScreen = adventureInt->terrain.tileCountOnScreen();
 
 		//draw radar
-		Rect oldClip;
 		Rect radar =
 		{
-			si16(adventureInt->position.x * pos.w / mapSizes.x + pos.x),
-			si16(adventureInt->position.y * pos.h / mapSizes.y + pos.y),
-			ui16(tileCountOnScreen.x * pos.w / mapSizes.x),
-			ui16(tileCountOnScreen.y * pos.h / mapSizes.y)
+			adventureInt->position.x * pos.w / mapSizes.x,
+			adventureInt->position.y * pos.h / mapSizes.y,
+			tileCountOnScreen.x * pos.w / mapSizes.x - 1,
+			tileCountOnScreen.y * pos.h / mapSizes.y - 1
 		};
 
-		if(adventureInt->mode == EAdvMapMode::WORLD_VIEW)
-		{
-			// adjusts radar so that it doesn't go out of map in world view mode (since there's no frame)
-			radar.x = std::min<int>(std::max(pos.x, radar.x), pos.x + pos.w - radar.w);
-			radar.y = std::min<int>(std::max(pos.y, radar.y), pos.y + pos.h - radar.h);
-
-			if(radar.x < pos.x && radar.y < pos.y)
-				return; // whole map is visible at once, no point in redrawing border
-		}
-
-		CSDL_Ext::getClipRect(to, oldClip);
-		CSDL_Ext::setClipRect(to, pos);
-		CSDL_Ext::drawDashedBorder(to, radar, Colors::PURPLE);
-		CSDL_Ext::setClipRect(to, oldClip);
+		Canvas clippedTarget(target, pos);
+		clippedTarget.drawBorderDashed(radar, CSDL_Ext::fromSDL(Colors::PURPLE));
 	}
 }
 
@@ -283,6 +195,9 @@ void CMinimap::update()
 
 void CMinimap::setLevel(int newLevel)
 {
+	if (level == newLevel)
+		return;
+
 	level = newLevel;
 	update();
 }
@@ -299,18 +214,13 @@ void CMinimap::setAIRadar(bool on)
 		aiShield->disable();
 		update();
 	}
-	// this my happen during AI turn when this interface is inactive
+
+	// this may happen during AI turn when this interface is inactive
 	// force redraw in order to properly update interface
 	GH.totalRedraw();
 }
 
-void CMinimap::hideTile(const int3 &pos)
-{
-	if(minimap)
-		minimap->refreshTile(pos);
-}
-
-void CMinimap::showTile(const int3 &pos)
+void CMinimap::updateTile(const int3 &pos)
 {
 	if(minimap)
 		minimap->refreshTile(pos);

+ 15 - 22
client/adventureMap/CMinimap.h

@@ -11,67 +11,60 @@
 
 #include "../gui/CIntObject.h"
 #include "../../lib/GameConstants.h"
+#include "../render/Canvas.h"
 
-
-struct SDL_Color;
+class ColorRGBA;
 class CMinimap;
 
 class CMinimapInstance : public CIntObject
 {
 	CMinimap * parent;
-	SDL_Surface * minimap;
+	std::unique_ptr<Canvas> minimap;
 	int level;
 
 	//get color of selected tile on minimap
-	const SDL_Color & getTileColor(const int3 & pos);
-
-	void blitTileWithColor(const SDL_Color & color, const int3 & pos, SDL_Surface * to, int x, int y);
+	ColorRGBA getTileColor(const int3 & pos) const;
 
-	//draw minimap already scaled.
-	//result is not antialiased. Will result in "missing" pixels on huge maps (>144)
-	void drawScaled(int level);
+	void redrawMinimap();
 public:
 	CMinimapInstance(CMinimap * parent, int level);
-	~CMinimapInstance();
 
 	void showAll(SDL_Surface * to) override;
-	void tileToPixels (const int3 & tile, int & x, int & y, int toX = 0, int toY = 0);
 	void refreshTile(const int3 & pos);
 };
 
 /// Minimap which is displayed at the right upper corner of adventure map
 class CMinimap : public CIntObject
 {
-protected:
 	std::shared_ptr<CPicture> aiShield; //the graphic displayed during AI turn
 	std::shared_ptr<CMinimapInstance> minimap;
 	int level;
 
-	//to initialize colors
-	std::map<TerrainId, std::pair<SDL_Color, SDL_Color> > loadColors();
-
 	void clickLeft(tribool down, bool previousState) override;
 	void clickRight(tribool down, bool previousState) override;
 	void hover (bool on) override;
 	void mouseMoved (const Point & cursorPosition) override;
 
+	/// relocates center of adventure map screen to currently hovered tile
 	void moveAdvMapSelection();
 
+protected:
+	/// computes coordinates of tile below cursor pos
+	int3 pixelToTile(const Point & cursorPos) const;
+
+	/// computes position of tile within minimap instance
+	Point tileToPixels(const int3 & position) const;
+
 public:
-	// terrainID -> (normal color, blocked color)
-	const std::map<TerrainId, std::pair<SDL_Color, SDL_Color> > colors;
 
-	CMinimap(const Rect & position);
+	explicit CMinimap(const Rect & position);
 
-	//should be called to invalidate whole map - different player or level
-	int3 translateMousePosition();
 	void update();
 	void setLevel(int level);
 	void setAIRadar(bool on);
 
 	void showAll(SDL_Surface * to) override;
 
-	void hideTile(const int3 &pos); //puts FoW
-	void showTile(const int3 &pos); //removes FoW
+	void updateTile(const int3 &pos);
 };
 

+ 31 - 5
client/render/Canvas.cpp

@@ -23,14 +23,14 @@ Canvas::Canvas(SDL_Surface * surface):
 	surface->refcount++;
 }
 
-Canvas::Canvas(Canvas & other):
+Canvas::Canvas(const Canvas & other):
 	surface(other.surface),
 	renderOffset(other.renderOffset)
 {
 	surface->refcount++;
 }
 
-Canvas::Canvas(Canvas & other, const Rect & newClipRect):
+Canvas::Canvas(const Canvas & other, const Rect & newClipRect):
 	Canvas(other)
 {
 	clipRect.emplace();
@@ -43,9 +43,9 @@ Canvas::Canvas(Canvas & other, const Rect & newClipRect):
 }
 
 Canvas::Canvas(const Point & size):
-	renderOffset(0,0)
+	renderOffset(0,0),
+	surface(CSDL_Ext::newSurface(size.x, size.y))
 {
-	surface = CSDL_Ext::newSurface(size.x, size.y);
 }
 
 Canvas::~Canvas()
@@ -75,9 +75,35 @@ void Canvas::draw(Canvas & image, const Point & pos)
 	CSDL_Ext::blitAt(image.surface, renderOffset.x + pos.x, renderOffset.y + pos.y, surface);
 }
 
+void Canvas::draw(Canvas & image, const Point & pos, const Point & targetSize)
+{
+	SDL_Rect targetRect = CSDL_Ext::toSDL(Rect(pos, targetSize));
+	SDL_BlitScaled(image.surface, nullptr, surface, &targetRect );
+}
+
+void Canvas::drawPoint(const Point & dest, const ColorRGBA & color)
+{
+	CSDL_Ext::putPixelWithoutRefreshIfInSurf(surface, dest.x, dest.y, color.r, color.g, color.b, color.a);
+}
+
 void Canvas::drawLine(const Point & from, const Point & dest, const ColorRGBA & colorFrom, const ColorRGBA & colorDest)
 {
-	CSDL_Ext::drawLine(surface, renderOffset.x + from.x, renderOffset.y + from.y, renderOffset.x + dest.x, renderOffset.y + dest.y, CSDL_Ext::toSDL(colorFrom), CSDL_Ext::toSDL(colorDest));
+	CSDL_Ext::drawLine(surface, renderOffset + from, renderOffset + dest, CSDL_Ext::toSDL(colorFrom), CSDL_Ext::toSDL(colorDest));
+}
+
+void Canvas::drawLineDashed(const Point & from, const Point & dest, const ColorRGBA & color)
+{
+	CSDL_Ext::drawLineDashed(surface, renderOffset + from, renderOffset + dest, CSDL_Ext::toSDL(color));
+}
+
+void Canvas::drawBorderDashed(const Rect & target, const ColorRGBA & color)
+{
+	Rect realTarget = target + renderOffset;
+
+	CSDL_Ext::drawLineDashed(surface, realTarget.topLeft(),    realTarget.topRight(),    CSDL_Ext::toSDL(color));
+	CSDL_Ext::drawLineDashed(surface, realTarget.bottomLeft(), realTarget.bottomRight(), CSDL_Ext::toSDL(color));
+	CSDL_Ext::drawLineDashed(surface, realTarget.topLeft(),    realTarget.bottomLeft(),  CSDL_Ext::toSDL(color));
+	CSDL_Ext::drawLineDashed(surface, realTarget.topRight(),   realTarget.bottomRight(), CSDL_Ext::toSDL(color));
 }
 
 void Canvas::drawText(const Point & position, const EFonts & font, const SDL_Color & colorDest, ETextAlignment alignment, const std::string & text )

+ 16 - 4
client/render/Canvas.h

@@ -34,16 +34,16 @@ class Canvas
 public:
 
 	/// constructs canvas using existing surface. Caller maintains ownership on the surface
-	Canvas(SDL_Surface * surface);
+	explicit Canvas(SDL_Surface * surface);
 
 	/// copy contructor
-	Canvas(Canvas & other);
+	Canvas(const Canvas & other);
 
 	/// creates canvas that only covers specified subsection of a surface
-	Canvas(Canvas & other, const Rect & clipRect);
+	Canvas(const Canvas & other, const Rect & clipRect);
 
 	/// constructs canvas of specified size
-	Canvas(const Point & size);
+	explicit Canvas(const Point & size);
 
 	~Canvas();
 
@@ -56,9 +56,21 @@ public:
 	/// renders another canvas onto this canvas
 	void draw(Canvas & image, const Point & pos);
 
+	/// renders another canvas onto this canvas with scaling
+	void draw(Canvas & image, const Point & pos, const Point & targetSize);
+
+	/// renders single pixels with specified color
+	void drawPoint(const Point & dest, const ColorRGBA & color);
+
 	/// renders continuous, 1-pixel wide line with color gradient
 	void drawLine(const Point & from, const Point & dest, const ColorRGBA & colorFrom, const ColorRGBA & colorDest);
 
+	/// renders dashed, 1-pixel wide line with specified color
+	void drawLineDashed(const Point & from, const Point & dest, const ColorRGBA & color);
+
+	/// renders rectangular, dashed border in specified location
+	void drawBorderDashed(const Rect & target, const ColorRGBA & color);
+
 	/// renders single line of text with specified parameters
 	void drawText(const Point & position, const EFonts & font, const SDL_Color & colorDest, ETextAlignment alignment, const std::string & text );
 

+ 71 - 37
client/renderSDL/SDL_Extensions.cpp

@@ -364,11 +364,40 @@ uint32_t CSDL_Ext::colorTouint32_t(const SDL_Color * color)
 	return ret;
 }
 
+static void drawLineXDashed(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color)
+{
+	double length(x2 - x1);
+
+	for(int x = x1; x <= x2; x++)
+	{
+		double f = (x - x1) / length;
+		int y = vstd::lerp(y1, y2, f);
+
+		if (std::abs(x - x1) % 5 != 4)
+			CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur, x, y, color.r, color.g, color.b);
+	}
+}
+
+static void drawLineYDashed(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color)
+{
+	double length(y2 - y1);
+
+	for(int y = y1; y <= y2; y++)
+	{
+		double f = (y - y1) / length;
+		int x = vstd::lerp(x1, x2, f);
+
+		if (std::abs(y - y1) % 5 != 4)
+			CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur, x, y, color.r, color.g, color.b);
+	}
+}
+
 static void drawLineX(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2)
 {
+	double length(x2 - x1);
 	for(int x = x1; x <= x2; x++)
 	{
-		float f = float(x - x1) / float(x2 - x1);
+		double f = (x - x1) / length;
 		int y = vstd::lerp(y1, y2, f);
 
 		uint8_t r = vstd::lerp(color1.r, color2.r, f);
@@ -383,9 +412,10 @@ static void drawLineX(SDL_Surface * sur, int x1, int y1, int x2, int y2, const S
 
 static void drawLineY(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2)
 {
+	double length(y2 - y1);
 	for(int y = y1; y <= y2; y++)
 	{
-		float f = float(y - y1) / float(y2 - y1);
+		double f = (y - y1) / length;
 		int x = vstd::lerp(x1, x2, f);
 
 		uint8_t r = vstd::lerp(color1.r, color2.r, f);
@@ -398,31 +428,60 @@ static void drawLineY(SDL_Surface * sur, int x1, int y1, int x2, int y2, const S
 	}
 }
 
-void CSDL_Ext::drawLine(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2)
+void CSDL_Ext::drawLine(SDL_Surface * sur, const Point & from, const Point & dest, const SDL_Color & color1, const SDL_Color & color2)
 {
-	int width  = std::abs(x1-x2);
-	int height = std::abs(y1-y2);
+	//FIXME: duplicated code with drawLineDashed
+	int width  = std::abs(from.x - dest.x);
+	int height = std::abs(from.y - dest.y);
 
 	if ( width == 0 && height == 0)
 	{
-		uint8_t *p = CSDL_Ext::getPxPtr(sur, x1, y1);
+		uint8_t *p = CSDL_Ext::getPxPtr(sur, from.x, from.y);
 		ColorPutter<4, 0>::PutColorAlpha(p, color1);
 		return;
 	}
 
 	if (width > height)
 	{
-		if ( x1 < x2)
-			drawLineX(sur, x1,y1,x2,y2, color1, color2);
+		if ( from.x < dest.x)
+			drawLineX(sur, from.x, from.y, dest.x, dest.y, color1, color2);
 		else
-			drawLineX(sur, x2,y2,x1,y1, color2, color1);
+			drawLineX(sur, dest.x, dest.y, from.x, from.y, color2, color1);
 	}
 	else
 	{
-		if ( y1 < y2)
-			drawLineY(sur, x1,y1,x2,y2, color1, color2);
+		if ( from.y < dest.y)
+			drawLineY(sur, from.x, from.y, dest.x, dest.y, color1, color2);
 		else
-			drawLineY(sur, x2,y2,x1,y1, color2, color1);
+			drawLineY(sur, dest.x, dest.y, from.x, from.y, color2, color1);
+	}
+}
+
+void CSDL_Ext::drawLineDashed(SDL_Surface * sur, const Point & from, const Point & dest, const SDL_Color & color)
+{
+	//FIXME: duplicated code with drawLine
+	int width  = std::abs(from.x - dest.x);
+	int height = std::abs(from.y - dest.y);
+
+	if ( width == 0 && height == 0)
+	{
+		CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur, from.x, from.y, color.r, color.g, color.b);
+		return;
+	}
+
+	if (width > height)
+	{
+		if ( from.x < dest.x)
+			drawLineXDashed(sur, from.x, from.y, dest.x, dest.y, color);
+		else
+			drawLineXDashed(sur, dest.x, dest.y, from.x, from.y, color);
+	}
+	else
+	{
+		if ( from.y < dest.y)
+			drawLineYDashed(sur, from.x, from.y, dest.x, dest.y, color);
+		else
+			drawLineYDashed(sur, dest.x, dest.y, from.x, from.y, color);
 	}
 }
 
@@ -449,31 +508,6 @@ void CSDL_Ext::drawBorder( SDL_Surface * sur, const Rect &r, const SDL_Color &co
 	drawBorder(sur, r.x, r.y, r.w, r.h, color, depth);
 }
 
-void CSDL_Ext::drawDashedBorder(SDL_Surface * sur, const Rect &r, const SDL_Color &color)
-{
-	const int y1 = r.y, y2 = r.y + r.h-1;
-	for (int i=0; i<r.w; i++)
-	{
-		const int x = r.x + i;
-		if (i%4 || (i==0))
-		{
-			CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur, x, y1, color.r, color.g, color.b);
-			CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur, x, y2, color.r, color.g, color.b);
-		}
-	}
-
-	const int x1 = r.x, x2 = r.x + r.w-1;
-	for (int i=0; i<r.h; i++)
-	{
-		const int y = r.y + i;
-		if ((i%4) || (i==0))
-		{
-			CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur, x1, y, color.r, color.g, color.b);
-			CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur, x2, y, color.r, color.g, color.b);
-		}
-	}
-}
-
 void CSDL_Ext::setPlayerColor(SDL_Surface * sur, PlayerColor player)
 {
 	if(player==PlayerColor::UNFLAGGABLE)

+ 3 - 2
client/renderSDL/SDL_Extensions.h

@@ -81,10 +81,11 @@ typedef void (*TColorPutterAlpha)(uint8_t *&ptr, const uint8_t & R, const uint8_
 	uint32_t colorTouint32_t(const SDL_Color * color); //little endian only
 	SDL_Color makeColor(ui8 r, ui8 g, ui8 b, ui8 a);
 
-	void drawLine(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2);
+	void drawLine(SDL_Surface * sur, const Point & from, const Point & dest, const SDL_Color & color1, const SDL_Color & color2);
+	void drawLineDashed(SDL_Surface * sur, const Point & from, const Point & dest, const SDL_Color & color);
+
 	void drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const SDL_Color &color, int depth = 1);
 	void drawBorder(SDL_Surface * sur, const Rect &r, const SDL_Color &color, int depth = 1);
-	void drawDashedBorder(SDL_Surface * sur, const Rect &r, const SDL_Color &color);
 	void setPlayerColor(SDL_Surface * sur, PlayerColor player); //sets correct color of flags; -1 for neutral
 
 	SDL_Surface * newSurface(int w, int h, SDL_Surface * mod); //creates new surface, with flags/format same as in surface given

+ 3 - 5
client/windows/CQuestLog.cpp

@@ -82,13 +82,11 @@ void CQuestMinimap::addQuestMarks (const QuestInfo * q)
 	else
 		tile = q->tile;
 
-	int x,y;
-	minimap->tileToPixels (tile, x, y);
+	Point offset = tileToPixels(tile);
 
-	if (level != tile.z)
-		setLevel(tile.z);
+	setLevel(tile.z);
 
-	auto pic = std::make_shared<CQuestIcon>("VwSymbol.def", 3, x, y);
+	auto pic = std::make_shared<CQuestIcon>("VwSymbol.def", 3, offset.x, offset.y);
 
 	pic->moveBy (Point ( -pic->pos.w/2, -pic->pos.h/2));
 	pic->callback = std::bind (&CQuestMinimap::iconClicked, this);