From 409aa786c48cb69a14d51337d424685a5988f8bd Mon Sep 17 00:00:00 2001
From: joris <joris.dauphin@gmail.com>
Date: Mon, 20 Feb 2012 10:11:29 +0100
Subject: [PATCH] Clean CViewPort interface : Use PixelPos or Vec2i instead of
 x, y

---
 src/editor/editloop.cpp          | 132 +++++++++---------
 src/include/minimap.h            |   5 +-
 src/include/particle.h           |   2 +-
 src/include/ui.h                 |  38 +++---
 src/map/map_draw.cpp             | 227 ++++++++++++-------------------
 src/map/minimap.cpp              |  11 +-
 src/particle/particlemanager.cpp |  10 +-
 src/stratagus/mainloop.cpp       |   5 +-
 src/stratagus/missile.cpp        |   2 +-
 src/tolua/ui.pkg                 |   2 -
 src/ui/interface.cpp             |   5 +-
 src/ui/mouse.cpp                 |  53 ++++----
 src/ui/ui.cpp                    |  14 +-
 src/unit/unit.cpp                |   4 +-
 src/unit/unit_draw.cpp           | 135 ++++++++----------
 src/video/cursor.cpp             |  21 +--
 16 files changed, 302 insertions(+), 364 deletions(-)

diff --git a/src/editor/editloop.cpp b/src/editor/editloop.cpp
index a5b96ab68..69cd89943 100644
--- a/src/editor/editloop.cpp
+++ b/src/editor/editloop.cpp
@@ -867,13 +867,8 @@ static void DrawEditorPanel()
 */
 static void DrawMapCursor()
 {
-	int x;
-	int y;
-
-	//
 	//  Affect CursorBuilding if necessary.
 	//  (Menu reset CursorBuilding)
-	//
 	if (!CursorBuilding) {
 		switch (Editor.State) {
 			case EditorSelecting:
@@ -892,44 +887,42 @@ static void DrawMapCursor()
 		}
 	}
 
-	//
 	// Draw map cursor
-	//
 	if (UI.MouseViewport && !CursorBuilding) {
-		x = UI.MouseViewport->Viewport2MapX(CursorX);
-		y = UI.MouseViewport->Viewport2MapY(CursorY);
-		x = UI.MouseViewport->Map2ViewportX(x);
-		y = UI.MouseViewport->Map2ViewportY(y);
+		const PixelPos screenCursorPos = { CursorX, CursorY };
+		const Vec2i tilePos = UI.MouseViewport->ScreenToTilePos(screenCursorPos);
+		const PixelPos screenPos = UI.MouseViewport->TilePosToScreen_TopLeft(tilePos);
+
 		if (Editor.State == EditorEditTile && Editor.SelectedTileIndex != -1) {
+			const unsigned short frame = Map.Tileset.Table[Editor.ShownTileTypes[Editor.SelectedTileIndex]];
 			PushClipping();
 			SetClipping(UI.MouseViewport->X, UI.MouseViewport->Y,
 				UI.MouseViewport->EndX, UI.MouseViewport->EndY);
+
+			PixelPos screenPosIt;
 			for (int j = 0; j < TileCursorSize; ++j) {
-				const int ty = y + j * PixelTileSize.y;
-				if (ty >= UI.MouseViewport->EndY) {
+				screenPosIt.y = screenPos.y + j * PixelTileSize.y;
+				if (screenPosIt.y >= UI.MouseViewport->EndY) {
 					break;
 				}
 				for (int i = 0; i < TileCursorSize; ++i) {
-					const int tx = x + i * PixelTileSize.x;
-					if (tx >= UI.MouseViewport->EndX) {
+					screenPosIt.x = screenPos.x + i * PixelTileSize.x;
+					if (screenPosIt.x >= UI.MouseViewport->EndX) {
 						break;
 					}
-					Map.TileGraphic->DrawFrameClip(
-						Map.Tileset.Table[Editor.ShownTileTypes[Editor.SelectedTileIndex]], tx, ty);
+					Map.TileGraphic->DrawFrameClip(frame, screenPosIt.x, screenPosIt.y);
 				}
 			}
-			Video.DrawRectangleClip(ColorWhite, x, y, PixelTileSize.x * TileCursorSize, PixelTileSize.y * TileCursorSize);
+			Video.DrawRectangleClip(ColorWhite, screenPos.x, screenPos.y, PixelTileSize.x * TileCursorSize, PixelTileSize.y * TileCursorSize);
 			PopClipping();
 		} else {
-			//
 			// If there is an unit under the cursor, it's selection thing
 			//  is drawn somewhere else (Check DrawUnitSelection.)
-			//
 			if (UnitUnderCursor != NULL) {
 				PushClipping();
 				SetClipping(UI.MouseViewport->X, UI.MouseViewport->Y,
 					UI.MouseViewport->EndX, UI.MouseViewport->EndY);
-				Video.DrawRectangleClip(ColorWhite, x, y, PixelTileSize.x, PixelTileSize.y);
+				Video.DrawRectangleClip(ColorWhite, screenPos.x, screenPos.y, PixelTileSize.x, PixelTileSize.y);
 				PopClipping();
 			}
 		}
@@ -948,14 +941,19 @@ static void DrawStartLocations()
 
 		for (int i = 0; i < PlayerMax; i++) {
 			if (Map.Info.PlayerType[i] != PlayerNobody && Map.Info.PlayerType[i] != PlayerNeutral) {
-				int x = vp->Map2ViewportX(Players[i].StartX);
-				int y = vp->Map2ViewportY(Players[i].StartY);
+				const Vec2i startTilePos = {Players[i].StartX, Players[i].StartY};
+				const PixelPos startScreenPos = vp->TilePosToScreen_TopLeft(startTilePos);
 
 				if (type) {
-					DrawUnitType(*type, type->Sprite, i, 0, x, y);
-				} else {
-					Video.DrawLineClip(PlayerColors[i][0], x, y, x + PixelTileSize.x, y + PixelTileSize.y);
-					Video.DrawLineClip(PlayerColors[i][0], x, y + PixelTileSize.y, x + PixelTileSize.x, y);
+					DrawUnitType(*type, type->Sprite, i, 0, startScreenPos.x, startScreenPos.y);
+				} else { // Draw a cross
+					const int x = startScreenPos.x;
+					const int y = startScreenPos.y;
+					const int w = PixelTileSize.x;
+					const int h = PixelTileSize.y;
+
+					Video.DrawLineClip(PlayerColors[i][0], x, y, x + w, y + h);
+					Video.DrawLineClip(PlayerColors[i][0], x, y + h, x + w, y);
 				}
 			}
 		}
@@ -1182,11 +1180,9 @@ static void EditorCallbackButtonDown(unsigned button)
 	//
 	if (CursorOn == CursorOnMinimap) {
 		if (MouseButtons & LeftButton) { // enter move mini-mode
-			UI.SelectedViewport->Set(
-				UI.Minimap.Screen2MapX(CursorX) -
-					UI.SelectedViewport->MapWidth / 2,
-				UI.Minimap.Screen2MapY(CursorY) -
-					UI.SelectedViewport->MapHeight / 2, PixelTileSize.x / 2, PixelTileSize.y / 2);
+			const PixelPos cursorPixelPos = {CursorX, CursorY};
+			const Vec2i tilePos = UI.Minimap.ScreenToTilePos(cursorPixelPos);
+			UI.SelectedViewport->Center(tilePos, PixelTileSize / 2);
 		}
 		return;
 	}
@@ -1319,7 +1315,8 @@ static void EditorCallbackButtonDown(unsigned button)
 		}
 
 		if (MouseButtons & LeftButton) {
-			const Vec2i tilePos = { UI.MouseViewport->Viewport2MapX(CursorX), UI.MouseViewport->Viewport2MapY(CursorY)};
+			const PixelPos screenPos = {CursorX, CursorY};
+			const Vec2i tilePos = UI.MouseViewport->ScreenToTilePos(screenPos);
 
 			if (Editor.State == EditorEditTile &&
 				Editor.SelectedTileIndex != -1) {
@@ -1553,47 +1550,46 @@ static void EditorCallbackMouse(int x, int y)
 	// Move map.
 	//
 	if (GameCursor == UI.Scroll.Cursor) {
-		int xo;
-		int yo;
+		Vec2i tilePos = {UI.MouseViewport->MapX, UI.MouseViewport->MapY};
 
 		// FIXME: Support with CTRL for faster scrolling.
 		// FIXME: code duplication, see ../ui/mouse.c
-		xo = UI.MouseViewport->MapX;
-		yo = UI.MouseViewport->MapY;
 		if (UI.MouseScrollSpeedDefault < 0) {
 			if (x < CursorStartX) {
-				xo++;
+				tilePos.x++;
 			} else if (x > CursorStartX) {
-				xo--;
+				tilePos.x--;
 			}
 			if (y < CursorStartY) {
-				yo++;
+				tilePos.y++;
 			} else if (y > CursorStartY) {
-				yo--;
+				tilePos.y--;
 			}
 		} else {
 			if (x < CursorStartX) {
-				xo--;
+				tilePos.x--;
 			} else if (x > CursorStartX) {
-				xo++;
+				tilePos.x++;
 			}
 			if (y < CursorStartY) {
-				yo--;
+				tilePos.y--;
 			} else if (y > CursorStartY) {
-				yo++;
+				tilePos.y++;
 			}
 		}
 		UI.MouseWarpX = CursorStartX;
 		UI.MouseWarpY = CursorStartY;
-		UI.MouseViewport->Set(xo, yo, PixelTileSize.x / 2, PixelTileSize.y / 2);
+		UI.MouseViewport->Set(tilePos, PixelTileSize / 2);
 		return;
 	}
 
 	// Automatically unpress when map tile has changed
-	if (LastMapX != UI.SelectedViewport->Viewport2MapX(CursorX) ||
-			LastMapY != UI.SelectedViewport->Viewport2MapY(CursorY)) {
-		LastMapX = UI.SelectedViewport->Viewport2MapX(CursorX);
-		LastMapY = UI.SelectedViewport->Viewport2MapY(CursorY);
+	const PixelPos screenPos = {CursorX, CursorY};
+	const Vec2i cursorTilePos = UI.SelectedViewport->ScreenToTilePos(screenPos);
+
+	if (LastMapX != cursorTilePos.x || LastMapY != cursorTilePos.y) {
+		LastMapX = cursorTilePos.x;
+		LastMapY = cursorTilePos.y;
 		UnitPlacedThisPress = false;
 	}
 	//
@@ -1601,37 +1597,32 @@ static void EditorCallbackMouse(int x, int y)
 	//
 	if (CursorOn == CursorOnMap && (MouseButtons & LeftButton) &&
 			(Editor.State == EditorEditTile || Editor.State == EditorEditUnit)) {
-
+		Vec2i vpTilePos = {UI.SelectedViewport->MapX, UI.SelectedViewport->MapX};
 		//
 		// Scroll the map
 		//
 		if (CursorX <= UI.SelectedViewport->X) {
-			UI.SelectedViewport->Set(
-				UI.SelectedViewport->MapX - 1,
-				UI.SelectedViewport->MapY, PixelTileSize.x / 2, PixelTileSize.y / 2);
+			vpTilePos.x--;
+			UI.SelectedViewport->Set(vpTilePos, PixelTileSize / 2);
 		} else if (CursorX >= UI.SelectedViewport->EndX) {
-			UI.SelectedViewport->Set(
-				UI.SelectedViewport->MapX + 1,
-				UI.SelectedViewport->MapY, PixelTileSize.x / 2, PixelTileSize.y / 2);
+			vpTilePos.x++;
+			UI.SelectedViewport->Set(vpTilePos, PixelTileSize / 2);
 		}
 
 		if (CursorY <= UI.SelectedViewport->Y) {
-			UI.SelectedViewport->Set(
-				UI.SelectedViewport->MapX,
-				UI.SelectedViewport->MapY - 1, PixelTileSize.x / 2, PixelTileSize.y / 2);
+			vpTilePos.y--;
+			UI.SelectedViewport->Set(vpTilePos, PixelTileSize / 2);
 		} else if (CursorY >= UI.SelectedViewport->EndY) {
-			UI.SelectedViewport->Set(
-				UI.SelectedViewport->MapX,
-				UI.SelectedViewport->MapY + 1, PixelTileSize.x / 2, PixelTileSize.y / 2);
-
+			vpTilePos.y++;
+			UI.SelectedViewport->Set(vpTilePos, PixelTileSize / 2);
 		}
 
 		//
 		// Scroll the map, if cursor moves outside the viewport.
 		//
 		RestrictCursorToViewport();
-
-		const Vec2i tilePos = {UI.SelectedViewport->Viewport2MapX(CursorX), UI.SelectedViewport->Viewport2MapY(CursorY)};
+		const PixelPos cursorPixelPos = {CursorX, CursorY};
+		const Vec2i tilePos = UI.SelectedViewport->ScreenToTilePos(cursorPixelPos);
 
 		if (Editor.State == EditorEditTile && Editor.SelectedTileIndex != -1) {
 			EditTiles(tilePos, Editor.ShownTileTypes[Editor.SelectedTileIndex], TileCursorSize);
@@ -1653,11 +1644,10 @@ static void EditorCallbackMouse(int x, int y)
 	//
 	if (CursorOn == CursorOnMinimap && (MouseButtons & LeftButton)) {
 		RestrictCursorToMinimap();
-		UI.SelectedViewport->Set(
-			UI.Minimap.Screen2MapX(CursorX)
-				- UI.SelectedViewport->MapWidth / 2,
-			UI.Minimap.Screen2MapY(CursorY)
-				- UI.SelectedViewport->MapHeight / 2, 0, 0);
+		const PixelPos cursorPixelPos = {CursorX, CursorY};
+		const Vec2i tilePos = UI.Minimap.ScreenToTilePos(cursorPixelPos);
+
+		UI.SelectedViewport->Center(tilePos, PixelTileSize / 2);
 		return;
 	}
 
diff --git a/src/include/minimap.h b/src/include/minimap.h
index 57be35862..5e53aeaca 100644
--- a/src/include/minimap.h
+++ b/src/include/minimap.h
@@ -63,8 +63,9 @@ public:
 	void DrawCursor(int vx, int vy);
 	void AddEvent(int x, int y, Uint32 color);
 
-	int Screen2MapX(int x);
-	int Screen2MapY(int y);
+	Vec2i ScreenToTilePos(const PixelPos& screenPos) const;
+	int Screen2MapX(int x) const;
+	int Screen2MapY(int y) const;
 
 	int X;
 	int Y;
diff --git a/src/include/particle.h b/src/include/particle.h
index 78f0cdb5d..04424534e 100644
--- a/src/include/particle.h
+++ b/src/include/particle.h
@@ -181,7 +181,7 @@ public:
 	void add(CParticle *particle);
 	void clear();
 
-	CPosition getScreenPos(const CPosition &pos);
+	CPosition getScreenPos(const CPosition &pos) const;
 
 	inline void setLowDetail(bool detail) { lowDetail = detail; }
 	inline bool getLowDetail() const { return lowDetail; }
diff --git a/src/include/ui.h b/src/include/ui.h
index 3a39ac364..a060a9971 100644
--- a/src/include/ui.h
+++ b/src/include/ui.h
@@ -169,29 +169,29 @@ public:
 	~CViewport();
 
 
-	/// Check if X and Y pixels are within map area
-	bool IsInsideMapArea(int x, int y) const;
-	/// Convert screen X pixel to map tile
-	int Viewport2MapX(int x) const;
-	/// Convert screen Y pixel to map tile
-	int Viewport2MapY(int y) const;
-	/// Convert map tile to screen X pixel
-	int Map2ViewportX(int x) const;
-	/// Convert map tile to screen Y pixel
-	int Map2ViewportY(int y) const;
-	/// Convert map pixel coordinates into viewport coordinates
-	void MapPixel2Viewport(int &x, int &y) const;
+	/// Check if pos pixels are within map area
+	bool IsInsideMapArea(const PixelPos &screenPixelPos) const;
 
-	// Convert screen coordinates into map pixel coordinates
-	PixelPos ScreenToMapPixelPos(const PixelPos& screenPixelPos) const;
+	/// Convert screen coordinates into map pixel coordinates
+	PixelPos ScreenToMapPixelPos(const PixelPos &screenPixelPos) const;
 	// Convert map pixel coordinates into screen coordinates
-	PixelPos MapToScreenPixelPos(const PixelPos& mapPixelPos) const;
+	PixelPos MapToScreenPixelPos(const PixelPos &mapPixelPos) const;
+
+	/// convert screen coordinate into tilepos
+	Vec2i ScreenToTilePos(const PixelPos &screenPixelPos) const;
+	/// convert tilepos coordonates into screen (take the top left of the tile)
+	PixelPos TilePosToScreen_TopLeft(const Vec2i &tilePos) const;
+	/// convert tilepos coordonates into screen (take the center of the tile)
+	PixelPos TilePosToScreen_Center(const Vec2i &tilePos) const;
 
 	/// Set the current map view to x,y(upper,left corner)
-	void Set(int x, int y, int offsetx, int offsety);
+	void Set(const Vec2i &tilePos, const PixelDiff &offset);
 	/// Center map on point in viewport
-	void Center(const Vec2i& pos, const PixelPos &offset);
+	void Center(const Vec2i& pos, const PixelDiff &offset);
+
 protected:
+	/// Set the current map view to x,y(upper,left corner)
+	void Set(const PixelPos &mapPixelPos);
 	/// Draw the map background
 	void DrawMapBackgroundInViewport() const;
 	/// Draw the map fog of war
@@ -203,8 +203,8 @@ public:
 	void Draw() const;
 	void DrawBorder() const;
 	/// Check if any part of an area is visible in viewport
-	bool AnyMapAreaVisibleInViewport(int sx, int sy, int ex, int ey) const;
-
+	bool AnyMapAreaVisibleInViewport(const Vec2i &boxmin, const Vec2i &boxmax) const;
+//private:
 	int X;                      /// Screen pixel left corner x coordinate
 	int Y;                      /// Screen pixel upper corner y coordinate
 	int EndX;                   /// Screen pixel right x coordinate
diff --git a/src/map/map_draw.cpp b/src/map/map_draw.cpp
index 7c1f1839d..0bda744ba 100644
--- a/src/map/map_draw.cpp
+++ b/src/map/map_draw.cpp
@@ -60,114 +60,36 @@
 /**
 **  Check if any part of an area is visible in a viewport.
 **
-**  @param sx  X map tile position of area in map to be checked.
-**  @param sy  Y map tile position of area in map to be checked.
-**  @param ex  X map tile position of area in map to be checked.
-**  @param ey  Y map tile position of area in map to be checked.
+**  @param boxmin  map tile position of area in map to be checked.
+**  @param boxmax  map tile position of area in map to be checked.
 **
 **  @return    True if any part of area is visible, false otherwise
 */
-bool CViewport::AnyMapAreaVisibleInViewport(int sx, int sy, int ex, int ey) const
+bool CViewport::AnyMapAreaVisibleInViewport(const Vec2i &boxmin, const Vec2i &boxmax) const
 {
-	if (ex < this->MapX || ey < this->MapY ||
-			sx >= this->MapX + this->MapWidth || sy >= this->MapY + this->MapHeight) {
+	Assert(boxmin.x <= boxmax.x && boxmin.y <= boxmax.y);
+
+	if (boxmax.x < this->MapX
+		|| boxmax.y < this->MapY
+		|| boxmin.x >= this->MapX + this->MapWidth
+		|| boxmin.y >= this->MapY + this->MapHeight) {
 		return false;
 	}
 	return true;
 }
 
-bool CViewport::IsInsideMapArea(int x, int y) const
+bool CViewport::IsInsideMapArea(const PixelPos &screenPixelPos) const
 {
-	int tilex;
-	int tiley;
+	const Vec2i tilePos = ScreenToTilePos(screenPixelPos);
 
-	tilex = x - this->X + this->MapX * PixelTileSize.x + this->OffsetX;
-	if (tilex < 0) {
-		tilex = (tilex - PixelTileSize.x + 1) / PixelTileSize.x;
-	} else {
-		tilex /= PixelTileSize.x;
-	}
-
-	tiley = y - this->Y + this->MapY * PixelTileSize.y + this->OffsetY;
-	if (tiley < 0) {
-		tiley = (tiley - PixelTileSize.y + 1) / PixelTileSize.y;
-	} else {
-		tiley /= PixelTileSize.y;
-	}
-
-	return (tilex >= 0 && tiley >= 0 && tilex < Map.Info.MapWidth && tiley < Map.Info.MapHeight);
-}
-
-/**
-**  Convert viewport x coordinate to map tile x coordinate.
-**
-**  @param x   X coordinate into this viewport (in pixels, relative
-**             to origin of Stratagus's window - not the viewport
-**             itself!).
-**
-**  @return    X map tile coordinate.
-*/
-int CViewport::Viewport2MapX(int x) const
-{
-	int r = (x - this->X + this->MapX * PixelTileSize.x + this->OffsetX) / PixelTileSize.x;
-	return std::min<int>(r, Map.Info.MapWidth - 1);
-}
-
-/**
-**  Convert viewport y coordinate to map tile y coordinate.
-**
-**  @param y   Y coordinate into this viewport (in pixels, relative
-**             to origin of Stratagus's window - not the viewport
-**             itself!).
-**
-**  @return    Y map tile coordinate.
-*/
-int CViewport::Viewport2MapY(int y) const
-{
-	int r = (y - this->Y + this->MapY * PixelTileSize.y + this->OffsetY) / PixelTileSize.y;
-	return std::min<int>(r, Map.Info.MapHeight - 1);
-}
-
-/**
-**  Convert a map tile X coordinate into a viewport x pixel coordinate.
-**
-**  @param x   The map tile's X coordinate.
-**
-**  @return    X screen coordinate in pixels (relative
-**             to origin of Stratagus's window).
-*/
-int CViewport::Map2ViewportX(int x) const
-{
-	return this->X + (x - this->MapX) * PixelTileSize.x - this->OffsetX;
-}
-
-/**
-**  Convert a map tile Y coordinate into a viewport y pixel coordinate.
-**
-**  @param y   The map tile's Y coordinate.
-**
-**  @return    Y screen coordinate in pixels (relative
-**             to origin of Stratagus's window).
-*/
-int CViewport::Map2ViewportY(int y) const
-{
-	return this->Y + (y - this->MapY) * PixelTileSize.y - this->OffsetY;
-}
-
-/**
-**  Convert map pixel coordinates into viewport coordinates.
-*/
-void CViewport::MapPixel2Viewport(int &x, int &y) const
-{
-	x = x + this->X - (this->MapX * PixelTileSize.x + this->OffsetX);
-	y = y + this->Y - (this->MapY * PixelTileSize.y + this->OffsetY);
+	return Map.Info.IsPointOnMap(tilePos);
 }
 
 // Convert viewport coordinates into map pixel coordinates
 PixelPos CViewport::ScreenToMapPixelPos(const PixelPos &screenPixelPos) const
 {
-	const int x = (screenPixelPos.x - this->X + this->MapX * PixelTileSize.x + this->OffsetX);
-	const int y = (screenPixelPos.y - this->Y + this->MapY * PixelTileSize.y + this->OffsetY);
+	const int x = screenPixelPos.x - this->X + this->MapX * PixelTileSize.x + this->OffsetX;
+	const int y = screenPixelPos.y - this->Y + this->MapY * PixelTileSize.y + this->OffsetY;
 	const PixelPos mapPixelPos = {x, y};
 
 	return mapPixelPos;
@@ -181,34 +103,49 @@ PixelPos CViewport::MapToScreenPixelPos(const PixelPos &mapPixelPos) const
 		mapPixelPos.y + this->Y - (this->MapY * PixelTileSize.y + this->OffsetY)
 	};
 	return screenPixelPos;
+}
 
+/// convert screen coordinate into tilepos
+Vec2i CViewport::ScreenToTilePos(const PixelPos& screenPixelPos) const
+{
+	const PixelPos mapPixelPos = ScreenToMapPixelPos(screenPixelPos);
+	const Vec2i tilePos = {mapPixelPos.x / PixelTileSize.x, mapPixelPos.y / PixelTileSize.y};
+
+	return tilePos;
+}
+
+/// convert tilepos coordonates into screen (take the top left of the tile)
+PixelPos CViewport::TilePosToScreen_TopLeft(const Vec2i &tilePos) const
+{
+	const PixelPos mapPos = {tilePos.x * PixelTileSize.x, tilePos.y * PixelTileSize.y};
+
+	return MapToScreenPixelPos(mapPos);
+}
+
+/// convert tilepos coordonates into screen (take the center of the tile)
+PixelPos CViewport::TilePosToScreen_Center(const Vec2i &tilePos) const
+{
+	const PixelPos topLeft = TilePosToScreen_TopLeft(tilePos);
+
+	return topLeft + PixelTileSize / 2;
 }
 
 /**
-**  Change viewpoint of map viewport v to x,y.
+**  Change viewpoint of map viewport v to tilePos.
 **
-**  @param x        X map tile position.
-**  @param y        Y map tile position.
-**  @param offsetx  X offset in tile.
-**  @param offsety  Y offset in tile.
+**  @param tilePos  map tile position.
+**  @param offset   offset in tile.
 */
-void CViewport::Set(int x, int y, int offsetx, int offsety)
+void CViewport::Set(const PixelPos &mapPos)
 {
-	x = x * PixelTileSize.x + offsetx;
-	y = y * PixelTileSize.y + offsety;
+	int x = mapPos.x;
+	int y = mapPos.y;
 
-	if (x < -UI.MapArea.ScrollPaddingLeft) {
-		x = -UI.MapArea.ScrollPaddingLeft;
-	}
-	if (y < -UI.MapArea.ScrollPaddingTop) {
-		y = -UI.MapArea.ScrollPaddingTop;
-	}
-	if (x > Map.Info.MapWidth * PixelTileSize.x - (this->EndX - this->X) - 1 + UI.MapArea.ScrollPaddingRight) {
-		x = Map.Info.MapWidth * PixelTileSize.x- (this->EndX - this->X) - 1 + UI.MapArea.ScrollPaddingRight;
-	}
-	if (y > Map.Info.MapHeight * PixelTileSize.y- (this->EndY - this->Y) - 1 + UI.MapArea.ScrollPaddingBottom) {
-		y = Map.Info.MapHeight * PixelTileSize.y- (this->EndY - this->Y) - 1 + UI.MapArea.ScrollPaddingBottom;
-	}
+	x = std::max(x, -UI.MapArea.ScrollPaddingLeft);
+	y = std::max(y, -UI.MapArea.ScrollPaddingTop);
+
+	x = std::min(x, Map.Info.MapWidth * PixelTileSize.x - (this->EndX - this->X) - 1 + UI.MapArea.ScrollPaddingRight);
+	y = std::min(y, Map.Info.MapHeight * PixelTileSize.y - (this->EndY - this->Y) - 1 + UI.MapArea.ScrollPaddingBottom);
 
 	this->MapX = x / PixelTileSize.x;
 	if (x < 0 && x % PixelTileSize.x) {
@@ -230,6 +167,21 @@ void CViewport::Set(int x, int y, int offsetx, int offsety)
 	this->MapHeight = ((this->EndY - this->Y) + this->OffsetY - 1) / PixelTileSize.y + 1;
 }
 
+/**
+**  Change viewpoint of map viewport v to tilePos.
+**
+**  @param tilePos  map tile position.
+**  @param offset   offset in tile.
+*/
+void CViewport::Set(const Vec2i &tilePos, const PixelDiff &offset)
+{
+	const int x = tilePos.x * PixelTileSize.x + offset.x;
+	const int y = tilePos.y * PixelTileSize.y + offset.y;
+	const PixelPos mapPixelPos = {x, y};
+
+	this->Set(mapPixelPos);
+}
+
 /**
 **  Center map viewport v on map tile (pos).
 **
@@ -238,9 +190,11 @@ void CViewport::Set(int x, int y, int offsetx, int offsety)
 */
 void CViewport::Center(const Vec2i &pos, const PixelDiff &offset)
 {
-	int x = pos.x * PixelTileSize.x + offset.x - (this->EndX - this->X) / 2;
-	int y = pos.y * PixelTileSize.y + offset.y - (this->EndY - this->Y) / 2;
-	this->Set(x / PixelTileSize.x, y / PixelTileSize.y, x % PixelTileSize.x, y % PixelTileSize.y);
+	const int x = pos.x * PixelTileSize.x + offset.x - (this->EndX - this->X) / 2;
+	const int y = pos.y * PixelTileSize.y + offset.y - (this->EndY - this->Y) / 2;
+	const PixelPos mapPixelPos = {x, y};
+
+	this->Set(mapPixelPos);
 }
 
 /**
@@ -353,38 +307,36 @@ void CViewport::DrawMapBackgroundInViewport() const
 
 class CDrawProxy {
 public:
-	CDrawProxy(): nunits(0), nmissiles(0) {}
+	CDrawProxy() : nunits(0), nmissiles(0) {}
 
-	void Update(const CViewport *const vp)
+	void Update(const CViewport &vp)
 	{
-		//
 		// We find and sort units after draw level.
-		//
 		if (lock.TryLock()) {
-			nunits = FindAndSortUnits(vp, unittable);
-			nmissiles = FindAndSortMissiles(*vp, missiletable, MAX_MISSILES * 9);
+			nunits = FindAndSortUnits(&vp, unittable);
+			nmissiles = FindAndSortMissiles(vp, missiletable, MAX_MISSILES * 9);
 			lock.UnLock();
 		}
 	}
 
-	void Draw(const CViewport *const vp)
+	void Draw(const CViewport &vp)
 	{
 		int i = 0, j = 0;
 		lock.Lock ();
 		while (i < nunits && j < nmissiles) {
 			if (unittable[i].Type->DrawLevel <= missiletable[j].Type->DrawLevel) {
-				unittable[i].Draw(vp);
+				unittable[i].Draw(&vp);
 				++i;
 			} else {
-				missiletable[j].DrawMissile(*vp);
+				missiletable[j].DrawMissile(vp);
 				++j;
 			}
 		}
 		for (; i < nunits; ++i) {
-			unittable[i].Draw(vp);
+			unittable[i].Draw(&vp);
 		}
 		for (; j < nmissiles; ++j) {
-			missiletable[j].DrawMissile(*vp);
+			missiletable[j].DrawMissile(vp);
 		}
 		lock.UnLock();
 	}
@@ -401,7 +353,7 @@ void CViewport::UpdateUnits()
 	if (!Proxy) {
 		Proxy = new CDrawProxy();
 	}
-	Proxy->Update(this);
+	Proxy->Update(*this);
 }
 
 /**
@@ -409,7 +361,6 @@ void CViewport::UpdateUnits()
 */
 void CViewport::Draw() const
 {
-
 	PushClipping();
 	SetClipping(this->X, this->Y, this->EndX, this->EndY);
 
@@ -418,16 +369,14 @@ void CViewport::Draw() const
 
 	CurrentViewport = this;
 	if (Proxy) {
-		Proxy->Draw(this);
-	} else 	{
+		Proxy->Draw(*this);
+	} else {
 		CUnit *unittable[UnitMax];
 		Missile* missiletable[MAX_MISSILES * 9];
 
-		//
 		// We find and sort units after draw level.
-		//
-		int nunits = FindAndSortUnits(this, unittable);
-		int nmissiles = FindAndSortMissiles(*this, missiletable, MAX_MISSILES * 9);
+		const int nunits = FindAndSortUnits(this, unittable);
+		const int nmissiles = FindAndSortMissiles(*this, missiletable, MAX_MISSILES * 9);
 		int i = 0;
 		int j = 0;
 
@@ -455,16 +404,14 @@ void CViewport::Draw() const
 	// Drawn here so that they are shown even when the unit is out of the screen.
 	//
 	//FIXME: This is still unsecure during parallel
-	if (!Preference.ShowOrders){}
-	else if (Preference.ShowOrders < 0 ||
+	if (!Preference.ShowOrders) {
+	} else if (Preference.ShowOrders < 0 ||
 		(ShowOrdersCount >= GameCycle) || (KeyModifiers & ModifierShift)) {
 		for (int i = 0; i < NumSelected; ++i) {
 			ShowOrder(*Selected[i]);
 		}
 	}
-
 	DrawBorder();
-
 	PopClipping();
 }
 
@@ -488,9 +435,7 @@ void CViewport::DrawBorder() const
 }
 
 CViewport::~CViewport() {
-	if (Proxy) {
-		delete Proxy;
-	}
+	delete Proxy;
 }
 
 //@}
diff --git a/src/map/minimap.cpp b/src/map/minimap.cpp
index 6eda0cac3..57a6ed346 100644
--- a/src/map/minimap.cpp
+++ b/src/map/minimap.cpp
@@ -662,7 +662,7 @@ void CMinimap::Draw(int, int)
 **
 **  @return   Tile X coordinate.
 */
-int CMinimap::Screen2MapX(int x)
+int CMinimap::Screen2MapX(int x) const
 {
 	int tx;
 
@@ -680,7 +680,7 @@ int CMinimap::Screen2MapX(int x)
 **
 **  @return   Tile Y coordinate.
 */
-int CMinimap::Screen2MapY(int y)
+int CMinimap::Screen2MapY(int y) const
 {
 	int ty;
 
@@ -691,6 +691,13 @@ int CMinimap::Screen2MapY(int y)
 	return std::min<int>(ty, Map.Info.MapHeight - 1);
 }
 
+Vec2i CMinimap::ScreenToTilePos(const PixelPos& screenPos) const
+{
+	const Vec2i tilePos = {Screen2MapX(screenPos.x), Screen2MapY(screenPos.y)};
+
+	return tilePos;
+}
+
 /**
 **  Destroy mini-map.
 */
diff --git a/src/particle/particlemanager.cpp b/src/particle/particlemanager.cpp
index bd06fc659..1a0bd46cd 100644
--- a/src/particle/particlemanager.cpp
+++ b/src/particle/particlemanager.cpp
@@ -109,12 +109,12 @@ void CParticleManager::add(CParticle *particle)
 	new_particles.push_back(particle);
 }
 
-CPosition CParticleManager::getScreenPos(const CPosition &pos)
+CPosition CParticleManager::getScreenPos(const CPosition &pos) const
 {
-	int x = (int)pos.x;
-	int y = (int)pos.y;
-	vp->MapPixel2Viewport(x, y);
-	return CPosition(x, y);
+	const PixelPos mapPixelPos = { (int)pos.x, (int)pos.y};
+	const PixelPos screenPixelPos = vp->MapToScreenPixelPos(mapPixelPos);
+
+	return CPosition(screenPixelPos.x, screenPixelPos.y);
 }
 
 //@}
diff --git a/src/stratagus/mainloop.cpp b/src/stratagus/mainloop.cpp
index fef4b70aa..711762f1b 100644
--- a/src/stratagus/mainloop.cpp
+++ b/src/stratagus/mainloop.cpp
@@ -182,7 +182,10 @@ void DoScrollArea(int state, bool fast)
 	if (state & ScrollLeft) {
 		stepx = -stepx;
 	}
-	vp->Set(vp->MapX, vp->MapY, vp->OffsetX + stepx, vp->OffsetY + stepy);
+	const Vec2i vpTilePos = {vp->MapX, vp->MapY};
+	const PixelDiff offset = {vp->OffsetX + stepx, vp->OffsetY + stepy};
+
+	vp->Set(vpTilePos, offset);
 
 	// This recalulates some values
 	HandleMouseMove(CursorX, CursorY);
diff --git a/src/stratagus/missile.cpp b/src/stratagus/missile.cpp
index 38afbcc61..ec86cca82 100644
--- a/src/stratagus/missile.cpp
+++ b/src/stratagus/missile.cpp
@@ -490,7 +490,7 @@ static int MissileVisibleInViewport(const CViewport &vp, const Missile &missile)
 	Vec2i boxmax;
 
 	GetMissileMapArea(missile, boxmin, boxmax);
-	if (!vp.AnyMapAreaVisibleInViewport(boxmin.x, boxmin.y, boxmax.x, boxmax.y)) {
+	if (!vp.AnyMapAreaVisibleInViewport(boxmin, boxmax)) {
 		return 0;
 	}
 	Vec2i pos;
diff --git a/src/tolua/ui.pkg b/src/tolua/ui.pkg
index 78fe082d0..fa1107f77 100644
--- a/src/tolua/ui.pkg
+++ b/src/tolua/ui.pkg
@@ -42,8 +42,6 @@ class CMapArea
 
 class CViewport
 {
-	int Viewport2MapX(int x);
-	int Viewport2MapY(int y);
 };
 
 class CFiller
diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp
index 12b9982ed..8fd0fd269 100644
--- a/src/ui/interface.cpp
+++ b/src/ui/interface.cpp
@@ -428,8 +428,9 @@ static void UiSaveMapPosition(unsigned position)
 */
 static void UiRecallMapPosition(unsigned position)
 {
-	UI.SelectedViewport->Set(
-		SavedMapPositionX[position], SavedMapPositionY[position], PixelTileSize.x / 2, PixelTileSize.y / 2);
+	const Vec2i savedTilePos = {SavedMapPositionX[position], SavedMapPositionY[position]};
+
+	UI.SelectedViewport->Set(savedTilePos, PixelTileSize / 2);
 }
 
 /**
diff --git a/src/ui/mouse.cpp b/src/ui/mouse.cpp
index a55380fdb..7c8add4d3 100644
--- a/src/ui/mouse.cpp
+++ b/src/ui/mouse.cpp
@@ -795,9 +795,11 @@ void MouseScrollMap(int x, int y)
 		speed = UI.MouseScrollSpeedDefault;
 	}
 
-	UI.MouseViewport->Set(UI.MouseViewport->MapX, UI.MouseViewport->MapY,
-		UI.MouseViewport->OffsetX + speed * (x - CursorStartX),
-		UI.MouseViewport->OffsetY + speed * (y - CursorStartY));
+	const Vec2i vpTilePos = {UI.MouseViewport->MapX, UI.MouseViewport->MapY};
+	const PixelDiff vpOffset = {UI.MouseViewport->OffsetX, UI.MouseViewport->OffsetY};
+	const PixelDiff diff = {x - CursorX, y - CursorY};
+
+	UI.MouseViewport->Set(vpTilePos, vpOffset + speed * diff);
 	UI.MouseWarpX = CursorStartX;
 	UI.MouseWarpY = CursorStartY;
 }
@@ -883,13 +885,15 @@ void UIHandleMouseMove(int x, int y)
 
 	// This is forbidden for unexplored and not visible space
 	// FIXME: This must done new, moving units, scrolling...
-	if (CursorOn == CursorOnMap && UI.MouseViewport->IsInsideMapArea(CursorX, CursorY)) {
-		const CViewport *vp = UI.MouseViewport;
-		const Vec2i tilePos = {vp->Viewport2MapX(x), vp->Viewport2MapY(y)};
+	const PixelPos cursorPixelPos = {CursorX, CursorY};
+	if (CursorOn == CursorOnMap && UI.MouseViewport->IsInsideMapArea(cursorPixelPos)) {
+		const CViewport &vp = *UI.MouseViewport;
+		const PixelPos screenPos = {x, y};
+		const Vec2i tilePos = vp.ScreenToTilePos(screenPos);
 
 		if (Map.IsFieldExplored(*ThisPlayer, tilePos) || ReplayRevealMap) {
-			UnitUnderCursor = UnitOnScreen(NULL, x - vp->X + vp->MapX * PixelTileSize.x + vp->OffsetX,
-				y - vp->Y + vp->MapY * PixelTileSize.y + vp->OffsetY);
+			const PixelPos mapPixelPos = vp.ScreenToMapPixelPos(screenPos);
+			UnitUnderCursor = UnitOnScreen(NULL, mapPixelPos.x, mapPixelPos.y);
 		}
 	} else if (CursorOn == CursorOnMinimap) {
 		const Vec2i tilePos = {UI.Minimap.Screen2MapX(x), UI.Minimap.Screen2MapY(y)};
@@ -1408,7 +1412,8 @@ static void UISelectStateButtonDown(unsigned)
 	//
 	//  Clicking on the map.
 	//
-	if (CursorOn == CursorOnMap && UI.MouseViewport->IsInsideMapArea(CursorX, CursorY)) {
+	const PixelPos screenPixelPos = {CursorX, CursorY};
+	if (CursorOn == CursorOnMap && UI.MouseViewport->IsInsideMapArea(screenPixelPos)) {
 		UI.StatusLine.Clear();
 		ClearCosts();
 		CursorState = CursorStatePoint;
@@ -1419,7 +1424,6 @@ static void UISelectStateButtonDown(unsigned)
 
 		if (MouseButtons & LeftButton) {
 			const CViewport &vp = *UI.MouseViewport;
-			const PixelPos screenPixelPos = {CursorX, CursorY};
 			const PixelPos mapPixelPos = vp.ScreenToMapPixelPos(screenPixelPos);
 
 			if (!ClickMissile.empty()) {
@@ -1575,16 +1579,15 @@ void UIHandleButtonDown(unsigned button)
 			if (!DoubleLeftButton)
 				return;
 #endif
+			const PixelPos cursorPixelPos = {CursorX, CursorY};
 			// Possible Selected[0] was removed from map
 			// need to make sure there is a unit to build
-			if (Selected[0] && (MouseButtons & LeftButton) &&
-					UI.MouseViewport->IsInsideMapArea(CursorX, CursorY)) {// enter select mode
-				int explored;
-				const Vec2i tilePos = {UI.MouseViewport->Viewport2MapX(CursorX),
-										UI.MouseViewport->Viewport2MapY(CursorY)};
+			if (Selected[0] && (MouseButtons & LeftButton)
+				&& UI.MouseViewport->IsInsideMapArea(cursorPixelPos)) {// enter select mode
+				int explored = 1;
+				const Vec2i tilePos = UI.MouseViewport->ScreenToTilePos(cursorPixelPos);
 				// FIXME: error messages
 
-				explored = 1;
 				for (int j = 0; explored && j < Selected[0]->Type->TileHeight; ++j) {
 					for (int i = 0; i < Selected[0]->Type->TileWidth; ++i) {
 						const Vec2i tempPos = {i, j};
@@ -1629,12 +1632,12 @@ void UIHandleButtonDown(unsigned button)
 #else
 		} else if (MouseButtons & RightButton) {
 #endif
-			if (!GameObserve && !GamePaused && UI.MouseViewport->IsInsideMapArea(CursorX, CursorY)) {
+			const PixelPos cursorPixelPos = {CursorX, CursorY};
+			if (!GameObserve && !GamePaused && UI.MouseViewport->IsInsideMapArea(cursorPixelPos)) {
 				CUnit *unit;
 				// FIXME: Rethink the complete chaos of coordinates here
 				// FIXME: Johns: Perhaps we should use a pixel map coordinates
-				const Vec2i tilePos = {UI.MouseViewport->Viewport2MapX(CursorX),
-										UI.MouseViewport->Viewport2MapY(CursorY)};
+				const Vec2i tilePos = UI.MouseViewport->ScreenToTilePos(cursorPixelPos);
 
 				if (UnitUnderCursor != NULL && (unit = UnitOnMapTile(tilePos, -1)) &&
 						!UnitUnderCursor->Type->Decoration) {
@@ -1933,13 +1936,13 @@ void UIHandleButtonUp(unsigned button)
 			//
 			// cade: cannot select unit on invisible space
 			// FIXME: johns: only complete invisibile units
-			const Vec2i cursorTilePos = {UI.MouseViewport->Viewport2MapX(CursorX),
-										UI.MouseViewport->Viewport2MapY(CursorY)};
-			if (Map.IsFieldVisible(*ThisPlayer, cursorTilePos) || ReplayRevealMap) {
-				int pixelposx = CursorX - UI.MouseViewport->X + UI.MouseViewport->MapX * PixelTileSize.x + UI.MouseViewport->OffsetX;
-				int pixelposy = CursorY - UI.MouseViewport->Y + UI.MouseViewport->MapY * PixelTileSize.y + UI.MouseViewport->OffsetY;
+			const PixelPos cursorPixelPos = {CursorX, CursorY};
+			const Vec2i cursorTilePos = UI.MouseViewport->ScreenToTilePos(cursorPixelPos);
 
-				unit = UnitOnScreen(unit, pixelposx, pixelposy);
+			if (Map.IsFieldVisible(*ThisPlayer, cursorTilePos) || ReplayRevealMap) {
+				const PixelPos cursorMapPos = UI.MouseViewport->ScreenToMapPixelPos(cursorPixelPos);
+
+				unit = UnitOnScreen(unit, cursorMapPos.x, cursorMapPos.y);
 			}
 			if (unit) {
 				// FIXME: Not nice coded, button number hardcoded!
diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp
index 2040638d8..cfa5e13c8 100644
--- a/src/ui/ui.cpp
+++ b/src/ui/ui.cpp
@@ -360,13 +360,15 @@ static void FinishViewportModeConfiguration(CViewport new_vps[], int num_vps)
 
 	// Affect the old viewport.
 	for (int i = 0; i < num_vps; ++i) {
-		CViewport *vp = UI.Viewports + i;
+		CViewport &vp = UI.Viewports[i];
 
-		vp->X = new_vps[i].X;
-		vp->EndX = new_vps[i].EndX;
-		vp->Y = new_vps[i].Y;
-		vp->EndY = new_vps[i].EndY;
-		vp->Set(new_vps[i].MapX, new_vps[i].MapY, new_vps[i].OffsetX, new_vps[i].OffsetY);
+		vp.X = new_vps[i].X;
+		vp.EndX = new_vps[i].EndX;
+		vp.Y = new_vps[i].Y;
+		vp.EndY = new_vps[i].EndY;
+		const Vec2i vpTilePos = {new_vps[i].MapX, new_vps[i].MapY};
+		const PixelDiff offset = {new_vps[i].OffsetX, new_vps[i].OffsetY};
+		vp.Set(vpTilePos, offset);
 	}
 	UI.NumViewports = num_vps;
 
diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp
index 07f2d96f0..ae8377081 100644
--- a/src/unit/unit.cpp
+++ b/src/unit/unit.cpp
@@ -2765,8 +2765,8 @@ CUnit *UnitOnScreen(CUnit *ounit, int x, int y)
 
 PixelPos CUnit::GetMapPixelPosCenter() const
 {
-	const PixelPos center = { tilePos.x * PixelTileSize.x + Type->TileWidth * PixelTileSize.x / 2,
-							tilePos.y * PixelTileSize.y + Type->TileHeight * PixelTileSize.y / 2};
+	const PixelPos center = { tilePos.x * PixelTileSize.x + IX + Type->TileWidth * PixelTileSize.x / 2,
+							tilePos.y * PixelTileSize.y + IY + Type->TileHeight * PixelTileSize.y / 2};
 	return center;
 }
 
diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp
index 5d56d7c85..2b8510a03 100644
--- a/src/unit/unit_draw.cpp
+++ b/src/unit/unit_draw.cpp
@@ -171,15 +171,14 @@ void DrawUnitSelection(const CViewport *vp, const CUnit &unit)
 		return;
 	}
 
-	const CUnitType *type = unit.Type;
-	int x = vp->Map2ViewportX(unit.tilePos.x) + unit.IX +
-		type->TileWidth * PixelTileSize.x / 2 - type->BoxWidth / 2 -
-		(type->Width - type->Sprite->Width) / 2;
-	int y = vp->Map2ViewportY(unit.tilePos.y) + unit.IY +
-		type->TileHeight * PixelTileSize.y / 2 - type->BoxHeight / 2 -
-		(type->Height - type->Sprite->Height) / 2;
+	const CUnitType &type = *unit.Type;
+	const PixelPos screenPos = vp->TilePosToScreen_TopLeft(unit.tilePos);
+	const int x = screenPos.x + unit.IX +type.TileWidth * PixelTileSize.x / 2
+		- type.BoxWidth / 2 - (type.Width - type.Sprite->Width) / 2;
+	const int y = screenPos.y + unit.IY + type.TileHeight * PixelTileSize.y / 2
+		- type.BoxHeight / 2 - (type.Height - type.Sprite->Height) / 2;
 
-	DrawSelection(color, x, y, x + type->BoxWidth, y + type->BoxHeight);
+	DrawSelection(color, x, y, x + type.BoxWidth, y + type.BoxHeight);
 }
 
 /**
@@ -670,36 +669,32 @@ void DrawShadow(const CUnitType &type, int frame, int x, int y)
 **
 **  @param unit   Pointer to unit.
 **  @param order  Pointer to order.
-**  @param x      Resulting screen X cordinate.
-**  @param y      Resulting screen Y cordinate.
+**  @param pos    Resulting screen cordinates.
 */
-static void GetOrderPosition(const CUnit &unit, const COrderPtr order, int *x, int *y)
+static void GetOrderPosition(const CUnit &unit, const COrder &order, PixelPos *screenPos)
 {
+	Assert(screenPos);
+
 	CUnit *goal;
 
 	// FIXME: n0body: Check for goal gone?
-	if ((goal = order->GetGoal()) && (!goal->Removed)) {
+	if ((goal = order.GetGoal()) && (!goal->Removed)) {
 		// Order has a goal, get it's location.
-		*x = CurrentViewport->Map2ViewportX(goal->tilePos.x) + goal->IX +
-			goal->Type->TileWidth * PixelTileSize.x / 2;
-		*y = CurrentViewport->Map2ViewportY(goal->tilePos.y) + goal->IY +
-			goal->Type->TileHeight * PixelTileSize.y / 2;
+		const PixelPos mapPos = goal->GetMapPixelPosCenter();
+		*screenPos = CurrentViewport->MapToScreenPixelPos(mapPos);
 	} else {
-		if (order->goalPos.x >= 0 && order->goalPos.y >= 0) {
+		if (Map.Info.IsPointOnMap(order.goalPos)) {
 			// Order is for a location, show that.
-			*x = CurrentViewport->Map2ViewportX(order->goalPos.x) + PixelTileSize.x / 2;
-			*y = CurrentViewport->Map2ViewportY(order->goalPos.y) + PixelTileSize.y / 2;
+			*screenPos = CurrentViewport->TilePosToScreen_Center(order.goalPos);
 		} else {
 			// Some orders ignore x,y (like StandStill).
 			// Use the unit's position instead.
-			*x = CurrentViewport->Map2ViewportX(unit.tilePos.x) + unit.IX +
-				unit.Type->TileWidth * PixelTileSize.x / 2;
-			*y = CurrentViewport->Map2ViewportY(unit.tilePos.y) + unit.IY +
-				unit.Type->TileHeight * PixelTileSize.y / 2;
+			const PixelPos mapPos = unit.GetMapPixelPosCenter();
+			*screenPos = CurrentViewport->MapToScreenPixelPos(mapPos);
 		}
-		if (order->Action == UnitActionBuild) {
-			*x += (order->Arg1.Type->TileWidth - 1) * PixelTileSize.x / 2;
-			*y += (order->Arg1.Type->TileHeight - 1) * PixelTileSize.y / 2;
+		if (order.Action == UnitActionBuild) {
+			screenPos->x += (order.Arg1.Type->TileWidth - 1) * PixelTileSize.x / 2;
+			screenPos->y += (order.Arg1.Type->TileHeight - 1) * PixelTileSize.y / 2;
 		}
 	}
 }
@@ -708,22 +703,20 @@ static void GetOrderPosition(const CUnit &unit, const COrderPtr order, int *x, i
 **  Show the order on map.
 **
 **  @param unit   Unit pointer.
-**  @param x1     X pixel coordinate.
-**  @param y1     Y pixel coordinate.
+**  @param pos    screen pixel coordinate.
 **  @param order  Order to display.
 */
-static void ShowSingleOrder(const CUnit &unit, int x1, int y1, const COrderPtr order)
+static void ShowSingleOrder(const CUnit &unit, const PixelPos &pos, const COrder &order)
 {
-	int x2;
-	int y2;
 	Uint32 color;
 	Uint32 e_color;
-	bool dest;
 
-	GetOrderPosition(unit, order, &x2, &y2);
+	PixelPos pos1 = pos;
+	PixelPos pos2;
+	GetOrderPosition(unit, order, &pos2);
 
-	dest = false;
-	switch (order->Action) {
+	bool dest = false;
+	switch (order.Action) {
 		case UnitActionNone:
 			e_color = color = ColorGray;
 			break;
@@ -743,10 +736,9 @@ static void ShowSingleOrder(const CUnit &unit, int x1, int y1, const COrderPtr o
 			break;
 
 		case UnitActionPatrol:
-			Video.DrawLineClip(ColorGreen, x1, y1, x2, y2);
+			Video.DrawLineClip(ColorGreen, pos1.x, pos1.y, pos2.x, pos2.y);
 			e_color = color = ColorBlue;
-			x1 = CurrentViewport->Map2ViewportX(order->Arg1.Patrol.x) + PixelTileSize.x / 2;
-			y1 = CurrentViewport->Map2ViewportY(order->Arg1.Patrol.y) + PixelTileSize.y / 2;
+			pos1 = CurrentViewport->TilePosToScreen_Center(order.Arg1.Patrol);
 			dest = true;
 			break;
 
@@ -756,8 +748,7 @@ static void ShowSingleOrder(const CUnit &unit, int x1, int y1, const COrderPtr o
 			break;
 
 		case UnitActionAttackGround:
-			x2 = CurrentViewport->Map2ViewportX(order->goalPos.x) + PixelTileSize.x / 2;
-			y2 = CurrentViewport->Map2ViewportY(order->goalPos.y) + PixelTileSize.y / 2;
+			pos2 = CurrentViewport->TilePosToScreen_Center(order.goalPos);
 			// FALL THROUGH
 		case UnitActionAttack:
 			if (unit.SubAction & 2) { // Show weak targets.
@@ -802,10 +793,9 @@ static void ShowSingleOrder(const CUnit &unit, int x1, int y1, const COrderPtr o
 
 		case UnitActionBuild:
 		{
-			int w = order->Arg1.Type->BoxWidth;
-			int h = order->Arg1.Type->BoxHeight;
-			DrawSelection(ColorGray, x2 - w / 2, y2 - h / 2, x2 + w / 2,
-				y2 + h / 2);
+			int w = order.Arg1.Type->BoxWidth;
+			int h = order.Arg1.Type->BoxHeight;
+			DrawSelection(ColorGray, pos2.x - w / 2, pos2.y - h / 2, pos2.x + w / 2, pos2.y + h / 2);
 			e_color = color = ColorGreen;
 			dest = true;
 		}
@@ -827,14 +817,14 @@ static void ShowSingleOrder(const CUnit &unit, int x1, int y1, const COrderPtr o
 
 		default:
 			e_color = color = ColorGray;
-			DebugPrint("Unknown action %d\n" _C_ order->Action);
+			DebugPrint("Unknown action %d\n" _C_ order.Action);
 			break;
 	}
 
-	Video.FillCircleClip(color, x1, y1, 2);
+	Video.FillCircleClip(color, pos1.x, pos1.y, 2);
 	if (dest) {
-		Video.DrawLineClip(color, x1, y1, x2, y2);
-		Video.FillCircleClip(e_color, x2, y2, 3);
+		Video.DrawLineClip(color, pos1.x, pos1.y, pos2.x, pos2.y);
+		Video.FillCircleClip(e_color, pos2.x, pos2.y, 3);
 	}
 }
 
@@ -845,23 +835,16 @@ static void ShowSingleOrder(const CUnit &unit, int x1, int y1, const COrderPtr o
 */
 void ShowOrder(const CUnit &unit)
 {
-	int x1;
-	int y1;
-	COrderPtr order;
-
 	if (unit.Destroyed) {
 		return;
 	}
-
 	if (unit.Player != ThisPlayer && !ThisPlayer->IsAllied(unit)) {
 		return;
 	}
-
 	// Get current position
-	x1 = CurrentViewport->Map2ViewportX(
-		unit.tilePos.x) + unit.IX + unit.Type->TileWidth * PixelTileSize.x / 2;
-	y1 = CurrentViewport->Map2ViewportY(
-		unit.tilePos.y) + unit.IY + unit.Type->TileHeight * PixelTileSize.y / 2;
+	const PixelPos mapPos = unit.GetMapPixelPosCenter();
+	PixelPos screenStartPos = CurrentViewport->MapToScreenPixelPos(mapPos);
+	COrderPtr order;
 
 	// If the current order is cancelled show the next one
 	if (unit.Orders.size() > 1 && unit.OrderFlush) {
@@ -869,17 +852,18 @@ void ShowOrder(const CUnit &unit)
 	} else {
 		order = unit.Orders[0];
 	}
-	ShowSingleOrder(unit, x1, y1, order);
+	ShowSingleOrder(unit, screenStartPos, *order);
 
 	// Show the rest of the orders
 	for (size_t i = 1 + (unit.OrderFlush ? 1 : 0); i < unit.Orders.size(); ++i) {
-		GetOrderPosition(unit, unit.Orders[i - 1], &x1, &y1);
-		ShowSingleOrder(unit, x1, y1, unit.Orders[i]);
+		PixelPos screenPos;
+		GetOrderPosition(unit, *unit.Orders[i - 1], &screenPos);
+		ShowSingleOrder(unit, screenPos, *unit.Orders[i]);
 	}
 
 	// Show order for new trained units
-	if (!unit.CanMove() && unit.NewOrder) {
-		ShowSingleOrder(unit, x1, y1, unit.NewOrder);
+	if (unit.NewOrder) {
+		ShowSingleOrder(unit, screenStartPos, *unit.NewOrder);
 	}
 }
 
@@ -1118,14 +1102,12 @@ void CUnit::Draw(const CViewport *vp) const
 	int player = this->RescuedFrom ? this->RescuedFrom->Index : this->Player->Index;
 	int action = this->CurrentAction();
 	if (ReplayRevealMap || IsVisible) {
+		const PixelPos &screenPos = vp->TilePosToScreen_TopLeft(this->tilePos);
 		type = this->Type;
 		frame = this->Frame;
-		y = this->IY;
-		x = this->IX;
-		x += vp->Map2ViewportX(this->tilePos.x);
-		y += vp->Map2ViewportY(this->tilePos.y);
-		state = (action == UnitActionBuilt) |
-				((action == UnitActionUpgradeTo) << 1);
+		x = screenPos.x + this->IX;
+		y = screenPos.y + this->IY;
+		state = (action == UnitActionBuilt) | ((action == UnitActionUpgradeTo) << 1);
 		constructed = this->Constructed;
 		// Reset Type to the type being upgraded to
 		if (state == 2) {
@@ -1134,10 +1116,11 @@ void CUnit::Draw(const CViewport *vp) const
 		// This is trash unless the unit is being built, and that's when we use it.
 		cframe = this->CurrentOrder()->Data.Built.Frame;
 	} else {
-		y = this->Seen.IY;
-		x = this->Seen.IX;
-		x += vp->Map2ViewportX(this->Seen.X);
-		y += vp->Map2ViewportY(this->Seen.Y);
+		const Vec2i seenTilePos = {this->Seen.X, this->Seen.Y};
+		const PixelPos &screenPos = vp->TilePosToScreen_TopLeft(seenTilePos);
+
+		x = screenPos.x + this->Seen.IX;
+		y = screenPos.y + this->Seen.IY;
 		frame = this->Seen.Frame;
 		type = this->Seen.Type;
 		constructed = this->Seen.Constructed;
@@ -1401,8 +1384,10 @@ void CUnitDrawProxy::DrawSelectionAt(int x, int y) const
 
 void CUnitDrawProxy::Draw(const CViewport *vp) const
 {
-	int x = this->IX + vp->Map2ViewportX(this->X);
-	int y = this->IY + vp->Map2ViewportY(this->Y);
+	const Vec2i tilePos = {this->X, this->Y};
+	const PixelPos screenPos = vp->TilePosToScreen_TopLeft(tilePos);
+	const int x = screenPos.x + this->IX;
+	const int y = screenPos.y + this->IY;
 
 	/* FIXME: check if we have to push real type here?*/
 	if (state == 1 && cframe) {
diff --git a/src/video/cursor.cpp b/src/video/cursor.cpp
index 4a476f07c..41b712eef 100644
--- a/src/video/cursor.cpp
+++ b/src/video/cursor.cpp
@@ -193,9 +193,12 @@ static void DrawBuildingCursor()
 {
 	// Align to grid
 	const CViewport &vp = *UI.MouseViewport;
-	int x = CursorX - (CursorX - vp.X + vp.OffsetX) % PixelTileSize.x;
-	int y = CursorY - (CursorY - vp.Y + vp.OffsetY) % PixelTileSize.y;
-	const Vec2i mpos = {vp.Viewport2MapX(x), vp.Viewport2MapY(y)};
+	const PixelPos cursorScreenPos = {CursorX, CursorY};
+//	int x = CursorX - (CursorX - vp.X + vp.OffsetX) % PixelTileSize.x;
+//	int y = CursorY - (CursorY - vp.Y + vp.OffsetY) % PixelTileSize.y;
+	const Vec2i mpos = vp.ScreenToTilePos(cursorScreenPos);
+	const PixelPos screenPos = vp.TilePosToScreen_TopLeft(mpos);
+
 	CUnit *ontop = NULL;
 
 	//
@@ -208,13 +211,13 @@ static void DrawBuildingCursor()
 #endif
 	PushClipping();
 	SetClipping(vp.X, vp.Y, vp.EndX, vp.EndY);
-	DrawShadow(*CursorBuilding, CursorBuilding->StillFrame, x, y);
+	DrawShadow(*CursorBuilding, CursorBuilding->StillFrame, screenPos.x, screenPos.y);
 	DrawUnitType(*CursorBuilding, CursorBuilding->Sprite, ThisPlayer->Index,
-		CursorBuilding->StillFrame, x, y);
+		CursorBuilding->StillFrame, screenPos.x, screenPos.y);
 	if (CursorBuilding->CanAttack && CursorBuilding->Stats->Variables[ATTACKRANGE_INDEX].Value>0){
 		Video.DrawCircleClip(ColorRed,
-					x + CursorBuilding->TileWidth * PixelTileSize.x / 2,
-					y + CursorBuilding->TileHeight * PixelTileSize.y / 2,
+					screenPos.x + CursorBuilding->TileWidth * PixelTileSize.x / 2,
+					screenPos.y + CursorBuilding->TileHeight * PixelTileSize.y / 2,
 					(CursorBuilding->Stats->Variables[ATTACKRANGE_INDEX].Max + (CursorBuilding->TileWidth - 1)) * PixelTileSize.x + 1);
 	}
 
@@ -261,8 +264,8 @@ static void DrawBuildingCursor()
 			} else {
 				color = ColorRed;
 			}
-			Video.FillTransRectangleClip(color, x + w * PixelTileSize.x, y + h *
-				PixelTileSize.y, PixelTileSize.x, PixelTileSize.y, 95);
+			Video.FillTransRectangleClip(color, screenPos.x + w * PixelTileSize.x,
+										screenPos.y + h * PixelTileSize.y, PixelTileSize.x, PixelTileSize.y, 95);
 		}
 	}
 	PopClipping();