← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/zoom into lp:widelands

 

SirVer has proposed merging lp:~widelands-dev/widelands/zoom into lp:widelands.

Commit message:
- Adds mouse wheel zoom to the MapView and adapt code for these changes.
  - Overlays (text & soldier icons) are drawn at integer scale only and not at
    all once scale is < 0.5.
  - This required to change all blitting to be sub-pixel - i.e. float - for the
    'destination'. 
- Adapted and simplified minimap rendering. It gained a feature too: Minimaps
  can be drawn using two modes :
    - the map scrolls and the view window stands still (the old one, stil used for in-game)
    - the view window scrolls and the map always looks like the minimap
      preview. This is now used in the editor.
- Renames Vector -> Vector3f, Point -> Vector2i, Pointf -> Vector2f, Rect -> Recti, FloatRect -> Rectf.
- Refactored object drawing to be simpler and slightly faster:
    - Never pass the field to be drawn to the draw routine. 
    - Do not calculate if statics or census should be shown inside the draw
      routines of the objects, but outside.
    - Move 'owner' field to MapObject - it was duplicated on Bob, Immovable and PlayerImmovable.

Known issues that I will not fix in this branch:
Lua is not aware of zoom and uses zoomless calculations for its moving
functions of the view. That means that if the player has zoomed in a scenario
and the code wants to move to a certain field, the movement will be wrong. My
plan is to remove the Lua functions and add a Animator class to the MapView
that will do smooth animations over time in the next branch.



Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #536461 in widelands: "Suggest a zooming function using the mouse wheel"
  https://bugs.launchpad.net/widelands/+bug/536461

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/zoom/+merge/309086

Jaaai - a journey of some 3 years starting with OpenGL finally enabling zoom!

Apologies for the huge diff. If it is unreviewable, I can pull out some of the
changes, like the renames and changing to floating point in rendering and
changing the minimap to two modes - but it would be a hassle and I'd prefer to
get it in as is after b19.
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/zoom into lp:widelands.
=== modified file 'src/base/CMakeLists.txt'
--- src/base/CMakeLists.txt	2016-08-15 10:43:23 +0000
+++ src/base/CMakeLists.txt	2016-10-22 18:17:28 +0000
@@ -37,9 +37,9 @@
 
 wl_library(base_geometry
   SRCS
-    point.h
-    point.cc
     rect.h
+    vector.h
+    vector.cc
 )
 
 wl_library(base_md5
@@ -50,7 +50,6 @@
     base_macros
 )
 
-
 wl_library(base_scoped_timer
   SRCS
     scoped_timer.h
@@ -68,3 +67,11 @@
   DEPENDS
     base_i18n
 )
+
+wl_library(base_math
+  SRCS
+    math.h
+    math.cc
+  DEPENDS
+    base_macros
+)

=== added file 'src/base/math.cc'
--- src/base/math.cc	1970-01-01 00:00:00 +0000
+++ src/base/math.cc	2016-10-22 18:17:28 +0000
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2006-2016 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+// Dummy file as cmake cannot handle header only libraries :(.

=== added file 'src/base/math.h'
--- src/base/math.h	1970-01-01 00:00:00 +0000
+++ src/base/math.h	2016-10-22 18:17:28 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006-2016 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_BASE_MATH_H
+#define WL_BASE_MATH_H
+
+#include "base/macros.h"
+
+namespace math {
+
+// Returns 1 for positive and -1 for negative numbers.
+template <typename T>
+T sign(const T& val) {
+	return val < T(0.) ? T(-1.) : T(1.);
+}
+
+// Clamps 'val' to 'min' and 'max'.
+template <typename T>
+T clamp(const T& val, const T& low, const T& high) {
+	if (val < low) { return low; }
+	if (val > high) { return high; }
+	return val;
+}
+
+}  // namespace math
+
+#endif  // end of include guard: WL_BASE_MATH_H

=== removed file 'src/base/point.h'
--- src/base/point.h	2016-08-04 15:49:05 +0000
+++ src/base/point.h	1970-01-01 00:00:00 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2002-2004, 2006-2013 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#ifndef WL_BASE_POINT_H
-#define WL_BASE_POINT_H
-
-#include <limits>
-
-#include <stdint.h>
-
-template <typename T> struct GenericPoint {
-	GenericPoint(const T& px, const T& py) : x(px), y(py) {
-	}
-	GenericPoint() : GenericPoint(T(0), T(0)) {
-	}
-
-	// Returns an invalid point.
-	static GenericPoint invalid() {
-		return GenericPoint(std::numeric_limits<T>::max(), std::numeric_limits<T>::max());
-	}
-
-	bool operator==(const GenericPoint& other) const {
-		return x == other.x && y == other.y;
-	}
-	bool operator!=(const GenericPoint& other) const {
-		return !(*this == other);
-	}
-
-	GenericPoint operator+(const GenericPoint& other) const {
-		return GenericPoint(x + other.x, y + other.y);
-	}
-
-	GenericPoint operator-() const {
-		return GenericPoint(-x, -y);
-	}
-
-	GenericPoint operator-(const GenericPoint& other) const {
-		return GenericPoint(x - other.x, y - other.y);
-	}
-
-	GenericPoint& operator+=(const GenericPoint& other) {
-		x += other.x;
-		y += other.y;
-		return *this;
-	}
-
-	GenericPoint& operator-=(const GenericPoint& other) {
-		x -= other.x;
-		y -= other.y;
-		return *this;
-	}
-
-	T x, y;
-};
-
-using Point = GenericPoint<int>;
-using FloatPoint = GenericPoint<float>;
-
-/// Returns the point in the middle between a and b (rounded to integer
-/// values).
-Point middle(const Point& a, const Point& b);
-
-#endif  // end of include guard: WL_BASE_POINT_H

=== modified file 'src/base/rect.h'
--- src/base/rect.h	2016-08-04 15:49:05 +0000
+++ src/base/rect.h	2016-10-22 18:17:28 +0000
@@ -20,41 +20,51 @@
 #ifndef WL_BASE_RECT_H
 #define WL_BASE_RECT_H
 
-#include "base/point.h"
+#include "base/vector.h"
 
-template <typename T> struct GenericRect {
-	/// Generates a degenerate Rect at (0, 0) with no height or width.
-	GenericRect() : GenericRect(T(0), T(0), T(0), T(0)) {
+template <typename T> struct Rect {
+	/// Generates a degenerate Recti at (0, 0) with no height or width.
+	Rect() : Rect(T(0), T(0), T(0), T(0)) {
 	}
 
-	GenericRect(const T& gx, const T& gy, const T& W, const T& H) : x(gx), y(gy), w(W), h(H) {
+	Rect(const T& gx, const T& gy, const T& W, const T& H) : x(gx), y(gy), w(W), h(H) {
 	}
 
 	template <typename PointType>
-	GenericRect(const GenericPoint<PointType>& p, const T& width, const T& height)
-	   : GenericRect(T(p.x), T(p.y), width, height) {
+	Rect(const Vector2<PointType>& p, const T& width, const T& height)
+	   : Rect(T(p.x), T(p.y), width, height) {
 	}
 
-	/// The Point (x, y).
-	GenericPoint<T> origin() const {
-		return GenericPoint<T>(x, y);
+	/// The Vector2i (x, y).
+	Vector2<T> origin() const {
+		return Vector2<T>(x, y);
 	}
 
 	/// The point (x + w, y + h).
-	GenericPoint<T> opposite_of_origin() const {
-		return GenericPoint<T>(x + w, y + h);
+	Vector2<T> opposite_of_origin() const {
+		return Vector2<T>(x + w, y + h);
 	}
 
 	/// Returns true if this rectangle contains the given point.
 	/// The bottom and right borders of the rectangle are considered to be excluded.
-	template <typename PointType> bool contains(const GenericPoint<PointType>& pt) const {
+	template <typename PointType> bool contains(const Vector2<PointType>& pt) const {
 		return T(pt.x) >= x && T(pt.x) < x + w && T(pt.y) >= y && T(pt.y) < y + h;
 	}
 
+	// The center point of 'r'.
+	Vector2f center() const {
+		return Vector2f(x + w / 2.f, y + h / 2.f);
+	}
+
+	template<typename Type>
+	Rect<Type> cast() const {
+		return Rect<Type>(Type(x), Type(y), Type(w), Type(h));
+	}
+
 	T x, y, w, h;
 };
 
-using Rect = GenericRect<int>;
-using FloatRect = GenericRect<float>;
+using Recti = Rect<int>;
+using Rectf = Rect<float>;
 
 #endif  // end of include guard: WL_BASE_RECT_H

=== renamed file 'src/base/point.cc' => 'src/base/vector.cc'
--- src/base/point.cc	2015-03-01 09:21:20 +0000
+++ src/base/vector.cc	2016-10-22 18:17:28 +0000
@@ -17,8 +17,14 @@
  *
  */
 
-#include "base/point.h"
-
-Point middle(const Point& a, const Point& b) {
-	return Point((a.x + b.x) / 2, (a.y + b.y) / 2);
+#include "base/vector.h"
+
+#include <cmath>
+
+Vector2f middle(const Vector2f& a, const Vector2f& b) {
+	return Vector2f((a.x + b.x) / 2.f, (a.y + b.y) / 2.f);
+}
+
+Vector2i round(const Vector2f& a) {
+	return Vector2i(std::lround(a.x), std::lround(a.y));
 }

=== renamed file 'src/wui/vector.h' => 'src/base/vector.h'
--- src/wui/vector.h	2016-08-04 15:49:05 +0000
+++ src/base/vector.h	2016-10-22 18:17:28 +0000
@@ -17,23 +17,88 @@
  *
  */
 
-#ifndef WL_WUI_VECTOR_H
-#define WL_WUI_VECTOR_H
+#ifndef WL_BASE_VECTOR_H
+#define WL_BASE_VECTOR_H
 
 #include <cmath>
-
-// hm, floats...
-// tried to be faster with fixed point arithmetics
-// it was, but i'll try to find other opts first
-struct Vector {
-	Vector() : x(0), y(0), z(0) {
-	}
-	Vector(const float X, const float Y, const float Z) : x(X), y(Y), z(Z) {
+#include <limits>
+
+#include <stdint.h>
+
+template <typename T> struct Vector2 {
+	Vector2(const T& px, const T& py) : x(px), y(py) {
+	}
+	Vector2() : Vector2(T(0), T(0)) {
+	}
+
+	// Returns an invalid point.
+	static Vector2 invalid() {
+		return Vector2(std::numeric_limits<T>::max(), std::numeric_limits<T>::max());
+	}
+
+	bool operator==(const Vector2& other) const {
+		return x == other.x && y == other.y;
+	}
+	bool operator!=(const Vector2& other) const {
+		return !(*this == other);
+	}
+
+	Vector2 operator+(const Vector2& other) const {
+		return Vector2(x + other.x, y + other.y);
+	}
+
+	Vector2 operator*(const float a) const {
+		return Vector2(a * x, a * y);
+	}
+
+	Vector2 operator/(const float a) const {
+		return Vector2(x / a, y / a);
+	}
+
+	Vector2 operator-() const {
+		return Vector2(-x, -y);
+	}
+
+	Vector2 operator-(const Vector2& other) const {
+		return Vector2(x - other.x, y - other.y);
+	}
+
+	Vector2& operator+=(const Vector2& other) {
+		x += other.x;
+		y += other.y;
+		return *this;
+	}
+
+	Vector2& operator-=(const Vector2& other) {
+		x -= other.x;
+		y -= other.y;
+		return *this;
+	}
+
+	template<typename Type>
+	Vector2<Type> cast() const {
+		return Vector2<Type>(Type(x), Type(y));
+	}
+
+	T x, y;
+};
+
+using Vector2i = Vector2<int>;
+using Vector2f = Vector2<float>;
+
+/// Returns the point in the middle between a and b.
+Vector2f middle(const Vector2f& a, const Vector2f& b);
+
+// Returns an point rounded to the closest integer.
+Vector2i round(const Vector2f& a);
+
+struct Vector3f {
+	Vector3f(const float X, const float Y, const float Z) : x(X), y(Y), z(Z) {
 	}
 
 	void normalize() {
-		const float f = static_cast<float>(sqrt(x * x + y * y + z * z));
-		if (fabs(f) < 0.00001)  // check for ==0
+		const float f = static_cast<float>(std::sqrt(x * x + y * y + z * z));
+		if (std::fabs(f) < 0.00001f)  // check for ==0
 			return;
 		x /= f;
 		y /= f;
@@ -41,16 +106,16 @@
 	}
 
 	// vector addition
-	Vector operator+(const Vector& other) const {
-		return Vector(x + other.x, y + other.y, z + other.z);
+	Vector3f operator+(const Vector3f& other) const {
+		return Vector3f(x + other.x, y + other.y, z + other.z);
 	}
 
 	// inner product
-	float operator*(const Vector& other) const {
+	float dot(const Vector3f& other) const {
 		return x * other.x + y * other.y + z * other.z;
 	}
 
 	float x, y, z;
 };
 
-#endif  // end of include guard: WL_WUI_VECTOR_H
+#endif  // end of include guard: WL_BASE_VECTOR_H

=== modified file 'src/economy/flag.h'
--- src/economy/flag.h	2016-08-04 15:49:05 +0000
+++ src/economy/flag.h	2016-10-22 18:17:28 +0000
@@ -25,6 +25,7 @@
 
 #include "base/macros.h"
 #include "economy/routing_node.h"
+#include "logic/map_objects/draw_text.h"
 #include "logic/map_objects/immovable.h"
 
 namespace Widelands {
@@ -144,7 +145,11 @@
 	void init(EditorGameBase&) override;
 	void cleanup(EditorGameBase&) override;
 
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          DrawText draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
 
 	void wake_up_capacity_queue(Game&);
 

=== modified file 'src/economy/portdock.cc'
--- src/economy/portdock.cc	2016-08-04 15:49:05 +0000
+++ src/economy/portdock.cc	2016-10-22 18:17:28 +0000
@@ -141,7 +141,7 @@
 		expedition_bootstrap_->set_economy(e);
 }
 
-void PortDock::draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) {
+void PortDock::draw(uint32_t, const DrawText, const Vector2f&, float, RenderTarget*) {
 	// do nothing
 }
 

=== modified file 'src/economy/portdock.h'
--- src/economy/portdock.h	2016-08-04 15:49:05 +0000
+++ src/economy/portdock.h	2016-10-22 18:17:28 +0000
@@ -96,7 +96,11 @@
 
 	Flag& base_flag() override;
 	PositionList get_positions(const EditorGameBase&) const override;
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          DrawText draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
 
 	void init(EditorGameBase&) override;
 	void cleanup(EditorGameBase&) override;

=== modified file 'src/economy/road.h'
--- src/economy/road.h	2016-08-04 15:49:05 +0000
+++ src/economy/road.h	2016-10-22 18:17:28 +0000
@@ -118,7 +118,11 @@
 	void init(EditorGameBase&) override;
 	void cleanup(EditorGameBase&) override;
 
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          DrawText draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
 
 private:
 	void set_path(EditorGameBase&, const Path&);

=== modified file 'src/editor/editorinteractive.cc'
--- src/editor/editorinteractive.cc	2016-09-25 18:46:29 +0000
+++ src/editor/editorinteractive.cc	2016-10-22 18:17:28 +0000
@@ -160,6 +160,8 @@
 	      [this](const Widelands::NoteFieldResourceChanged& note) {
 		      update_resource_overlay(note, egbase().world(), mutable_field_overlay_manager());
 		   });
+
+	minimap_registry().minimap_type = MiniMapType::kStaticMap;
 }
 
 void EditorInteractive::register_overlays() {
@@ -173,7 +175,7 @@
 			const Image* player_image = g_gr->images().get(player_pictures[p - 1]);
 			assert(player_image);
 			mutable_field_overlay_manager()->register_overlay(
-			   sp, player_image, 8, Point(player_image->width() / 2, STARTING_POS_HOTSPOT_Y));
+			   sp, player_image, 8, Vector2i(player_image->width() / 2, STARTING_POS_HOTSPOT_Y));
 		}
 	}
 
@@ -669,7 +671,7 @@
 		}
 
 		// Make sure that we will start at coordinates (0,0).
-		set_viewpoint(Point(0, 0), true);
+		set_viewpoint(Vector2i(0, 0), true);
 		set_sel_pos(Widelands::NodeAndTriangle<>(
 		   Widelands::Coords(0, 0),
 		   Widelands::TCoords<>(Widelands::Coords(0, 0), Widelands::TCoords<>::D)));

=== modified file 'src/editor/tools/set_origin_tool.cc'
--- src/editor/tools/set_origin_tool.cc	2016-08-04 15:49:05 +0000
+++ src/editor/tools/set_origin_tool.cc	2016-10-22 18:17:28 +0000
@@ -30,9 +30,7 @@
                                                Widelands::Map* map) {
 	map->set_origin(center.node);
 	eia.map_changed(EditorInteractive::MapWas::kGloballyMutated);
-	eia.set_rel_viewpoint(Point(-(center.node.x * 2 + (center.node.y & 1)) * (kTriangleWidth / 2),
-	                            -center.node.y * kTriangleHeight),
-	                      true);
+	eia.center_view_on_coords(Widelands::Coords(0, 0));
 	return 0;
 }
 
@@ -46,8 +44,7 @@
 	   map->get_width() - 1 - center.node.x, map->get_height() - 1 - center.node.y);
 	map->set_origin(nc);
 	eia.map_changed(EditorInteractive::MapWas::kGloballyMutated);
-	eia.set_rel_viewpoint(
-	   Point(-(nc.x * 2 + (nc.y & 1)) * (kTriangleWidth / 2), -nc.y * kTriangleHeight), true);
+	eia.center_view_on_coords(Widelands::Coords(0, 0));
 	return 0;
 }
 

=== modified file 'src/editor/tools/set_starting_pos_tool.cc'
--- src/editor/tools/set_starting_pos_tool.cc	2016-08-04 15:49:05 +0000
+++ src/editor/tools/set_starting_pos_tool.cc	2016-10-22 18:17:28 +0000
@@ -113,7 +113,7 @@
 
 			//  add new overlay
 			overlay_manager->register_overlay(
-			   center.node, player_image, 4, Point(player_image->width() / 2, STARTING_POS_HOTSPOT_Y));
+			   center.node, player_image, 4, Vector2i(player_image->width() / 2, STARTING_POS_HOTSPOT_Y));
 
 			//  set new player pos
 			map->set_starting_pos(current_player_, center.node);

=== modified file 'src/editor/ui_menus/main_menu_load_or_save_map.cc'
--- src/editor/ui_menus/main_menu_load_or_save_map.cc	2016-08-04 18:09:55 +0000
+++ src/editor/ui_menus/main_menu_load_or_save_map.cc	2016-10-22 18:17:28 +0000
@@ -89,7 +89,7 @@
 	vbox->add(show_mapnames_, UI::Align::kLeft, true);
 
 	/** TRANSLATORS: Checkbox title. If this checkbox is enabled, map names aren't translated. */
-	cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Point(0, 0), _("Show original map names"));
+	cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Vector2i(0, 0), _("Show original map names"));
 	cb_dont_localize_mapnames_->set_state(false);
 	vbox->add_space(2 * padding_);
 	vbox->add(cb_dont_localize_mapnames_, UI::Align::kLeft, true);

=== modified file 'src/editor/ui_menus/main_menu_map_options.cc'
--- src/editor/ui_menus/main_menu_map_options.cc	2016-08-07 10:10:18 +0000
+++ src/editor/ui_menus/main_menu_map_options.cc	2016-10-22 18:17:28 +0000
@@ -227,7 +227,7 @@
                                           std::string tag,
                                           std::string displ_name) {
 	UI::Box* box = new UI::Box(parent, 0, 0, UI::Box::Horizontal, max_w_, checkbox_space_, 0);
-	UI::Checkbox* cb = new UI::Checkbox(box, Point(0, 0), displ_name);
+	UI::Checkbox* cb = new UI::Checkbox(box, Vector2i(0, 0), displ_name);
 	box->add(cb, UI::Align::kLeft, true);
 	box->add_space(checkbox_space_);
 	parent->add(box, UI::Align::kLeft);

=== modified file 'src/editor/ui_menus/main_menu_random_map.cc'
--- src/editor/ui_menus/main_menu_random_map.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/main_menu_random_map.cc	2016-10-22 18:17:28 +0000
@@ -184,7 +184,7 @@
                 resources_label_.get_h(),
                 (boost::format(_("%i %%")) % mountainsval_).str(),
                 UI::Align::kHCenter),
-     island_mode_(&box_, Point(0, 0), _("Island mode")),
+     island_mode_(&box_, Vector2i(0, 0), _("Island mode")),
      // Geeky stuff
      map_number_box_(&box_, 0, 0, UI::Box::Horizontal, 0, 0, margin_),
      map_number_label_(&map_number_box_, 0, 0, _("Random Number:")),

=== modified file 'src/editor/ui_menus/main_menu_save_map.h'
--- src/editor/ui_menus/main_menu_save_map.h	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/main_menu_save_map.h	2016-10-22 18:17:28 +0000
@@ -40,7 +40,7 @@
 
 private:
 	EditorInteractive& eia();
-	void clicked_ok();
+	void clicked_ok() override;
 	void clicked_make_directory();
 	void clicked_edit_options();
 	void clicked_item();

=== modified file 'src/editor/ui_menus/player_menu.cc'
--- src/editor/ui_menus/player_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/player_menu.cc	2016-10-22 18:17:28 +0000
@@ -97,11 +97,11 @@
 	set_inner_size(375, 135);
 
 	UI::Textarea* ta = new UI::Textarea(this, 0, 0, _("Number of Players"));
-	ta->set_pos(Point((get_inner_w() - ta->get_w()) / 2, posy + 5));
+	ta->set_pos(Vector2i((get_inner_w() - ta->get_w()) / 2, posy + 5));
 	posy += spacing + width;
 
 	nr_of_players_ta_ = new UI::Textarea(this, 0, 0, "5");
-	nr_of_players_ta_->set_pos(Point((get_inner_w() - nr_of_players_ta_->get_w()) / 2, posy + 5));
+	nr_of_players_ta_->set_pos(Vector2i((get_inner_w() - nr_of_players_ta_->get_w()) / 2, posy + 5));
 
 	posy += width + spacing + spacing;
 
@@ -297,7 +297,7 @@
 	//  jump to the current node
 	Widelands::Map& map = menu.egbase().map();
 	if (Widelands::Coords const sp = map.get_starting_pos(n))
-		menu.move_view_to(sp);
+		menu.center_view_on_coords(sp);
 
 	//  select tool set mplayer
 	menu.select_tool(menu.tools()->set_starting_pos, EditorTool::First);

=== modified file 'src/editor/ui_menus/tool_change_resources_options_menu.cc'
--- src/editor/ui_menus/tool_change_resources_options_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/tool_change_resources_options_menu.cc	2016-10-22 18:17:28 +0000
@@ -100,7 +100,7 @@
 
 	for (Widelands::DescriptionIndex i = 0; i < nr_resources; ++i) {
 		const Widelands::ResourceDescription& resource = *world.get_resource(i);
-		radiogroup_.add_button(&resources_box_, Point(0, 0),
+		radiogroup_.add_button(&resources_box_, Vector2i(0, 0),
 		                       g_gr->images().get(resource.representative_image()),
 		                       resource.descname());
 		resources_box_.add(radiogroup_.get_first_button(), UI::Align::kLeft, false, true);

=== modified file 'src/editor/ui_menus/tool_menu.cc'
--- src/editor/ui_menus/tool_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/tool_menu.cc	2016-10-22 18:17:28 +0000
@@ -45,8 +45,8 @@
    : UI::UniqueWindow(&parent, "tool_menu", &registry, 350, 400, _("Tools")) {
 
 #define spacing 5
-	Point const offs(spacing, spacing);
-	Point pos = offs;
+	Vector2i const offs(spacing, spacing);
+	Vector2i pos = offs;
 	int32_t const width = 34;
 	int32_t const height = 34;
 

=== modified file 'src/editor/ui_menus/tool_place_bob_options_menu.cc'
--- src/editor/ui_menus/tool_place_bob_options_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/tool_place_bob_options_menu.cc	2016-10-22 18:17:28 +0000
@@ -64,14 +64,14 @@
 	}
 
 	const Image* tab_icon = g_gr->images().get("images/ui_basic/list_first_entry.png");
-	Point pos;
+	Vector2i pos;
 	uint32_t cur_x = bobs_in_row;
 	int32_t i = 0;
 	UI::Box* box = nullptr;
 	while (i < nr_bobs) {
 		if (cur_x == bobs_in_row) {
 			cur_x = 0;
-			pos = Point(5, 15);
+			pos = Vector2i(5, 15);
 			box = new UI::Box(&tabpanel_, 0, 0, UI::Box::Horizontal);
 			tabpanel_.add("icons", tab_icon, box);
 		}

=== modified file 'src/editor/ui_menus/tool_place_immovable_options_menu.cc'
--- src/editor/ui_menus/tool_place_immovable_options_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/tool_place_immovable_options_menu.cc	2016-10-22 18:17:28 +0000
@@ -39,7 +39,7 @@
 
 UI::Checkbox* create_immovable_checkbox(UI::Panel* parent, const ImmovableDescr& immovable_descr) {
 	const Image* pic = immovable_descr.representative_image();
-	UI::Checkbox* cb = new UI::Checkbox(parent, Point(0, 0), pic, immovable_descr.descname());
+	UI::Checkbox* cb = new UI::Checkbox(parent, Vector2i(0, 0), pic, immovable_descr.descname());
 	const int kMinClickableArea = 24;
 	cb->set_desired_size(std::max<int>(pic->width(), kMinClickableArea),
 	                     std::max<int>(pic->height(), kMinClickableArea));

=== modified file 'src/editor/ui_menus/tool_set_terrain_options_menu.cc'
--- src/editor/ui_menus/tool_set_terrain_options_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/tool_set_terrain_options_menu.cc	2016-10-22 18:17:28 +0000
@@ -53,10 +53,10 @@
 	// Blit the main terrain image
 	const Image& terrain_texture = terrain_descr.get_texture(0);
 	Texture* texture = new Texture(terrain_texture.width(), terrain_texture.height());
-	texture->blit(Rect(0, 0, terrain_texture.width(), terrain_texture.height()), terrain_texture,
-	              Rect(0, 0, terrain_texture.width(), terrain_texture.height()), 1.,
+	texture->blit(Rectf(0, 0, terrain_texture.width(), terrain_texture.height()), terrain_texture,
+	              Rectf(0, 0, terrain_texture.width(), terrain_texture.height()), 1.,
 	              BlendMode::UseAlpha);
-	Point pt(1, terrain_texture.height() - kSmallPicSize - 1);
+	Vector2i pt(1, terrain_texture.height() - kSmallPicSize - 1);
 
 	// Collect tooltips and blit small icons representing "is" values
 	for (const TerrainDescription::Type& terrain_type : terrain_descr.get_types()) {
@@ -64,9 +64,9 @@
 		                terrain_descr.custom_tooltips().end());
 		tooltips.push_back(terrain_type.descname);
 
-		texture->blit(Rect(pt.x, pt.y, terrain_type.icon->width(), terrain_type.icon->height()),
+		texture->blit(Rectf(pt.x, pt.y, terrain_type.icon->width(), terrain_type.icon->height()),
 		              *terrain_type.icon,
-		              Rect(0, 0, terrain_type.icon->width(), terrain_type.icon->height()), 1.,
+		              Rectf(0, 0, terrain_type.icon->width(), terrain_type.icon->height()), 1.,
 		              BlendMode::UseAlpha);
 		pt.x += kSmallPicSize + 1;
 	}
@@ -79,7 +79,7 @@
 	                               .str();
 
 	std::unique_ptr<const Image>& image = offscreen_images->back();
-	UI::Checkbox* cb = new UI::Checkbox(parent, Point(0, 0), image.get(), tooltip);
+	UI::Checkbox* cb = new UI::Checkbox(parent, Vector2i(0, 0), image.get(), tooltip);
 	cb->set_desired_size(image->width() + 1, image->height() + 1);
 	return cb;
 }

=== modified file 'src/game_io/CMakeLists.txt'
--- src/game_io/CMakeLists.txt	2016-01-20 20:12:00 +0000
+++ src/game_io/CMakeLists.txt	2016-10-22 18:17:28 +0000
@@ -30,6 +30,7 @@
     build_info
     economy
     graphic
+    graphic_image_io
     graphic_minimap_renderer
     io_fileread
     io_filesystem

=== modified file 'src/game_io/game_interactive_player_packet.cc'
--- src/game_io/game_interactive_player_packet.cc	2016-08-04 15:49:05 +0000
+++ src/game_io/game_interactive_player_packet.cc	2016-10-22 18:17:28 +0000
@@ -60,7 +60,7 @@
 			uint32_t const display_flags = fr.unsigned_32();
 
 			if (InteractiveBase* const ibase = game.get_ibase()) {
-				ibase->set_viewpoint(Point(x, y), true);
+				ibase->set_viewpoint(Vector2i(x, y), true);
 
 				uint32_t const loaded_df =
 				   InteractiveBase::dfShowCensus | InteractiveBase::dfShowStatistics;
@@ -78,7 +78,7 @@
 					size_t no_of_landmarks = fr.unsigned_8();
 					for (size_t i = 0; i < no_of_landmarks; ++i) {
 						uint8_t set = fr.unsigned_8();
-						Point landmark(fr.signed_32(), fr.signed_32());
+						Vector2i landmark(fr.signed_32(), fr.signed_32());
 						if (set > 0) {
 							ibase->set_landmark(i, landmark);
 						}

=== modified file 'src/game_io/game_preload_packet.cc'
--- src/game_io/game_preload_packet.cc	2016-08-05 12:32:08 +0000
+++ src/game_io/game_preload_packet.cc	2016-10-22 18:17:28 +0000
@@ -27,6 +27,7 @@
 #include "base/time_string.h"
 #include "build_info.h"
 #include "graphic/graphic.h"
+#include "graphic/image_io.h"
 #include "graphic/minimap_renderer.h"
 #include "logic/game.h"
 #include "logic/game_data_error.h"
@@ -120,13 +121,17 @@
 
 	std::unique_ptr<::StreamWrite> sw(fs.open_stream_write(kMinimapFilename));
 	if (sw.get() != nullptr) {
-		const MiniMapLayer flags =
+		const MiniMapLayer layers =
 		   MiniMapLayer::Owner | MiniMapLayer::Building | MiniMapLayer::Terrain;
+		std::unique_ptr<Texture> texture;
 		if (ipl != nullptr) {  // Player
-			write_minimap_image(game, &ipl->player(), ipl->get_viewpoint(), flags, sw.get());
+			texture = draw_minimap(
+			   game, &ipl->player(), ipl->get_view_area(), MiniMapType::kStaticViewWindow, layers);
 		} else {  // Observer
-			write_minimap_image(game, nullptr, Point(0, 0), flags, sw.get());
+			texture = draw_minimap(game, nullptr, Rectf(), MiniMapType::kStaticMap, layers);
 		}
+		assert(texture != nullptr);
+		save_to_png(texture.get(), sw.get(), ColorType::RGBA);
 		sw->flush();
 	}
 }

=== modified file 'src/graphic/CMakeLists.txt'
--- src/graphic/CMakeLists.txt	2016-02-19 19:10:44 +0000
+++ src/graphic/CMakeLists.txt	2016-10-22 18:17:28 +0000
@@ -124,6 +124,7 @@
     graphic_surface
     io_filesystem
     logic
+    logic_widelands_geometry
 )
 
 wl_library(graphic_draw_programs
@@ -209,7 +210,6 @@
     base_macros
     economy
     graphic
-    graphic_image_io
     graphic_surface
     logic
     wui_mapview_pixelfunctions

=== modified file 'src/graphic/align.cc'
--- src/graphic/align.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/align.cc	2016-10-22 18:17:28 +0000
@@ -53,11 +53,11 @@
 	return alignment;
 }
 
-void correct_for_align(Align align, uint32_t w, uint32_t h, Point* pt) {
+void correct_for_align(Align align, uint32_t w, uint32_t h, Vector2f* pt) {
 	// Vertical Align
 	if (static_cast<int>(align & (Align::kVCenter | Align::kBottom))) {
 		if (static_cast<int>(align & Align::kVCenter))
-			pt->y -= h / 2;
+			pt->y -= h / 2.f;
 		else
 			pt->y -= h;
 	}
@@ -65,7 +65,7 @@
 	// Horizontal Align
 	if ((align & Align::kHorizontal) != Align::kLeft) {
 		if (static_cast<int>(align & Align::kHCenter))
-			pt->x -= w / 2;
+			pt->x -= w / 2.f;
 		else if (static_cast<int>(align & Align::kRight))
 			pt->x -= w;
 	}

=== modified file 'src/graphic/align.h'
--- src/graphic/align.h	2016-08-04 15:49:05 +0000
+++ src/graphic/align.h	2016-10-22 18:17:28 +0000
@@ -20,7 +20,7 @@
 #ifndef WL_GRAPHIC_ALIGN_H
 #define WL_GRAPHIC_ALIGN_H
 
-#include "base/point.h"
+#include "base/vector.h"
 
 namespace UI {
 
@@ -58,6 +58,6 @@
 }
 
 Align mirror_alignment(Align alignment);
-void correct_for_align(Align, uint32_t w, uint32_t h, Point* pt);
+void correct_for_align(Align, uint32_t w, uint32_t h, Vector2f* pt);
 }
 #endif  // end of include guard: WL_GRAPHIC_ALIGN_H

=== modified file 'src/graphic/animation.cc'
--- src/graphic/animation.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/animation.cc	2016-10-22 18:17:28 +0000
@@ -44,7 +44,7 @@
 
 namespace {
 // Parses an array { 12, 23 } into a point.
-void get_point(const LuaTable& table, Point* p) {
+void get_point(const LuaTable& table, Vector2i* p) {
 	std::vector<int> pts = table.array_entries<int>();
 	if (pts.size() != 2) {
 		throw wexception("Expected 2 entries, but got %" PRIuS ".", pts.size());
@@ -68,11 +68,14 @@
 	uint16_t height() const override;
 	uint16_t nr_frames() const override;
 	uint32_t frametime() const override;
-	const Point& hotspot() const override;
+	const Vector2i& hotspot() const override;
 	Image* representative_image(const RGBColor* clr) const override;
 	const std::string& representative_image_filename() const override;
-	virtual void blit(
-	   uint32_t time, const Point&, const Rect& srcrc, const RGBColor* clr, Surface*) const override;
+	virtual void blit(uint32_t time,
+	                  const Rectf& dstrc,
+	                  const Rectf& srcrc,
+	                  const RGBColor* clr,
+	                  Surface*) const override;
 	void trigger_sound(uint32_t framenumber, uint32_t stereo_position) const override;
 
 private:
@@ -85,7 +88,7 @@
 	uint32_t current_frame(uint32_t time) const;
 
 	uint32_t frametime_;
-	Point hotspot_;
+	Vector2i hotspot_;
 	bool hasplrclrs_;
 	std::vector<std::string> image_files_;
 	std::vector<std::string> pc_mask_image_files_;
@@ -207,7 +210,7 @@
 	return frametime_;
 }
 
-const Point& NonPackedAnimation::hotspot() const {
+const Vector2i& NonPackedAnimation::hotspot() const {
 	return hotspot_;
 }
 
@@ -221,11 +224,11 @@
 	Texture* rv = new Texture(w, h);
 	if (!hasplrclrs_ || clr == nullptr) {
 		// No player color means we simply want an exact copy of the original image.
-		rv->blit(Rect(Point(0, 0), w, h), *image, Rect(Point(0, 0), w, h), 1., BlendMode::Copy);
+		rv->blit(Rectf(0, 0, w, h), *image, Rectf(0, 0, w, h), 1., BlendMode::Copy);
 	} else {
-		rv->fill_rect(Rect(Point(0, 0), w, h), RGBAColor(0, 0, 0, 0));
-		rv->blit_blended(Rect(Point(0, 0), w, h), *image,
-		                 *g_gr->images().get(pc_mask_image_files_[0]), Rect(Point(0, 0), w, h), *clr);
+		rv->fill_rect(Rectf(0, 0, w, h), RGBAColor(0, 0, 0, 0));
+		rv->blit_blended(Rectf(0, 0, w, h), *image, *g_gr->images().get(pc_mask_image_files_[0]),
+		                 Rectf(0, 0, w, h), *clr);
 	}
 	return rv;
 }
@@ -255,19 +258,20 @@
 	}
 }
 
-void NonPackedAnimation::blit(
-   uint32_t time, const Point& dst, const Rect& srcrc, const RGBColor* clr, Surface* target) const {
+void NonPackedAnimation::blit(uint32_t time,
+                              const Rectf& dstrc,
+                              const Rectf& srcrc,
+                              const RGBColor* clr,
+                              Surface* target) const {
 	assert(target);
 
 	const uint32_t idx = current_frame(time);
 	assert(idx < nr_frames());
 
 	if (!hasplrclrs_ || clr == nullptr) {
-		target->blit(
-		   Rect(dst.x, dst.y, srcrc.w, srcrc.h), *frames_.at(idx), srcrc, 1., BlendMode::UseAlpha);
+		target->blit(dstrc, *frames_.at(idx), srcrc, 1., BlendMode::UseAlpha);
 	} else {
-		target->blit_blended(
-		   Rect(dst.x, dst.y, srcrc.w, srcrc.h), *frames_.at(idx), *pcmasks_.at(idx), srcrc, *clr);
+		target->blit_blended(dstrc, *frames_.at(idx), *pcmasks_.at(idx), srcrc, *clr);
 	}
 }
 

=== modified file 'src/graphic/animation.h'
--- src/graphic/animation.h	2016-08-04 15:49:05 +0000
+++ src/graphic/animation.h	2016-10-22 18:17:28 +0000
@@ -29,8 +29,8 @@
 #include <boost/utility.hpp>
 
 #include "base/macros.h"
-#include "base/point.h"
 #include "base/rect.h"
+#include "base/vector.h"
 
 class Image;
 class LuaTable;
@@ -68,7 +68,7 @@
 
 	/// The hotspot of this animation. Note that this is ignored when blitting,
 	/// so the caller has to adjust for the hotspot himself.
-	virtual const Point& hotspot() const = 0;
+	virtual const Vector2i& hotspot() const = 0;
 
 	/// An image of the first frame, blended with the given player color.
 	/// The 'clr' is the player color used for blending - the parameter can be
@@ -83,8 +83,11 @@
 	/// color used for blitting - the parameter can be 'nullptr', in which case the
 	/// neutral image will be blitted. The Surface is the target for the blit
 	/// operation and must be non-null.
-	virtual void
-	blit(uint32_t time, const Point&, const Rect& srcrc, const RGBColor* clr, Surface*) const = 0;
+	virtual void blit(uint32_t time,
+	                  const Rectf& dstrc,
+	                  const Rectf& srcrc,
+	                  const RGBColor* clr,
+	                  Surface*) const = 0;
 
 	/// Play the sound effect associated with this animation at the given time.
 	virtual void trigger_sound(uint32_t time, uint32_t stereo_position) const = 0;

=== modified file 'src/graphic/font_handler.cc'
--- src/graphic/font_handler.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/font_handler.cc	2016-10-22 18:17:28 +0000
@@ -46,16 +46,15 @@
  */
 void draw_caret(RenderTarget& dst,
                 const TextStyle& style,
-                const Point& dstpoint,
+                const Vector2f& dstpoint,
                 const std::string& text,
                 uint32_t caret_offset) {
 	int caret_x = style.calc_bare_width(text.substr(0, caret_offset));
 
 	const Image* caret_image = g_gr->images().get("images/ui_basic/caret.png");
-	Point caretpt;
+	Vector2f caretpt;
 	caretpt.x = dstpoint.x + caret_x + LINE_MARGIN - caret_image->width();
-	caretpt.y = dstpoint.y + (style.font->height() - caret_image->height()) / 2;
-
+	caretpt.y = dstpoint.y + (style.font->height() - caret_image->height()) / 2.f;
 	dst.blit(caretpt, caret_image);
 }
 
@@ -202,7 +201,7 @@
  */
 void FontHandler::draw_text(RenderTarget& dst,
                             const TextStyle& style,
-                            Point dstpoint,
+                            Vector2i dstpoint_i,
                             const std::string& text,
                             Align align,
                             uint32_t caret) {
@@ -212,10 +211,11 @@
 	copytext = i18n::make_ligatures(copytext.c_str());
 	const LineCacheEntry& lce = d->get_line(style, copytext);
 
+	Vector2f dstpoint = dstpoint_i.cast<float>();
 	UI::correct_for_align(align, lce.width + 2 * LINE_MARGIN, lce.height, &dstpoint);
 
 	if (lce.image)
-		dst.blit(Point(dstpoint.x + LINE_MARGIN, dstpoint.y), lce.image.get());
+		dst.blit(Vector2f(dstpoint.x + LINE_MARGIN, dstpoint.y), lce.image.get());
 
 	if (caret <= copytext.size())
 		draw_caret(dst, style, dstpoint, copytext, caret);
@@ -226,12 +226,13 @@
  */
 uint32_t FontHandler::draw_text_raw(RenderTarget& dst,
                                     const UI::TextStyle& style,
-                                    Point dstpoint,
+                                    Vector2i dstpoint,
                                     const std::string& text) {
 	const LineCacheEntry& lce = d->get_line(style, text);
 
-	if (lce.image)
-		dst.blit(dstpoint, lce.image.get());
+	if (lce.image) {
+		dst.blit(dstpoint.cast<float>(), lce.image.get());
+	}
 
 	return lce.width;
 }

=== modified file 'src/graphic/font_handler.h'
--- src/graphic/font_handler.h	2016-08-04 15:49:05 +0000
+++ src/graphic/font_handler.h	2016-10-22 18:17:28 +0000
@@ -24,7 +24,7 @@
 #include <memory>
 #include <string>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/align.h"
 
 class RenderTarget;
@@ -42,11 +42,11 @@
 
 	void draw_text(RenderTarget&,
 	               const TextStyle&,
-	               Point dstpoint,
+	               Vector2i dstpoint,
 	               const std::string& text,
 	               Align align = UI::Align::kCenterLeft,
 	               uint32_t caret = std::numeric_limits<uint32_t>::max());
-	uint32_t draw_text_raw(RenderTarget&, const TextStyle&, Point dstpoint, const std::string& text);
+	uint32_t draw_text_raw(RenderTarget&, const TextStyle&, Vector2i dstpoint, const std::string& text);
 
 	void get_size(const TextStyle&,
 	              const std::string& text,

=== modified file 'src/graphic/font_handler1.h'
--- src/graphic/font_handler1.h	2016-08-04 15:49:05 +0000
+++ src/graphic/font_handler1.h	2016-10-22 18:17:28 +0000
@@ -25,7 +25,7 @@
 #include <string>
 
 #include "base/macros.h"
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/align.h"
 #include "graphic/text/font_set.h"
 

=== modified file 'src/graphic/game_renderer.cc'
--- src/graphic/game_renderer.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/game_renderer.cc	2016-10-22 18:17:28 +0000
@@ -97,23 +97,214 @@
 	return brightness / 255.;
 }
 
-// Returns the road that should be rendered here. The format is like in field,
-// but this is not the physically present road, but the one that should be
-// drawn (i.e. taking into account if there is fog of war involved or road
-// building overlays enabled).
-uint8_t field_roads(const FCoords& coords,
-                    const Map& map,
-                    const EdgeOverlayManager& edge_overlay_manager,
-                    const Player* const player) {
-	uint8_t roads;
-	if (player && !player->see_all()) {
-		const Player::Field& pf = player->fields()[Map::get_index(coords, map.get_width())];
-		roads = pf.roads | edge_overlay_manager.get_overlay(coords);
-	} else {
-		roads = coords.field->get_roads();
-	}
-	roads |= edge_overlay_manager.get_overlay(coords);
-	return roads;
+void draw_objects_for_visible_field(const EditorGameBase& egbase,
+                                    const FieldsToDraw::Field& field,
+                                    const float zoom,
+                                    const DrawText draw_text,
+                                    const Player* player,
+                                    RenderTarget* dst) {
+	BaseImmovable* const imm = field.fcoords.field->get_immovable();
+	if (imm != nullptr && imm->get_positions(egbase).front() == field.fcoords) {
+		DrawText draw_text_for_this_immovable = draw_text;
+		const Player* owner = imm->get_owner();
+		if (player != nullptr && owner != nullptr && !player->see_all() &&
+		    player->is_hostile(*owner)) {
+			draw_text_for_this_immovable =
+			   static_cast<DrawText>(draw_text_for_this_immovable & ~DrawText::kStatistics);
+		}
+
+		imm->draw(
+		   egbase.get_gametime(), draw_text_for_this_immovable, field.rendertarget_pixel, zoom, dst);
+	}
+	for (Bob* bob = field.fcoords.field->get_first_bob(); bob; bob = bob->get_next_bob()) {
+		DrawText draw_text_for_this_immovable = draw_text;
+		const Player* owner = bob->get_owner();
+		if (player != nullptr && owner != nullptr && !player->see_all() &&
+		    player->is_hostile(*owner)) {
+			draw_text_for_this_immovable =
+			   static_cast<DrawText>(draw_text_for_this_immovable & ~DrawText::kStatistics);
+		}
+		bob->draw(egbase, draw_text_for_this_immovable, field.rendertarget_pixel, zoom, dst);
+	}
+}
+
+void draw_objets_for_formerly_visible_field(const FieldsToDraw::Field& field,
+                                            const Player::Field& player_field,
+                                            const float zoom,
+                                            RenderTarget* dst) {
+	if (const MapObjectDescr* const map_object_descr =
+	       player_field.map_object_descr[TCoords<>::None]) {
+		if (player_field.constructionsite.becomes) {
+			assert(field.owner != nullptr);
+			const ConstructionsiteInformation& csinf = player_field.constructionsite;
+			// draw the partly finished constructionsite
+			uint32_t anim_idx;
+			try {
+				anim_idx = csinf.becomes->get_animation("build");
+			} catch (MapObjectDescr::AnimationNonexistent&) {
+				try {
+					anim_idx = csinf.becomes->get_animation("unoccupied");
+				} catch (MapObjectDescr::AnimationNonexistent) {
+					anim_idx = csinf.becomes->get_animation("idle");
+				}
+			}
+			const Animation& anim = g_gr->animations().get_animation(anim_idx);
+			const size_t nr_frames = anim.nr_frames();
+			uint32_t cur_frame =
+			   csinf.totaltime ? csinf.completedtime * nr_frames / csinf.totaltime : 0;
+			uint32_t tanim = cur_frame * FRAME_LENGTH;
+
+			const uint16_t w = anim.width();
+			const uint16_t h = anim.height();
+			uint32_t lines = h * csinf.completedtime * nr_frames;
+			if (csinf.totaltime)
+				lines /= csinf.totaltime;
+			assert(h * cur_frame <= lines);
+			lines -= h * cur_frame;
+
+			if (cur_frame) {  // not the first frame
+				// draw the prev frame from top to where next image will be drawing
+				dst->blit_animation(field.rendertarget_pixel, zoom, anim_idx, tanim - FRAME_LENGTH,
+				                    field.owner->get_playercolor(),
+				                    Recti(Vector2i(0, 0), w, h - lines));
+			} else if (csinf.was) {
+				// Is the first frame, but there was another building here before,
+				// get its last build picture and draw it instead.
+				uint32_t a;
+				try {
+					a = csinf.was->get_animation("unoccupied");
+				} catch (MapObjectDescr::AnimationNonexistent&) {
+					a = csinf.was->get_animation("idle");
+				}
+				dst->blit_animation(field.rendertarget_pixel, zoom, a, tanim - FRAME_LENGTH,
+				                    field.owner->get_playercolor(),
+				                    Recti(Vector2i(0, 0), w, h - lines));
+			}
+			assert(lines <= h);
+			dst->blit_animation(field.rendertarget_pixel, zoom, anim_idx, tanim,
+			                    field.owner->get_playercolor(),
+			                    Recti(Vector2i(0, h - lines), w, lines));
+		} else if (upcast(const BuildingDescr, building, map_object_descr)) {
+			assert(field.owner != nullptr);
+			// this is a building therefore we either draw unoccupied or idle animation
+			uint32_t pic;
+			try {
+				pic = building->get_animation("unoccupied");
+			} catch (MapObjectDescr::AnimationNonexistent&) {
+				pic = building->get_animation("idle");
+			}
+			dst->blit_animation(
+			   field.rendertarget_pixel, zoom, pic, 0, field.owner->get_playercolor());
+		} else if (map_object_descr->type() == MapObjectType::FLAG) {
+			assert(field.owner != nullptr);
+			dst->blit_animation(field.rendertarget_pixel, zoom, field.owner->tribe().flag_animation(),
+			                    0, field.owner->get_playercolor());
+		} else if (const uint32_t pic = map_object_descr->main_animation()) {
+			if (field.owner != nullptr) {
+				dst->blit_animation(
+				   field.rendertarget_pixel, zoom, pic, 0, field.owner->get_playercolor());
+			} else {
+				dst->blit_animation(field.rendertarget_pixel, zoom, pic, 0);
+			}
+		}
+	}
+}
+
+// Draws the objects (animations & overlays).
+void draw_objects(const EditorGameBase& egbase,
+                  const float zoom,
+                  const FieldsToDraw& fields_to_draw,
+                  const Player* player,
+                  const DrawText draw_text,
+                  RenderTarget* dst) {
+	std::vector<FieldOverlayManager::OverlayInfo> overlay_info;
+	for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
+		const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
+		if (!field.all_neighbors_valid()) {
+			continue;
+		}
+
+		const FieldsToDraw::Field& rn = fields_to_draw.at(field.rn_index);
+		const FieldsToDraw::Field& bln = fields_to_draw.at(field.bln_index);
+		const FieldsToDraw::Field& brn = fields_to_draw.at(field.brn_index);
+
+		if (field.is_border) {
+			assert(field.owner != nullptr);
+			uint32_t const anim_idx = field.owner->tribe().frontier_animation();
+			if (field.vision) {
+				dst->blit_animation(
+				   field.rendertarget_pixel, zoom, anim_idx, 0, field.owner->get_playercolor());
+			}
+			for (const auto& nf : {rn, bln, brn}) {
+				if ((field.vision || nf.vision) && nf.is_border &&
+				    (field.owner == nf.owner || nf.owner == nullptr)) {
+					dst->blit_animation(middle(field.rendertarget_pixel, nf.rendertarget_pixel), zoom,
+					                    anim_idx, 0, field.owner->get_playercolor());
+				}
+			}
+		}
+
+		if (1 < field.vision) {  // Render stuff that belongs to the node.
+			draw_objects_for_visible_field(egbase, field, zoom, draw_text, player, dst);
+		} else if (field.vision == 1) {
+			// We never show census or statistics for objects in the fog.
+			assert(player != nullptr);
+			const Map& map = egbase.map();
+			const Player::Field& player_field =
+			   player->fields()[map.get_index(field.fcoords, map.get_width())];
+			draw_objets_for_formerly_visible_field(field, player_field, zoom, dst);
+		}
+
+		const FieldOverlayManager& overlay_manager = egbase.get_ibase()->field_overlay_manager();
+		{
+			overlay_info.clear();
+			overlay_manager.get_overlays(field.fcoords, &overlay_info);
+			for (const auto& overlay : overlay_info) {
+				dst->blitrect_scale(
+				   Rectf(field.rendertarget_pixel - overlay.hotspot.cast<float>() * zoom,
+				         overlay.pic->width() * zoom, overlay.pic->height() * zoom),
+				   overlay.pic, Recti(0, 0, overlay.pic->width(), overlay.pic->height()), 1.f,
+				   BlendMode::UseAlpha);
+			}
+		}
+
+		{
+			// Render overlays on the right triangle
+			overlay_info.clear();
+			overlay_manager.get_overlays(TCoords<>(field.fcoords, TCoords<>::R), &overlay_info);
+
+			Vector2f tripos(
+			   (field.rendertarget_pixel.x + rn.rendertarget_pixel.x + brn.rendertarget_pixel.x) / 3.f,
+			   (field.rendertarget_pixel.y + rn.rendertarget_pixel.y + brn.rendertarget_pixel.y) /
+			      3.f);
+			for (const auto& overlay : overlay_info) {
+				dst->blitrect_scale(Rectf(tripos - overlay.hotspot.cast<float>() * zoom,
+				                          overlay.pic->width() * zoom, overlay.pic->height() * zoom),
+				                    overlay.pic,
+				                    Recti(0, 0, overlay.pic->width(), overlay.pic->height()), 1.f,
+				                    BlendMode::UseAlpha);
+			}
+		}
+
+		{
+			// Render overlays on the D triangle
+			overlay_info.clear();
+			overlay_manager.get_overlays(TCoords<>(field.fcoords, TCoords<>::D), &overlay_info);
+
+			Vector2f tripos(
+			   (field.rendertarget_pixel.x + bln.rendertarget_pixel.x + brn.rendertarget_pixel.x) /
+			      3.f,
+			   (field.rendertarget_pixel.y + bln.rendertarget_pixel.y + brn.rendertarget_pixel.y) /
+			      3.f);
+			for (const auto& overlay : overlay_info) {
+				dst->blitrect_scale(Rectf(tripos - overlay.hotspot.cast<float>() * zoom,
+				                          overlay.pic->width() * zoom, overlay.pic->height() * zoom),
+				                    overlay.pic,
+				                    Recti(0, 0, overlay.pic->width(), overlay.pic->height()), 1.f,
+				                    BlendMode::UseAlpha);
+			}
+		}
+	}
 }
 
 }  // namespace
@@ -124,46 +315,60 @@
 GameRenderer::~GameRenderer() {
 }
 
-void GameRenderer::rendermap(RenderTarget& dst,
-                             const Widelands::EditorGameBase& egbase,
-                             const Point& view_offset,
-
-                             const Widelands::Player& player) {
-	draw(dst, egbase, view_offset, &player);
-}
-
-void GameRenderer::rendermap(RenderTarget& dst,
-                             const Widelands::EditorGameBase& egbase,
-                             const Point& view_offset) {
-	draw(dst, egbase, view_offset, nullptr);
-}
-
-void GameRenderer::draw(RenderTarget& dst,
-                        const EditorGameBase& egbase,
-                        const Point& view_offset,
-                        const Player* player) {
-	Point tl_map = dst.get_offset() + view_offset;
-
-	assert(tl_map.x >= 0);  // divisions involving negative numbers are bad
-	assert(tl_map.y >= 0);
-
-	int minfx = tl_map.x / kTriangleWidth - 1;
-	int minfy = tl_map.y / kTriangleHeight - 1;
-	int maxfx = (tl_map.x + dst.get_rect().w + (kTriangleWidth / 2)) / kTriangleWidth;
-	int maxfy = (tl_map.y + dst.get_rect().h) / kTriangleHeight;
-
-	// fudge for triangle boundary effects and for height differences
-	minfx -= 1;
-	minfy -= 1;
-	maxfx += 1;
+void GameRenderer::rendermap(const Widelands::EditorGameBase& egbase,
+                             const Vector2f& viewpoint,
+                             const float zoom,
+                             const Widelands::Player& player,
+                             const DrawText draw_text,
+                             RenderTarget* dst) {
+	draw(egbase, viewpoint, zoom, draw_text, &player, dst);
+}
+
+void GameRenderer::rendermap(const Widelands::EditorGameBase& egbase,
+                             const Vector2f& viewpoint,
+                             const float zoom,
+                             const DrawText draw_text,
+                             RenderTarget* dst) {
+	draw(egbase, viewpoint, zoom, draw_text, nullptr, dst);
+}
+
+void GameRenderer::draw(const EditorGameBase& egbase,
+                        const Vector2f& viewpoint,
+                        const float zoom,
+                        const DrawText draw_text,
+                        const Player* player,
+                        RenderTarget* dst) {
+	assert(viewpoint.x >= 0);  // divisions involving negative numbers are bad
+	assert(viewpoint.y >= 0);
+	assert(dst->get_offset().x <= 0);
+	assert(dst->get_offset().y <= 0);
+
+	int minfx = std::floor(viewpoint.x / kTriangleWidth);
+	int minfy = std::floor(viewpoint.y / kTriangleHeight);
+
+	// If a view window is partially moved outside of the display, its 'rect' is
+	// adjusted to be fully contained on the screen - i.e. x = 0 and width is
+	// made smaller. Its offset is made negativ to account for this change.
+	// To figure out which fields we need to draw, we have to add the absolute
+	// value of 'offset' to the actual dimension of the 'rect' to get to desired
+	// dimension of the 'rect'
+	const Vector2f br_map = MapviewPixelFunctions::panel_to_map(
+	   viewpoint, zoom, Vector2f(dst->get_rect().w + std::abs(dst->get_offset().x),
+	                             dst->get_rect().h + std::abs(dst->get_offset().y)));
+	int maxfx = std::ceil(br_map.x / kTriangleWidth);
+	int maxfy = std::ceil(br_map.y / kTriangleHeight);
+
+	// Adjust for triangle boundary effects and for height differences.
+	minfx -= 2;
+	maxfx += 2;
+	minfy -= 2;
 	maxfy += 10;
 
-	Surface* surface = dst.get_surface();
+	Surface* surface = dst->get_surface();
 	if (!surface)
 		return;
 
-	const Rect& bounding_rect = dst.get_rect();
-	const Point surface_offset = bounding_rect.origin() + dst.get_offset() - view_offset;
+	const Recti& bounding_rect = dst->get_rect();
 	const int surface_width = surface->width();
 	const int surface_height = surface->height();
 
@@ -171,46 +376,59 @@
 	const EdgeOverlayManager& edge_overlay_manager = egbase.get_ibase()->edge_overlay_manager();
 	const uint32_t gametime = egbase.get_gametime();
 
+	const float scale = 1.f / zoom;
 	fields_to_draw_.reset(minfx, maxfx, minfy, maxfy);
 	for (int32_t fy = minfy; fy <= maxfy; ++fy) {
 		for (int32_t fx = minfx; fx <= maxfx; ++fx) {
 			FieldsToDraw::Field& f =
 			   *fields_to_draw_.mutable_field(fields_to_draw_.calculate_index(fx, fy));
 
-			f.fx = fx;
-			f.fy = fy;
-
-			Coords coords(fx, fy);
-			int x, y;
-			MapviewPixelFunctions::get_basepix(coords, x, y);
-
-			map.normalize_coords(coords);
-			const FCoords& fcoords = map.get_fcoords(coords);
+			f.geometric_coords = Coords(fx, fy);
+
+			f.ln_index = fields_to_draw_.calculate_index(fx - 1, fy);
+			f.rn_index = fields_to_draw_.calculate_index(fx + 1, fy);
+			f.trn_index = fields_to_draw_.calculate_index(fx + (fy & 1), fy - 1);
+			f.bln_index = fields_to_draw_.calculate_index(fx + (fy & 1) - 1, fy + 1);
+			f.brn_index = fields_to_draw_.calculate_index(fx + (fy & 1), fy + 1);
 
 			// Texture coordinates for pseudo random tiling of terrain and road
 			// graphics. Since screen space X increases top-to-bottom and OpenGL
 			// increases bottom-to-top we flip the y coordinate to not have
 			// terrains and road graphics vertically mirrorerd.
-			f.texture_x = float(x) / kTextureSideLength;
-			f.texture_y = -float(y) / kTextureSideLength;
-
-			f.gl_x = f.pixel_x = x + surface_offset.x;
-			f.gl_y = f.pixel_y = y + surface_offset.y - fcoords.field->get_height() * kHeightFactor;
-			pixel_to_gl_renderbuffer(surface_width, surface_height, &f.gl_x, &f.gl_y);
-
-			f.ter_d = fcoords.field->terrain_d();
-			f.ter_r = fcoords.field->terrain_r();
-
-			f.brightness = field_brightness(fcoords, gametime, map, player);
-
-			PlayerNumber owner_number = fcoords.field->get_owned_by();
-			if (owner_number > 0) {
-				f.road_textures = &egbase.player(owner_number).tribe().road_textures();
-			} else {
-				f.road_textures = nullptr;
+			Vector2f map_pixel = MapviewPixelFunctions::to_map_pixel_ignoring_height(f.geometric_coords);
+			f.texture_coords.x = map_pixel.x / kTextureSideLength;
+			f.texture_coords.y = -map_pixel.y / kTextureSideLength;
+
+			Coords normalized = f.geometric_coords;
+			map.normalize_coords(normalized);
+			f.fcoords = map.get_fcoords(normalized);
+
+			map_pixel.y -= f.fcoords.field->get_height() * kHeightFactor;
+
+			f.rendertarget_pixel = MapviewPixelFunctions::map_to_panel(viewpoint, zoom, map_pixel);
+			f.gl_position = f.surface_pixel = f.rendertarget_pixel +
+			                                  dst->get_rect().origin().cast<float>() +
+			                                  dst->get_offset().cast<float>();
+			pixel_to_gl_renderbuffer(
+			   surface_width, surface_height, &f.gl_position.x, &f.gl_position.y);
+
+			f.brightness = field_brightness(f.fcoords, gametime, map, player);
+
+			PlayerNumber owned_by = f.fcoords.field->get_owned_by();
+			f.owner = owned_by != 0 ? &egbase.player(owned_by) : nullptr;
+			f.is_border = f.fcoords.field->is_border();
+			f.vision = 2;
+			f.roads = f.fcoords.field->get_roads();
+			if (player && !player->see_all()) {
+				const Player::Field& pf = player->fields()[map.get_index(f.fcoords, map.get_width())];
+				f.roads = pf.roads;
+				f.vision = pf.vision;
+				if (pf.vision == 1) {
+					f.owner = pf.owner != 0 ? &egbase.player(owned_by) : nullptr;
+					f.is_border = pf.border;
+				}
 			}
-
-			f.roads = field_roads(fcoords, map, edge_overlay_manager, player);
+			f.roads |= edge_overlay_manager.get_overlay(f.fcoords);
 		}
 	}
 
@@ -219,13 +437,14 @@
 	i.program_id = RenderQueue::Program::kTerrainBase;
 	i.blend_mode = BlendMode::Copy;
 	i.terrain_arguments.destination_rect =
-	   FloatRect(bounding_rect.x, surface_height - bounding_rect.y - bounding_rect.h,
+	   Rectf(bounding_rect.x, surface_height - bounding_rect.y - bounding_rect.h,
 	             bounding_rect.w, bounding_rect.h);
 	i.terrain_arguments.gametime = gametime;
 	i.terrain_arguments.renderbuffer_width = surface_width;
 	i.terrain_arguments.renderbuffer_height = surface_height;
 	i.terrain_arguments.terrains = &egbase.world().terrains();
 	i.terrain_arguments.fields_to_draw = &fields_to_draw_;
+	i.terrain_arguments.scale = scale;
 	RenderQueue::instance().enqueue(i);
 
 	// Enqueue the drawing of the dither layer.
@@ -237,191 +456,5 @@
 	i.program_id = RenderQueue::Program::kTerrainRoad;
 	RenderQueue::instance().enqueue(i);
 
-	draw_objects(dst, egbase, view_offset, player, minfx, maxfx, minfy, maxfy);
-}
-
-void GameRenderer::draw_objects(RenderTarget& dst,
-                                const EditorGameBase& egbase,
-                                const Point& view_offset,
-                                const Player* player,
-                                int minfx,
-                                int maxfx,
-                                int minfy,
-                                int maxfy) {
-	// TODO(sirver): this should use FieldsToDraw. Would simplify this function a lot.
-	static const uint32_t F = 0;
-	static const uint32_t R = 1;
-	static const uint32_t BL = 2;
-	static const uint32_t BR = 3;
-	const Map& map = egbase.map();
-
-	std::vector<FieldOverlayManager::OverlayInfo> overlay_info;
-	for (int32_t fy = minfy; fy <= maxfy; ++fy) {
-		for (int32_t fx = minfx; fx <= maxfx; ++fx) {
-			Coords ncoords(fx, fy);
-			map.normalize_coords(ncoords);
-			FCoords coords[4];
-			coords[F] = map.get_fcoords(ncoords);
-			coords[R] = map.r_n(coords[F]);
-			coords[BL] = map.bl_n(coords[F]);
-			coords[BR] = map.br_n(coords[F]);
-			Point pos[4];
-			MapviewPixelFunctions::get_basepix(Coords(fx, fy), pos[F].x, pos[F].y);
-			MapviewPixelFunctions::get_basepix(Coords(fx + 1, fy), pos[R].x, pos[R].y);
-			MapviewPixelFunctions::get_basepix(
-			   Coords(fx + (fy & 1) - 1, fy + 1), pos[BL].x, pos[BL].y);
-			MapviewPixelFunctions::get_basepix(Coords(fx + (fy & 1), fy + 1), pos[BR].x, pos[BR].y);
-			for (uint32_t d = 0; d < 4; ++d) {
-				pos[d].y -= coords[d].field->get_height() * kHeightFactor;
-				pos[d] -= view_offset;
-			}
-
-			PlayerNumber owner_number[4];
-			bool isborder[4];
-			Vision vision[4] = {2, 2, 2, 2};
-			for (uint32_t d = 0; d < 4; ++d)
-				owner_number[d] = coords[d].field->get_owned_by();
-			for (uint32_t d = 0; d < 4; ++d)
-				isborder[d] = coords[d].field->is_border();
-
-			if (player && !player->see_all()) {
-				for (uint32_t d = 0; d < 4; ++d) {
-					const Player::Field& pf =
-					   player->fields()[map.get_index(coords[d], map.get_width())];
-					vision[d] = pf.vision;
-					if (pf.vision == 1) {
-						owner_number[d] = pf.owner;
-						isborder[d] = pf.border;
-					}
-				}
-			}
-
-			if (isborder[F]) {
-				const Player& owner = egbase.player(owner_number[F]);
-				uint32_t const anim_idx = owner.tribe().frontier_animation();
-				if (vision[F])
-					dst.blit_animation(pos[F], anim_idx, 0, owner.get_playercolor());
-				for (uint32_t d = 1; d < 4; ++d) {
-					if ((vision[F] || vision[d]) && isborder[d] &&
-					    (owner_number[d] == owner_number[F] || !owner_number[d])) {
-						dst.blit_animation(middle(pos[F], pos[d]), anim_idx, 0, owner.get_playercolor());
-					}
-				}
-			}
-
-			if (1 < vision[F]) {  // Render stuff that belongs to the node.
-				if (BaseImmovable* const imm = coords[F].field->get_immovable())
-					imm->draw(egbase, dst, coords[F], pos[F]);
-				for (Bob* bob = coords[F].field->get_first_bob(); bob; bob = bob->get_next_bob())
-					bob->draw(egbase, dst, pos[F]);
-			} else if (vision[F] == 1) {
-				const Player::Field& f_pl = player->fields()[map.get_index(coords[F], map.get_width())];
-				const Player* owner = owner_number[F] ? egbase.get_player(owner_number[F]) : nullptr;
-				if (const MapObjectDescr* const map_object_descr =
-				       f_pl.map_object_descr[TCoords<>::None]) {
-					if (f_pl.constructionsite.becomes) {
-						assert(owner != nullptr);
-						const ConstructionsiteInformation& csinf = f_pl.constructionsite;
-						// draw the partly finished constructionsite
-						uint32_t anim_idx;
-						try {
-							anim_idx = csinf.becomes->get_animation("build");
-						} catch (MapObjectDescr::AnimationNonexistent&) {
-							try {
-								anim_idx = csinf.becomes->get_animation("unoccupied");
-							} catch (MapObjectDescr::AnimationNonexistent) {
-								anim_idx = csinf.becomes->get_animation("idle");
-							}
-						}
-						const Animation& anim = g_gr->animations().get_animation(anim_idx);
-						const size_t nr_frames = anim.nr_frames();
-						uint32_t cur_frame =
-						   csinf.totaltime ? csinf.completedtime * nr_frames / csinf.totaltime : 0;
-						uint32_t tanim = cur_frame * FRAME_LENGTH;
-
-						const uint16_t w = anim.width();
-						const uint16_t h = anim.height();
-						uint32_t lines = h * csinf.completedtime * nr_frames;
-						if (csinf.totaltime)
-							lines /= csinf.totaltime;
-						assert(h * cur_frame <= lines);
-						lines -= h * cur_frame;
-
-						if (cur_frame) {  // not the first frame
-							// draw the prev frame from top to where next image will be drawing
-							dst.blit_animation(pos[F], anim_idx, tanim - FRAME_LENGTH,
-							                   owner->get_playercolor(), Rect(Point(0, 0), w, h - lines));
-						} else if (csinf.was) {
-							// Is the first frame, but there was another building here before,
-							// get its last build picture and draw it instead.
-							uint32_t a;
-							try {
-								a = csinf.was->get_animation("unoccupied");
-							} catch (MapObjectDescr::AnimationNonexistent&) {
-								a = csinf.was->get_animation("idle");
-							}
-							dst.blit_animation(pos[F], a, tanim - FRAME_LENGTH, owner->get_playercolor(),
-							                   Rect(Point(0, 0), w, h - lines));
-						}
-						assert(lines <= h);
-						dst.blit_animation(pos[F], anim_idx, tanim, owner->get_playercolor(),
-						                   Rect(Point(0, h - lines), w, lines));
-					} else if (upcast(const BuildingDescr, building, map_object_descr)) {
-						assert(owner != nullptr);
-						// this is a building therefore we either draw unoccupied or idle animation
-						uint32_t pic;
-						try {
-							pic = building->get_animation("unoccupied");
-						} catch (MapObjectDescr::AnimationNonexistent&) {
-							pic = building->get_animation("idle");
-						}
-						dst.blit_animation(pos[F], pic, 0, owner->get_playercolor());
-					} else if (map_object_descr->type() == MapObjectType::FLAG) {
-						assert(owner != nullptr);
-						dst.blit_animation(
-						   pos[F], owner->tribe().flag_animation(), 0, owner->get_playercolor());
-					} else if (const uint32_t pic = map_object_descr->main_animation()) {
-						if (owner != nullptr) {
-							dst.blit_animation(pos[F], pic, 0, owner->get_playercolor());
-						} else {
-							dst.blit_animation(pos[F], pic, 0);
-						}
-					}
-				}
-			}
-
-			const FieldOverlayManager& overlay_manager = egbase.get_ibase()->field_overlay_manager();
-			{
-				overlay_info.clear();
-				overlay_manager.get_overlays(coords[F], &overlay_info);
-				for (const auto& overlay : overlay_info) {
-					dst.blit(pos[F] - overlay.hotspot, overlay.pic);
-				}
-			}
-
-			{
-				// Render overlays on the R triangle
-				overlay_info.clear();
-				overlay_manager.get_overlays(TCoords<>(coords[F], TCoords<>::R), &overlay_info);
-
-				Point tripos(
-				   (pos[F].x + pos[R].x + pos[BR].x) / 3, (pos[F].y + pos[R].y + pos[BR].y) / 3);
-				for (const auto& overlay : overlay_info) {
-					dst.blit(tripos - overlay.hotspot, overlay.pic);
-				}
-			}
-
-			{
-				// Render overlays on the D triangle
-				overlay_info.clear();
-				overlay_manager.get_overlays(TCoords<>(coords[F], TCoords<>::D), &overlay_info);
-
-				Point tripos(
-				   (pos[F].x + pos[BL].x + pos[BR].x) / 3, (pos[F].y + pos[BL].y + pos[BR].y) / 3);
-				for (const auto& overlay : overlay_info) {
-					dst.blit(tripos - overlay.hotspot, overlay.pic);
-				}
-			}
-		}
-	}
+	draw_objects(egbase, scale, fields_to_draw_, player, draw_text, dst);
 }

=== modified file 'src/graphic/game_renderer.h'
--- src/graphic/game_renderer.h	2016-08-04 15:49:05 +0000
+++ src/graphic/game_renderer.h	2016-10-22 18:17:28 +0000
@@ -23,8 +23,9 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/gl/fields_to_draw.h"
+#include "logic/map_objects/draw_text.h"
 
 namespace Widelands {
 class Player;
@@ -33,51 +34,39 @@
 
 class RenderTarget;
 
-/**
- * This abstract base class renders the main game view into an
- * arbitrary @ref RenderTarget.
- *
- * Specializations exist for SDL software rendering and for OpenGL rendering.
- *
- * Users of this class should keep instances alive for as long as possible,
- * so that target-specific optimizations (such as caching data) can
- * be effective.
- */
+// Renders the MapView on screen.
 class GameRenderer {
 public:
 	GameRenderer();
 	~GameRenderer();
 
-	// Renders the map from a player's point of view into the given
-	// drawing window. 'view_offset' is the offset of the upper left
-	// corner of the window into the map, in pixels.
-	void rendermap(RenderTarget& dst,
-	               const Widelands::EditorGameBase& egbase,
-	               const Point& view_offset,
-	               const Widelands::Player& player);
+	// Renders the map from a player's point of view into the given drawing
+	// window. The 'viewpoint' is the top left screens pixel map pixel and
+	// 'scale' is the magnification of the view.
+	void rendermap(const Widelands::EditorGameBase& egbase,
+	               const Vector2f& viewpoint,
+	               float scale,
+	               const Widelands::Player& player,
+	               DrawText draw_text,
+	               RenderTarget* dst);
 
 	// Renders the map from an omniscient perspective. This is used
 	// for spectators, players that see all, and in the editor.
-	void
-	rendermap(RenderTarget& dst, const Widelands::EditorGameBase& egbase, const Point& view_offset);
+	void rendermap(const Widelands::EditorGameBase& egbase,
+	               const Vector2f& viewpoint,
+	               float scale,
+	               DrawText draw_text,
+	               RenderTarget* dst);
 
 private:
 	// Draw the map for the given parameters (see rendermap). 'player'
 	// can be nullptr in which case the whole map is drawn.
-	void draw(RenderTarget& dst,
-	          const Widelands::EditorGameBase& egbase,
-	          const Point& view_offset,
-	          const Widelands::Player* player);
-
-	// Draws the objects (animations & overlays).
-	void draw_objects(RenderTarget& dst,
-	                  const Widelands::EditorGameBase& egbase,
-	                  const Point& view_offset,
-	                  const Widelands::Player* player,
-	                  int minfx,
-	                  int maxfx,
-	                  int minfy,
-	                  int maxfy);
+	void draw(const Widelands::EditorGameBase& egbase,
+	          const Vector2f& viewpoint,
+	          float scale,
+	          DrawText draw_text,
+	          const Widelands::Player* player,
+	          RenderTarget* dst);
 
 	// This is owned and handled by us, but handed to the RenderQueue, so we
 	// basically promise that this stays valid for one frame.

=== modified file 'src/graphic/gl/blit_data.h'
--- src/graphic/gl/blit_data.h	2016-01-04 20:54:08 +0000
+++ src/graphic/gl/blit_data.h	2016-10-22 18:17:28 +0000
@@ -38,7 +38,7 @@
 	int parent_height;
 
 	// The subrect in the parent texture.
-	Rect rect;
+	Rectf rect;
 };
 
 #endif  // end of include guard: WL_GRAPHIC_GL_BLIT_DATA_H

=== modified file 'src/graphic/gl/blit_program.cc'
--- src/graphic/gl/blit_program.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/blit_program.cc	2016-10-22 18:17:28 +0000
@@ -108,8 +108,8 @@
 			const float blend_b = current_args.blend.b / 255.;
 			const float blend_a = current_args.blend.a / 255.;
 
-			const FloatRect texture_rect = to_gl_texture(current_args.texture);
-			const FloatRect mask_rect = to_gl_texture(current_args.mask);
+			const Rectf texture_rect = to_gl_texture(current_args.texture);
+			const Rectf mask_rect = to_gl_texture(current_args.mask);
 			float program_flavor = 0;
 			switch (current_args.blit_mode) {
 			case BlitMode::kDirect:
@@ -176,7 +176,7 @@
 	}
 }
 
-void BlitProgram::draw(const FloatRect& gl_dest_rect,
+void BlitProgram::draw(const Rectf& gl_dest_rect,
                        const float z_value,
                        const BlitData& texture,
                        const BlitData& mask,
@@ -186,11 +186,11 @@
 	                mask.texture_id != 0 ? BlitMode::kBlendedWithMask : BlitMode::kDirect}});
 }
 
-void BlitProgram::draw_monochrome(const FloatRect& dest_rect,
+void BlitProgram::draw_monochrome(const Rectf& dest_rect,
                                   const float z_value,
                                   const BlitData& texture,
                                   const RGBAColor& blend) {
-	draw({Arguments{dest_rect, z_value, texture, BlitData{0, 0, 0, Rect()}, blend,
+	draw({Arguments{dest_rect, z_value, texture, BlitData{0, 0, 0, Rectf()}, blend,
 	                BlendMode::UseAlpha, BlitMode::kMonochrome}});
 }
 

=== modified file 'src/graphic/gl/blit_program.h'
--- src/graphic/gl/blit_program.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/blit_program.h	2016-10-22 18:17:28 +0000
@@ -36,7 +36,7 @@
 class BlitProgram {
 public:
 	struct Arguments {
-		FloatRect destination_rect;
+		Rectf destination_rect;
 		float z_value;
 		BlitData texture;
 		BlitData mask;
@@ -53,7 +53,7 @@
 	// 'gl_texture_image' to 'gl_dest_rect' in the currently bound framebuffer. All
 	// coordinates are in the OpenGL frame. The 'texture_mask' is used to selectively apply
 	// the 'blend'. This is used for blitting player colored images.
-	void draw(const FloatRect& gl_dest_rect,
+	void draw(const Rectf& gl_dest_rect,
 	          const float z_value,
 	          const BlitData& texture,
 	          const BlitData& mask,
@@ -64,7 +64,7 @@
 	// 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All
 	// coordinates are in the OpenGL frame. The image is first converted to
 	// luminance, then all values are multiplied with blend.
-	void draw_monochrome(const FloatRect& gl_dest_rect,
+	void draw_monochrome(const Rectf& gl_dest_rect,
 	                     const float z_value,
 	                     const BlitData& blit_source,
 	                     const RGBAColor& blend);

=== modified file 'src/graphic/gl/coordinate_conversion.h'
--- src/graphic/gl/coordinate_conversion.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/coordinate_conversion.h	2016-10-22 18:17:28 +0000
@@ -38,34 +38,34 @@
 // Converts 'rect' given on a screen of 'width' x 'height' pixels into a rect
 // in opengl coordinates in a renderbuffer, i.e. in [-1, 1]. The returned
 // rectangle has positive width and height.
-inline FloatRect rect_to_gl_renderbuffer(const int width, const int height, const Rect& rect) {
+inline Rectf rect_to_gl_renderbuffer(const int width, const int height, const Rectf& rect) {
 	float left = rect.x;
 	float top = rect.y;
 	float right = rect.x + rect.w;
 	float bottom = rect.y + rect.h;
 	pixel_to_gl_renderbuffer(width, height, &left, &top);
 	pixel_to_gl_renderbuffer(width, height, &right, &bottom);
-	return FloatRect(left, bottom, right - left, top - bottom);
+	return Rectf(left, bottom, right - left, top - bottom);
 }
 
 // Converts 'rect' given on a texture of 'width' x 'height' pixels into a rect
 // in opengl coordinates in a texture, i.e. in [0, 1]. Texture pixels are sampled in their center.
 // The returned rectangle has positive width and height.
-inline FloatRect rect_to_gl_texture(const int width, const int height, const FloatRect& rect) {
+inline Rectf rect_to_gl_texture(const int width, const int height, const Rectf& rect) {
 	float left = rect.x;
 	float top = rect.y;
 	float right = rect.x + rect.w;
 	float bottom = rect.y + rect.h;
 	pixel_to_gl_texture(width, height, &left, &top);
 	pixel_to_gl_texture(width, height, &right, &bottom);
-	return FloatRect(left, bottom, right - left, top - bottom);
+	return Rectf(left, bottom, right - left, top - bottom);
 }
 
 // Convert 'blit_data' from pixel space into opengl space.
-inline FloatRect to_gl_texture(const BlitData& blit_data) {
+inline Rectf to_gl_texture(const BlitData& blit_data) {
 	return rect_to_gl_texture(
 	   blit_data.parent_width, blit_data.parent_height,
-	   FloatRect(blit_data.rect.x, blit_data.rect.y, blit_data.rect.w, blit_data.rect.h));
+	   Rectf(blit_data.rect.x, blit_data.rect.y, blit_data.rect.w, blit_data.rect.h));
 }
 
 #endif  // end of include guard: WL_GRAPHIC_GL_COORDINATE_CONVERSION_H

=== modified file 'src/graphic/gl/dither_program.cc'
--- src/graphic/gl/dither_program.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/dither_program.cc	2016-10-22 18:17:28 +0000
@@ -56,14 +56,14 @@
 
 void DitherProgram::add_vertex(const FieldsToDraw::Field& field,
                                const TrianglePoint triangle_point,
-                               const FloatPoint& texture_offset) {
+                               const Vector2f& texture_offset) {
 	vertices_.emplace_back();
 	PerVertexData& back = vertices_.back();
 
-	back.gl_x = field.gl_x;
-	back.gl_y = field.gl_y;
-	back.texture_x = field.texture_x;
-	back.texture_y = field.texture_y;
+	back.gl_x = field.gl_position.x;
+	back.gl_y = field.gl_position.y;
+	back.texture_x = field.texture_coords.x;
+	back.texture_y = field.texture_coords.y;
 	back.brightness = field.brightness;
 	back.texture_offset_x = texture_offset.x;
 	back.texture_offset_y = texture_offset.y;
@@ -98,7 +98,7 @@
 	}
 	const Widelands::TerrainDescription& other_terrain_description = terrains.get(other_terrain);
 	if (terrains.get(my_terrain).dither_layer() < other_terrain_description.dither_layer()) {
-		const FloatPoint texture_offset =
+		const Vector2f texture_offset =
 		   to_gl_texture(other_terrain_description.get_texture(gametime).blit_data()).origin();
 		add_vertex(fields_to_draw.at(idx1), TrianglePoint::kTopRight, texture_offset);
 		add_vertex(fields_to_draw.at(idx2), TrianglePoint::kTopLeft, texture_offset);
@@ -156,50 +156,49 @@
 		// The bottom right neighbor fields_to_draw is needed for both triangles
 		// associated with this field. If it is not in fields_to_draw, there is no need to
 		// draw any triangles.
-		const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
-		if (brn_index == -1) {
+		if (field.brn_index == -1) {
 			continue;
 		}
 
 		// Dithering triangles for Down triangle.
-		const int bln_index =
-		   fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
-		if (bln_index != -1) {
-			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, brn_index, current_index,
-			                             bln_index, field.ter_d, field.ter_r);
-
-			const int terrain_dd = fields_to_draw.at(bln_index).ter_r;
-			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, bln_index, brn_index,
-			                             current_index, field.ter_d, terrain_dd);
-
-			const int ln_index = fields_to_draw.calculate_index(field.fx - 1, field.fy);
-			if (ln_index != -1) {
-				const int terrain_l = fields_to_draw.at(ln_index).ter_r;
+		if (field.bln_index != -1) {
+			maybe_add_dithering_triangle(
+			   gametime, terrains, fields_to_draw, field.brn_index, current_index, field.bln_index,
+			   field.fcoords.field->terrain_d(), field.fcoords.field->terrain_r());
+
+			const int terrain_dd = fields_to_draw.at(field.bln_index).fcoords.field->terrain_r();
+			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, field.bln_index,
+			                             field.brn_index, current_index,
+			                             field.fcoords.field->terrain_d(), terrain_dd);
+
+			if (field.ln_index != -1) {
+				const int terrain_l = fields_to_draw.at(field.ln_index).fcoords.field->terrain_r();
 				maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, current_index,
-				                             bln_index, brn_index, field.ter_d, terrain_l);
+				                             field.bln_index, field.brn_index,
+				                             field.fcoords.field->terrain_d(), terrain_l);
 			}
 		}
 
 		// Dithering for right triangle.
-		const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
-		if (rn_index != -1) {
-			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, current_index, brn_index,
-			                             rn_index, field.ter_r, field.ter_d);
-			int terrain_rr = fields_to_draw.at(rn_index).ter_d;
-			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, brn_index, rn_index,
-			                             current_index, field.ter_r, terrain_rr);
+		if (field.rn_index != -1) {
+			maybe_add_dithering_triangle(
+			   gametime, terrains, fields_to_draw, current_index, field.brn_index, field.rn_index,
+			   field.fcoords.field->terrain_r(), field.fcoords.field->terrain_d());
+			int terrain_rr = fields_to_draw.at(field.rn_index).fcoords.field->terrain_d();
+			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, field.brn_index,
+			                             field.rn_index, current_index,
+			                             field.fcoords.field->terrain_r(), terrain_rr);
 
-			const int trn_index =
-			   fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy - 1);
-			if (trn_index != -1) {
-				const int terrain_u = fields_to_draw.at(trn_index).ter_d;
-				maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, rn_index,
-				                             current_index, brn_index, field.ter_r, terrain_u);
+			if (field.trn_index != -1) {
+				const int terrain_u = fields_to_draw.at(field.trn_index).fcoords.field->terrain_d();
+				maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, field.rn_index,
+				                             current_index, field.brn_index,
+				                             field.fcoords.field->terrain_r(), terrain_u);
 			}
 		}
 	}
 
 	const BlitData& blit_data = terrains.get(0).get_texture(0).blit_data();
-	const FloatRect texture_coordinates = to_gl_texture(blit_data);
+	const Rectf texture_coordinates = to_gl_texture(blit_data);
 	gl_draw(blit_data.texture_id, texture_coordinates.w, texture_coordinates.h, z_value);
 }

=== modified file 'src/graphic/gl/dither_program.h'
--- src/graphic/gl/dither_program.h	2016-01-08 21:00:39 +0000
+++ src/graphic/gl/dither_program.h	2016-10-22 18:17:28 +0000
@@ -22,7 +22,7 @@
 
 #include <memory>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/gl/fields_to_draw.h"
 #include "graphic/gl/utils.h"
 #include "logic/description_maintainer.h"
@@ -66,7 +66,7 @@
 	// this vertex.
 	void add_vertex(const FieldsToDraw::Field& field,
 	                TrianglePoint triangle_point,
-	                const FloatPoint& texture_offset);
+	                const Vector2f& texture_offset);
 
 	struct PerVertexData {
 		float gl_x;

=== modified file 'src/graphic/gl/draw_line_program.h'
--- src/graphic/gl/draw_line_program.h	2016-02-02 09:02:53 +0000
+++ src/graphic/gl/draw_line_program.h	2016-10-22 18:17:28 +0000
@@ -22,8 +22,8 @@
 
 #include <vector>
 
-#include "base/point.h"
 #include "base/rect.h"
+#include "base/vector.h"
 #include "graphic/blend_mode.h"
 #include "graphic/color.h"
 #include "graphic/gl/utils.h"

=== modified file 'src/graphic/gl/fields_to_draw.h'
--- src/graphic/gl/fields_to_draw.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/fields_to_draw.h	2016-10-22 18:17:28 +0000
@@ -26,24 +26,55 @@
 
 #include <stdint.h>
 
+#include "base/vector.h"
 #include "logic/map_objects/tribes/road_textures.h"
+#include "logic/player.h"
+#include "logic/widelands.h"
+#include "logic/widelands_geometry.h"
 
 // Helper struct that contains the data needed for drawing all fields. All
 // methods are inlined for performance reasons.
 class FieldsToDraw {
 public:
 	struct Field {
-		int fx, fy;        // geometric coordinates (i.e. map coordinates that can be out of bounds).
-		float gl_x, gl_y;  // GL Position of this field.
-		float pixel_x, pixel_y;             // Pixel position relative to top left.
-		float texture_x, texture_y;         // Texture coordinates.
-		float brightness;                   // brightness of the pixel
-		uint8_t ter_r, ter_d;               // Texture index of the right and down triangle.
-		uint8_t roads;                      // Bitmask of roads to render, see logic/roadtype.h.
-		const RoadTextures* road_textures;  // Road Textures to use for drawing.
+		Widelands::Coords geometric_coords;  // geometric coordinates (i.e. map coordinates that can
+		                                     // be out of bounds).
+		Widelands::FCoords fcoords;  // The normalized coords and the field this is refering to.
+		Vector2f gl_position;        // GL Position of this field.
+
+		// Surface pixel this will be plotted on.
+		Vector2f surface_pixel;
+
+		// Rendertarget pixel this will be plotted on. This is only different by
+		// the Rendertarget::get_rect().origin() of the view window.
+		Vector2f rendertarget_pixel;
+		Vector2f texture_coords;  // Texture coordinates.
+		float brightness;         // brightness of the pixel
+
+		// The next values are not necessarily the true data of this field, but
+		// what the player should see. For example in fog of war we always draw
+		// what we saw last.
+		uint8_t roads;  // Bitmask of roads to render, see logic/roadtype.h.
+		bool is_border;
+		Widelands::Vision vision;
+		Widelands::Player* owner;  // can be nullptr.
+
+		// Index of neighbors in this 'FieldsToDraw'. -1 if this neighbor is not
+		// contained.
+		int ln_index;
+		int rn_index;
+		int trn_index;
+		int bln_index;
+		int brn_index;
+
+		inline bool all_neighbors_valid() const {
+			return ln_index >= 0 && rn_index >= 0 && trn_index >= 0 && bln_index >= 0 &&
+			       brn_index >= 0;
+		}
 	};
 
-	FieldsToDraw() = default;
+	FieldsToDraw() {
+	}
 
 	// Resize this fields to draw for reuse.
 	void reset(int minfx, int maxfx, int minfy, int maxfy) {

=== modified file 'src/graphic/gl/fill_rect_program.cc'
--- src/graphic/gl/fill_rect_program.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/fill_rect_program.cc	2016-10-22 18:17:28 +0000
@@ -37,7 +37,7 @@
 	attr_color_ = glGetAttribLocation(gl_program_.object(), "attr_color");
 }
 
-void FillRectProgram::draw(const FloatRect& destination_rect,
+void FillRectProgram::draw(const Rectf& destination_rect,
                            const float z_value,
                            const RGBAColor& color,
                            const BlendMode blend_mode) {

=== modified file 'src/graphic/gl/fill_rect_program.h'
--- src/graphic/gl/fill_rect_program.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/fill_rect_program.h	2016-10-22 18:17:28 +0000
@@ -30,7 +30,7 @@
 class FillRectProgram {
 public:
 	struct Arguments {
-		FloatRect destination_rect;
+		Rectf destination_rect;
 		float z_value;
 		RGBAColor color;
 		BlendMode blend_mode;
@@ -41,7 +41,7 @@
 
 	// Fills a solid rect in 'color'. If blend_mode is BlendMode::UseAlpha, this
 	// will brighten the rect, if it is BlendMode::Subtract it darkens it.
-	void draw(const FloatRect& destination_rect,
+	void draw(const Rectf& destination_rect,
 	          float z_value,
 	          const RGBAColor& color,
 	          BlendMode blend_mode);

=== modified file 'src/graphic/gl/road_program.cc'
--- src/graphic/gl/road_program.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/road_program.cc	2016-10-22 18:17:28 +0000
@@ -50,6 +50,7 @@
                            const int renderbuffer_height,
                            const FieldsToDraw::Field& start,
                            const FieldsToDraw::Field& end,
+									const float scale,
                            const Widelands::RoadType road_type,
                            const Direction direction,
                            uint32_t* gl_texture) {
@@ -59,8 +60,8 @@
 	// The overshot of the road in either direction in percent.
 	static constexpr float kRoadElongationInPercent = .1;
 
-	const float delta_x = end.pixel_x - start.pixel_x;
-	const float delta_y = end.pixel_y - start.pixel_y;
+	const float delta_x = end.surface_pixel.x - start.surface_pixel.x;
+	const float delta_y = end.surface_pixel.y - start.surface_pixel.y;
 	const float vector_length = std::hypot(delta_x, delta_y);
 
 	const float road_overshoot_x = delta_x * kRoadElongationInPercent;
@@ -68,13 +69,15 @@
 
 	// Find the reciprocal unit vector, so that we can calculate start and end
 	// points for the quad that will make the road.
-	const float road_thickness_x = (-delta_y / vector_length) * kRoadThicknessInPixels;
-	const float road_thickness_y = (delta_x / vector_length) * kRoadThicknessInPixels;
+	const float road_thickness_x = (-delta_y / vector_length) * kRoadThicknessInPixels * scale;
+	const float road_thickness_y = (delta_x / vector_length) * kRoadThicknessInPixels * scale;
 
+	assert(start.owner != nullptr);
 	const Image& texture =
 	   road_type == Widelands::RoadType::kNormal ?
-	      start.road_textures->get_normal_texture(start.fx, start.fy, direction) :
-	      start.road_textures->get_busy_texture(start.fx, start.fy, direction);
+	      start.owner->tribe().road_textures().get_normal_texture(
+	         start.geometric_coords, direction) :
+	      start.owner->tribe().road_textures().get_busy_texture(start.geometric_coords, direction);
 	if (*gl_texture == 0) {
 		*gl_texture = texture.blit_data().texture_id;
 	}
@@ -82,27 +85,27 @@
 	// one texture atlas.
 	assert(*gl_texture == texture.blit_data().texture_id);
 
-	const FloatRect texture_rect = to_gl_texture(texture.blit_data());
+	const Rectf texture_rect = to_gl_texture(texture.blit_data());
 
 	vertices_.emplace_back(PerVertexData{
-	   start.pixel_x - road_overshoot_x + road_thickness_x,
-	   start.pixel_y - road_overshoot_y + road_thickness_y, texture_rect.x, texture_rect.y,
+	   start.surface_pixel.x - road_overshoot_x + road_thickness_x,
+	   start.surface_pixel.y - road_overshoot_y + road_thickness_y, texture_rect.x, texture_rect.y,
 	   start.brightness,
 	});
 	pixel_to_gl_renderbuffer(
 	   renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
 
 	vertices_.emplace_back(PerVertexData{
-	   start.pixel_x - road_overshoot_x - road_thickness_x,
-	   start.pixel_y - road_overshoot_y - road_thickness_y, texture_rect.x,
+	   start.surface_pixel.x - road_overshoot_x - road_thickness_x,
+	   start.surface_pixel.y - road_overshoot_y - road_thickness_y, texture_rect.x,
 	   texture_rect.y + texture_rect.h, start.brightness,
 	});
 	pixel_to_gl_renderbuffer(
 	   renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
 
 	vertices_.emplace_back(PerVertexData{
-	   end.pixel_x + road_overshoot_x + road_thickness_x,
-	   end.pixel_y + road_overshoot_y + road_thickness_y, texture_rect.x + texture_rect.w,
+	   end.surface_pixel.x + road_overshoot_x + road_thickness_x,
+	   end.surface_pixel.y + road_overshoot_y + road_thickness_y, texture_rect.x + texture_rect.w,
 	   texture_rect.y, end.brightness,
 	});
 	pixel_to_gl_renderbuffer(
@@ -116,8 +119,8 @@
 	vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
 
 	vertices_.emplace_back(PerVertexData{
-	   end.pixel_x + road_overshoot_x - road_thickness_x,
-	   end.pixel_y + road_overshoot_y - road_thickness_y, texture_rect.x + texture_rect.w,
+	   end.surface_pixel.x + road_overshoot_x - road_thickness_x,
+	   end.surface_pixel.y + road_overshoot_y - road_thickness_y, texture_rect.x + texture_rect.w,
 	   texture_rect.y + texture_rect.h, end.brightness,
 	});
 	pixel_to_gl_renderbuffer(
@@ -127,7 +130,8 @@
 void RoadProgram::draw(const int renderbuffer_width,
                        const int renderbuffer_height,
                        const FieldsToDraw& fields_to_draw,
-                       float z_value) {
+							  const float scale,
+                       const float z_value) {
 	vertices_.clear();
 
 	uint32_t gl_texture = 0;
@@ -135,36 +139,32 @@
 		const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
 
 		// Road to right neighbor.
-		const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
-		if (rn_index != -1) {
+		if (field.rn_index != -1) {
 			const Widelands::RoadType road =
 			   static_cast<Widelands::RoadType>(field.roads & Widelands::RoadType::kMask);
 			if (road != Widelands::RoadType::kNone) {
-				add_road(renderbuffer_width, renderbuffer_height, field, fields_to_draw.at(rn_index),
-				         road, kEast, &gl_texture);
+				add_road(renderbuffer_width, renderbuffer_height, field, fields_to_draw.at(field.rn_index),
+				         scale, road, kEast, &gl_texture);
 			}
 		}
 
 		// Road to bottom right neighbor.
-		const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
-		if (brn_index != -1) {
+		if (field.brn_index != -1) {
 			const Widelands::RoadType road =
 			   static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::RoadType::kMask);
 			if (road != Widelands::RoadType::kNone) {
-				add_road(renderbuffer_width, renderbuffer_height, field, fields_to_draw.at(brn_index),
-				         road, kSouthEast, &gl_texture);
+				add_road(renderbuffer_width, renderbuffer_height, field, fields_to_draw.at(field.brn_index),
+				         scale, road, kSouthEast, &gl_texture);
 			}
 		}
 
 		// Road to bottom right neighbor.
-		const int bln_index =
-		   fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
-		if (bln_index != -1) {
+		if (field.bln_index != -1) {
 			const Widelands::RoadType road =
 			   static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::RoadType::kMask);
 			if (road != Widelands::RoadType::kNone) {
-				add_road(renderbuffer_width, renderbuffer_height, field, fields_to_draw.at(bln_index),
-				         road, kSouthWest, &gl_texture);
+				add_road(renderbuffer_width, renderbuffer_height, field,
+				         fields_to_draw.at(field.bln_index), scale, road, kSouthWest, &gl_texture);
 			}
 		}
 	}

=== modified file 'src/graphic/gl/road_program.h'
--- src/graphic/gl/road_program.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/road_program.h	2016-10-22 18:17:28 +0000
@@ -42,6 +42,7 @@
 	void draw(int renderbuffer_width,
 	          int renderbuffer_height,
 	          const FieldsToDraw& fields_to_draw,
+				 float scale,
 	          float z_value);
 
 private:
@@ -61,6 +62,7 @@
 	              int renderbuffer_height,
 	              const FieldsToDraw::Field& start,
 	              const FieldsToDraw::Field& end,
+					  float scale,
 	              const Widelands::RoadType road_type,
 	              const Direction direction,
 	              uint32_t* gl_texture);

=== modified file 'src/graphic/gl/terrain_program.cc'
--- src/graphic/gl/terrain_program.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/terrain_program.cc	2016-10-22 18:17:28 +0000
@@ -71,15 +71,15 @@
 }
 
 void TerrainProgram::add_vertex(const FieldsToDraw::Field& field,
-                                const FloatPoint& texture_offset) {
+                                const Vector2f& texture_offset) {
 	vertices_.emplace_back();
 	PerVertexData& back = vertices_.back();
 
-	back.gl_x = field.gl_x;
-	back.gl_y = field.gl_y;
+	back.gl_x = field.gl_position.x;
+	back.gl_y = field.gl_position.y;
 	back.brightness = field.brightness;
-	back.texture_x = field.texture_x;
-	back.texture_y = field.texture_y;
+	back.texture_x = field.texture_coords.x;
+	back.texture_y = field.texture_coords.y;
 	back.texture_offset_x = texture_offset.x;
 	back.texture_offset_y = texture_offset.y;
 }
@@ -101,34 +101,34 @@
 		// The bottom right neighbor fields_to_draw is needed for both triangles
 		// associated with this field. If it is not in fields_to_draw, there is no need to
 		// draw any triangles.
-		const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
-		if (brn_index == -1) {
+		if (field.brn_index == -1) {
 			continue;
 		}
 
 		// Down triangle.
-		const int bln_index =
-		   fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
-		if (bln_index != -1) {
-			const FloatPoint texture_offset =
-			   to_gl_texture(terrains.get(field.ter_d).get_texture(gametime).blit_data()).origin();
+		if (field.bln_index != -1) {
+			const Vector2f texture_offset =
+			   to_gl_texture(
+			      terrains.get(field.fcoords.field->terrain_d()).get_texture(gametime).blit_data())
+			      .origin();
 			add_vertex(fields_to_draw.at(current_index), texture_offset);
-			add_vertex(fields_to_draw.at(bln_index), texture_offset);
-			add_vertex(fields_to_draw.at(brn_index), texture_offset);
+			add_vertex(fields_to_draw.at(field.bln_index), texture_offset);
+			add_vertex(fields_to_draw.at(field.brn_index), texture_offset);
 		}
 
 		// Right triangle.
-		const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
-		if (rn_index != -1) {
-			const FloatPoint texture_offset =
-			   to_gl_texture(terrains.get(field.ter_r).get_texture(gametime).blit_data()).origin();
+		if (field.rn_index != -1) {
+			const Vector2f texture_offset =
+			   to_gl_texture(
+			      terrains.get(field.fcoords.field->terrain_r()).get_texture(gametime).blit_data())
+			      .origin();
 			add_vertex(fields_to_draw.at(current_index), texture_offset);
-			add_vertex(fields_to_draw.at(brn_index), texture_offset);
-			add_vertex(fields_to_draw.at(rn_index), texture_offset);
+			add_vertex(fields_to_draw.at(field.brn_index), texture_offset);
+			add_vertex(fields_to_draw.at(field.rn_index), texture_offset);
 		}
 	}
 
 	const BlitData& blit_data = terrains.get(0).get_texture(0).blit_data();
-	const FloatRect texture_coordinates = to_gl_texture(blit_data);
+	const Rectf texture_coordinates = to_gl_texture(blit_data);
 	gl_draw(blit_data.texture_id, texture_coordinates.w, texture_coordinates.h, z_value);
 }

=== modified file 'src/graphic/gl/terrain_program.h'
--- src/graphic/gl/terrain_program.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/terrain_program.h	2016-10-22 18:17:28 +0000
@@ -22,7 +22,7 @@
 
 #include <vector>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/gl/fields_to_draw.h"
 #include "graphic/gl/utils.h"
 #include "logic/description_maintainer.h"
@@ -54,7 +54,7 @@
 	void gl_draw(int gl_texture, float texture_w, float texture_h, float z_value);
 
 	// Adds a vertex to the end of vertices with data from 'field' and 'texture_coordinates'.
-	void add_vertex(const FieldsToDraw::Field& field, const FloatPoint& texture_coordinates);
+	void add_vertex(const FieldsToDraw::Field& field, const Vector2f& texture_coordinates);
 
 	// The program used for drawing the terrain.
 	Gl::Program gl_program_;

=== modified file 'src/graphic/minimap_renderer.cc'
--- src/graphic/minimap_renderer.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/minimap_renderer.cc	2016-10-22 18:17:28 +0000
@@ -25,13 +25,9 @@
 #include "economy/flag.h"
 #include "economy/road.h"
 #include "graphic/graphic.h"
-#include "graphic/image_io.h"
-#include "graphic/texture.h"
 #include "logic/field.h"
-#include "logic/map.h"
 #include "logic/map_objects/world/terrain_description.h"
 #include "logic/map_objects/world/world.h"
-#include "logic/player.h"
 #include "wui/mapviewpixelconstants.h"
 #include "wui/mapviewpixelfunctions.h"
 
@@ -40,12 +36,17 @@
 namespace {
 
 const RGBColor kWhite(255, 255, 255);
+const RGBColor kRed(255, 0, 0);
 
 // Blend two colors.
 inline RGBColor blend_color(const RGBColor& c1, const RGBColor& c2) {
 	return RGBColor((c1.r + c2.r) / 2, (c1.g + c2.g) / 2, (c1.b + c2.b) / 2);
 }
 
+int round_up_to_nearest_even(int number) {
+	return number % 2 == 0 ? number : number + 1;
+}
+
 // Returns the color to be used in the minimap for the given field.
 inline RGBColor calc_minimap_color(const Widelands::EditorGameBase& egbase,
                                    const Widelands::FCoords& f,
@@ -85,83 +86,81 @@
 	return color;
 }
 
-// Draws the dotted frame border onto the minimap.
-bool is_minimap_frameborder(const Widelands::FCoords& f,
-                            const Point& ptopleft,
-                            const Point& pbottomright,
-                            int32_t mapwidth,
-                            int32_t mapheight,
-                            int32_t modx,
-                            int32_t mody) {
-	bool isframepixel = false;
-
-	if (ptopleft.x <= pbottomright.x) {
-		if (f.x >= ptopleft.x && f.x <= pbottomright.x &&
-		    (f.y == ptopleft.y || f.y == pbottomright.y) && f.x % 2 == modx)
-			isframepixel = true;
-	} else {
-		if (((f.x >= ptopleft.x && f.x <= mapwidth) || (f.x >= 0 && f.x <= pbottomright.x)) &&
-		    (f.y == ptopleft.y || f.y == pbottomright.y) && (f.x % 2) == modx)
-			isframepixel = true;
-	}
-
-	if (ptopleft.y <= pbottomright.y) {
-		if (f.y >= ptopleft.y && f.y <= pbottomright.y &&
-		    (f.x == ptopleft.x || f.x == pbottomright.x) && f.y % 2 == mody)
-			isframepixel = true;
-	} else {
-		if (((f.y >= ptopleft.y && f.y <= mapheight) || (f.y >= 0 && f.y <= pbottomright.y)) &&
-		    (f.x == ptopleft.x || f.x == pbottomright.x) && f.y % 2 == mody)
-			isframepixel = true;
-	}
-
-	return isframepixel;
+void draw_view_window(const Map& map,
+                      const Rectf& view_area,
+                      const MiniMapType minimap_type,
+                      const bool zoom,
+                      Texture* texture) {
+	const float divider = zoom ? 1.f : 2.f;
+	const int half_width = round_up_to_nearest_even(std::ceil(view_area.w / kTriangleWidth / divider));
+	const int half_height = round_up_to_nearest_even(std::ceil(view_area.h / kTriangleHeight / divider));
+
+	Vector2i center_pixel;
+	switch (minimap_type) {
+		case MiniMapType::kStaticViewWindow:
+		   center_pixel = Vector2i(texture->width() / 2, texture->height() / 2);
+		   break;
+
+		case MiniMapType::kStaticMap: {
+		   Vector2i origin = round(view_area.center());
+		   MapviewPixelFunctions::normalize_pix(map, &origin);
+		   center_pixel =
+		      Vector2i(origin.x / kTriangleWidth, origin.y / kTriangleHeight) * (zoom ? 2 : 1);
+		   break;
+	   }
+	}
+
+	const int width = zoom ? map.get_width() * 2 : map.get_width();
+	const int height = zoom ? map.get_height() * 2 : map.get_height();
+	const auto make_red = [width, height, &texture](int x, int y) {
+		if (x < 0) {
+			x += width;
+		}
+		if (x >= width) {
+			x -= width;
+		}
+		if (y < 0) {
+			y += height;
+		}
+		if (y >= height) {
+			y -= height;
+		}
+		texture->set_pixel(x, y, kRed);
+	};
+
+	bool draw = true;
+	for (int y = -half_height; y <= half_height; ++y) {
+		if (draw) {
+			make_red(-half_width + center_pixel.x, y + center_pixel.y);
+			make_red(half_width + center_pixel.x, y + center_pixel.y);
+		}
+		draw = !draw;
+	}
+
+	draw = true;
+	for (int x = -half_width; x <= half_width; ++x) {
+		if (draw) {
+			make_red(x + center_pixel.x, -half_height + center_pixel.y);
+			make_red(x + center_pixel.x, half_height + center_pixel.y);
+		}
+		draw = !draw;
+	}
 }
 
 // Does the actual work of drawing the minimap.
-void draw_minimap_int(Texture* texture,
-                      const Widelands::EditorGameBase& egbase,
-                      const Widelands::Player* player,
-                      const Point& viewpoint,
-                      MiniMapLayer layers) {
+void do_draw_minimap(Texture* texture,
+                     const Widelands::EditorGameBase& egbase,
+                     const Widelands::Player* player,
+                     const Vector2i& top_left,
+                     MiniMapLayer layers) {
 	const Widelands::Map& map = egbase.map();
-
 	const uint16_t surface_h = texture->height();
 	const uint16_t surface_w = texture->width();
-
-	// size of the display frame
-	int32_t xsize = g_gr->get_xres() / kTriangleWidth / 2;
-	int32_t ysize = g_gr->get_yres() / kTriangleHeight / 2;
-
 	const int32_t mapwidth = egbase.get_map().get_width();
-	const int32_t mapheight = map.get_height();
-
-	Point ptopleft;  // top left point of the current display frame
-	ptopleft.x = viewpoint.x + mapwidth / 2 - xsize;
-	if (ptopleft.x < 0) {
-		ptopleft.x += mapwidth;
-	}
-	ptopleft.y = viewpoint.y + mapheight / 2 - ysize;
-	if (ptopleft.y < 0) {
-		ptopleft.y += mapheight;
-	}
-
-	Point pbottomright;  // bottom right point of the current display frame
-	pbottomright.x = viewpoint.x + mapwidth / 2 + xsize;
-	if (pbottomright.x >= mapwidth) {
-		pbottomright.x -= mapwidth;
-	}
-	pbottomright.y = viewpoint.y + mapheight / 2 + ysize;
-	if (pbottomright.y >= mapheight) {
-		pbottomright.y -= mapheight;
-	}
-
-	uint32_t modx = pbottomright.x % 2;
-	uint32_t mody = pbottomright.y % 2;
 
 	for (uint32_t y = 0; y < surface_h; ++y) {
 		Widelands::FCoords f(
-		   Widelands::Coords(viewpoint.x, viewpoint.y + (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
+		   Widelands::Coords(top_left.x, top_left.y + (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
 		map.normalize_coords(f);
 		f.field = &map[f];
 		Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);
@@ -170,30 +169,19 @@
 				move_r(mapwidth, f, i);
 			}
 
-			RGBColor pixel_color;
-			if ((layers & MiniMapLayer::ViewWindow) &&
-			    is_minimap_frameborder(f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {
-				pixel_color = RGBColor(255, 0, 0);
-			} else {
-				uint16_t vision =
-				   0;  // See Player::Field::Vision: 1 if seen once, > 1 if seen right now.
-				Widelands::PlayerNumber owner = 0;
-				if (player == nullptr || player->see_all()) {
-					vision = 2;  // Seen right now.
-					owner = f.field->get_owned_by();
-				} else if (player != nullptr) {
-					const auto& field = player->fields()[i];
-					vision = field.vision;
-					owner = field.owner;
-				}
-
-				if (vision > 0) {
-					pixel_color = calc_minimap_color(egbase, f, layers, owner, vision > 1);
-				}
+			uint16_t vision = 0;  // See Player::Field::Vision: 1 if seen once, > 1 if seen right now.
+			Widelands::PlayerNumber owner = 0;
+			if (player == nullptr || player->see_all()) {
+				vision = 2;  // Seen right now.
+				owner = f.field->get_owned_by();
+			} else if (player != nullptr) {
+				const auto& field = player->fields()[i];
+				vision = field.vision;
+				owner = field.owner;
 			}
 
-			if (pixel_color.r != 0 || pixel_color.g != 0 || pixel_color.b != 0) {
-				texture->set_pixel(x, y, pixel_color);
+			if (vision > 0) {
+				texture->set_pixel(x, y, calc_minimap_color(egbase, f, layers, owner, vision > 1));
 			}
 		}
 	}
@@ -201,11 +189,38 @@
 
 }  // namespace
 
+Vector2i minimap_pixel_to_mappixel(const Widelands::Map& map,
+                                const Vector2i& minimap_pixel,
+                                const Rectf& view_area,
+                                MiniMapType minimap_type,
+										  const bool zoom) {
+	Vector2f top_left;
+	switch (minimap_type) {
+		case MiniMapType::kStaticViewWindow:
+			top_left =
+			view_area.center() -
+			Vector2f(map.get_width() * kTriangleWidth, map.get_height() * kTriangleHeight) / 2.f;
+			break;
+
+		case MiniMapType::kStaticMap:
+			top_left = Vector2f(0., 0.);
+			break;
+	}
+
+	const float multiplier = zoom ? 2.f : 1.f;
+	Vector2i map_pixel =
+	   round(top_left + Vector2f(minimap_pixel.x / multiplier * kTriangleWidth,
+	                               minimap_pixel.y / multiplier * kTriangleHeight));
+	MapviewPixelFunctions::normalize_pix(map, &map_pixel);
+	return map_pixel;
+}
+
 std::unique_ptr<Texture> draw_minimap(const EditorGameBase& egbase,
                                       const Player* player,
-                                      const Point& viewpoint,
+                                      const Rectf& view_area,
+                                      const MiniMapType& minimap_type,
                                       MiniMapLayer layers) {
-	// TODO(unknown): Currently the minimap is redrawn every frame. That is not really
+	// TODO(sirver): Currently the minimap is redrawn every frame. That is not really
 	//       necesary. The created texture could be cached and only redrawn two
 	//       or three times per second
 	const Map& map = egbase.map();
@@ -214,44 +229,22 @@
 
 	std::unique_ptr<Texture> texture(new Texture(map_w, map_h));
 
-	texture->fill_rect(Rect(0, 0, texture->width(), texture->height()), RGBAColor(0, 0, 0, 255));
+	texture->fill_rect(Rectf(0, 0, texture->width(), texture->height()), RGBAColor(0, 0, 0, 255));
+
+	// Center the view on the middle of the 'view_area'.
+	const bool zoom = layers & MiniMapLayer::Zoom2;
+	Vector2i top_left = minimap_pixel_to_mappixel(map, Vector2i(0, 0), view_area, minimap_type, zoom);
+	const Coords node =
+	   MapviewPixelFunctions::calc_node_and_triangle(map, top_left.x, top_left.y).node;
 
 	texture->lock();
-	draw_minimap_int(texture.get(), egbase, player, viewpoint, layers);
+	do_draw_minimap(
+	   texture.get(), egbase, player, Vector2i(node.x, node.y), layers);
+
+	if (layers & MiniMapLayer::ViewWindow) {
+		draw_view_window(map, view_area, minimap_type, zoom, texture.get());
+	}
 	texture->unlock(Texture::Unlock_Update);
 
 	return texture;
 }
-
-void write_minimap_image(const EditorGameBase& egbase,
-                         const Player* player,
-                         const Point& gviewpoint,
-                         MiniMapLayer layers,
-                         ::StreamWrite* const streamwrite) {
-	assert(streamwrite != nullptr);
-
-	Point viewpoint(gviewpoint);
-
-	// map dimension
-	const int16_t map_w = egbase.get_map().get_width();
-	const int16_t map_h = egbase.get_map().get_height();
-	const int32_t maxx = MapviewPixelFunctions::get_map_end_screen_x(egbase.get_map());
-	const int32_t maxy = MapviewPixelFunctions::get_map_end_screen_y(egbase.get_map());
-	// adjust the viewpoint top topleft in map coords
-	viewpoint.x += g_gr->get_xres() / 2;
-	if (viewpoint.x >= maxx) {
-		viewpoint.x -= maxx;
-	}
-	viewpoint.y += g_gr->get_yres() / 2;
-	if (viewpoint.y >= maxy) {
-		viewpoint.y -= maxy;
-	}
-	viewpoint.x /= kTriangleWidth;
-	viewpoint.y /= kTriangleHeight;
-	viewpoint.x -= map_w / 2;
-	viewpoint.y -= map_h / 2;
-
-	// Render minimap
-	std::unique_ptr<Texture> texture(draw_minimap(egbase, player, viewpoint, layers));
-	save_to_png(texture.get(), streamwrite, ColorType::RGBA);
-}

=== modified file 'src/graphic/minimap_renderer.h'
--- src/graphic/minimap_renderer.h	2016-08-04 15:49:05 +0000
+++ src/graphic/minimap_renderer.h	2016-10-22 18:17:28 +0000
@@ -22,15 +22,12 @@
 
 #include <memory>
 
-#include "base/point.h"
-
-class StreamWrite;
-class Texture;
-
-namespace Widelands {
-class Player;
-class EditorGameBase;
-}
+#include "base/rect.h"
+#include "base/vector.h"
+#include "graphic/texture.h"
+#include "logic/editor_game_base.h"
+#include "logic/map.h"
+#include "logic/player.h"
 
 // Layers for selecting what do display on the minimap.
 enum class MiniMapLayer {
@@ -54,20 +51,31 @@
 	return MiniMapLayer(static_cast<int>(left) ^ static_cast<int>(right));
 }
 
-/// Render the minimap. If player is not nullptr, it renders from that player's
-/// point of view.
-/// \param viewpoint top left corner in map coordinates
+enum class MiniMapType {
+	// Keep the view window always in the center of the minimap and pan the underlying map.
+	kStaticViewWindow,
+
+	// Always align the map at (0, 0) and move the view window instead.
+	kStaticMap,
+};
+
+// Converts between minimap pixel and map pixel.
+// Remember to call 'normalize_pix' after applying the transformation.
+Vector2i minimap_pixel_to_mappixel(const Widelands::Map& map,
+                                const Vector2i& minimap_pixel,
+                                const Rectf& view_area,
+                                MiniMapType minimap_type,
+										  const bool zoom);
+
+// Render the minimap. If player is not nullptr, it renders from that player's
+// point of view. The 'view_area' designates the currently visible area in the
+// main view in map pixel coordinates and is used to draw the wire frame view
+// window. The 'view_point' is map pixel that will be drawn as the top-left
+// point in the resulting minimap.
 std::unique_ptr<Texture> draw_minimap(const Widelands::EditorGameBase& egbase,
                                       const Widelands::Player* player,
-                                      const Point& viewpoint,
+                                      const Rectf& view_area,
+                                      const MiniMapType& map_draw_type,
                                       MiniMapLayer layers);
 
-/// Render the minimap to a file. 1 pixel will be used for each fields.
-/// \param viewpoint : The game point of view as returned by interactive_base.get_viewpoint();
-void write_minimap_image(const Widelands::EditorGameBase& egbase,
-                         Widelands::Player const* player,
-                         const Point& viewpoint,
-                         MiniMapLayer layers,
-                         StreamWrite* const streamwrite);
-
 #endif  // end of include guard: WL_GRAPHIC_MINIMAP_RENDERER_H

=== modified file 'src/graphic/render_queue.cc'
--- src/graphic/render_queue.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/render_queue.cc	2016-10-22 18:17:28 +0000
@@ -120,14 +120,14 @@
 // creation. Disables GL_SCISSOR_TEST at desctruction again.
 class ScopedScissor {
 public:
-	ScopedScissor(const FloatRect& rect);
+	ScopedScissor(const Rectf& rect);
 	~ScopedScissor();
 
 private:
 	DISALLOW_COPY_AND_ASSIGN(ScopedScissor);
 };
 
-ScopedScissor::ScopedScissor(const FloatRect& rect) {
+ScopedScissor::ScopedScissor(const Rectf& rect) {
 	glScissor(rect.x, rect.y, rect.w, rect.h);
 	glEnable(GL_SCISSOR_TEST);
 }
@@ -233,7 +233,7 @@
 			break;
 
 		case Program::kTerrainBase: {
-			ScopedScissor scoped_scissor(item.terrain_arguments.destination_rect);
+			// ScopedScissor scoped_scissor(item.terrain_arguments.destination_rect);
 			terrain_program_->draw(item.terrain_arguments.gametime, *item.terrain_arguments.terrains,
 			                       *item.terrain_arguments.fields_to_draw, item.z_value);
 			++i;
@@ -249,9 +249,10 @@
 
 		case Program::kTerrainRoad: {
 			ScopedScissor scoped_scissor(item.terrain_arguments.destination_rect);
-			road_program_->draw(
-			   item.terrain_arguments.renderbuffer_width, item.terrain_arguments.renderbuffer_height,
-			   *item.terrain_arguments.fields_to_draw, item.z_value + 2 * kOpenGlZDelta);
+			road_program_->draw(item.terrain_arguments.renderbuffer_width,
+			                    item.terrain_arguments.renderbuffer_height,
+			                    *item.terrain_arguments.fields_to_draw, item.terrain_arguments.scale,
+			                    item.z_value + 2 * kOpenGlZDelta);
 			++i;
 		} break;
 

=== modified file 'src/graphic/render_queue.h'
--- src/graphic/render_queue.h	2016-08-04 15:49:05 +0000
+++ src/graphic/render_queue.h	2016-10-22 18:17:28 +0000
@@ -99,12 +99,12 @@
 		BlitData texture;
 		BlitData mask;
 		RGBAColor blend;
-		FloatRect destination_rect;
+		Rectf destination_rect;
 	};
 
 	struct RectArguments {
 		RGBAColor color;
-		FloatRect destination_rect;
+		Rectf destination_rect;
 	};
 
 	// TODO(sirver): these are really triangle arguments.
@@ -121,7 +121,8 @@
 		int renderbuffer_height;
 		const DescriptionMaintainer<Widelands::TerrainDescription>* terrains;
 		FieldsToDraw* fields_to_draw;
-		FloatRect destination_rect;
+		float scale;
+		Rectf destination_rect;
 	};
 
 	// The union of all possible program arguments represents an Item that is

=== modified file 'src/graphic/rendertarget.cc'
--- src/graphic/rendertarget.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/rendertarget.cc	2016-10-22 18:17:28 +0000
@@ -35,7 +35,7 @@
 /**
  * Sets an arbitrary drawing window.
  */
-void RenderTarget::set_window(const Rect& rc, const Point& ofs) {
+void RenderTarget::set_window(const Recti& rc, const Vector2i& ofs) {
 	rect_ = rc;
 	offset_ = ofs;
 
@@ -69,15 +69,15 @@
  * Returns false if the subwindow is invisible. In that case, the window state
  * is not changed at all. Otherwise, the function returns true.
  */
-bool RenderTarget::enter_window(const Rect& rc, Rect* previous, Point* prevofs) {
-	Rect newrect = rc;
-
-	if (clip(newrect)) {
+bool RenderTarget::enter_window(const Recti& rc, Recti* previous, Vector2i* prevofs) {
+	Rectf newrect_f = rc.cast<float>();
+	if (clip(newrect_f)) {
 		if (previous)
 			*previous = rect_;
 		if (prevofs)
 			*prevofs = offset_;
 
+		const Recti newrect = newrect_f.cast<int>();
 		// Apply the changes
 		offset_ = rc.origin() - (newrect.origin() - rect_.origin() - offset_);
 		rect_ = newrect;
@@ -104,10 +104,10 @@
 /**
  * This functions draws a line in the target
  */
-void RenderTarget::draw_line_strip(const std::vector<FloatPoint>& points,
+void RenderTarget::draw_line_strip(const std::vector<Vector2f>& points,
                                    const RGBColor& color,
                                    float line_width) {
-	std::vector<FloatPoint> adjusted_points;
+	std::vector<Vector2f> adjusted_points;
 	adjusted_points.reserve(points.size());
 	for (const auto& p : points) {
 		adjusted_points.emplace_back(p.x + offset_.x + rect_.x, p.y + offset_.y + rect_.y);
@@ -118,21 +118,21 @@
 /**
  * Clip against window and pass those primitives along to the bitmap.
  */
-void RenderTarget::draw_rect(const Rect& rect, const RGBColor& clr) {
-	Rect r(rect);
+void RenderTarget::draw_rect(const Rectf& rect, const RGBColor& clr) {
+	Rectf r(rect);
 	if (clip(r)) {
 		::draw_rect(r, clr, surface_);
 	}
 }
 
-void RenderTarget::fill_rect(const Rect& rect, const RGBAColor& clr, BlendMode blend_mode) {
-	Rect r(rect);
+void RenderTarget::fill_rect(const Rectf& rect, const RGBAColor& clr, BlendMode blend_mode) {
+	Rectf r(rect);
 	if (clip(r))
 		surface_->fill_rect(r, clr, blend_mode);
 }
 
-void RenderTarget::brighten_rect(const Rect& rect, int32_t factor) {
-	Rect r(rect);
+void RenderTarget::brighten_rect(const Rectf& rect, int32_t factor) {
+	Rectf r(rect);
 	if (clip(r))
 		surface_->brighten_rect(r, factor);
 }
@@ -142,30 +142,31 @@
  *
  * This blit function copies the pixels to the destination surface.
  */
-void RenderTarget::blit(const Point& dst,
+void RenderTarget::blit(const Vector2f& dst,
                         const Image* image,
                         BlendMode blend_mode,
                         UI::Align align) {
-	Point destination_point(dst);
+	Vector2f destination_point(dst);
 	UI::correct_for_align(align, image->width(), image->height(), &destination_point);
 
-	Rect source_rect(Point(0, 0), image->width(), image->height());
-	Rect destination_rect(destination_point.x, destination_point.y, source_rect.w, source_rect.h);
+	Rectf source_rect(Vector2i(0, 0), image->width(), image->height());
+	Rectf destination_rect(destination_point.x, destination_point.y, source_rect.w, source_rect.h);
 
 	if (to_surface_geometry(&destination_rect, &source_rect)) {
-		surface_->blit(destination_rect, *image, source_rect, 1., blend_mode);
+		constexpr float kFullyOpaque = 1.f;
+		surface_->blit(destination_rect, *image, source_rect, kFullyOpaque, blend_mode);
 	}
 }
 
-void RenderTarget::blit_monochrome(const Point& dst,
+void RenderTarget::blit_monochrome(const Vector2f& dst,
                                    const Image* image,
                                    const RGBAColor& blend_mode,
                                    UI::Align align) {
-	Point destination_point(dst);
+	Vector2f destination_point(dst);
 	UI::correct_for_align(align, image->width(), image->height(), &destination_point);
 
-	Rect source_rect(Point(0, 0), image->width(), image->height());
-	Rect destination_rect(destination_point.x, destination_point.y, source_rect.w, source_rect.h);
+	Rectf source_rect(Vector2i(0, 0), image->width(), image->height());
+	Rectf destination_rect(destination_point.x, destination_point.y, source_rect.w, source_rect.h);
 
 	if (to_surface_geometry(&destination_rect, &source_rect)) {
 		surface_->blit_monochrome(destination_rect, *image, source_rect, blend_mode);
@@ -175,38 +176,40 @@
 /**
  * Like \ref blit, but use only a sub-rectangle of the source image.
  */
-void RenderTarget::blitrect(const Point& dst,
+void RenderTarget::blitrect(const Vector2f& dst,
                             const Image* image,
-                            const Rect& gsrcrc,
+                            const Recti& gsrcrc,
                             BlendMode blend_mode) {
 	assert(0 <= gsrcrc.x);
 	assert(0 <= gsrcrc.y);
 
 	// We want to use the given srcrc, but we must make sure that we are not
 	// blitting outside of the boundaries of 'image'.
-	Rect source_rect(gsrcrc.x, gsrcrc.y, std::min<int32_t>(image->width() - gsrcrc.x, gsrcrc.w),
+	Rectf source_rect(gsrcrc.x, gsrcrc.y, std::min<int32_t>(image->width() - gsrcrc.x, gsrcrc.w),
 	                 std::min<int32_t>(image->height() - gsrcrc.y, gsrcrc.h));
-	Rect destination_rect(dst.x, dst.y, source_rect.w, source_rect.h);
+	Rectf destination_rect(dst.x, dst.y, source_rect.w, source_rect.h);
 
 	if (to_surface_geometry(&destination_rect, &source_rect)) {
 		surface_->blit(destination_rect, *image, source_rect, 1., blend_mode);
 	}
 }
 
-void RenderTarget::blitrect_scale(Rect destination_rect,
+void RenderTarget::blitrect_scale(Rectf destination_rect,
                                   const Image* image,
-                                  Rect source_rect,
+                                  Recti source_rect_i,
                                   const float opacity,
                                   const BlendMode blend_mode) {
+	Rectf source_rect = source_rect_i.cast<float>();
 	if (to_surface_geometry(&destination_rect, &source_rect)) {
 		surface_->blit(destination_rect, *image, source_rect, opacity, blend_mode);
 	}
 }
 
-void RenderTarget::blitrect_scale_monochrome(Rect destination_rect,
+void RenderTarget::blitrect_scale_monochrome(Rectf destination_rect,
                                              const Image* image,
-                                             Rect source_rect,
+                                             Recti source_rect_i,
                                              const RGBAColor& blend) {
+	Rectf source_rect = source_rect_i.cast<float>();
 	if (to_surface_geometry(&destination_rect, &source_rect)) {
 		surface_->blit_monochrome(destination_rect, *image, source_rect, blend);
 	}
@@ -218,15 +221,15 @@
  * The pixel from ofs inside image is placed at the top-left corner of
  * the filled rectangle.
  */
-void RenderTarget::tile(const Rect& rect,
+void RenderTarget::tile(const Recti& rect,
                         const Image* image,
-                        const Point& gofs,
+                        const Vector2i& gofs,
                         BlendMode blend_mode) {
 	int32_t srcw = image->width();
 	int32_t srch = image->height();
 
-	Rect r(rect);
-	Point ofs(gofs);
+	Rectf r = rect.cast<float>();
+	Vector2i ofs(gofs);
 	if (clip(r)) {
 		if (offset_.x < 0)
 			ofs.x -= offset_.x;
@@ -251,7 +254,7 @@
 		while (ty < r.h) {
 			int tx = 0;
 			int32_t tofsx = ofs.x;
-			Rect srcrc;
+			Rectf srcrc;
 
 			srcrc.y = ofs.y;
 			srcrc.h = srch - ofs.y;
@@ -266,7 +269,7 @@
 				if (tx + srcrc.w > r.w)
 					srcrc.w = r.w - tx;
 
-				const Rect dst_rect(r.x + tx, r.y + ty, srcrc.w, srcrc.h);
+				const Rectf dst_rect(r.x + tx, r.y + ty, srcrc.w, srcrc.h);
 				surface_->blit(dst_rect, *image, srcrc, 1., blend_mode);
 
 				tx += srcrc.w;
@@ -280,54 +283,50 @@
 	}
 }
 
-/**
- * Draws a frame of an animation at the given location
- * Plays sound effect that is registered with this frame (the SoundHandler
- * decides if the sound really does get played)
- *
- * \param dstx, dsty the on-screen location of the animation hot spot
- * \param animation the animation ID
- * \param time the time, in milliseconds, in the animation
- * \param player the player this object belongs to, for player colour
- * purposes. May be 0 (for example, for world objects).
- */
-// TODO(unknown): Correctly calculate the stereo position for sound effects
-// TODO(unknown): The chosen semantics of animation sound effects is problematic:
-// What if the game runs very slowly or very quickly?
-void RenderTarget::blit_animation(const Point& dst, uint32_t animation, uint32_t time) {
+void RenderTarget::blit_animation(const Vector2f& dst,
+                                  const float scale,
+                                  uint32_t animation,
+                                  uint32_t time) {
+	// TODO(unknown): Correctly calculate the stereo position for sound effects
+	// TODO(unknown): The chosen semantics of animation sound effects is problematic:
+	// What if the game runs very slowly or very quickly?
 	const Animation& anim = g_gr->animations().get_animation(animation);
-	do_blit_animation(dst, anim, time, nullptr, Rect(Point(0, 0), anim.width(), anim.height()));
+	do_blit_animation(
+	   dst, scale, anim, time, nullptr, Recti(Vector2i(0, 0), anim.width(), anim.height()));
 }
 
-void RenderTarget::blit_animation(const Point& dst,
+void RenderTarget::blit_animation(const Vector2f& dst,
+                                  const float scale,
                                   uint32_t animation,
                                   uint32_t time,
                                   const RGBColor& player_color) {
 	const Animation& anim = g_gr->animations().get_animation(animation);
 	do_blit_animation(
-	   dst, anim, time, &player_color, Rect(Point(0, 0), anim.width(), anim.height()));
+	   dst, scale, anim, time, &player_color, Recti(Vector2i(0, 0), anim.width(), anim.height()));
 }
 
-void RenderTarget::blit_animation(const Point& dst,
+void RenderTarget::blit_animation(const Vector2f& dst,
+                                  const float scale,
                                   uint32_t animation,
                                   uint32_t time,
                                   const RGBColor& player_color,
-                                  const Rect& source_rect) {
+                                  const Recti& source_rect) {
 	do_blit_animation(
-	   dst, g_gr->animations().get_animation(animation), time, &player_color, source_rect);
+	   dst, scale, g_gr->animations().get_animation(animation), time, &player_color, source_rect);
 }
 
-void RenderTarget::do_blit_animation(const Point& dst,
+void RenderTarget::do_blit_animation(const Vector2f& dst,
+                                     const float scale,
                                      const Animation& animation,
                                      uint32_t time,
                                      const RGBColor* player_color,
-                                     const Rect& source_rect) {
-	Rect destination_rect(dst.x - animation.hotspot().x + source_rect.x,
-	                      dst.y - animation.hotspot().y + source_rect.y, source_rect.w,
-	                      source_rect.h);
-	Rect srcrc(source_rect);
-	if (to_surface_geometry(&destination_rect, &srcrc)) {
-		animation.blit(time, destination_rect.origin(), srcrc, player_color, surface_);
+                                     const Recti& source_rect_i) {
+	Rectf source_rect = source_rect_i.cast<float>();
+	Rectf destination_rect(dst.x - (animation.hotspot().x - source_rect.x) * scale,
+	                      dst.y - (animation.hotspot().y - source_rect.y) * scale,
+	                      source_rect.w * scale, source_rect.h * scale);
+	if (to_surface_geometry(&destination_rect, &source_rect)) {
+		animation.blit(time, destination_rect, source_rect, player_color, surface_);
 	}
 
 	// Look if there is a sound effect registered for this frame and trigger the
@@ -355,7 +354,7 @@
  * If true is returned, r a valid rectangle that can be used.
  * If false is returned, r may not be used and may be partially modified.
  */
-bool RenderTarget::clip(Rect& r) const {
+bool RenderTarget::clip(Rectf& r) const {
 	r.x += offset_.x;
 	r.y += offset_.y;
 
@@ -397,7 +396,7 @@
  * Clip against window and source bitmap, returns false if blitting is
  * unnecessary because image is not inside the target surface.
  */
-bool RenderTarget::to_surface_geometry(Rect* destination_rect, Rect* source_rect) const {
+bool RenderTarget::to_surface_geometry(Rectf* destination_rect, Rectf* source_rect) const {
 	assert(0 <= source_rect->x);
 	assert(0 <= source_rect->y);
 	destination_rect->x += offset_.x;
@@ -409,17 +408,16 @@
 	// destination_rect, we do this by making the proportional change.
 
 	// Clipping, from the left.
-	if (destination_rect->x < 0) {
+	if (destination_rect->x < 0.f) {
 		if (destination_rect->w <= -destination_rect->x) {
 			return false;
 		}
-		// Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
-		const int source_rect_pixel_change =
-		   0.5 + -static_cast<double>(destination_rect->x) / destination_rect->w * source_rect->w;
+		const float source_rect_pixel_change =
+		   -destination_rect->x / destination_rect->w * source_rect->w;
 		source_rect->x += source_rect_pixel_change;
 		source_rect->w -= source_rect_pixel_change;
 		destination_rect->w += destination_rect->x;
-		destination_rect->x = 0;
+		destination_rect->x = 0.f;
 	}
 
 	// Clipping, from the right.
@@ -427,25 +425,23 @@
 		if (rect_.w <= destination_rect->x) {
 			return false;
 		}
-		const int new_destination_w = rect_.w - destination_rect->x;
-		// Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
+		const float new_destination_w = rect_.w - destination_rect->x;
 		source_rect->w =
-		   0.5 + static_cast<double>(new_destination_w) / destination_rect->w * source_rect->w;
+		    new_destination_w / destination_rect->w * source_rect->w;
 		destination_rect->w = new_destination_w;
 	}
 
 	// Clipping, from the top.
-	if (destination_rect->y < 0) {
+	if (destination_rect->y < 0.f) {
 		if (destination_rect->h <= -destination_rect->y) {
 			return false;
 		}
-		// Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
-		const int source_rect_pixel_change =
-		   0.5 + -static_cast<double>(destination_rect->y) / destination_rect->h * source_rect->h;
+		const float source_rect_pixel_change =
+		   -destination_rect->y / destination_rect->h * source_rect->h;
 		source_rect->y += source_rect_pixel_change;
 		source_rect->h -= source_rect_pixel_change;
 		destination_rect->h += destination_rect->y;
-		destination_rect->y = 0;
+		destination_rect->y = 0.f;
 	}
 
 	// Clipping, from the bottom.
@@ -453,13 +449,10 @@
 		if (rect_.h <= destination_rect->y) {
 			return false;
 		}
-		const int new_destination_h = rect_.h - destination_rect->y;
-		// Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
-		source_rect->h =
-		   0.5 + static_cast<double>(new_destination_h) / destination_rect->h * source_rect->h;
+		const float new_destination_h = rect_.h - destination_rect->y;
+		source_rect->h = new_destination_h / destination_rect->h * source_rect->h;
 		destination_rect->h = new_destination_h;
 	}
-
 	destination_rect->x += rect_.x;
 	destination_rect->y += rect_.y;
 	return true;

=== modified file 'src/graphic/rendertarget.h'
--- src/graphic/rendertarget.h	2016-08-04 15:49:05 +0000
+++ src/graphic/rendertarget.h	2016-10-22 18:17:28 +0000
@@ -51,31 +51,31 @@
 class RenderTarget {
 public:
 	RenderTarget(Surface*);
-	void set_window(const Rect& rc, const Point& ofs);
-	bool enter_window(const Rect& rc, Rect* previous, Point* prevofs);
+	void set_window(const Recti& rc, const Vector2i& ofs);
+	bool enter_window(const Recti& rc, Recti* previous, Vector2i* prevofs);
 
 	int32_t width() const;
 	int32_t height() const;
 
-	void draw_line_strip(const std::vector<FloatPoint>& points, const RGBColor& color, float width);
-	void draw_rect(const Rect&, const RGBColor&);
-	void fill_rect(const Rect&, const RGBAColor&, BlendMode blend_mode = BlendMode::Copy);
-	void brighten_rect(const Rect&, int32_t factor);
+	void draw_line_strip(const std::vector<Vector2f>& points, const RGBColor& color, float width);
+	void draw_rect(const Rectf&, const RGBColor&);
+	void fill_rect(const Rectf&, const RGBAColor&, BlendMode blend_mode = BlendMode::Copy);
+	void brighten_rect(const Rectf&, int32_t factor);
 
-	void blit(const Point& dst,
+	void blit(const Vector2f& dst,
 	          const Image* image,
 	          BlendMode blend_mode = BlendMode::UseAlpha,
 	          UI::Align = UI::Align::kTopLeft);
 
 	// Like blit. See MonochromeBlitProgram for details.
-	void blit_monochrome(const Point& dst,
+	void blit_monochrome(const Vector2f& dst,
 	                     const Image* image,
 	                     const RGBAColor& blend_mode,
 	                     UI::Align = UI::Align::kTopLeft);
 
-	void blitrect(const Point& dst,
+	void blitrect(const Vector2f& dst,
 	              const Image* image,
-	              const Rect& src,
+	              const Recti& src,
 	              BlendMode blend_mode = BlendMode::UseAlpha);
 
 	// Blits the 'source_rect' from 'image' into the
@@ -83,68 +83,71 @@
 	// multiplied with 'opacity' before blitting. The 'blend_mode'
 	// defines if values are blended with whats already there or just
 	// copied over.
-	// Rect's are taken by value on purpose.
-	void blitrect_scale(Rect destination_rect,
+	// Takes by value on purpose.
+	void blitrect_scale(Rectf destination_rect,
 	                    const Image* image,
-	                    Rect source_rect,
+	                    Recti source_rect,
 	                    float opacity,
 	                    BlendMode blend_mode);
 
-	// Like blitrect_scale. See MonochromeBlitProgram for details. Rect's are
-	// taken by value on purpose.
-	void blitrect_scale_monochrome(Rect destination_rect,
+	// Like blitrect_scale. See MonochromeBlitProgram for details. Takes by
+	// value on purpose.
+	void blitrect_scale_monochrome(Rectf destination_rect,
 	                               const Image* image,
-	                               Rect source_rect,
+	                               Recti source_rect,
 	                               const RGBAColor& blend);
 
-	void tile(const Rect&,
+	void tile(const Recti&,
 	          const Image* image,
-	          const Point& ofs,
+	          const Vector2i& ofs,
 	          BlendMode blend_mode = BlendMode::UseAlpha);
 
-	// Draw the 'animation' as it should appear at 'time' in this target at 'dst'. Optionally, the
-	// animation is
-	// tinted with 'player_color' and cropped to 'source_rect'.
-	void blit_animation(const Point& dst, uint32_t animation, uint32_t time);
-	void blit_animation(const Point& dst,
+	// Draw the 'animation' as it should appear at 'time' in this target at
+	// 'dst'. Optionally, the animation is tinted with 'player_color' and
+	// cropped to 'source_rect'.
+	void blit_animation(const Vector2f& dst, float scale, uint32_t animation, uint32_t time);
+	void blit_animation(const Vector2f& dst,
+	                    float scale,
 	                    uint32_t animation,
 	                    uint32_t time,
 	                    const RGBColor& player_color);
-	void blit_animation(const Point& dst,
+	void blit_animation(const Vector2f& dst,
+	                    float scale,
 	                    uint32_t animation,
 	                    uint32_t time,
 	                    const RGBColor& player_color,
-	                    const Rect& source_rect);
+	                    const Recti& source_rect);
 
 	void reset();
 
 	Surface* get_surface() const {
 		return surface_;
 	}
-	const Rect& get_rect() const {
+	const Recti& get_rect() const {
 		return rect_;
 	}
-	const Point& get_offset() const {
+	const Vector2i& get_offset() const {
 		return offset_;
 	}
 
 protected:
-	bool clip(Rect& r) const;
-	bool to_surface_geometry(Rect* destination_rect, Rect* source_rect) const;
+	bool clip(Rectf& r) const;
+	bool to_surface_geometry(Rectf* destination_rect, Rectf* source_rect) const;
 
 	// Does the actual blitting.
-	void do_blit_animation(const Point& dst,
+	void do_blit_animation(const Vector2f& dst,
+	                       const float scale,
 	                       const Animation& animation,
 	                       uint32_t time,
 	                       const RGBColor* player_color,
-	                       const Rect& source_rect);
+	                       const Recti& source_rect);
 
 	/// The target surface
 	Surface* surface_;
 	/// The current clip rectangle
-	Rect rect_;
+	Recti rect_;
 	/// Drawing offset
-	Point offset_;
+	Vector2i offset_;
 };
 
 #endif  // end of include guard: WL_GRAPHIC_RENDERTARGET_H

=== modified file 'src/graphic/richtext.cc'
--- src/graphic/richtext.cc	2016-08-04 16:24:09 +0000
+++ src/graphic/richtext.cc	2016-10-22 18:17:28 +0000
@@ -41,7 +41,7 @@
  * rectangular bounding box.
  */
 struct Element {
-	explicit Element(const Rect& bounding_box) : bbox(bounding_box) {
+	explicit Element(const Recti& bounding_box) : bbox(bounding_box) {
 	}
 	virtual ~Element() {
 	}
@@ -52,23 +52,23 @@
 	 */
 	virtual void draw(RenderTarget& dst) = 0;
 
-	Rect bbox;
+	Recti bbox;
 };
 
 struct ImageElement : Element {
-	ImageElement(const Rect& bounding_box, const Image* init_image)
+	ImageElement(const Recti& bounding_box, const Image* init_image)
 	   : Element(bounding_box), image(init_image) {
 	}
 
 	void draw(RenderTarget& dst) override {
-		dst.blit(Point(0, 0), image);
+		dst.blit(Vector2f(0, 0), image);
 	}
 
 	const Image* image;
 };
 
 struct TextlineElement : Element {
-	TextlineElement(const Rect& bounding_box,
+	TextlineElement(const Recti& bounding_box,
 	                const TextStyle& init_style,
 	                std::vector<std::string>::const_iterator words_begin,
 	                std::vector<std::string>::const_iterator words_end)
@@ -107,16 +107,16 @@
 			}
 		}
 		// Now render
-		uint32_t x = g_fh->draw_text_raw(dst, style, Point(0, 0), result_words[0]);
+		uint32_t x = g_fh->draw_text_raw(dst, style, Vector2i(0, 0), result_words[0]);
 
 		it = result_words.begin() + 1;
 		if (it != result_words.end()) {
 			do {
 				if (style.underline)
-					x += g_fh->draw_text_raw(dst, style, Point(x, 0), " ");
+					x += g_fh->draw_text_raw(dst, style, Vector2i(x, 0), " ");
 				else
 					x += spacewidth;
-				x += g_fh->draw_text_raw(dst, style, Point(x, 0), *it++);
+				x += g_fh->draw_text_raw(dst, style, Vector2i(x, 0), *it++);
 			} while (it != result_words.end());
 		}
 	}
@@ -357,7 +357,7 @@
 			if (!image)
 				continue;
 
-			Rect bbox;
+			Recti bbox;
 			bbox.x = text.images_width;
 			bbox.y = m->height;
 			bbox.w = image->width();
@@ -423,7 +423,7 @@
 				TextBuilder::Elt elt;
 				elt.miny = elt.maxy = 0;
 
-				Rect bbox;
+				Recti bbox;
 				bbox.x = text.linewidth ? text.linewidth + text.spacewidth : 0;
 				bbox.y = 0;  // filled in later
 				bbox.w = 0;
@@ -486,16 +486,16 @@
  * @note this function may draw content outside the box given offset
  * and @ref width and @ref height, if there were wrapping problems.
  */
-void RichText::draw(RenderTarget& dst, const Point& offset, bool background) {
+void RichText::draw(RenderTarget& dst, const Vector2i& offset, bool background) {
 	for (std::vector<Element*>::const_iterator elt = m->elements.begin(); elt != m->elements.end();
 	     ++elt) {
-		Rect oldbox;
-		Point oldofs;
-		Rect bbox((*elt)->bbox.origin() + offset, (*elt)->bbox.w, (*elt)->bbox.h);
+		Recti oldbox;
+		Vector2i oldofs;
+		Recti bbox((*elt)->bbox.origin() + offset, (*elt)->bbox.w, (*elt)->bbox.h);
 
 		if (dst.enter_window(bbox, &oldbox, &oldofs)) {
 			if (background)
-				dst.fill_rect(Rect(Point(0, 0), bbox.w, bbox.h), m->background_color);
+				dst.fill_rect(Rectf(0.f, 0.f, bbox.w, bbox.h), m->background_color);
 			(*elt)->draw(dst);
 			dst.set_window(oldbox, oldofs);
 		}

=== modified file 'src/graphic/richtext.h'
--- src/graphic/richtext.h	2016-08-04 15:49:05 +0000
+++ src/graphic/richtext.h	2016-10-22 18:17:28 +0000
@@ -24,7 +24,7 @@
 #include <memory>
 #include <string>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/color.h"
 
 class RenderTarget;
@@ -50,7 +50,7 @@
 	uint32_t height();
 
 	void parse(const std::string& text);
-	void draw(RenderTarget& dst, const Point& offset, bool background = false);
+	void draw(RenderTarget& dst, const Vector2i& offset, bool background = false);
 
 private:
 	std::unique_ptr<RichTextImpl> m;

=== modified file 'src/graphic/screen.cc'
--- src/graphic/screen.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/screen.cc	2016-10-22 18:17:28 +0000
@@ -53,7 +53,7 @@
 	return std::unique_ptr<Texture>(new Texture(surface));
 }
 
-void Screen::do_blit(const FloatRect& dst_rect,
+void Screen::do_blit(const Rectf& dst_rect,
                      const BlitData& texture,
                      float opacity,
                      BlendMode blend_mode) {
@@ -68,7 +68,7 @@
 	RenderQueue::instance().enqueue(i);
 }
 
-void Screen::do_blit_blended(const FloatRect& dst_rect,
+void Screen::do_blit_blended(const Rectf& dst_rect,
                              const BlitData& texture,
                              const BlitData& mask,
                              const RGBColor& blend) {
@@ -83,7 +83,7 @@
 	RenderQueue::instance().enqueue(i);
 }
 
-void Screen::do_blit_monochrome(const FloatRect& dst_rect,
+void Screen::do_blit_monochrome(const Rectf& dst_rect,
                                 const BlitData& texture,
                                 const RGBAColor& blend) {
 	RenderQueue::Item i;
@@ -105,7 +105,7 @@
 	RenderQueue::instance().enqueue(i);
 }
 
-void Screen::do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) {
+void Screen::do_fill_rect(const Rectf& dst_rect, const RGBAColor& color, BlendMode blend_mode) {
 	RenderQueue::Item i;
 	i.blend_mode = blend_mode;
 	i.program_id = RenderQueue::Program::kRect;

=== modified file 'src/graphic/screen.h'
--- src/graphic/screen.h	2016-08-04 15:49:05 +0000
+++ src/graphic/screen.h	2016-10-22 18:17:28 +0000
@@ -43,20 +43,20 @@
 	std::unique_ptr<Texture> to_texture() const;
 
 private:
-	void do_blit(const FloatRect& dst_rect,
+	void do_blit(const Rectf& dst_rect,
 	             const BlitData& texture,
 	             float opacity,
 	             BlendMode blend_mode) override;
-	void do_blit_blended(const FloatRect& dst_rect,
+	void do_blit_blended(const Rectf& dst_rect,
 	                     const BlitData& texture,
 	                     const BlitData& mask,
 	                     const RGBColor& blend) override;
-	void do_blit_monochrome(const FloatRect& dst_rect,
+	void do_blit_monochrome(const Rectf& dst_rect,
 	                        const BlitData& texture,
 	                        const RGBAColor& blend) override;
 	void do_draw_line_strip(std::vector<DrawLineProgram::PerVertexData> vertices) override;
 	void
-	do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
+	do_fill_rect(const Rectf& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
 
 	const int w_, h_;
 

=== modified file 'src/graphic/surface.cc'
--- src/graphic/surface.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/surface.cc	2016-10-22 18:17:28 +0000
@@ -26,15 +26,15 @@
 #include <SDL.h>
 
 #include "base/macros.h"
-#include "base/point.h"
 #include "base/rect.h"
+#include "base/vector.h"
 #include "graphic/gl/coordinate_conversion.h"
 #include "graphic/gl/utils.h"
 
 namespace {
 
 // Adjust 'original' so that only 'src_rect' is actually blitted.
-BlitData adjust_for_src(BlitData blit_data, const Rect& src_rect) {
+BlitData adjust_for_src(BlitData blit_data, const Rectf& src_rect) {
 	blit_data.rect.x += src_rect.x;
 	blit_data.rect.y += src_rect.y;
 	blit_data.rect.w = src_rect.w;
@@ -44,11 +44,11 @@
 
 // Get the normal of the line between 'start' and 'end'.
 template <typename PointType>
-FloatPoint calculate_line_normal(const PointType& start, const PointType& end) {
+Vector2f calculate_line_normal(const PointType& start, const PointType& end) {
 	const float dx = end.x - start.x;
 	const float dy = end.y - start.y;
 	const float len = std::hypot(dx, dy);
-	return FloatPoint(-dy / len, dx / len);
+	return Vector2f(-dy / len, dx / len);
 }
 
 // Tesselates the line made up of 'points' ino triangles and converts them into
@@ -60,7 +60,7 @@
                           int h,
                           const RGBColor& color,
                           float line_width,
-                          const std::vector<FloatPoint>& points,
+                          const std::vector<Vector2f>& points,
                           std::vector<DrawLineProgram::PerVertexData>* vertices) {
 	const float r = color.r / 255.;
 	const float g = color.g / 255.;
@@ -69,27 +69,27 @@
 	// Iterate over each line segment, i.e. all points but the last, convert
 	// them from pixel space to gl space and draw them.
 	for (size_t i = 0; i < points.size() - 1; ++i) {
-		const FloatPoint p1 = FloatPoint(points[i].x, points[i].y);
-		const FloatPoint p2 = FloatPoint(points[i + 1].x, points[i + 1].y);
+		const Vector2f p1 = Vector2f(points[i].x, points[i].y);
+		const Vector2f p2 = Vector2f(points[i + 1].x, points[i + 1].y);
 
-		const FloatPoint normal = calculate_line_normal(p1, p2);
-		const FloatPoint scaled_normal(0.5f * line_width * normal.x, 0.5f * line_width * normal.y);
+		const Vector2f normal = calculate_line_normal(p1, p2);
+		const Vector2f scaled_normal(0.5f * line_width * normal.x, 0.5f * line_width * normal.y);
 
 		// Quad points are created in rendering order for OpenGL.
 		{
-			FloatPoint p = p1 - scaled_normal;
-			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
-			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, 1.});
-		}
-
-		{
-			FloatPoint p = p2 - scaled_normal;
-			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
-			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, 1.});
-		}
-
-		{
-			FloatPoint p = p1 + scaled_normal;
+			Vector2f p = p1 - scaled_normal;
+			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
+			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, 1.});
+		}
+
+		{
+			Vector2f p = p2 - scaled_normal;
+			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
+			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, 1.});
+		}
+
+		{
+			Vector2f p = p1 + scaled_normal;
 			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
 			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, -1.});
 		}
@@ -98,7 +98,7 @@
 		vertices->push_back(vertices->at(vertices->size() - 2));
 
 		{
-			FloatPoint p = p2 + scaled_normal;
+			Vector2f p = p2 + scaled_normal;
 			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
 			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, -1.});
 		}
@@ -107,12 +107,12 @@
 
 }  // namespace
 
-void Surface::fill_rect(const Rect& rc, const RGBAColor& clr, BlendMode blend_mode) {
-	const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), rc);
+void Surface::fill_rect(const Rectf& rc, const RGBAColor& clr, BlendMode blend_mode) {
+	const Rectf rect = rect_to_gl_renderbuffer(width(), height(), rc);
 	do_fill_rect(rect, clr, blend_mode);
 }
 
-void Surface::brighten_rect(const Rect& rc, const int32_t factor) {
+void Surface::brighten_rect(const Rectf& rc, const int32_t factor) {
 	if (!factor) {
 		return;
 	}
@@ -120,11 +120,11 @@
 	const BlendMode blend_mode = factor < 0 ? BlendMode::Subtract : BlendMode::UseAlpha;
 	const int abs_factor = std::abs(factor);
 	const RGBAColor color(abs_factor, abs_factor, abs_factor, 0);
-	const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), rc);
+	const Rectf rect = rect_to_gl_renderbuffer(width(), height(), rc);
 	do_fill_rect(rect, color, blend_mode);
 }
 
-void Surface::draw_line_strip(std::vector<FloatPoint> points,
+void Surface::draw_line_strip(std::vector<Vector2f> points,
                               const RGBColor& color,
                               float line_width) {
 	if (points.size() < 2) {
@@ -138,41 +138,41 @@
 	do_draw_line_strip(std::move(vertices));
 }
 
-void Surface::blit_monochrome(const Rect& dst_rect,
+void Surface::blit_monochrome(const Rectf& dst_rect,
                               const Image& image,
-                              const Rect& src_rect,
+                              const Rectf& src_rect,
                               const RGBAColor& blend) {
-	const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
+	const Rectf rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
 	do_blit_monochrome(rect, adjust_for_src(image.blit_data(), src_rect), blend);
 }
 
-void Surface::blit_blended(const Rect& dst_rect,
+void Surface::blit_blended(const Rectf& dst_rect,
                            const Image& image,
                            const Image& texture_mask,
-                           const Rect& src_rect,
+                           const Rectf& src_rect,
                            const RGBColor& blend) {
-	const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
+	const Rectf rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
 	do_blit_blended(rect, adjust_for_src(image.blit_data(), src_rect),
 	                adjust_for_src(texture_mask.blit_data(), src_rect), blend);
 }
 
-void Surface::blit(const Rect& dst_rect,
+void Surface::blit(const Rectf& dst_rect,
                    const Image& image,
-                   const Rect& src_rect,
+                   const Rectf& src_rect,
                    float opacity,
                    BlendMode blend_mode) {
-	const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
+	const Rectf rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
 	do_blit(rect, adjust_for_src(image.blit_data(), src_rect), opacity, blend_mode);
 }
 
-void draw_rect(const Rect& rc, const RGBColor& clr, Surface* surface) {
-	const FloatPoint top_left = FloatPoint(rc.x + 0.5f, rc.y + 0.5f);
-	const FloatPoint top_right = FloatPoint(rc.x + rc.w - 0.5f, rc.y + 0.5f);
-	const FloatPoint bottom_right = FloatPoint(rc.x + rc.w - 0.5f, rc.y + rc.h - 0.5f);
-	const FloatPoint bottom_left = FloatPoint(rc.x + 0.5f, rc.y + rc.h - 0.5f);
+void draw_rect(const Rectf& rc, const RGBColor& clr, Surface* surface) {
+	const Vector2f top_left = Vector2f(rc.x + 0.5f, rc.y + 0.5f);
+	const Vector2f top_right = Vector2f(rc.x + rc.w - 0.5f, rc.y + 0.5f);
+	const Vector2f bottom_right = Vector2f(rc.x + rc.w - 0.5f, rc.y + rc.h - 0.5f);
+	const Vector2f bottom_left = Vector2f(rc.x + 0.5f, rc.y + rc.h - 0.5f);
 
 	surface->draw_line_strip({top_left, top_right, bottom_right}, clr, 1);
 	// We need to split this up in order not to miss a pixel on the bottom right corner.
 	surface->draw_line_strip(
-	   {FloatPoint(bottom_right.x + 1, bottom_right.y), bottom_left, top_left}, clr, 1);
+	   {Vector2f(bottom_right.x + 1, bottom_right.y), bottom_left, top_left}, clr, 1);
 }

=== modified file 'src/graphic/surface.h'
--- src/graphic/surface.h	2016-08-04 15:49:05 +0000
+++ src/graphic/surface.h	2016-10-22 18:17:28 +0000
@@ -46,42 +46,42 @@
 
 	/// This draws a part of 'texture'.
 	void blit(
-	   const Rect& dst, const Image&, const Rect& srcrc, const float opacity, BlendMode blend_mode);
+	   const Rectf& dst, const Image&, const Rectf& srcrc, const float opacity, BlendMode blend_mode);
 
 	/// This draws a playercolor blended image.
-	void blit_blended(const Rect& dst,
+	void blit_blended(const Rectf& dst,
 	                  const Image& image,
 	                  const Image& texture_mask,
-	                  const Rect& srcrc,
+	                  const Rectf& srcrc,
 	                  const RGBColor& blend);
 
 	/// This draws a grayed out version.
 	void
-	blit_monochrome(const Rect& dst, const Image&, const Rect& srcrc, const RGBAColor& multiplier);
+	blit_monochrome(const Rectf& dst, const Image&, const Rectf& srcrc, const RGBAColor& multiplier);
 
 	/// Draws a filled rect to the destination.
-	void fill_rect(const Rect&, const RGBAColor&, BlendMode blend_mode = BlendMode::Copy);
+	void fill_rect(const Rectf& dst, const RGBAColor&, BlendMode blend_mode = BlendMode::Copy);
 
 	// Draw a 'width' pixel wide line to the destination. 'points' are taken by
 	// value on purpose.
-	void draw_line_strip(std::vector<FloatPoint> points, const RGBColor& color, float width);
+	void draw_line_strip(std::vector<Vector2f> points, const RGBColor& color, float width);
 
 	/// makes a rectangle on the destination brighter (or darker).
-	void brighten_rect(const Rect&, int factor);
+	void brighten_rect(const Rectf&, int factor);
 
 private:
 	/// The actual implementation of the methods below.
-	virtual void do_blit(const FloatRect& dst_rect,
+	virtual void do_blit(const Rectf& dst_rect,
 	                     const BlitData& texture,
 	                     float opacity,
 	                     BlendMode blend_mode) = 0;
 
-	virtual void do_blit_blended(const FloatRect& dst_rect,
+	virtual void do_blit_blended(const Rectf& dst_rect,
 	                             const BlitData& texture,
 	                             const BlitData& mask,
 	                             const RGBColor& blend) = 0;
 
-	virtual void do_blit_monochrome(const FloatRect& dst_rect,
+	virtual void do_blit_monochrome(const Rectf& dst_rect,
 	                                const BlitData& texture,
 	                                const RGBAColor& blend) = 0;
 
@@ -90,7 +90,7 @@
 	virtual void do_draw_line_strip(std::vector<DrawLineProgram::PerVertexData> vertices) = 0;
 
 	virtual void
-	do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) = 0;
+	do_fill_rect(const Rectf& dst_rect, const RGBAColor& color, BlendMode blend_mode) = 0;
 
 	DISALLOW_COPY_AND_ASSIGN(Surface);
 };
@@ -98,6 +98,6 @@
 /// Draws a rect (frame only) to the surface. The width of the surrounding line
 /// is 1 pixel, i.e. the transparent inner box of the drawn rectangle starts at
 /// (x+1, y+1) and has dimension (w - 2, h - 2).
-void draw_rect(const Rect& rect, const RGBColor&, Surface* destination);
+void draw_rect(const Rectf& rect, const RGBColor&, Surface* destination);
 
 #endif  // end of include guard: WL_GRAPHIC_SURFACE_H

=== modified file 'src/graphic/text/rt_render.cc'
--- src/graphic/text/rt_render.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/text/rt_render.cc	2016-10-22 18:17:28 +0000
@@ -32,8 +32,8 @@
 #include "base/i18n.h"
 #include "base/log.h"
 #include "base/macros.h"
-#include "base/point.h"
 #include "base/rect.h"
+#include "base/vector.h"
 #include "base/wexception.h"
 #include "graphic/align.h"
 #include "graphic/graphic.h"
@@ -173,7 +173,7 @@
 }
 
 struct Reference {
-	Rect dim;
+	Recti dim;
 	string ref;
 };
 
@@ -185,7 +185,7 @@
 		// Should this linear algorithm proof to be too slow (doubtful), the
 		// RefMap could also be efficiently implemented using an R-Tree
 		for (const Reference& c : refs_)
-			if (c.dim.contains(Point(x, y)))
+			if (c.dim.contains(Vector2i(x, y)))
 				return c.ref;
 		return "";
 	}
@@ -469,7 +469,7 @@
 	const vector<Reference> get_references() override {
 		vector<Reference> rv;
 		if (!nodestyle_.reference.empty()) {
-			Reference r = {Rect(0, 0, w_, h_), nodestyle_.reference};
+			Reference r = {Recti(0, 0, w_, h_), nodestyle_.reference};
 			rv.push_back(r);
 		}
 		return rv;
@@ -501,7 +501,7 @@
 	const Texture& img =
 	   font_.render(txt_, nodestyle_.font_color, nodestyle_.font_style, texture_cache);
 	Texture* rv = new Texture(img.width(), img.height());
-	rv->blit(Rect(0, 0, img.width(), img.height()), img, Rect(0, 0, img.width(), img.height()), 1.,
+	rv->blit(Rectf(0, 0, img.width(), img.height()), img, Rectf(0, 0, img.width(), img.height()), 1.,
 	         BlendMode::Copy);
 	return rv;
 }
@@ -536,8 +536,8 @@
 	   font_.render(txt_, nodestyle_.font_color, nodestyle_.font_style, texture_cache);
 	Texture* rv = new Texture(w_, h_);
 	for (uint16_t curx = 0; curx < w_; curx += t.width()) {
-		Rect srcrect(Point(0, 0), min<int>(t.width(), w_ - curx), h_);
-		rv->blit(Rect(curx, 0, srcrect.w, srcrect.h), t, srcrect, 1., BlendMode::Copy);
+		Rectf srcrect(0.f, 0.f, min<int>(t.width(), w_ - curx), h_);
+		rv->blit(Rectf(curx, 0, srcrect.w, srcrect.h), t, srcrect, 1., BlendMode::Copy);
 	}
 	return rv;
 }
@@ -557,7 +557,7 @@
 	Texture* render(TextureCache* texture_cache) override {
 		if (show_spaces_) {
 			Texture* rv = new Texture(w_, h_);
-			rv->fill_rect(Rect(0, 0, w_, h_), RGBAColor(0xcc, 0, 0, 0xcc));
+			rv->fill_rect(Rectf(0, 0, w_, h_), RGBAColor(0xcc, 0, 0, 0xcc));
 			return rv;
 		}
 		return TextNode::render(texture_cache);
@@ -619,8 +619,8 @@
 
 		// Draw background image (tiling)
 		if (background_image_) {
-			Rect dst;
-			Rect srcrect(Point(0, 0), 1, 1);
+			Rectf dst;
+			Rectf srcrect(0, 0, 1, 1);
 			for (uint16_t curx = 0; curx < w_; curx += background_image_->width()) {
 				dst.x = curx;
 				dst.y = 0;
@@ -629,7 +629,7 @@
 				rv->blit(dst, *background_image_, srcrect, 1., BlendMode::Copy);
 			}
 		} else {
-			rv->fill_rect(Rect(0, 0, w_, h_), RGBAColor(255, 255, 255, 0));
+			rv->fill_rect(Rectf(0, 0, w_, h_), RGBAColor(255, 255, 255, 0));
 		}
 		return rv;
 	}
@@ -689,19 +689,19 @@
 			throw TextureTooBig(error_message);
 		}
 		Texture* rv = new Texture(width(), height());
-		rv->fill_rect(Rect(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0));
+		rv->fill_rect(Rectf(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0));
 
 		// Draw Solid background Color
 		bool set_alpha = true;
 		if (is_background_color_set_) {
-			rv->fill_rect(Rect(Point(margin_.left, margin_.top), w_, h_), background_color_);
+			rv->fill_rect(Rectf(margin_.left, margin_.top, w_, h_), background_color_);
 			set_alpha = false;
 		}
 
 		// Draw background image (tiling)
 		if (background_image_) {
-			Rect dst;
-			Rect src(0, 0, 0, 0);
+			Rectf dst;
+			Rectf src(0, 0, 0, 0);
 
 			for (uint16_t cury = margin_.top; cury < h_ + margin_.top;
 			     cury += background_image_->height()) {
@@ -720,10 +720,9 @@
 		for (RenderNode* n : nodes_to_render_) {
 			Texture* node_texture = n->render(texture_cache);
 			if (node_texture) {
-				Rect dst = Rect(n->x() + margin_.left, n->y() + margin_.top, node_texture->width(),
+				Rectf dst(n->x() + margin_.left, n->y() + margin_.top, node_texture->width(),
 				                node_texture->height());
-				Rect src = Rect(0, 0, node_texture->width(), node_texture->height());
-
+				Rectf src(0, 0, node_texture->width(), node_texture->height());
 				rv->blit(
 				   dst, *node_texture, src, 1., set_alpha ? BlendMode::Copy : BlendMode::UseAlpha);
 				delete node_texture;
@@ -754,7 +753,7 @@
 		nodes_to_render_ = n;
 	}
 	void add_reference(int16_t gx, int16_t gy, uint16_t w, uint16_t h, const string& s) {
-		Reference r = {Rect(gx, gy, w, h), s};
+		Reference r = {Recti(gx, gy, w, h), s};
 		refs_.push_back(r);
 	}
 
@@ -790,8 +789,8 @@
 
 Texture* ImgRenderNode::render(TextureCache* /* texture_cache */) {
 	Texture* rv = new Texture(image_.width(), image_.height());
-	rv->blit(Rect(0, 0, image_.width(), image_.height()), image_,
-	         Rect(0, 0, image_.width(), image_.height()), 1., BlendMode::Copy);
+	rv->blit(Rectf(0, 0, image_.width(), image_.height()), image_,
+	         Rectf(0, 0, image_.width(), image_.height()), 1., BlendMode::Copy);
 	return rv;
 }
 // End: Helper Stuff

=== modified file 'src/graphic/texture.cc'
--- src/graphic/texture.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/texture.cc	2016-10-22 18:17:28 +0000
@@ -144,14 +144,14 @@
 	SDL_FreeSurface(surface);
 }
 
-Texture::Texture(const GLuint texture, const Rect& subrect, int parent_w, int parent_h)
+Texture::Texture(const GLuint texture, const Recti& subrect, int parent_w, int parent_h)
    : owns_texture_(false) {
 	if (parent_w == 0 || parent_h == 0) {
 		throw wexception("Created a sub Texture with zero height and width parent.");
 	}
 
 	blit_data_ = BlitData{
-	   texture, parent_w, parent_h, subrect,
+	   texture, parent_w, parent_h, subrect.cast<float>(),
 	};
 }
 
@@ -172,7 +172,7 @@
 void Texture::init(uint16_t w, uint16_t h) {
 	blit_data_ = {
 	   0,  // initialized below
-	   w, h, Rect(0, 0, w, h),
+	   w, h, Rectf(0, 0, w, h),
 	};
 	if (w * h == 0) {
 		return;
@@ -250,7 +250,7 @@
 	glViewport(0, 0, width(), height());
 }
 
-void Texture::do_blit(const FloatRect& dst_rect,
+void Texture::do_blit(const Rectf& dst_rect,
                       const BlitData& texture,
                       float opacity,
                       BlendMode blend_mode) {
@@ -258,11 +258,11 @@
 		return;
 	}
 	setup_gl();
-	BlitProgram::instance().draw(dst_rect, 0.f, texture, BlitData{0, 0, 0, Rect()},
+	BlitProgram::instance().draw(dst_rect, 0.f, texture, BlitData{0, 0, 0, Rectf()},
 	                             RGBAColor(0, 0, 0, 255 * opacity), blend_mode);
 }
 
-void Texture::do_blit_blended(const FloatRect& dst_rect,
+void Texture::do_blit_blended(const Rectf& dst_rect,
                               const BlitData& texture,
                               const BlitData& mask,
                               const RGBColor& blend) {
@@ -274,7 +274,7 @@
 	BlitProgram::instance().draw(dst_rect, 0.f, texture, mask, blend, BlendMode::UseAlpha);
 }
 
-void Texture::do_blit_monochrome(const FloatRect& dst_rect,
+void Texture::do_blit_monochrome(const Rectf& dst_rect,
                                  const BlitData& texture,
                                  const RGBAColor& blend) {
 	if (blit_data_.texture_id == 0) {
@@ -293,7 +293,7 @@
 	   {DrawLineProgram::Arguments{vertices, 0.f, BlendMode::UseAlpha}});
 }
 
-void Texture::do_fill_rect(const FloatRect& dst_rect,
+void Texture::do_fill_rect(const Rectf& dst_rect,
                            const RGBAColor& color,
                            BlendMode blend_mode) {
 	if (blit_data_.texture_id == 0) {

=== modified file 'src/graphic/texture.h'
--- src/graphic/texture.h	2016-08-04 15:49:05 +0000
+++ src/graphic/texture.h	2016-10-22 18:17:28 +0000
@@ -39,7 +39,7 @@
 
 	// Create a logical texture that is a 'subrect' (in Pixel) in
 	// another texture. Ownership of 'texture' is not taken.
-	Texture(const GLuint texture, const Rect& subrect, int parent_w, int parent_h);
+	Texture(const GLuint texture, const Recti& subrect, int parent_w, int parent_h);
 
 	virtual ~Texture();
 
@@ -83,20 +83,20 @@
 	void init(uint16_t w, uint16_t h);
 
 	// Implements surface.
-	void do_blit(const FloatRect& dst_rect,
+	void do_blit(const Rectf& dst_rect,
 	             const BlitData& texture,
 	             float opacity,
 	             BlendMode blend_mode) override;
-	void do_blit_blended(const FloatRect& dst_rect,
+	void do_blit_blended(const Rectf& dst_rect,
 	                     const BlitData& texture,
 	                     const BlitData& mask,
 	                     const RGBColor& blend) override;
-	void do_blit_monochrome(const FloatRect& dst_rect,
+	void do_blit_monochrome(const Rectf& dst_rect,
 	                        const BlitData& texture,
 	                        const RGBAColor& blend) override;
 	void do_draw_line_strip(std::vector<DrawLineProgram::PerVertexData> vertices) override;
 	void
-	do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
+	do_fill_rect(const Rectf& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
 
 	// True if we own the texture, i.e. if we need to delete it.
 	bool owns_texture_;

=== modified file 'src/graphic/texture_atlas.cc'
--- src/graphic/texture_atlas.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/texture_atlas.cc	2016-10-22 18:17:28 +0000
@@ -34,14 +34,14 @@
 
 }  // namespace
 
-TextureAtlas::Node::Node(const Rect& init_r) : used(false), r(init_r) {
+TextureAtlas::Node::Node(const Recti& init_r) : used(false), r(init_r) {
 }
 
 void TextureAtlas::Node::split(int item_w, int item_h) {
 	assert(!used);
 
-	down.reset(new Node(Rect(r.x, r.y + item_h, r.w, r.h - item_h)));
-	right.reset(new Node(Rect(r.x + item_w, r.y, r.w - item_w, item_h)));
+	down.reset(new Node(Recti(r.x, r.y + item_h, r.w, r.h - item_h)));
+	right.reset(new Node(Recti(r.x + item_w, r.y, r.w - item_w, item_h)));
 	used = true;
 
 	// Note: we do not change the size of the root. It is not needed
@@ -77,21 +77,21 @@
 std::unique_ptr<Texture> TextureAtlas::pack_as_many_as_possible(
    const int max_dimension, const int texture_atlas_index, std::vector<PackedTexture>* pack_info) {
 
-	std::unique_ptr<Node> root(new Node(Rect(0, 0, blocks_.begin()->texture->width() + kPadding,
+	std::unique_ptr<Node> root(new Node(Recti(0, 0, blocks_.begin()->texture->width() + kPadding,
 	                                         blocks_.begin()->texture->height() + kPadding)));
 
 	const auto grow_right = [&root](int delta_w) {
-		std::unique_ptr<Node> new_root(new Node(Rect(0, 0, root->r.w + delta_w, root->r.h)));
+		std::unique_ptr<Node> new_root(new Node(Recti(0, 0, root->r.w + delta_w, root->r.h)));
 		new_root->used = true;
-		new_root->right.reset(new Node(Rect(root->r.w, 0, delta_w, root->r.h)));
+		new_root->right.reset(new Node(Recti(root->r.w, 0, delta_w, root->r.h)));
 		new_root->down.reset(root.release());
 		root.reset(new_root.release());
 	};
 
 	const auto grow_down = [&root](int delta_h) {
-		std::unique_ptr<Node> new_root(new Node(Rect(0, 0, root->r.w, root->r.h + delta_h)));
+		std::unique_ptr<Node> new_root(new Node(Recti(0, 0, root->r.w, root->r.h + delta_h)));
 		new_root->used = true;
-		new_root->down.reset(new Node(Rect(0, root->r.h, root->r.w, delta_h)));
+		new_root->down.reset(new Node(Recti(0, root->r.h, root->r.w, delta_h)));
 		new_root->right.reset(root.release());
 		root.reset(new_root.release());
 	};
@@ -134,20 +134,20 @@
 	}
 
 	std::unique_ptr<Texture> texture_atlas(new Texture(root->r.w, root->r.h));
-	texture_atlas->fill_rect(Rect(0, 0, root->r.w, root->r.h), RGBAColor(0, 0, 0, 0));
+	texture_atlas->fill_rect(Rectf(0, 0, root->r.w, root->r.h), RGBAColor(0, 0, 0, 0));
 
 	const auto packed_texture_id = texture_atlas->blit_data().texture_id;
 	for (Block& block : packed) {
 		texture_atlas->blit(
-		   Rect(block.node->r.x, block.node->r.y, block.texture->width(), block.texture->height()),
-		   *block.texture, Rect(0, 0, block.texture->width(), block.texture->height()), 1.,
+		   Rectf(block.node->r.x, block.node->r.y, block.texture->width(), block.texture->height()),
+		   *block.texture, Rectf(0, 0, block.texture->width(), block.texture->height()), 1.,
 		   BlendMode::Copy);
 
 		pack_info->emplace_back(PackedTexture(
 		   texture_atlas_index, block.index,
 		   std::unique_ptr<Texture>(new Texture(
 		      packed_texture_id,
-		      Rect(block.node->r.origin(), block.texture->width(), block.texture->height()),
+		      Recti(block.node->r.origin(), block.texture->width(), block.texture->height()),
 		      root->r.w, root->r.h))));
 	}
 	blocks_ = not_packed;

=== modified file 'src/graphic/texture_atlas.h'
--- src/graphic/texture_atlas.h	2016-08-04 15:49:05 +0000
+++ src/graphic/texture_atlas.h	2016-10-22 18:17:28 +0000
@@ -68,11 +68,11 @@
 
 private:
 	struct Node {
-		Node(const Rect& init_r);
+		Node(const Recti& init_r);
 		void split(int w, int h);
 
 		bool used;
-		Rect r;
+		Recti r;
 		std::unique_ptr<Node> right;
 		std::unique_ptr<Node> down;
 

=== modified file 'src/graphic/wordwrap.cc'
--- src/graphic/wordwrap.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/wordwrap.cc	2016-10-22 18:17:28 +0000
@@ -303,7 +303,7 @@
  *
  * \note This also draws the caret, if any.
  */
-void WordWrap::draw(RenderTarget& dst, Point where, Align align, uint32_t caret) {
+void WordWrap::draw(RenderTarget& dst, Vector2i where, Align align, uint32_t caret) {
 	if (lines_.empty())
 		return;
 
@@ -329,7 +329,7 @@
 		if (where.y >= dst.height() || int32_t(where.y + fontheight) <= 0)
 			continue;
 
-		Point point(where.x, where.y);
+		Vector2f point(where.x, where.y);
 
 		if (static_cast<int>(alignment & UI::Align::kRight)) {
 			point.x += wrapwidth_ - LINE_MARGIN;
@@ -346,9 +346,9 @@
 			int caret_x = text_width(line_to_caret, style_.font->size());
 
 			const Image* caret_image = g_gr->images().get("images/ui_basic/caret.png");
-			Point caretpt;
+			Vector2f caretpt;
 			caretpt.x = point.x + caret_x - caret_image->width() + LINE_MARGIN;
-			caretpt.y = point.y + (fontheight - caret_image->height()) / 2;
+			caretpt.y = point.y + (fontheight - caret_image->height()) / 2.f;
 			dst.blit(caretpt, caret_image);
 		}
 	}

=== modified file 'src/graphic/wordwrap.h'
--- src/graphic/wordwrap.h	2016-08-04 15:49:05 +0000
+++ src/graphic/wordwrap.h	2016-10-22 18:17:28 +0000
@@ -21,7 +21,7 @@
 
 #include <string>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/align.h"
 #include "graphic/text_layout.h"
 
@@ -50,7 +50,7 @@
 	}
 
 	void draw(RenderTarget& dst,
-	          Point where,
+	          Vector2i where,
 	          Align align = UI::Align::kLeft,
 	          uint32_t caret = std::numeric_limits<uint32_t>::max());
 

=== modified file 'src/logic/CMakeLists.txt'
--- src/logic/CMakeLists.txt	2016-05-14 07:35:39 +0000
+++ src/logic/CMakeLists.txt	2016-10-22 18:17:28 +0000
@@ -119,6 +119,7 @@
     widelands_geometry_io.cc
     widelands_geometry_io.h
     widelands.h
+    map_objects/draw_text.h
     map_objects/attackable.h
     map_objects/bob.cc
     map_objects/bob.h
@@ -126,15 +127,13 @@
     map_objects/buildcost.h
     map_objects/checkstep.cc
     map_objects/checkstep.h
-    map_objects/immovable_program.h
     map_objects/immovable.cc
     map_objects/immovable.h
+    map_objects/immovable_program.h
     map_objects/map_object.cc
     map_objects/map_object.h
     map_objects/terrain_affinity.cc
     map_objects/terrain_affinity.h
-    map_objects/walkingdir.cc
-    map_objects/walkingdir.h
     map_objects/tribes/battle.cc
     map_objects/tribes/battle.h
     map_objects/tribes/bill_of_materials.h
@@ -181,15 +180,17 @@
     map_objects/tribes/warelist.h
     map_objects/tribes/wareworker.h
     map_objects/tribes/workarea_info.h
+    map_objects/tribes/worker.cc
+    map_objects/tribes/worker.h
     map_objects/tribes/worker_descr.cc
     map_objects/tribes/worker_descr.h
     map_objects/tribes/worker_program.cc
     map_objects/tribes/worker_program.h
-    map_objects/tribes/worker.cc
-    map_objects/tribes/worker.h
-    map_objects/world/critter_program.h
+    map_objects/walkingdir.cc
+    map_objects/walkingdir.h
     map_objects/world/critter.cc
     map_objects/world/critter.h
+    map_objects/world/critter_program.h
     map_objects/world/editor_category.cc
     map_objects/world/editor_category.h
     map_objects/world/map_gen.cc
@@ -209,6 +210,7 @@
     base_i18n
     base_log
     base_macros
+    base_math
     base_md5
     base_scoped_timer
     base_time_string

=== modified file 'src/logic/game.cc'
--- src/logic/game.cc	2016-08-04 15:49:05 +0000
+++ src/logic/game.cc	2016-10-22 18:17:28 +0000
@@ -455,7 +455,7 @@
 		}
 
 		if (get_ipl())
-			get_ipl()->move_view_to(map().get_starting_pos(get_ipl()->player_number()));
+			get_ipl()->center_view_on_coords(map().get_starting_pos(get_ipl()->player_number()));
 
 		// Prepare the map, set default textures
 		map().recalc_default_resources(world());

=== modified file 'src/logic/game_controller.h'
--- src/logic/game_controller.h	2016-08-04 15:49:05 +0000
+++ src/logic/game_controller.h	2016-10-22 18:17:28 +0000
@@ -100,9 +100,6 @@
 	/**
 	 * Report a player result once he has left the game. This may be done through lua
 	 * by the win_condition scripts.
-	 * \param player : the player idx;
-	 * \param result : the player result
-	 * \param info : The info string (\see \struct PlayerEndStatus)
 	 */
 	virtual void report_result(uint8_t /* player */,
 	                           Widelands::PlayerEndResult /*result*/,

=== modified file 'src/logic/map_objects/bob.cc'
--- src/logic/map_objects/bob.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/bob.cc	2016-10-22 18:17:28 +0000
@@ -25,6 +25,7 @@
 #include <stdint.h>
 
 #include "base/macros.h"
+#include "base/math.h"
 #include "base/wexception.h"
 #include "economy/route.h"
 #include "economy/transfer.h"
@@ -88,7 +89,6 @@
 
 Bob::Bob(const BobDescr& init_descr)
    : MapObject(&init_descr),
-     owner_(nullptr),
      position_(FCoords(Coords(0, 0), nullptr)),  // not linked anywhere
      linknext_(nullptr),
      linkpprev_(nullptr),
@@ -685,45 +685,51 @@
 		return schedule_act(game, walkend_ - game.get_gametime());
 }
 
-/// Calculates the actual position to draw on from the base node position.
-/// This function takes walking etc. into account.
-///
-/// pos is the location, in pixels, of the node position_ (height is already
-/// taken into account).
-Point Bob::calc_drawpos(const EditorGameBase& game, const Point pos) const {
+// Calculates the actual position to draw on from the base node position. This
+// function takes walking etc. into account.
+//
+// pos is the location, in pixels, of the node position_ on screen with scale
+// and height taken into account.
+Vector2f Bob::calc_drawpos(const EditorGameBase& game,
+                             const Vector2f& field_on_dst,
+                             const float scale) const {
 	const Map& map = game.get_map();
 	const FCoords end = position_;
 	FCoords start;
-	Point spos = pos, epos = pos;
+	Vector2f spos = field_on_dst;
+	Vector2f epos = field_on_dst;
+
+	const float triangle_w = kTriangleWidth * scale;
+	const float triangle_h = kTriangleHeight * scale;
 
 	switch (walking_) {
 	case WALK_NW:
 		map.get_brn(end, &start);
-		spos.x += kTriangleWidth / 2;
-		spos.y += kTriangleHeight;
+		spos.x += triangle_w / 2.f;
+		spos.y += triangle_h;
 		break;
 	case WALK_NE:
 		map.get_bln(end, &start);
-		spos.x -= kTriangleWidth / 2;
-		spos.y += kTriangleHeight;
+		spos.x -= triangle_w / 2.f;
+		spos.y += triangle_h;
 		break;
 	case WALK_W:
 		map.get_rn(end, &start);
-		spos.x += kTriangleWidth;
+		spos.x += triangle_w;
 		break;
 	case WALK_E:
 		map.get_ln(end, &start);
-		spos.x -= kTriangleWidth;
+		spos.x -= triangle_w;
 		break;
 	case WALK_SW:
 		map.get_trn(end, &start);
-		spos.x += kTriangleWidth / 2;
-		spos.y -= kTriangleHeight;
+		spos.x += triangle_w / 2.f;
+		spos.y -= triangle_h;
 		break;
 	case WALK_SE:
 		map.get_tln(end, &start);
-		spos.x -= kTriangleWidth / 2;
-		spos.y -= kTriangleHeight;
+		spos.x -= triangle_w / 2.f;
+		spos.y -= triangle_h;
 		break;
 
 	case IDLE:
@@ -732,37 +738,39 @@
 	}
 
 	if (start.field) {
-		spos.y += end.field->get_height() * kHeightFactor;
-		spos.y -= start.field->get_height() * kHeightFactor;
+		spos.y += end.field->get_height() * kHeightFactor * scale;
+		spos.y -= start.field->get_height() * kHeightFactor * scale;
 
 		assert(static_cast<uint32_t>(walkstart_) <= game.get_gametime());
 		assert(walkstart_ < walkend_);
-		float f = static_cast<float>(game.get_gametime() - walkstart_) / (walkend_ - walkstart_);
-
-		if (f < 0)
-			f = 0;
-		else if (f > 1)
-			f = 1;
-
-		epos.x = static_cast<int32_t>(f * epos.x + (1 - f) * spos.x);
-		epos.y = static_cast<int32_t>(f * epos.y + (1 - f) * spos.y);
+		const float f = math::clamp(
+				static_cast<float>(game.get_gametime() - walkstart_) / (walkend_ - walkstart_),
+				0.f, 1.f);
+		epos.x = f * epos.x + (1.f - f) * spos.x;
+		epos.y = f * epos.y + (1.f - f) * spos.y;
 	}
-
 	return epos;
 }
 
 /// It LERPs between start and end position when we are walking.
 /// Note that the current node is actually the node that we are walking to, not
 /// the the one that we start from.
-void Bob::draw(const EditorGameBase& egbase, RenderTarget& dst, const Point& pos) const {
-	if (anim_) {
-		auto* const owner = get_owner();
-		if (owner != nullptr) {
-			dst.blit_animation(calc_drawpos(egbase, pos), anim_, egbase.get_gametime() - animstart_,
-			                   owner->get_playercolor());
-		} else {
-			dst.blit_animation(calc_drawpos(egbase, pos), anim_, egbase.get_gametime() - animstart_);
-		}
+void Bob::draw(const EditorGameBase& egbase,
+               const DrawText&,
+               const Vector2f& field_on_dst,
+               const float scale,
+               RenderTarget* dst) const {
+	if (!anim_) {
+		return;
+	}
+
+	auto* const owner = get_owner();
+	const Vector2f point_on_dst = calc_drawpos(egbase, field_on_dst, scale);
+	if (owner != nullptr) {
+		dst->blit_animation(
+		   point_on_dst, scale, anim_, egbase.get_gametime() - animstart_, owner->get_playercolor());
+	} else {
+		dst->blit_animation(point_on_dst, scale, anim_, egbase.get_gametime() - animstart_);
 	}
 }
 

=== modified file 'src/logic/map_objects/bob.h'
--- src/logic/map_objects/bob.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/bob.h	2016-10-22 18:17:28 +0000
@@ -21,10 +21,11 @@
 #define WL_LOGIC_MAP_OBJECTS_BOB_H
 
 #include "base/macros.h"
-#include "base/point.h"
+#include "base/vector.h"
 #include "economy/route.h"
 #include "graphic/animation.h"
 #include "graphic/diranimations.h"
+#include "logic/map_objects/draw_text.h"
 #include "logic/map_objects/map_object.h"
 #include "logic/map_objects/walkingdir.h"
 #include "logic/widelands_geometry.h"
@@ -240,11 +241,9 @@
 	void schedule_destroy(Game&);
 	void schedule_act(Game&, uint32_t tdelta);
 	void skip_act();
-	Point calc_drawpos(const EditorGameBase&, Point) const;
+	Vector2f calc_drawpos(const EditorGameBase&, const Vector2f& field_on_dst, float scale) const;
 	void set_owner(Player*);
-	Player* get_owner() const {
-		return owner_;
-	}
+
 	void set_position(EditorGameBase&, const Coords&);
 	const FCoords& get_position() const {
 		return position_;
@@ -260,7 +259,15 @@
 	///    onto the \p to node if this function allows it to.
 	virtual bool check_node_blocked(Game&, const FCoords&, bool commit);
 
-	virtual void draw(const EditorGameBase&, RenderTarget&, const Point&) const;
+	// Draws the bob onto the screen with 'field_on_dst' being the position of
+	// the field associated with this bob (if it is walking, that is its
+	// starting field) in pixel space of 'dst' (including scale). The 'scale' is
+	// required to draw the bob in the right size.
+	virtual void draw(const EditorGameBase&,
+	                  const DrawText& draw_text,
+	                  const Vector2f& field_on_dst,
+	                  float scale,
+	                  RenderTarget* dst) const;
 
 	// For debug
 	void log_general_info(const EditorGameBase&) override;
@@ -366,7 +373,6 @@
 	static Task const taskMovepath;
 	static Task const taskMove;
 
-	Player* owner_;     ///< can be 0
 	FCoords position_;  ///< where are we right now?
 	Bob* linknext_;     ///< next object on this node
 	Bob** linkpprev_;

=== added file 'src/logic/map_objects/draw_text.h'
--- src/logic/map_objects/draw_text.h	1970-01-01 00:00:00 +0000
+++ src/logic/map_objects/draw_text.h	2016-10-22 18:17:28 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2006-2016 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_LOGIC_MAP_OBJECTS_DRAW_TEXT_H
+#define WL_LOGIC_MAP_OBJECTS_DRAW_TEXT_H
+
+enum DrawText {
+	kNone = 0,
+	kCensus = 1,
+	kStatistics = 2,
+};
+
+#endif  // end of include guard: WL_LOGIC_MAP_OBJECTS_DRAW_TEXT_H
+

=== modified file 'src/logic/map_objects/immovable.cc'
--- src/logic/map_objects/immovable.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/immovable.cc	2016-10-22 18:17:28 +0000
@@ -324,7 +324,6 @@
  * Create an immovable of this type
 */
 Immovable& ImmovableDescr::create(EditorGameBase& egbase, const Coords& coords) const {
-	assert(this != nullptr);
 	Immovable& result = *new Immovable(*this);
 	result.position_ = coords;
 	result.init(egbase);
@@ -341,7 +340,6 @@
 
 Immovable::Immovable(const ImmovableDescr& imm_descr)
    : BaseImmovable(imm_descr),
-     owner_(nullptr),
      anim_(0),
      animstart_(0),
      program_(nullptr),
@@ -439,19 +437,26 @@
 	}
 }
 
-void Immovable::draw(const EditorGameBase& game,
-                     RenderTarget& dst,
-                     const FCoords&,
-                     const Point& pos) {
-	if (anim_) {
-		if (!anim_construction_total_)
-			dst.blit_animation(pos, anim_, game.get_gametime() - animstart_);
-		else
-			draw_construction(game, dst, pos);
+void Immovable::draw(uint32_t gametime,
+                     const DrawText draw_text,
+                     const Vector2f& point_on_dst,
+                     float scale,
+                     RenderTarget* dst) {
+	if (!anim_) {
+		return;
+	}
+	if (!anim_construction_total_) {
+		dst->blit_animation(point_on_dst, scale, anim_, gametime - animstart_);
+	} else {
+		draw_construction(gametime, draw_text, point_on_dst, scale, dst);
 	}
 }
 
-void Immovable::draw_construction(const EditorGameBase& game, RenderTarget& dst, const Point pos) {
+void Immovable::draw_construction(const uint32_t gametime,
+                                  const DrawText draw_text,
+                                  const Vector2f& point_on_dst,
+                                  const float scale,
+                                  RenderTarget* dst) {
 	const ImmovableProgram::ActConstruction* constructionact = nullptr;
 	if (program_ptr_ < program_->size())
 		constructionact =
@@ -462,7 +467,7 @@
 	uint32_t done = 0;
 	if (anim_construction_done_ > 0) {
 		done = steptime * (anim_construction_done_ - 1);
-		done += std::min(steptime, game.get_gametime() - animstart_);
+		done += std::min(steptime, gametime - animstart_);
 	}
 
 	uint32_t total = anim_construction_total_ * steptime;
@@ -483,21 +488,19 @@
 	const RGBColor& player_color = get_owner()->get_playercolor();
 	if (current_frame > 0) {
 		// Not the first pic, so draw the previous one in the back
-		dst.blit_animation(pos, anim_, (current_frame - 1) * frametime, player_color);
+		dst->blit_animation(point_on_dst, scale, anim_, (current_frame - 1) * frametime, player_color);
 	}
 
 	assert(lines <= curh);
-	dst.blit_animation(pos, anim_, current_frame * frametime, player_color,
-	                   Rect(Point(0, curh - lines), curw, lines));
+	dst->blit_animation(point_on_dst, scale, anim_, current_frame * frametime, player_color,
+	                   Recti(Vector2i(0, curh - lines), curw, lines));
 
 	// Additionally, if statistics are enabled, draw a progression string
-	uint32_t const display_flags = game.get_ibase()->get_display_flags();
-	do_draw_info(display_flags & InteractiveBase::dfShowCensus, descr().descname(),
-	             display_flags & InteractiveBase::dfShowStatistics,
+	do_draw_info(draw_text, descr().descname(),
 	             (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_DARK.hex_value() %
 	              (boost::format(_("%i%% built")) % (100 * done / total)).str())
 	                .str(),
-	             dst, pos);
+	             point_on_dst, scale, dst);
 }
 
 /**
@@ -1179,7 +1182,7 @@
  * Zero-initialize
 */
 PlayerImmovable::PlayerImmovable(const MapObjectDescr& mo_descr)
-   : BaseImmovable(mo_descr), owner_(nullptr), economy_(nullptr) {
+   : BaseImmovable(mo_descr), economy_(nullptr) {
 }
 
 /**

=== modified file 'src/logic/map_objects/immovable.h'
--- src/logic/map_objects/immovable.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/immovable.h	2016-10-22 18:17:28 +0000
@@ -26,6 +26,7 @@
 #include "base/macros.h"
 #include "graphic/animation.h"
 #include "logic/map_objects/buildcost.h"
+#include "logic/map_objects/draw_text.h"
 #include "logic/map_objects/map_object.h"
 #include "logic/widelands_geometry.h"
 #include "notifications/note_ids.h"
@@ -91,7 +92,18 @@
 	 * if one can be chosen as main.
 	 */
 	virtual PositionList get_positions(const EditorGameBase&) const = 0;
-	virtual void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) = 0;
+
+	// Draw this immovable onto 'dst' choosing the frame appropriate for
+	// 'gametime'. 'draw_text' decides if census and statistics are written too.
+	// The 'coords_to_draw' are passed one to give objects that occupy multiple
+	// fields a way to only draw themselves once. The 'point_on_dst' determines
+	// the point for the hotspot of the animation and 'scale' determines how big
+	// the immovable will be plotted.
+	virtual void draw(uint32_t gametime,
+	          DrawText draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) = 0;
 
 	static int32_t string_to_size(const std::string& size);
 	static std::string size_to_string(int32_t size);
@@ -189,10 +201,7 @@
 	Immovable(const ImmovableDescr&);
 	~Immovable();
 
-	Player* get_owner() const {
-		return owner_;
-	}
-	void set_owner(Player* player);
+	void set_owner(Player*);
 
 	Coords get_position() const {
 		return position_;
@@ -212,8 +221,11 @@
 	void init(EditorGameBase&) override;
 	void cleanup(EditorGameBase&) override;
 	void act(Game&, uint32_t data) override;
-
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          DrawText draw_text,
+	          const Vector2f& point_on_dst,
+	          float scale,
+	          RenderTarget* dst) override;
 
 	void switch_program(Game& game, const std::string& programname);
 	bool construct_ware(Game& game, DescriptionIndex index);
@@ -230,7 +242,6 @@
 	}
 
 protected:
-	Player* owner_;
 	Coords position_;
 
 	uint32_t anim_;
@@ -289,8 +300,11 @@
 
 private:
 	void increment_program_pointer();
-
-	void draw_construction(const EditorGameBase&, RenderTarget&, Point);
+	void draw_construction(uint32_t gametime,
+	                       DrawText draw_text,
+	                       const Vector2f& point_on_dst,
+	                       float scale,
+	                       RenderTarget* dst);
 };
 
 /**
@@ -360,7 +374,6 @@
 	void cleanup(EditorGameBase&) override;
 
 private:
-	Player* owner_;
 	Economy* economy_;
 
 	Workers workers_;

=== modified file 'src/logic/map_objects/map_object.cc'
--- src/logic/map_objects/map_object.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/map_object.cc	2016-10-22 18:17:28 +0000
@@ -393,7 +393,7 @@
  * Zero-initialize a map object
  */
 MapObject::MapObject(const MapObjectDescr* const the_descr)
-   : descr_(the_descr), serial_(0), logsink_(nullptr), reserved_by_worker_(false) {
+   : descr_(the_descr), serial_(0), logsink_(nullptr), owner_(nullptr), reserved_by_worker_(false) {
 }
 
 /**
@@ -445,27 +445,36 @@
 	egbase.objects().remove(*this);
 }
 
-void MapObject::do_draw_info(bool show_census,
+void MapObject::do_draw_info(const DrawText& draw_text,
                              const std::string& census,
-                             bool show_statictics,
                              const std::string& statictics,
-                             RenderTarget& dst,
-                             const Point& pos) const {
-	if (show_census || show_statictics) {
-		// We always render this so we can have a stable position for the statistics string.
-		const Image* rendered_census_info =
-		   UI::g_fh1->render(as_condensed(census, UI::Align::kCenter), 120);
-		const Point census_pos(pos - Point(0, 48));
-
-		if (show_census) {
-			dst.blit(census_pos, rendered_census_info, BlendMode::UseAlpha, UI::Align::kCenter);
-		}
-
-		if (show_statictics && !statictics.empty()) {
-			dst.blit(census_pos + Point(0, rendered_census_info->height() / 2 + 10),
-			         UI::g_fh1->render(as_condensed(statictics)), BlendMode::UseAlpha,
-			         UI::Align::kCenter);
-		}
+                             const Vector2f& field_on_dst,
+                             float scale,
+                             RenderTarget* dst) const {
+	if (draw_text == DrawText::kNone) {
+		return;
+	}
+
+	// Rendering text is expensive, so let's just do it for only a few sizes.
+	scale = std::round(scale);
+	if (scale == 0.f) {
+		return;
+	}
+	const int font_size = scale * UI_FONT_SIZE_SMALL;
+
+	// We always render this so we can have a stable position for the statistics string.
+	const Image* rendered_census_info =
+	   UI::g_fh1->render(as_condensed(census, UI::Align::kCenter, font_size), 120);
+	const Vector2f census_pos = field_on_dst - Vector2f(0, 48) * scale;
+
+	if (draw_text & DrawText::kCensus) {
+		dst->blit(census_pos, rendered_census_info, BlendMode::UseAlpha, UI::Align::kCenter);
+	}
+
+	if (draw_text & DrawText::kStatistics && !statictics.empty()) {
+		dst->blit(census_pos + Vector2f(0, rendered_census_info->height() / 2.f + 10 * scale),
+		          UI::g_fh1->render(as_condensed(statictics, UI::Align::kLeft, font_size)),
+		          BlendMode::UseAlpha, UI::Align::kCenter);
 	}
 }
 

=== modified file 'src/logic/map_objects/map_object.h'
--- src/logic/map_objects/map_object.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/map_object.h	2016-10-22 18:17:28 +0000
@@ -35,6 +35,7 @@
 #include "graphic/color.h"
 #include "graphic/image.h"
 #include "logic/cmd_queue.h"
+#include "logic/map_objects/draw_text.h"
 #include "logic/map_objects/tribes/training_attribute.h"
 #include "logic/widelands.h"
 #include "scripting/lua_table.h"
@@ -306,6 +307,10 @@
 	/// Called when a new logsink is set. Used to give general information.
 	virtual void log_general_info(const EditorGameBase&);
 
+	Player* get_owner() const {
+		return owner_;
+	}
+
 	// Header bytes to distinguish between data packages for the different
 	// MapObject classes. Be careful in changing those, since they are written
 	// to files.
@@ -401,18 +406,19 @@
 	virtual void cleanup(EditorGameBase&);
 
 	/// Draws census and statistics on screen
-	void do_draw_info(bool show_census,
+	void do_draw_info(const DrawText& draw_text,
 	                  const std::string& census,
-	                  bool show_statictics,
 	                  const std::string& statictics,
-	                  RenderTarget& dst,
-	                  const Point& pos) const;
+	                  const Vector2f& field_on_dst,
+	                  const float scale,
+	                  RenderTarget* dst) const;
 
 	void molog(char const* fmt, ...) const __attribute__((format(printf, 2, 3)));
 
 	const MapObjectDescr* descr_;
 	Serial serial_;
 	LogSink* logsink_;
+	Player* owner_;
 
 	/**
 	 * MapObjects like trees are reserved by a worker that is walking

=== modified file 'src/logic/map_objects/tribes/building.cc'
--- src/logic/map_objects/tribes/building.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/building.cc	2016-10-22 18:17:28 +0000
@@ -586,24 +586,19 @@
 	return false;
 }
 
-/*
-===============
-Draw the building.
-===============
-*/
-void Building::draw(const EditorGameBase& game,
-                    RenderTarget& dst,
-                    const FCoords& coords,
-                    const Point& pos) {
-	if (coords == position_) {  // draw big buildings only once
-		dst.blit_animation(
-		   pos, anim_, game.get_gametime() - animstart_, get_owner()->get_playercolor());
-
-		//  door animation?
-
-		//  overlay strings (draw when enabled)
-		draw_info(game, dst, pos);
-	}
+
+void Building::draw(uint32_t gametime,
+                    const DrawText draw_text,
+                    const Vector2f& point_on_dst,
+                    const float scale,
+                    RenderTarget* dst) {
+	dst->blit_animation(
+	   point_on_dst, scale, anim_, gametime - animstart_, get_owner()->get_playercolor());
+
+	//  door animation?
+
+	//  overlay strings (draw when enabled)
+	draw_info(draw_text, point_on_dst, scale, dst);
 }
 
 /*
@@ -611,24 +606,14 @@
 Draw overlay help strings when enabled.
 ===============
 */
-void Building::draw_info(const EditorGameBase& game, RenderTarget& dst, const Point& pos) {
-	const InteractiveGameBase& igbase = dynamic_cast<const InteractiveGameBase&>(*game.get_ibase());
-	uint32_t const display_flags = igbase.get_display_flags();
-
-	bool show_statistics_string = display_flags & InteractiveBase::dfShowStatistics;
-	if (show_statistics_string) {
-		if (upcast(InteractivePlayer const, iplayer, &igbase)) {
-			if (!iplayer->player().see_all() && iplayer->player().is_hostile(*get_owner())) {
-				show_statistics_string = false;
-			}
-		}
-	}
+void Building::draw_info(const DrawText draw_text,
+                         const Vector2f& point_on_dst,
+								 const float scale,
+                         RenderTarget* dst) {
 	const std::string statistics_string =
-	   show_statistics_string ? info_string(InfoStringFormat::kStatistics) : "";
-
-	do_draw_info(display_flags & InteractiveBase::dfShowCensus,
-	             info_string(InfoStringFormat::kCensus), show_statistics_string, statistics_string,
-	             dst, pos);
+	   (draw_text & DrawText::kStatistics) ? info_string(InfoStringFormat::kStatistics) : "";
+	do_draw_info(draw_text, info_string(InfoStringFormat::kCensus), statistics_string, point_on_dst,
+	             scale, dst);
 }
 
 int32_t

=== modified file 'src/logic/map_objects/tribes/building.h'
--- src/logic/map_objects/tribes/building.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/building.h	2016-10-22 18:17:28 +0000
@@ -241,7 +241,7 @@
 	virtual bool burn_on_destroy();
 	void destroy(EditorGameBase&) override;
 
-	void show_options(InteractiveGameBase&, bool avoid_fastclick = false, Point pos = Point(-1, -1));
+	void show_options(InteractiveGameBase&, bool avoid_fastclick = false, Vector2i pos = Vector2i(-1, -1));
 	void hide_options();
 	void refresh_options(InteractiveGameBase&);
 
@@ -311,8 +311,12 @@
 	void cleanup(EditorGameBase&) override;
 	void act(Game&, uint32_t data) override;
 
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
-	void draw_info(const EditorGameBase&, RenderTarget&, const Point&);
+	void draw(uint32_t gametime,
+	          DrawText draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
+	void draw_info(DrawText draw_text, const Vector2f& point_on_dst, float scale, RenderTarget* dst);
 
 	virtual void create_options_window(InteractiveGameBase&, UI::Window*& registry) = 0;
 

=== modified file 'src/logic/map_objects/tribes/constructionsite.cc'
--- src/logic/map_objects/tribes/constructionsite.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/constructionsite.cc	2016-10-22 18:17:28 +0000
@@ -153,7 +153,7 @@
 		}
 		// Open the new building window if needed
 		if (optionswindow_) {
-			Point window_position = optionswindow_->get_pos();
+			Vector2i window_position = optionswindow_->get_pos();
 			hide_options();
 			InteractiveGameBase& igbase = dynamic_cast<InteractiveGameBase&>(*egbase.get_ibase());
 			b.show_options(igbase, false, window_position);
@@ -297,19 +297,15 @@
 Draw the construction site.
 ===============
 */
-void ConstructionSite::draw(const EditorGameBase& game,
-                            RenderTarget& dst,
-                            const FCoords& coords,
-                            const Point& pos) {
-	const uint32_t gametime = game.get_gametime();
+void ConstructionSite::draw(uint32_t gametime,
+                            DrawText draw_text,
+                            const Vector2f& point_on_dst,
+                            float scale,
+                            RenderTarget* dst) {
 	uint32_t tanim = gametime - animstart_;
-
-	if (coords != position_)
-		return;  // draw big buildings only once
-
 	// Draw the construction site marker
 	const RGBColor& player_color = get_owner()->get_playercolor();
-	dst.blit_animation(pos, anim_, tanim, player_color);
+	dst->blit_animation(point_on_dst, scale, anim_, tanim, player_color);
 
 	// Draw the partially finished building
 
@@ -324,7 +320,6 @@
 	}
 
 	uint32_t anim_idx;
-	uint32_t cur_frame;
 	try {
 		anim_idx = building().get_animation("build");
 	} catch (MapObjectDescr::AnimationNonexistent&) {
@@ -336,23 +331,23 @@
 	}
 	const Animation& anim = g_gr->animations().get_animation(anim_idx);
 	const size_t nr_frames = anim.nr_frames();
-	cur_frame = info_.totaltime ? info_.completedtime * nr_frames / info_.totaltime : 0;
-	// Redefine tanim
+	const uint32_t cur_frame = info_.totaltime ? info_.completedtime * nr_frames / info_.totaltime : 0;
 	tanim = cur_frame * FRAME_LENGTH;
 
 	const uint16_t w = anim.width();
 	const uint16_t h = anim.height();
 
 	uint32_t lines = h * info_.completedtime * nr_frames;
-	if (info_.totaltime)
+	if (info_.totaltime) {
 		lines /= info_.totaltime;
+	}
 	assert(h * cur_frame <= lines);
 	lines -= h * cur_frame;  //  This won't work if pictures have various sizes.
 
 	if (cur_frame) {  //  not the first pic
 		//  draw the prev pic from top to where next image will be drawing
-		dst.blit_animation(
-		   pos, anim_idx, tanim - FRAME_LENGTH, player_color, Rect(Point(0, 0), w, h - lines));
+		dst->blit_animation(point_on_dst, scale, anim_idx, tanim - FRAME_LENGTH, player_color,
+		                    Recti(Vector2i(0, 0), w, h - lines));
 	} else if (!old_buildings_.empty()) {
 		DescriptionIndex prev_idx = old_buildings_.back();
 		const BuildingDescr* prev_building = owner().tribe().get_building_descr(prev_idx);
@@ -366,15 +361,17 @@
 		}
 		const Animation& prev_building_anim =
 		   g_gr->animations().get_animation(prev_building_anim_idx);
-		dst.blit_animation(pos, prev_building_anim_idx, tanim - FRAME_LENGTH, player_color,
-		                   Rect(Point(0, 0), prev_building_anim.width(),
-		                        std::min<int>(prev_building_anim.height(), h - lines)));
+		dst->blit_animation(point_on_dst, scale, prev_building_anim_idx, tanim - FRAME_LENGTH,
+		                    player_color,
+		                    Recti(Vector2i(0, 0), prev_building_anim.width(),
+		                         std::min<int>(prev_building_anim.height(), h - lines)));
 	}
 
 	assert(lines <= h);
-	dst.blit_animation(pos, anim_idx, tanim, player_color, Rect(Point(0, h - lines), w, lines));
+	dst->blit_animation(point_on_dst, scale, anim_idx, tanim,
+	                    player_color, Recti(Vector2i(0, h - lines), w, lines));
 
 	// Draw help strings
-	draw_info(game, dst, pos);
+	draw_info(draw_text, point_on_dst, scale, dst);
 }
 }

=== modified file 'src/logic/map_objects/tribes/constructionsite.h'
--- src/logic/map_objects/tribes/constructionsite.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/constructionsite.h	2016-10-22 18:17:28 +0000
@@ -114,7 +114,11 @@
 
 	static void wares_queue_callback(Game&, WaresQueue*, DescriptionIndex, void* data);
 
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          DrawText draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
 
 private:
 	int32_t fetchfromflag_;  // # of wares to fetch from flag

=== modified file 'src/logic/map_objects/tribes/dismantlesite.cc'
--- src/logic/map_objects/tribes/dismantlesite.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/dismantlesite.cc	2016-10-22 18:17:28 +0000
@@ -212,20 +212,16 @@
 Draw it.
 ===============
 */
-void DismantleSite::draw(const EditorGameBase& game,
-                         RenderTarget& dst,
-                         const FCoords& coords,
-                         const Point& pos) {
-	const uint32_t gametime = game.get_gametime();
+void DismantleSite::draw(uint32_t gametime,
+                         const DrawText draw_text,
+                         const Vector2f& point_on_dst,
+                         float scale,
+                         RenderTarget* dst) {
 	uint32_t tanim = gametime - animstart_;
-
-	if (coords != position_)
-		return;  // draw big buildings only once
-
 	const RGBColor& player_color = get_owner()->get_playercolor();
 
 	// Draw the construction site marker
-	dst.blit_animation(pos, anim_, tanim, player_color);
+	dst->blit_animation(point_on_dst, scale, anim_, tanim, player_color);
 
 	// Draw the partially dismantled building
 	static_assert(0 <= DISMANTLESITE_STEP_TIME, "assert(0 <= DISMANTLESITE_STEP_TIME) failed.");
@@ -247,9 +243,10 @@
 
 	const uint32_t lines = total_time ? h * completed_time / total_time : 0;
 
-	dst.blit_animation(pos, anim_idx, tanim, player_color, Rect(Point(0, lines), w, h - lines));
+	dst->blit_animation(
+	   point_on_dst, scale, anim_idx, tanim, player_color, Recti(Vector2i(0, lines), w, h - lines));
 
 	// Draw help strings
-	draw_info(game, dst, pos);
+	draw_info(draw_text, point_on_dst, scale, dst);
 }
 }

=== modified file 'src/logic/map_objects/tribes/dismantlesite.h'
--- src/logic/map_objects/tribes/dismantlesite.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/dismantlesite.h	2016-10-22 18:17:28 +0000
@@ -89,7 +89,11 @@
 
 	void create_options_window(InteractiveGameBase&, UI::Window*& registry) override;
 
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          DrawText draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
 };
 }
 

=== modified file 'src/logic/map_objects/tribes/road_textures.cc'
--- src/logic/map_objects/tribes/road_textures.cc	2016-01-13 07:27:55 +0000
+++ src/logic/map_objects/tribes/road_textures.cc	2016-10-22 18:17:28 +0000
@@ -21,12 +21,12 @@
 
 #include <memory>
 
-const Image& RoadTextures::get_normal_texture(int x, int y, int direction) const {
-	return *normal_textures_.at((x + y + direction) % normal_textures_.size());
+const Image& RoadTextures::get_normal_texture(const Widelands::Coords& coords, int direction) const {
+	return *normal_textures_.at((coords.x + coords.y + direction) % normal_textures_.size());
 }
 
-const Image& RoadTextures::get_busy_texture(int x, int y, int direction) const {
-	return *busy_textures_.at((x + y + direction) % busy_textures_.size());
+const Image& RoadTextures::get_busy_texture(const Widelands::Coords& coords, int direction) const {
+	return *busy_textures_.at((coords.x + coords.y + direction) % busy_textures_.size());
 }
 
 void RoadTextures::add_normal_road_texture(const Image* image) {

=== modified file 'src/logic/map_objects/tribes/road_textures.h'
--- src/logic/map_objects/tribes/road_textures.h	2016-01-13 07:27:55 +0000
+++ src/logic/map_objects/tribes/road_textures.h	2016-10-22 18:17:28 +0000
@@ -24,14 +24,15 @@
 #include <vector>
 
 #include "graphic/image.h"
+#include "logic/widelands_geometry.h"
 
 // Simple container to give access of the road textures of a tribe.
 class RoadTextures {
 public:
-	// Returns the road texture that should be used for the Cooordinate x, y and
-	// the road going into direction 'direction' (which can be any number).
-	const Image& get_normal_texture(int x, int y, int direction) const;
-	const Image& get_busy_texture(int x, int y, int direction) const;
+	// Returns the road texture that should be used for 'coords' and the road
+	// going into direction 'direction' (which can be any number).
+	const Image& get_normal_texture(const Widelands::Coords& coords, int direction) const;
+	const Image& get_busy_texture(const Widelands::Coords& coords, int direction) const;
 
 	// Adds a new road texture.
 	void add_normal_road_texture(const Image* texture);

=== modified file 'src/logic/map_objects/tribes/ship.cc'
--- src/logic/map_objects/tribes/ship.cc	2016-09-07 09:30:49 +0000
+++ src/logic/map_objects/tribes/ship.cc	2016-10-22 18:17:28 +0000
@@ -942,13 +942,16 @@
 	close_window();
 }
 
-void Ship::draw(const EditorGameBase& game, RenderTarget& dst, const Point& pos) const {
-	Bob::draw(game, dst, pos);
+void Ship::draw(const EditorGameBase& egbase,
+                const DrawText& draw_text,
+                const Vector2f& field_on_dst,
+                const float scale,
+                RenderTarget* dst) const {
+	Bob::draw(egbase, draw_text, field_on_dst, scale, dst);
 
 	// Show ship name and current activity
-	uint32_t const display_flags = game.get_ibase()->get_display_flags();
 	std::string statistics_string = "";
-	if (display_flags & InteractiveBase::dfShowStatistics) {
+	if (draw_text & DrawText::kStatistics) {
 		switch (ship_state_) {
 		case (ShipStates::kTransport):
 			/** TRANSLATORS: This is a ship state */
@@ -980,9 +983,8 @@
 		                       .str();
 	}
 
-	do_draw_info(display_flags & InteractiveBase::dfShowCensus, shipname_,
-	             display_flags & InteractiveBase::dfShowStatistics, statistics_string, dst,
-	             calc_drawpos(game, pos));
+	do_draw_info(
+	   draw_text, shipname_, statistics_string, calc_drawpos(egbase, field_on_dst, scale), scale, dst);
 }
 
 void Ship::log_general_info(const EditorGameBase& egbase) {

=== modified file 'src/logic/map_objects/tribes/ship.h'
--- src/logic/map_objects/tribes/ship.h	2016-09-07 09:30:49 +0000
+++ src/logic/map_objects/tribes/ship.h	2016-10-22 18:17:28 +0000
@@ -235,7 +235,11 @@
 	void sink_ship(Game&);
 
 protected:
-	void draw(const EditorGameBase&, RenderTarget&, const Point&) const override;
+	void draw(const EditorGameBase&,
+	          const DrawText& draw_text,
+	          const Vector2f& field_on_dst,
+	          float scale,
+	          RenderTarget* dst) const override;
 
 private:
 	friend struct Fleet;

=== modified file 'src/logic/map_objects/tribes/soldier.cc'
--- src/logic/map_objects/tribes/soldier.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/soldier.cc	2016-10-22 18:17:28 +0000
@@ -26,6 +26,7 @@
 #include <boost/format.hpp>
 
 #include "base/macros.h"
+#include "base/math.h"
 #include "base/wexception.h"
 #include "economy/economy.h"
 #include "economy/flag.h"
@@ -384,56 +385,53 @@
 ///
 /// pos is the location, in pixels, of the node position_ (height is already
 /// taken into account).
-Point Soldier::calc_drawpos(const EditorGameBase& game, const Point pos) const {
+Vector2f Soldier::calc_drawpos(const EditorGameBase& game,
+                                 const Vector2f& field_on_dst,
+                                 const float scale) const {
 	if (combat_walking_ == CD_NONE) {
-		return Bob::calc_drawpos(game, pos);
+		return Bob::calc_drawpos(game, field_on_dst, scale);
 	}
 
 	bool moving = false;
-	Point spos = pos, epos = pos;
+	Vector2f spos = field_on_dst, epos = field_on_dst;
 
+	const float triangle_width = kTriangleWidth * scale;
 	switch (combat_walking_) {
 	case CD_WALK_W:
 		moving = true;
-		epos.x -= kTriangleWidth / 4;
+		epos.x -= triangle_width / 4;
 		break;
 	case CD_WALK_E:
 		moving = true;
-		epos.x += kTriangleWidth / 4;
+		epos.x += triangle_width / 4;
 		break;
 	case CD_RETURN_W:
 		moving = true;
-		spos.x -= kTriangleWidth / 4;
+		spos.x -= triangle_width / 4;
 		break;
 	case CD_RETURN_E:
 		moving = true;
-		spos.x += kTriangleWidth / 4;
+		spos.x += triangle_width / 4;
 		break;
 	case CD_COMBAT_W:
 		moving = false;
-		epos.x -= kTriangleWidth / 4;
+		epos.x -= triangle_width / 4;
 		break;
 	case CD_COMBAT_E:
 		moving = false;
-		epos.x += kTriangleWidth / 4;
+		epos.x += triangle_width / 4;
 		break;
 	case CD_NONE:
 		break;
 	}
 
 	if (moving) {
-
-		float f = static_cast<float>(game.get_gametime() - combat_walkstart_) /
-		          (combat_walkend_ - combat_walkstart_);
+		const float f = math::clamp(static_cast<float>(game.get_gametime() - combat_walkstart_) /
+		                               (combat_walkend_ - combat_walkstart_),
+		                            0.f, 1.f);
 		assert(combat_walkstart_ <= game.get_gametime());
 		assert(combat_walkstart_ < combat_walkend_);
-
-		if (f < 0)
-			f = 0;
-		else if (f > 1)
-			f = 1;
-
-		epos.x = static_cast<int32_t>(f * epos.x + (1 - f) * spos.x);
+		epos.x = f * epos.x + (1 - f) * spos.x;
 	}
 	return epos;
 }
@@ -441,79 +439,104 @@
 /*
  * Draw this soldier. This basically draws him as a worker, but add health points
  */
-void Soldier::draw(const EditorGameBase& game, RenderTarget& dst, const Point& pos) const {
-	if (const uint32_t anim = get_current_anim()) {
-		const Point drawpos = calc_drawpos(game, pos);
-		draw_info_icon(
-		   dst, Point(drawpos.x, drawpos.y - g_gr->animations().get_animation(anim).height() - 7),
-		   true);
-
-		draw_inner(game, dst, drawpos);
+void Soldier::draw(const EditorGameBase& game,
+                   const DrawText&,
+                   const Vector2f& field_on_dst,
+                   const float scale,
+                   RenderTarget* dst) const {
+	const uint32_t anim = get_current_anim();
+	if (!anim) {
+		return;
 	}
+
+	const Vector2f point_on_dst = calc_drawpos(game, field_on_dst, scale);
+	draw_info_icon(
+	   point_on_dst -
+	      Vector2f(0.f, (g_gr->animations().get_animation(get_current_anim()).height() - 7) * scale),
+	   scale, true, dst);
+	draw_inner(game, point_on_dst, scale, dst);
 }
 
 /**
  * Draw the info icon (level indicators + health bar) for this soldier.
- *
- * \param anchor_below if \c true, the icon is drawn horizontally centered above
- * \p pt. Otherwise, the icon is drawn below and right of \p pt.
  */
-void Soldier::draw_info_icon(RenderTarget& dst, Point pt, bool anchor_below) const {
-	// Gather information to determine coordinates
-	uint32_t w;
-	w = kSoldierHealthBarWidth;
+void Soldier::draw_info_icon(Vector2f draw_position,
+                             float scale,
+                             const bool anchor_below,
+                             RenderTarget* dst) const {
+	// Since the graphics below are all pixel perfect and scaling them as floats
+	// looks weird, we round to the nearest fullest integer.
+	scale = std::round(scale);
+	if (scale == 0.f) {
+		return;
+	}
 
 	const Image* healthpic = get_health_level_pic();
 	const Image* attackpic = get_attack_level_pic();
 	const Image* defensepic = get_defense_level_pic();
 	const Image* evadepic = get_evade_level_pic();
 
-	uint16_t hpw = healthpic->width();
-	uint16_t hph = healthpic->height();
-	uint16_t atw = attackpic->width();
-	uint16_t ath = attackpic->height();
-	uint16_t dew = defensepic->width();
-	uint16_t deh = defensepic->height();
-	uint16_t evw = evadepic->width();
-	uint16_t evh = evadepic->height();
+#ifndef NDEBUG
+	// This function assumes stuff about our data files: level icons are all the
+	// same size and this is smaller than the width of the healthbar. This
+	// simplifies the drawing code below a lot. Before it had a lot of if () that
+	// were never tested - since our data files never changed.
+	const int dimension = attackpic->width();
+	assert(attackpic->height() == dimension);
+	assert(healthpic->width() == dimension);
+	assert(healthpic->height() == dimension);
+	assert(defensepic->width() == dimension);
+	assert(defensepic->height() == dimension);
+	assert(evadepic->width() == dimension);
+	assert(evadepic->height() == dimension);
+	assert(kSoldierHealthBarWidth > dimension);
+#endif
 
-	uint32_t totalwidth = std::max<int>(std::max<int>(atw + dew, hpw + evw), 2 * w);
-	uint32_t totalheight = 5 + std::max<int>(hph + ath, evh + deh);
+	const float icon_size = healthpic->width();
+	const float half_width = kSoldierHealthBarWidth;
 
 	if (!anchor_below) {
-		pt.x += totalwidth / 2;
-		pt.y += totalheight - 5;
+		float totalwidth = 2 * half_width;
+		float totalheight = 5.f + 2 * icon_size;
+		draw_position.x += (totalwidth / 2.f) * scale;
+		draw_position.y += (totalheight - 5.f) * scale;
 	} else {
-		pt.y -= 5;
+		draw_position.y -= 5.f * scale;
 	}
 
 	// Draw energy bar
-	Rect energy_outer(Point(pt.x - w, pt.y), w * 2, 5);
-	dst.draw_rect(energy_outer, RGBColor(255, 255, 255));
-
 	assert(get_max_health());
-	uint32_t health_width = 2 * (w - 1) * current_health_ / get_max_health();
-	Rect energy_inner(Point(pt.x - w + 1, pt.y + 1), health_width, 3);
-	Rect energy_complement(
-	   energy_inner.origin() + Point(health_width, 0), 2 * (w - 1) - health_width, 3);
+	const Rectf energy_outer(
+	   draw_position - Vector2f(half_width, 0.f) * scale, half_width * 2.f * scale, 5.f * scale);
+	dst->fill_rect(energy_outer, RGBColor(255, 255, 255));
+
+	float health_width = 2.f * (half_width - 1.f) * current_health_ / get_max_health();
+	Rectf energy_inner(
+	   draw_position + Vector2f(-half_width + 1.f, 1.f) * scale, health_width * scale, 3 * scale);
+	Rectf energy_complement(energy_inner.origin() + Vector2f(health_width, 0.f) * scale,
+	                        (2 * (half_width - 1) - health_width) * scale, 3 * scale);
+
 	const RGBColor& color = owner().get_playercolor();
 	RGBColor complement_color;
-
-	if (static_cast<uint32_t>(color.r) + color.g + color.b > 128 * 3)
+	if (static_cast<uint32_t>(color.r) + color.g + color.b > 128 * 3) {
 		complement_color = RGBColor(32, 32, 32);
-	else
+	} else {
 		complement_color = RGBColor(224, 224, 224);
-
-	dst.fill_rect(energy_inner, color);
-	dst.fill_rect(energy_complement, complement_color);
-
-	// Draw level pictures
-	{
-		dst.blit(pt + Point(-atw, -(hph + ath)), attackpic);
-		dst.blit(pt + Point(0, -(evh + deh)), defensepic);
-		dst.blit(pt + Point(-hpw, -hph), healthpic);
-		dst.blit(pt + Point(0, -evh), evadepic);
 	}
+
+	dst->fill_rect(energy_inner, color);
+	dst->fill_rect(energy_complement, complement_color);
+
+	const auto draw_level_image = [icon_size, scale, &draw_position, dst](
+	   const Vector2f& offset, const Image* image) {
+		dst->blitrect_scale(
+		   Rectf(draw_position + offset * icon_size * scale, icon_size * scale, icon_size * scale),
+		   image, Recti(0, 0, icon_size, icon_size), 1.f, BlendMode::UseAlpha);
+	};
+	draw_level_image(Vector2f(-1.f, -2.f), attackpic);
+	draw_level_image(Vector2f(0.f, -2.f), defensepic);
+	draw_level_image(Vector2f(-1.f, -1.f), healthpic);
+	draw_level_image(Vector2f(0.f, -1.f), evadepic);
 }
 
 /**
@@ -594,7 +617,7 @@
  * each other.
  */
 bool Soldier::can_be_challenged() {
-	if (current_health_ < 1) {  //< Soldier is dead!
+	if (current_health_ < 1) {  // Soldier is dead!
 		return false;
 	}
 	if (!is_on_battlefield()) {
@@ -896,9 +919,6 @@
 
 /**
  * Accept Bob when is a Soldier alive that is attacking the Player.
- *
- * \param g
- * \param p
  */
 struct FindBobSoldierAttackingPlayer : public FindBob {
 	FindBobSoldierAttackingPlayer(Game& g, Player& p) : player(p), game(g) {

=== modified file 'src/logic/map_objects/tribes/soldier.h'
--- src/logic/map_objects/tribes/soldier.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/soldier.h	2016-10-22 18:17:28 +0000
@@ -204,12 +204,25 @@
 	/// Automatically select a task.
 	void init_auto_task(Game&) override;
 
-	Point calc_drawpos(const EditorGameBase&, Point) const;
+	Vector2f
+	calc_drawpos(const EditorGameBase& game, const Vector2f& field_on_dst, const float scale) const;
+
 	/// Draw this soldier
-	void draw(const EditorGameBase&, RenderTarget&, const Point&) const override;
+	void draw(const EditorGameBase&,
+	          const DrawText& draw_text,
+	          const Vector2f& point_on_dst,
+	          float scale,
+	          RenderTarget* dst) const override;
 
 	static void calc_info_icon_size(const TribeDescr&, uint32_t& w, uint32_t& h);
-	void draw_info_icon(RenderTarget&, Point, bool anchor_below) const;
+
+	// Draw the info icon containing health bar and levels. If 'anchor_below' is
+	// true, the icon is drawn horizontally centered above Otherwise, the icon
+	// is drawn below and right of 'draw_position'.
+	void draw_info_icon(Vector2f draw_position,
+	                    const float scale,
+	                    const bool anchor_below,
+	                    RenderTarget*) const;
 
 	uint32_t get_current_health() const {
 		return current_health_;

=== modified file 'src/logic/map_objects/tribes/worker.cc'
--- src/logic/map_objects/tribes/worker.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/worker.cc	2016-10-22 18:17:28 +0000
@@ -2512,25 +2512,37 @@
 	return;
 }
 
-void Worker::draw_inner(const EditorGameBase& game, RenderTarget& dst, const Point& drawpos) const {
+void Worker::draw_inner(const EditorGameBase& game,
+                  const Vector2f& point_on_dst,
+                  const float scale,
+                  RenderTarget* dst) const {
 	assert(get_owner() != nullptr);
 	const RGBColor& player_color = get_owner()->get_playercolor();
 
-	dst.blit_animation(
-	   drawpos, get_current_anim(), game.get_gametime() - get_animstart(), player_color);
+	dst->blit_animation(
+	   point_on_dst, scale, get_current_anim(), game.get_gametime() - get_animstart(), player_color);
 
 	if (WareInstance const* const carried_ware = get_carried_ware(game)) {
-		dst.blit_animation(drawpos - descr().get_ware_hotspot(),
-		                   carried_ware->descr().get_animation("idle"), 0, player_color);
+		const Vector2f hotspot = descr().get_ware_hotspot().cast<float>();
+		const Vector2f location(
+		   point_on_dst.x - hotspot.x * scale, point_on_dst.y - hotspot.y * scale);
+		dst->blit_animation(
+		   location, scale, carried_ware->descr().get_animation("idle"), 0, player_color);
 	}
 }
 
 /**
  * Draw the worker, taking the carried ware into account.
  */
-void Worker::draw(const EditorGameBase& game, RenderTarget& dst, const Point& pos) const {
-	if (get_current_anim())
-		draw_inner(game, dst, calc_drawpos(game, pos));
+void Worker::draw(const EditorGameBase& egbase,
+                  const DrawText&,
+                  const Vector2f& field_on_dst,
+                  const float scale,
+                  RenderTarget* dst) const {
+	if (!get_current_anim()) {
+		return;
+	}
+	draw_inner(egbase, calc_drawpos(egbase, field_on_dst, scale), scale, dst);
 }
 
 /*

=== modified file 'src/logic/map_objects/tribes/worker.h'
--- src/logic/map_objects/tribes/worker.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/worker.h	2016-10-22 18:17:28 +0000
@@ -176,8 +176,15 @@
 
 protected:
 	virtual bool is_evict_allowed();
-	void draw_inner(const EditorGameBase&, RenderTarget&, const Point&) const;
-	void draw(const EditorGameBase&, RenderTarget&, const Point&) const override;
+	void draw_inner(const EditorGameBase& game,
+	                const Vector2f& point_on_dst,
+	                const float scale,
+	                RenderTarget* dst) const;
+	void draw(const EditorGameBase&,
+	          const DrawText& draw_text,
+	          const Vector2f& field_on_dst,
+	          float scale,
+	          RenderTarget* dst) const override;
 	void init_auto_task(Game&) override;
 
 	bool does_carry_ware() {

=== modified file 'src/logic/map_objects/tribes/worker_descr.cc'
--- src/logic/map_objects/tribes/worker_descr.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/worker_descr.cc	2016-10-22 18:17:28 +0000
@@ -22,7 +22,7 @@
 #include <memory>
 
 #include "base/i18n.h"
-#include "base/point.h"
+#include "base/vector.h"
 #include "base/wexception.h"
 #include "graphic/graphic.h"
 #include "logic/game_data_error.h"
@@ -41,7 +41,7 @@
                          const LuaTable& table,
                          const EditorGameBase& egbase)
    : BobDescr(init_descname, init_type, MapObjectDescr::OwnerType::kTribe, table),
-     ware_hotspot_(Point(0, 15)),
+     ware_hotspot_(Vector2i(0, 15)),
      buildable_(false),
      needed_experience_(INVALID_INDEX),
      becomes_(INVALID_INDEX),
@@ -122,7 +122,7 @@
 	}
 	if (table.has_key("ware_hotspot")) {
 		items_table = table.get_table("ware_hotspot");
-		ware_hotspot_ = Point(items_table->get_int(1), items_table->get_int(2));
+		ware_hotspot_ = Vector2i(items_table->get_int(1), items_table->get_int(2));
 	}
 }
 

=== modified file 'src/logic/map_objects/tribes/worker_descr.h'
--- src/logic/map_objects/tribes/worker_descr.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/worker_descr.h	2016-10-22 18:17:28 +0000
@@ -62,7 +62,7 @@
 		return buildcost_;
 	}
 
-	Point get_ware_hotspot() const {
+	Vector2i get_ware_hotspot() const {
 		return ware_hotspot_;
 	}
 
@@ -124,7 +124,7 @@
 	}
 
 protected:
-	Point ware_hotspot_;
+	Vector2i ware_hotspot_;
 	Quantity default_target_quantity_;
 	std::string helptext_script_;  // The path and filename to the worker's helptext script
 	DirAnimations walk_anims_;

=== modified file 'src/logic/widelands_geometry.h'
--- src/logic/widelands_geometry.h	2016-08-04 15:49:05 +0000
+++ src/logic/widelands_geometry.h	2016-10-22 18:17:28 +0000
@@ -38,6 +38,7 @@
 /**
  * Structure used to store map coordinates
  */
+// TODO(sirver): This should go away and be replaced by Vector2i16.
 struct Coords {
 	Coords();
 	Coords(int16_t nx, int16_t ny);

=== modified file 'src/map_io/map_saver.cc'
--- src/map_io/map_saver.cc	2016-08-13 18:54:33 +0000
+++ src/map_io/map_saver.cc	2016-10-22 18:17:28 +0000
@@ -296,11 +296,12 @@
 
 	// Write minimap
 	{
-		std::unique_ptr<Texture> minimap(
-		   draw_minimap(egbase_, nullptr, Point(0, 0), MiniMapLayer::Terrain));
+		std::unique_ptr<Texture> minimap(draw_minimap(
+		   egbase_, nullptr, Rectf(), MiniMapType::kStaticMap, MiniMapLayer::Terrain));
 		FileWrite fw;
 		save_to_png(minimap.get(), &fw, ColorType::RGBA);
 		fw.write(fs_, "minimap.png");
 	}
 }
-}
+
+}  // namespace Widelands

=== modified file 'src/profile/profile.cc'
--- src/profile/profile.cc	2016-08-13 20:01:13 +0000
+++ src/profile/profile.cc	2016-10-22 18:17:28 +0000
@@ -137,14 +137,14 @@
 	throw wexception("%s: '%s' is not a boolean value", get_name(), get_string());
 }
 
-Point Section::Value::get_point() const {
+Vector2i Section::Value::get_point() const {
 	char* endp = value_.get();
 	long int const x = strtol(endp, &endp, 0);
 	long int const y = strtol(endp, &endp, 0);
 	if (*endp)
-		throw wexception("%s: '%s' is not a Point", get_name(), get_string());
+		throw wexception("%s: '%s' is not a Vector2i", get_name(), get_string());
 
-	return Point(x, y);
+	return Vector2i(x, y);
 }
 
 void Section::Value::set_string(char const* const value) {
@@ -413,7 +413,7 @@
 	return v ? v->get_string() : def;
 }
 
-Point Section::get_point(const char* const name, const Point def) {
+Vector2i Section::get_point(const char* const name, const Vector2i def) {
 	Value const* const v = get_val(name);
 	return v ? v->get_point() : def;
 }

=== modified file 'src/profile/profile.h'
--- src/profile/profile.h	2016-08-04 15:49:05 +0000
+++ src/profile/profile.h	2016-10-22 18:17:28 +0000
@@ -26,7 +26,7 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/point.h"
+#include "base/vector.h"
 #include "io/filesystem/layered_filesystem.h"
 // TODO(unknown): as soon as g_fs is not needed anymore,
 // include "filesystem.h" instead of layered_filesystem.h.
@@ -85,7 +85,7 @@
 		char* get_string() {
 			return value_.get();
 		}
-		Point get_point() const;
+		Vector2i get_point() const;
 
 		void set_string(char const*);
 
@@ -126,7 +126,7 @@
 	uint32_t get_positive(char const* name, uint32_t def = 1);
 	bool get_bool(char const* name, bool def = false);
 	const char* get_string(char const* name, char const* def = nullptr);
-	Point get_point(char const* name, Point def = Point(0, 0));
+	Vector2i get_point(char const* name, Vector2i def = Vector2i(0, 0));
 
 	int32_t get_safe_int(const char* name);
 	uint32_t get_safe_natural(char const* name);

=== modified file 'src/scripting/lua_game.cc'
--- src/scripting/lua_game.cc	2016-08-07 20:39:44 +0000
+++ src/scripting/lua_game.cc	2016-10-22 18:17:28 +0000
@@ -448,7 +448,7 @@
 		lua_getfield(L, 4, "field");
 		if (!lua_isnil(L, -1)) {
 			Coords c = (*get_user_class<LuaField>(L, -1))->coords();
-			game.get_ipl()->move_view_to(c);
+			game.get_ipl()->center_view_on_coords(c);
 		}
 		lua_pop(L, 1);
 	}

=== modified file 'src/scripting/lua_map.cc'
--- src/scripting/lua_map.cc	2016-09-07 09:30:49 +0000
+++ src/scripting/lua_map.cc	2016-10-22 18:17:28 +0000
@@ -4970,15 +4970,15 @@
       this field for the current interactive player
 */
 int LuaField::get_viewpoint_x(lua_State* L) {
-	int32_t px, py;
-	MapviewPixelFunctions::get_save_pix(get_egbase(L).map(), coords_, px, py);
-	lua_pushint32(L, px);
+	Vector2f point =
+	   MapviewPixelFunctions::to_map_pixel_with_normalization(get_egbase(L).map(), coords_);
+	lua_pushdouble(L, point.x);
 	return 1;
 }
 int LuaField::get_viewpoint_y(lua_State* L) {
-	int32_t px, py;
-	MapviewPixelFunctions::get_save_pix(get_egbase(L).map(), coords_, px, py);
-	lua_pushint32(L, py);
+	Vector2f point =
+	   MapviewPixelFunctions::to_map_pixel_with_normalization(get_egbase(L).map(), coords_);
+	lua_pushdouble(L, point.y);
 	return 1;
 }
 

=== modified file 'src/scripting/lua_ui.cc'
--- src/scripting/lua_ui.cc	2016-08-04 15:49:05 +0000
+++ src/scripting/lua_ui.cc	2016-10-22 18:17:28 +0000
@@ -192,7 +192,7 @@
 }
 int LuaPanel::set_mouse_position_x(lua_State* L) {
 	assert(panel_);
-	Point p = panel_->get_mouse_position();
+	Vector2i p = panel_->get_mouse_position();
 	p.x = floor(luaL_checkdouble(L, -1));
 	panel_->set_mouse_pos(p);
 	return 1;
@@ -204,7 +204,7 @@
 }
 int LuaPanel::set_mouse_position_y(lua_State* L) {
 	assert(panel_);
-	Point p = panel_->get_mouse_position();
+	Vector2i p = panel_->get_mouse_position();
 	p.y = floor(luaL_checkdouble(L, -1));
 	panel_->set_mouse_pos(p);
 	return 1;
@@ -244,27 +244,27 @@
 */
 int LuaPanel::get_position_x(lua_State* L) {
 	assert(panel_);
-	Point p = panel_->to_parent(Point(0, 0));
+	Vector2i p = panel_->to_parent(Vector2i(0, 0));
 
 	lua_pushint32(L, p.x);
 	return 1;
 }
 int LuaPanel::set_position_x(lua_State* L) {
 	assert(panel_);
-	Point p(luaL_checkint32(L, -1) - panel_->get_lborder(), panel_->get_y());
+	Vector2i p(luaL_checkint32(L, -1) - panel_->get_lborder(), panel_->get_y());
 	panel_->set_pos(p);
 	return 1;
 }
 int LuaPanel::get_position_y(lua_State* L) {
 	assert(panel_);
-	Point p = panel_->to_parent(Point(0, 0));
+	Vector2i p = panel_->to_parent(Vector2i(0, 0));
 
 	lua_pushint32(L, p.y);
 	return 1;
 }
 int LuaPanel::set_position_y(lua_State* L) {
 	assert(panel_);
-	Point p(panel_->get_x(), luaL_checkint32(L, -1) - panel_->get_tborder());
+	Vector2i p(panel_->get_x(), luaL_checkint32(L, -1) - panel_->get_tborder());
 	panel_->set_pos(p);
 	return 1;
 }
@@ -289,9 +289,9 @@
 
 	UI::Panel* cur = (*get_base_user_class<LuaPanel>(L, 2))->panel_;
 
-	Point cp = Point(0, 0);
+	Vector2i cp = Vector2i(0, 0);
 	while (cur && cur != panel_) {
-		cp += cur->to_parent(Point(0, 0));
+		cp += cur->to_parent(Vector2i(0, 0));
 		cur = cur->get_parent();
 	}
 
@@ -526,7 +526,7 @@
 	}
 
 	MapView* mv = get();
-	Point p = mv->get_viewpoint();
+	Vector2i p = mv->get_viewpoint();
 	p.x = floor(luaL_checkdouble(L, -1));
 	mv->set_viewpoint(p, true);
 	return 0;
@@ -543,7 +543,7 @@
 	}
 
 	MapView* mv = get();
-	Point p = mv->get_viewpoint();
+	Vector2i p = mv->get_viewpoint();
 	p.y = floor(luaL_checkdouble(L, -1));
 	mv->set_viewpoint(p, true);
 	return 0;

=== modified file 'src/sound/sound_handler.cc'
--- src/sound/sound_handler.cc	2016-08-04 15:49:05 +0000
+++ src/sound/sound_handler.cc	2016-10-22 18:17:28 +0000
@@ -310,26 +310,26 @@
 	// Viewpoint is the point of the map in pixel which is shown in the upper
 	// left corner of window or fullscreen
 	const InteractiveBase& ibase = *egbase_->get_ibase();
-	Point const vp = ibase.get_viewpoint();
+	Vector2i const vp = ibase.get_viewpoint();
 
 	// Resolution of window or fullscreen
 	int32_t const xres = g_gr->get_xres();
 	int32_t const yres = g_gr->get_yres();
 
 	// Get pixel coordinates of sound source from map coordinates
-	Point position_pix;
-	MapviewPixelFunctions::get_pix(egbase_->map(), position_map, position_pix.x, position_pix.y);
+	Vector2f position_pix = MapviewPixelFunctions::to_map_pixel(egbase_->map(), position_map);
 
 	// Adjust pixel coordinates to viewpoint
 	position_pix.x -= vp.x;
 	position_pix.y -= vp.y;
 	// Normalizing correct invalid pixel coordinates
-	MapviewPixelFunctions::normalize_pix(egbase_->map(), position_pix);
+	Vector2i rounded = round(position_pix);
+	MapviewPixelFunctions::normalize_pix(egbase_->map(), &rounded);
 
 	// Make sure position is inside viewport
-	if (position_pix.x >= 0 && position_pix.x <= xres && position_pix.y >= 0 &&
-	    position_pix.y <= yres)
-		return position_pix.x * 254 / xres;
+	if (rounded.x >= 0 && rounded.x <= xres && rounded.y >= 0 && rounded.y <= yres) {
+		return rounded.x * 254 / xres;
+	}
 
 	return -1;
 }

=== modified file 'src/ui_basic/box.cc'
--- src/ui_basic/box.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/box.cc	2016-10-22 18:17:28 +0000
@@ -169,7 +169,7 @@
 			scrollbar_.reset(new Scrollbar(this, sb_x, sb_y, sb_w, sb_h, orientation_ == Horizontal));
 			scrollbar_->moved.connect(boost::bind(&Box::scrollbar_moved, this, _1));
 		} else {
-			scrollbar_->set_pos(Point(sb_x, sb_y));
+			scrollbar_->set_pos(Vector2i(sb_x, sb_y));
 			scrollbar_->set_size(sb_w, sb_h);
 		}
 		scrollbar_->set_steps(totaldepth - pagesize);
@@ -379,9 +379,9 @@
 		}
 
 		if (orientation_ == Horizontal)
-			it.u.panel.panel->set_pos(Point(pos, breadth));
+			it.u.panel.panel->set_pos(Vector2i(pos, breadth));
 		else
-			it.u.panel.panel->set_pos(Point(breadth, pos));
+			it.u.panel.panel->set_pos(Vector2i(breadth, pos));
 		break;
 	}
 

=== modified file 'src/ui_basic/button.cc'
--- src/ui_basic/button.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/button.cc	2016-10-22 18:17:28 +0000
@@ -154,48 +154,46 @@
 	// Draw the background
 	if (!flat_ || draw_flat_background_) {
 		assert(pic_background_);
-		dst.fill_rect(Rect(Point(0, 0), get_w(), get_h()), RGBAColor(0, 0, 0, 255));
-		dst.tile(Rect(Point(0, 0), get_w(), get_h()), pic_background_, Point(get_x(), get_y()));
+		dst.fill_rect(Rectf(0.f, 0.f, get_w(), get_h()), RGBAColor(0, 0, 0, 255));
+		dst.tile(Recti(Vector2i(0, 0), get_w(), get_h()), pic_background_, Vector2i(get_x(), get_y()));
 	}
 
 	if (enabled_ && highlighted_ && !flat_)
-		dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
 
 	//  If we've got a picture, draw it centered
 	if (pic_custom_) {
 		if (keep_image_size_) {
 			if (enabled_) {
-				//  ">> 1" is almost like "/ 2", but simpler for signed types (difference
-				//  is that -1 >> 1 is -1 but -1 / 2 is 0).
-				dst.blit(Point((get_w() - static_cast<int32_t>(pic_custom_->width())) >> 1,
-				               (get_h() - static_cast<int32_t>(pic_custom_->height())) >> 1),
+				dst.blit(Vector2f((get_w() - static_cast<int32_t>(pic_custom_->width())) / 2.f,
+				                  (get_h() - static_cast<int32_t>(pic_custom_->height())) / 2.f),
 				         pic_custom_);
 			} else {
-				//  ">> 1" is almost like "/ 2", but simpler for signed types (difference
-				//  is that -1 >> 1 is -1 but -1 / 2 is 0).
-				dst.blit_monochrome(Point((get_w() - static_cast<int32_t>(pic_custom_->width())) >> 1,
-				                          (get_h() - static_cast<int32_t>(pic_custom_->height())) >> 1),
-				                    pic_custom_, RGBAColor(255, 255, 255, 127));
+				dst.blit_monochrome(
+				   Vector2f((get_w() - static_cast<int32_t>(pic_custom_->width())) / 2.f,
+				            (get_h() - static_cast<int32_t>(pic_custom_->height())) / 2.f),
+				   pic_custom_, RGBAColor(255, 255, 255, 127));
 			}
 		} else {
 			const int max_image_w = get_w() - 2 * kButtonImageMargin;
 			const int max_image_h = get_h() - 2 * kButtonImageMargin;
-			double image_scale =
-			   std::min(1., std::min(static_cast<double>(max_image_w) / pic_custom_->width(),
-			                         static_cast<double>(max_image_h) / pic_custom_->height()));
+			const float image_scale =
+			   std::min(1.f, std::min(static_cast<float>(max_image_w) / pic_custom_->width(),
+			                          static_cast<float>(max_image_h) / pic_custom_->height()));
 			int blit_width = image_scale * pic_custom_->width();
 			int blit_height = image_scale * pic_custom_->height();
 
 			if (enabled_) {
-				dst.blitrect_scale(Rect((get_w() - blit_width) / 2, (get_h() - blit_height) / 2,
-				                        blit_width, blit_height),
-				                   pic_custom_, Rect(0, 0, pic_custom_->width(), pic_custom_->height()),
-				                   1., BlendMode::UseAlpha);
+				dst.blitrect_scale(Rectf((get_w() - blit_width) / 2.f, (get_h() - blit_height) / 2.f,
+				                         blit_width, blit_height),
+				                   pic_custom_,
+				                   Recti(0, 0, pic_custom_->width(), pic_custom_->height()), 1.,
+				                   BlendMode::UseAlpha);
 			} else {
 				dst.blitrect_scale_monochrome(
-				   Rect(
-				      (get_w() - blit_width) / 2, (get_h() - blit_height) / 2, blit_width, blit_height),
-				   pic_custom_, Rect(0, 0, pic_custom_->width(), pic_custom_->height()),
+				   Rectf((get_w() - blit_width) / 2.f, (get_h() - blit_height) / 2.f, blit_width,
+				         blit_height),
+				   pic_custom_, Recti(0, 0, pic_custom_->width(), pic_custom_->height()),
 				   RGBAColor(255, 255, 255, 127));
 			}
 		}
@@ -207,7 +205,7 @@
 		                   enabled_ ? UI_FONT_CLR_FG : UI_FONT_CLR_DISABLED);
 
 		dst.blit(
-		   Point((get_w() - entry_text_im->width()) / 2, (get_h() - entry_text_im->height()) / 2),
+		   Vector2f((get_w() - entry_text_im->width()) / 2.f, (get_h() - entry_text_im->height()) / 2.f),
 		   entry_text_im);
 	}
 
@@ -226,36 +224,36 @@
 		//  button is a normal one, not flat
 		if (!draw_pressed) {
 			//  top edge
-			dst.brighten_rect(Rect(Point(0, 0), get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
+			dst.brighten_rect(Rectf(0.f, 0.f, get_w(), 2.f), BUTTON_EDGE_BRIGHT_FACTOR);
 			//  left edge
-			dst.brighten_rect(Rect(Point(0, 2), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+			dst.brighten_rect(Rectf(0, 2, 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 			//  bottom edge
-			dst.fill_rect(Rect(Point(2, get_h() - 2), get_w() - 2, 1), black);
-			dst.fill_rect(Rect(Point(1, get_h() - 1), get_w() - 1, 1), black);
+			dst.fill_rect(Rectf(2, get_h() - 2, get_w() - 2, 1), black);
+			dst.fill_rect(Rectf(1, get_h() - 1, get_w() - 1, 1), black);
 			//  right edge
-			dst.fill_rect(Rect(Point(get_w() - 2, 2), 1, get_h() - 2), black);
-			dst.fill_rect(Rect(Point(get_w() - 1, 1), 1, get_h() - 1), black);
+			dst.fill_rect(Rectf(get_w() - 2, 2, 1, get_h() - 2), black);
+			dst.fill_rect(Rectf(get_w() - 1, 1, 1, get_h() - 1), black);
 		} else {
 			//  bottom edge
-			dst.brighten_rect(Rect(Point(0, get_h() - 2), get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
+			dst.brighten_rect(Rectf(0, get_h() - 2, get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
 			//  right edge
-			dst.brighten_rect(Rect(Point(get_w() - 2, 0), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+			dst.brighten_rect(Rectf(get_w() - 2, 0, 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 			//  top edge
-			dst.fill_rect(Rect(Point(0, 0), get_w() - 1, 1), black);
-			dst.fill_rect(Rect(Point(0, 1), get_w() - 2, 1), black);
+			dst.fill_rect(Rectf(0, 0, get_w() - 1, 1), black);
+			dst.fill_rect(Rectf(0, 1, get_w() - 2, 1), black);
 			//  left edge
-			dst.fill_rect(Rect(Point(0, 0), 1, get_h() - 1), black);
-			dst.fill_rect(Rect(Point(1, 0), 1, get_h() - 2), black);
+			dst.fill_rect(Rectf(0, 0, 1, get_h() - 1), black);
+			dst.fill_rect(Rectf(1, 0, 1, get_h() - 2), black);
 		}
 	} else {
 		//  Button is flat, do not draw borders, instead, if it is pressed, draw
 		//  a box around it.
 		if (enabled_ && highlighted_) {
 			RGBAColor shade(100, 100, 100, 80);
-			dst.fill_rect(Rect(Point(0, 0), get_w(), 2), shade);
-			dst.fill_rect(Rect(Point(0, 2), 2, get_h() - 2), shade);
-			dst.fill_rect(Rect(Point(0, get_h() - 2), get_w(), get_h()), shade);
-			dst.fill_rect(Rect(Point(get_w() - 2, 0), get_w(), get_h()), shade);
+			dst.fill_rect(Rectf(0, 0, get_w(), 2), shade);
+			dst.fill_rect(Rectf(0, 2, 2, get_h() - 2), shade);
+			dst.fill_rect(Rectf(0, get_h() - 2, get_w(), get_h()), shade);
+			dst.fill_rect(Rectf(get_w() - 2, 0, get_w(), get_h()), shade);
 		}
 	}
 }

=== modified file 'src/ui_basic/checkbox.cc'
--- src/ui_basic/checkbox.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/checkbox.cc	2016-10-22 18:17:28 +0000
@@ -33,7 +33,7 @@
  * checkbox graphics.
 */
 Statebox::Statebox(Panel* const parent,
-                   Point const p,
+                   Vector2i const p,
                    const Image* pic,
                    const std::string& tooltip_text)
    : Panel(parent, p.x, p.y, kStateboxSize, kStateboxSize, tooltip_text),
@@ -49,7 +49,7 @@
 }
 
 Statebox::Statebox(Panel* const parent,
-                   Point const p,
+                   Vector2i const p,
                    const std::string& label_text,
                    const std::string& tooltip_text,
                    uint32_t width)
@@ -113,18 +113,18 @@
 		const uint16_t w = pic_graphics_->width();
 		const uint16_t h = pic_graphics_->height();
 
-		dst.blit(Point((get_inner_w() - w) / 2, (get_inner_h() - h) / 2), pic_graphics_);
+		dst.blit(Vector2f((get_inner_w() - w) / 2., (get_inner_h() - h) / 2.), pic_graphics_);
 
 		if (flags_ & Is_Checked) {
-			dst.draw_rect(Rect(Point(0, 0), get_w(), get_h()), RGBColor(229, 116, 2));
+			dst.draw_rect(Rectf(0.f, 0.f, get_w(), get_h()), RGBColor(229, 116, 2));
 		} else if (flags_ & Is_Highlighted) {
-			dst.draw_rect(Rect(Point(0, 0), get_w(), get_h()), RGBColor(100, 100, 80));
+			dst.draw_rect(Rectf(0.f, 0.f, get_w(), get_h()), RGBColor(100, 100, 80));
 		}
 	} else {
 		static_assert(0 <= kStateboxSize, "assert(0 <= STATEBOX_WIDTH) failed.");
 		static_assert(0 <= kStateboxSize, "assert(0 <= STATEBOX_HEIGHT) failed.");
-		Point image_anchor(0, 0);
-		Point text_anchor(kStateboxSize + kPadding, 0);
+		Vector2f image_anchor(0.f, 0.f);
+		Vector2f text_anchor(kStateboxSize + kPadding, 0);
 
 		if (rendered_text_) {
 			if (UI::g_fh1->fontset()->is_rtl()) {
@@ -137,11 +137,11 @@
 
 		dst.blitrect(
 		   image_anchor, pic_graphics_,
-		   Rect(Point(flags_ & Is_Checked ? kStateboxSize : 0, 0), kStateboxSize, kStateboxSize));
+		   Recti(Vector2i(flags_ & Is_Checked ? kStateboxSize : 0, 0), kStateboxSize, kStateboxSize));
 
 		if (flags_ & Is_Highlighted)
 			dst.draw_rect(
-			   Rect(image_anchor, kStateboxSize + 1, kStateboxSize + 1), RGBColor(100, 100, 80));
+			   Rectf(image_anchor, kStateboxSize + 1, kStateboxSize + 1), RGBColor(100, 100, 80));
 	}
 }
 

=== modified file 'src/ui_basic/checkbox.h'
--- src/ui_basic/checkbox.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/checkbox.h	2016-10-22 18:17:28 +0000
@@ -39,7 +39,7 @@
 	 * Pictorial Statebox
 	 */
 	Statebox(Panel* parent,
-	         Point,
+	         Vector2i,
 	         const Image* pic,
 	         const std::string& tooltip_text = std::string());
 
@@ -49,7 +49,7 @@
 	 * Otherwise, it will take up multiple lines if necessary (automatic height).
 	 */
 	Statebox(Panel* parent,
-	         Point,
+	         Vector2i,
 	         const std::string& label_text,
 	         const std::string& tooltip_text = std::string(),
 	         uint32_t width = 0);
@@ -111,7 +111,7 @@
 	 * Pictorial Checkbox
 	 */
 	Checkbox(Panel* const parent,
-	         Point const p,
+	         Vector2i const p,
 	         const Image* pic,
 	         const std::string& tooltip_text = std::string())
 	   : Statebox(parent, p, pic, tooltip_text) {
@@ -123,7 +123,7 @@
 	 * Otherwise, it will take up multiple lines if necessary (automatic height).
 	 */
 	Checkbox(Panel* const parent,
-	         Point const p,
+	         Vector2i const p,
 	         const std::string& label_text,
 	         const std::string& tooltip_text = std::string(),
 	         uint32_t width = 0)

=== modified file 'src/ui_basic/editbox.cc'
--- src/ui_basic/editbox.cc	2016-08-07 08:18:51 +0000
+++ src/ui_basic/editbox.cc	2016-10-22 18:17:28 +0000
@@ -359,26 +359,26 @@
 	RenderTarget& dst = odst;
 
 	// Draw the background
-	dst.tile(Rect(Point(0, 0), get_w(), get_h()), m_->background, Point(get_x(), get_y()));
+	dst.tile(Recti(0, 0, get_w(), get_h()), m_->background, Vector2i(get_x(), get_y()));
 
 	// Draw border.
 	if (get_w() >= 2 && get_h() >= 2) {
 		static const RGBColor black(0, 0, 0);
 
 		// bottom edge
-		dst.brighten_rect(Rect(Point(0, get_h() - 2), get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0, get_h() - 2, get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// right edge
-		dst.brighten_rect(Rect(Point(get_w() - 2, 0), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(get_w() - 2, 0, 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// top edge
-		dst.fill_rect(Rect(Point(0, 0), get_w() - 1, 1), black);
-		dst.fill_rect(Rect(Point(0, 1), get_w() - 2, 1), black);
+		dst.fill_rect(Rectf(0.f, 0.f, get_w() - 1, 1), black);
+		dst.fill_rect(Rectf(0.f, 1.f, get_w() - 2, 1), black);
 		// left edge
-		dst.fill_rect(Rect(Point(0, 0), 1, get_h() - 1), black);
-		dst.fill_rect(Rect(Point(1, 0), 1, get_h() - 2), black);
+		dst.fill_rect(Rectf(0.f, 0.f, 1, get_h() - 1), black);
+		dst.fill_rect(Rectf(1.f, 0.f, 1, get_h() - 2), black);
 	}
 
 	if (has_focus()) {
-		dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
 	}
 
 	const int max_width = get_w() - 2 * kMarginX;
@@ -393,7 +393,7 @@
 	         ->height() :
 	      entry_text_im->height();
 
-	Point point(kMarginX, get_h() / 2);
+	Vector2f point(kMarginX, get_h() / 2.f);
 
 	if (static_cast<int>(m_->align & UI::Align::kRight)) {
 		point.x += max_width;
@@ -405,23 +405,23 @@
 	if (max_width < linewidth) {
 		// Fix positioning for BiDi languages.
 		if (UI::g_fh1->fontset()->is_rtl()) {
-			point.x = 0;
+			point.x = 0.f;
 		}
 		// We want this always on, e.g. for mixed language savegame filenames
 		if (i18n::has_rtl_character(m_->text.c_str(), 100)) {  // Restrict check for efficiency
 			// TODO(GunChleoc): Arabic: Fix scrolloffset
-			dst.blitrect(point, entry_text_im, Rect(linewidth - max_width, 0, linewidth, lineheight));
+			dst.blitrect(point, entry_text_im, Recti(linewidth - max_width, 0, linewidth, lineheight));
 		} else {
 			if (static_cast<int>(m_->align & UI::Align::kRight)) {
 				// TODO(GunChleoc): Arabic: Fix scrolloffset
 				dst.blitrect(point, entry_text_im,
-				             Rect(point.x + m_->scrolloffset + kMarginX, 0, max_width, lineheight));
+				             Recti(point.x + m_->scrolloffset + kMarginX, 0, max_width, lineheight));
 			} else {
-				dst.blitrect(point, entry_text_im, Rect(-m_->scrolloffset, 0, max_width, lineheight));
+				dst.blitrect(point, entry_text_im, Recti(-m_->scrolloffset, 0, max_width, lineheight));
 			}
 		}
 	} else {
-		dst.blitrect(point, entry_text_im, Rect(0, 0, max_width, lineheight));
+		dst.blitrect(point, entry_text_im, Recti(0, 0, max_width, lineheight));
 	}
 
 	if (has_focus()) {
@@ -433,9 +433,9 @@
 		const uint16_t fontheight = text_height(m_->text, m_->fontsize);
 
 		const Image* caret_image = g_gr->images().get("images/ui_basic/caret.png");
-		Point caretpt;
+		Vector2f caretpt;
 		caretpt.x = point.x + m_->scrolloffset + caret_x - caret_image->width() + LINE_MARGIN;
-		caretpt.y = point.y + (fontheight - caret_image->height()) / 2;
+		caretpt.y = point.y + (fontheight - caret_image->height()) / 2.f;
 		dst.blit(caretpt, caret_image);
 	}
 }

=== modified file 'src/ui_basic/icon.cc'
--- src/ui_basic/icon.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/icon.cc	2016-10-22 18:17:28 +0000
@@ -52,19 +52,18 @@
 
 void Icon::draw(RenderTarget& dst) {
 	if (pic_) {
-		double scale = std::min(static_cast<double>(get_w()) / pic_->width(),
-		                        static_cast<double>(get_h()) / pic_->height());
-		scale = std::min(1., scale);
+		const float scale = std::min(1.f, std::min(static_cast<float>(get_w()) / pic_->width(),
+		                                           static_cast<float>(get_h()) / pic_->height()));
 
-		int width = scale * get_w();
-		int height = scale * get_h();
-		int x = (get_w() - width) / 2;
-		int y = (get_h() - height) / 2;
-		dst.blitrect_scale(Rect(x, y, width, height), pic_, Rect(0, 0, pic_->width(), pic_->height()),
-		                   1., BlendMode::UseAlpha);
+		const float width = scale * get_w();
+		const float height = scale * get_h();
+		const float x = (get_w() - width) / 2.f;
+		const float y = (get_h() - height) / 2.f;
+		dst.blitrect_scale(Rectf(x, y, width, height), pic_,
+		                   Recti(0, 0, pic_->width(), pic_->height()), 1., BlendMode::UseAlpha);
 	}
 	if (draw_frame_) {
-		dst.draw_rect(Rect(0, 0, get_w(), get_h()), framecolor_);
+		dst.draw_rect(Rectf(0.f, 0.f, get_w(), get_h()), framecolor_);
 	}
 }
 }

=== modified file 'src/ui_basic/listselect.cc'
--- src/ui_basic/listselect.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/listselect.cc	2016-10-22 18:17:28 +0000
@@ -309,9 +309,9 @@
 	// draw text lines
 	const uint32_t lineheight = get_lineheight();
 	uint32_t idx = scrollpos_ / lineheight;
-	int32_t y = 1 + idx * lineheight - scrollpos_;
+	float y = 1 + idx * lineheight - scrollpos_;
 
-	dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), ms_darken_value);
+	dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), ms_darken_value);
 
 	while (idx < entry_records_.size()) {
 		assert(get_h() < std::numeric_limits<int32_t>::max());
@@ -321,12 +321,12 @@
 
 		const EntryRecord& er = *entry_records_[idx];
 
-		Point point(1, y);
+		Vector2f point(1.f, y);
 		uint32_t maxw = get_eff_w() - 2;
 
 		// Highlight the current selected entry
 		if (idx == selection_) {
-			Rect r = Rect(point, maxw, lineheight_);
+			Rectf r(point, maxw, lineheight_);
 			if (r.x < 0) {
 				r.w += r.x;
 				r.x = 0;
@@ -346,8 +346,8 @@
 
 		// Now draw pictures
 		if (er.pic) {
-			dst.blit(Point(UI::g_fh1->fontset()->is_rtl() ? get_eff_w() - er.pic->width() - 1 : 1,
-			               y + (get_lineheight() - er.pic->height()) / 2),
+			dst.blit(Vector2f(UI::g_fh1->fontset()->is_rtl() ? get_eff_w() - er.pic->width() - 1 : 1,
+			                  y + (get_lineheight() - er.pic->height()) / 2.f),
 			         er.pic);
 		}
 
@@ -383,9 +383,9 @@
 			// We want this always on, e.g. for mixed language savegame filenames, or the languages
 			// list
 			dst.blitrect(point, entry_text_im,
-			             Rect(entry_text_im->width() - maxw + picw, 0, maxw, entry_text_im->height()));
+			             Recti(entry_text_im->width() - maxw + picw, 0, maxw, entry_text_im->height()));
 		} else {
-			dst.blitrect(point, entry_text_im, Rect(0, 0, maxw, entry_text_im->height()));
+			dst.blitrect(point, entry_text_im, Recti(0, 0, maxw, entry_text_im->height()));
 		}
 
 		y += lineheight;

=== modified file 'src/ui_basic/multilineeditbox.cc'
--- src/ui_basic/multilineeditbox.cc	2016-08-07 10:10:18 +0000
+++ src/ui_basic/multilineeditbox.cc	2016-10-22 18:17:28 +0000
@@ -424,32 +424,32 @@
  */
 void MultilineEditbox::draw(RenderTarget& dst) {
 	// Draw the background
-	dst.tile(Rect(Point(0, 0), get_w(), get_h()), d_->background, Point(get_x(), get_y()));
+	dst.tile(Recti(Vector2i(0, 0), get_w(), get_h()), d_->background, Vector2i(get_x(), get_y()));
 
 	// Draw border.
 	if (get_w() >= 4 && get_h() >= 4) {
 		static const RGBColor black(0, 0, 0);
 
 		// bottom edge
-		dst.brighten_rect(Rect(Point(0, get_h() - 2), get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0.f, get_h() - 2, get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// right edge
-		dst.brighten_rect(Rect(Point(get_w() - 2, 0), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(get_w() - 2, 0, 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// top edge
-		dst.fill_rect(Rect(Point(0, 0), get_w() - 1, 1), black);
-		dst.fill_rect(Rect(Point(0, 1), get_w() - 2, 1), black);
+		dst.fill_rect(Rectf(0, 0, get_w() - 1, 1), black);
+		dst.fill_rect(Rectf(0, 1, get_w() - 2, 1), black);
 		// left edge
-		dst.fill_rect(Rect(Point(0, 0), 1, get_h() - 1), black);
-		dst.fill_rect(Rect(Point(1, 0), 1, get_h() - 2), black);
+		dst.fill_rect(Rectf(0, 0, 1, get_h() - 1), black);
+		dst.fill_rect(Rectf(1, 0, 1, get_h() - 2), black);
 	}
 
 	if (has_focus())
-		dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0, 0, get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
 
 	d_->refresh_ww();
 
 	d_->ww.set_draw_caret(has_focus());
 
-	d_->ww.draw(dst, Point(0, -int32_t(d_->scrollbar.get_scrollpos())), UI::Align::kLeft,
+	d_->ww.draw(dst, Vector2i(0, -int32_t(d_->scrollbar.get_scrollpos())), UI::Align::kLeft,
 	            has_focus() ? d_->cursor_pos : std::numeric_limits<uint32_t>::max());
 }
 

=== modified file 'src/ui_basic/multilinetextarea.cc'
--- src/ui_basic/multilinetextarea.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/multilinetextarea.cc	2016-10-22 18:17:28 +0000
@@ -134,7 +134,7 @@
 	recompute();
 
 	// Take care of the scrollbar
-	scrollbar_.set_pos(Point(get_w() - Scrollbar::kSize, 0));
+	scrollbar_.set_pos(Vector2i(get_w() - Scrollbar::kSize, 0));
 	scrollbar_.set_size(Scrollbar::kSize, get_h());
 	scrollbar_.set_pagesize(get_h() - 2 * UI_FONT_SIZE_BIG);
 }
@@ -144,7 +144,7 @@
  */
 void MultilineTextarea::draw(RenderTarget& dst) {
 	if (use_old_renderer_) {
-		rt.draw(dst, Point(RICHTEXT_MARGIN, RICHTEXT_MARGIN - scrollbar_.get_scrollpos()));
+		rt.draw(dst, Vector2i(RICHTEXT_MARGIN, RICHTEXT_MARGIN - scrollbar_.get_scrollpos()));
 	} else {
 		const Image* text_im;
 		if (!is_richtext(text_)) {
@@ -157,11 +157,11 @@
 		uint32_t blit_height = std::min(text_im->height(), static_cast<int>(get_inner_h()));
 
 		if (blit_width > 0 && blit_height > 0) {
-			int32_t anchor = 0;
+			float anchor = 0.f;
 			Align alignment = mirror_alignment(align_);
 			switch (alignment & UI::Align::kHorizontal) {
 			case UI::Align::kHCenter:
-				anchor = (get_eff_w() - blit_width) / 2;
+				anchor = (get_eff_w() - blit_width) / 2.f;
 				break;
 			case UI::Align::kRight:
 				anchor = get_eff_w() - blit_width - RICHTEXT_MARGIN;
@@ -170,9 +170,9 @@
 				anchor = RICHTEXT_MARGIN;
 			}
 
-			dst.blitrect_scale(Rect(anchor, 0, blit_width, blit_height), text_im,
-			                   Rect(0, scrollbar_.get_scrollpos(), blit_width, blit_height), 1.,
-			                   BlendMode::UseAlpha);
+			dst.blitrect(Vector2f(anchor, 0), text_im,
+			             Recti(0, scrollbar_.get_scrollpos(), blit_width, blit_height),
+			             BlendMode::UseAlpha);
 		}
 	}
 }

=== modified file 'src/ui_basic/panel.cc'
--- src/ui_basic/panel.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/panel.cc	2016-10-22 18:17:28 +0000
@@ -190,9 +190,9 @@
 		if (start_time >= next_draw_time) {
 			RenderTarget& rt = *g_gr->get_render_target();
 			forefather->do_draw(rt);
-			rt.blit(app->get_mouse_position() - Point(3, 7), WLApplication::get()->is_mouse_pressed() ?
-			                                                    default_cursor_click_ :
-			                                                    default_cursor_);
+			rt.blit(
+			   (app->get_mouse_position() - Vector2i(3, 7)).cast<float>(),
+			   WLApplication::get()->is_mouse_pressed() ? default_cursor_click_ : default_cursor_);
 			forefather->do_tooltip();
 			g_gr->refresh();
 			next_draw_time = start_time + draw_delay;
@@ -252,7 +252,7 @@
 /**
  * Move the panel. Panel's position is relative to the parent.
  */
-void Panel::set_pos(const Point n) {
+void Panel::set_pos(const Vector2i n) {
 	x_ = n.x;
 	y_ = n.y;
 }
@@ -320,11 +320,11 @@
  * and translate it into the interior coordinate system of the parent
  * and return the result.
  */
-Point Panel::to_parent(const Point& pt) const {
+Vector2i Panel::to_parent(const Vector2i& pt) const {
 	if (!parent_)
 		return pt;
 
-	return pt + Point(lborder_ + x_, tborder_ + y_);
+	return pt + Vector2i(lborder_ + x_, tborder_ + y_);
 }
 
 /**
@@ -447,16 +447,16 @@
 /**
  * Get mouse position relative to this panel
 */
-Point Panel::get_mouse_position() const {
+Vector2i Panel::get_mouse_position() const {
 	return (parent_ ? parent_->get_mouse_position() : WLApplication::get()->get_mouse_position()) -
-	       Point(get_x() + get_lborder(), get_y() + get_tborder());
+	       Vector2i(get_x() + get_lborder(), get_y() + get_tborder());
 }
 
 /**
  * Set mouse position relative to this panel
 */
-void Panel::set_mouse_pos(const Point p) {
-	const Point relative_p = p + Point(get_x() + get_lborder(), get_y() + get_tborder());
+void Panel::set_mouse_pos(const Vector2i p) {
+	const Vector2i relative_p = p + Vector2i(get_x() + get_lborder(), get_y() + get_tborder());
 	if (parent_)
 		parent_->set_mouse_pos(relative_p);
 	else
@@ -467,7 +467,7 @@
  * Center the mouse on this panel.
 */
 void Panel::center_mouse() {
-	set_mouse_pos(Point(get_w() / 2, get_h() / 2));
+	set_mouse_pos(Vector2i(get_w() / 2, get_h() / 2));
 }
 
 /**
@@ -728,16 +728,16 @@
 	if (!is_visible())
 		return;
 
-	Rect outerrc;
-	Point outerofs;
+	Recti outerrc;
+	Vector2i outerofs;
 
-	if (!dst.enter_window(Rect(Point(x_, y_), w_, h_), &outerrc, &outerofs))
+	if (!dst.enter_window(Recti(Vector2i(x_, y_), w_, h_), &outerrc, &outerofs))
 		return;
 
 	draw_border(dst);
 
-	Rect innerwindow(
-	   Point(lborder_, tborder_), w_ - (lborder_ + rborder_), h_ - (tborder_ + bborder_));
+	Recti innerwindow(
+	   Vector2i(lborder_, tborder_), w_ - (lborder_ + rborder_), h_ - (tborder_ + bborder_));
 
 	if (dst.enter_window(innerwindow, nullptr, nullptr))
 		do_draw_inner(dst);
@@ -804,7 +804,7 @@
 	return handle_mousepress(btn, x, y);
 }
 
-bool Panel::do_mousewheel(uint32_t which, int32_t x, int32_t y, Point rel_mouse_pos) {
+bool Panel::do_mousewheel(uint32_t which, int32_t x, int32_t y, Vector2i rel_mouse_pos) {
 
 	// Check if a child-panel is beneath the mouse and processes the event
 	for (Panel* child = first_child_; child; child = child->next_) {
@@ -819,7 +819,7 @@
 		}
 		// Found a child at the position
 		if (child->do_mousewheel(
-		       which, x, y, rel_mouse_pos - Point(child->get_x() + child->get_lborder(),
+		       which, x, y, rel_mouse_pos - Vector2i(child->get_x() + child->get_lborder(),
 		                                          child->get_y() + child->get_tborder()))) {
 			return true;
 		}
@@ -1051,9 +1051,9 @@
 	uint16_t tip_width = rendered_text->width() + 4;
 	uint16_t tip_height = rendered_text->height() + 4;
 
-	Rect r(WLApplication::get()->get_mouse_position() + Point(2, 32), tip_width, tip_height);
-	const Point tooltip_bottom_right = r.opposite_of_origin();
-	const Point screen_bottom_right(g_gr->get_xres(), g_gr->get_yres());
+	Rectf r(WLApplication::get()->get_mouse_position() + Vector2i(2, 32), tip_width, tip_height);
+	const Vector2f tooltip_bottom_right = r.opposite_of_origin();
+	const Vector2f screen_bottom_right(g_gr->get_xres(), g_gr->get_yres());
 	if (screen_bottom_right.x < tooltip_bottom_right.x)
 		r.x -= 4 + r.w;
 	if (screen_bottom_right.y < tooltip_bottom_right.y)
@@ -1061,7 +1061,7 @@
 
 	dst.fill_rect(r, RGBColor(63, 52, 34));
 	dst.draw_rect(r, RGBColor(0, 0, 0));
-	dst.blit(r.origin() + Point(2, 2), rendered_text);
+	dst.blit(r.origin() + Vector2f(2.f, 2.f), rendered_text);
 	return true;
 }
 }

=== modified file 'src/ui_basic/panel.h'
--- src/ui_basic/panel.h	2016-08-04 15:59:26 +0000
+++ src/ui_basic/panel.h	2016-10-22 18:17:28 +0000
@@ -28,7 +28,7 @@
 #include <boost/signals2/trackable.hpp>
 
 #include "base/macros.h"
-#include "base/point.h"
+#include "base/vector.h"
 
 class RenderTarget;
 class Image;
@@ -113,7 +113,7 @@
 	// Geometry
 	void set_size(int nw, int nh);
 	void set_desired_size(int w, int h);
-	void set_pos(Point);
+	void set_pos(Vector2i);
 	virtual void move_inside_parent();
 	virtual void layout();
 
@@ -128,8 +128,8 @@
 	int32_t get_y() const {
 		return y_;
 	}
-	Point get_pos() const {
-		return Point(x_, y_);
+	Vector2i get_pos() const {
+		return Vector2i(x_, y_);
 	}
 	// int instead of uint because of overflow situations
 	int32_t get_w() const {
@@ -139,7 +139,7 @@
 		return h_;
 	}
 
-	Point to_parent(const Point&) const;
+	Vector2i to_parent(const Vector2i&) const;
 
 	virtual bool is_snap_target() const {
 		return false;
@@ -229,8 +229,8 @@
 	// Events
 	virtual void think();
 
-	Point get_mouse_position() const;
-	void set_mouse_pos(Point);
+	Vector2i get_mouse_position() const;
+	void set_mouse_pos(Vector2i);
 	void center_mouse();
 
 	virtual void handle_mousein(bool inside);
@@ -337,7 +337,7 @@
 	bool do_mousepress(const uint8_t btn, int32_t x, int32_t y);
 	bool do_mouserelease(const uint8_t btn, int32_t x, int32_t y);
 	bool do_mousemove(const uint8_t state, int32_t x, int32_t y, int32_t xdiff, int32_t ydiff);
-	bool do_mousewheel(uint32_t which, int32_t x, int32_t y, Point rel_mouse_pos);
+	bool do_mousewheel(uint32_t which, int32_t x, int32_t y, Vector2i rel_mouse_pos);
 	bool do_key(bool down, SDL_Keysym code);
 	bool do_textinput(const std::string& text);
 	bool do_tooltip();

=== modified file 'src/ui_basic/progressbar.cc'
--- src/ui_basic/progressbar.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/progressbar.cc	2016-10-22 18:17:28 +0000
@@ -62,26 +62,26 @@
 	assert(0 < get_w());
 	assert(0 < get_h());
 	assert(total_);
-	const float fraction = state_ < total_ ? static_cast<float>(state_) / total_ : 1.0;
+	const float fraction = state_ < total_ ? static_cast<float>(state_) / total_ : 1.0f;
 	assert(0 <= fraction);
 	assert(fraction <= 1);
 
-	const RGBColor color = fraction <= 0.33 ? RGBColor(255, 0, 0) : fraction <= 0.67 ?
+	const RGBColor color = fraction <= 0.33f ? RGBColor(255, 0, 0) : fraction <= 0.67f ?
 	                                          RGBColor(255, 255, 0) :
 	                                          RGBColor(0, 255, 0);
 
 	// Draw the actual bar
 	if (orientation_ == Horizontal) {
-		const uint32_t w = static_cast<uint32_t>(get_w() * fraction);
-		assert(w <= static_cast<uint32_t>(get_w()));
+		const float w = get_w() * fraction;
+		assert(w <= get_w());
 
-		dst.fill_rect(Rect(Point(0, 0), w, get_h()), color);
-		dst.fill_rect(Rect(Point(w, 0), get_w() - w, get_h()), RGBColor(0, 0, 0));
+		dst.fill_rect(Rectf(0.f, 0.f, w, get_h()), color);
+		dst.fill_rect(Rectf(w, 0.f, get_w() - w, get_h()), RGBColor(0, 0, 0));
 	} else {
-		const uint32_t h = static_cast<uint32_t>(get_h() * (1.0 - fraction));
+		const uint32_t h = static_cast<uint32_t>(get_h() * (1.0f - fraction));
 
-		dst.fill_rect(Rect(Point(0, 0), get_w(), h), RGBColor(0, 0, 0));
-		dst.fill_rect(Rect(Point(0, h), get_w(), get_h() - h), color);
+		dst.fill_rect(Rectf(0.f, 0.f, get_w(), h), RGBColor(0, 0, 0));
+		dst.fill_rect(Rectf(0.f, h, get_w(), get_h() - h), color);
 	}
 
 	// Print the state in percent
@@ -89,8 +89,7 @@
 	uint32_t percent = static_cast<uint32_t>(fraction * 100);
 	const std::string progress_text =
 	   (boost::format("<font color=%1$s>%2$i%%</font>") % "ffffff" % percent).str();
-	const Point pos(get_w() / 2, get_h() / 2);
-	dst.blit(
-	   pos, UI::g_fh1->render(as_uifont(progress_text)), BlendMode::UseAlpha, UI::Align::kCenter);
+	dst.blit(Vector2f(get_w() / 2.f, get_h() / 2.f), UI::g_fh1->render(as_uifont(progress_text)),
+	         BlendMode::UseAlpha, UI::Align::kCenter);
 }
 }

=== modified file 'src/ui_basic/progresswindow.cc'
--- src/ui_basic/progresswindow.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/progresswindow.cc	2016-10-22 18:17:28 +0000
@@ -57,23 +57,23 @@
 }
 
 void ProgressWindow::draw_background(RenderTarget& rt, const uint32_t xres, const uint32_t yres) {
-	label_center_.x = xres / 2;
-	label_center_.y = yres * PROGRESS_LABEL_POSITION_Y / 100;
-	Rect wnd_rect(Point(0, 0), xres, yres);
+	label_center_.x = xres / 2.f;
+	label_center_.y = yres * PROGRESS_LABEL_POSITION_Y / 100.f;
+	Recti wnd_rect(Vector2i(0, 0), xres, yres);
 
 	const uint32_t h =
 	   UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height();
 
-	label_rectangle_.x = xres / 4;
-	label_rectangle_.w = xres / 2;
-	label_rectangle_.y = label_center_.y - h / 2 - PROGRESS_STATUS_RECT_PADDING;
-	label_rectangle_.h = h + 2 * PROGRESS_STATUS_RECT_PADDING;
+	label_rectangle_.x = xres / 4.f;
+	label_rectangle_.w = xres / 2.f;
+	label_rectangle_.y = label_center_.y - h / 2.f - PROGRESS_STATUS_RECT_PADDING;
+	label_rectangle_.h = h + 2.f * PROGRESS_STATUS_RECT_PADDING;
 
 	const Image* bg = g_gr->images().get(background_);
-	rt.blitrect_scale(
-	   Rect(0, 0, xres, yres), bg, Rect(0, 0, bg->width(), bg->height()), 1., BlendMode::UseAlpha);
+	rt.blitrect_scale(Rectf(0.f, 0.f, xres, yres), bg, Recti(0, 0, bg->width(), bg->height()), 1.,
+	                  BlendMode::UseAlpha);
 
-	Rect border_rect = label_rectangle_;
+	Rectf border_rect = label_rectangle_;
 	border_rect.x -= PROGRESS_STATUS_BORDER_X;
 	border_rect.y -= PROGRESS_STATUS_BORDER_Y;
 	border_rect.w += 2 * PROGRESS_STATUS_BORDER_X;

=== modified file 'src/ui_basic/progresswindow.h'
--- src/ui_basic/progresswindow.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/progresswindow.h	2016-10-22 18:17:28 +0000
@@ -24,8 +24,8 @@
 #include <string>
 #include <vector>
 
-#include "base/point.h"
 #include "base/rect.h"
+#include "base/vector.h"
 
 class Image;
 class RenderTarget;
@@ -62,8 +62,8 @@
 
 private:
 	using VisualizationArray = std::vector<IProgressVisualization*>;
-	Point label_center_;
-	Rect label_rectangle_;
+	Vector2f label_center_;
+	Rectf label_rectangle_;
 	VisualizationArray visualizations_;
 	std::string background_;
 

=== modified file 'src/ui_basic/radiobutton.cc'
--- src/ui_basic/radiobutton.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/radiobutton.cc	2016-10-22 18:17:28 +0000
@@ -27,7 +27,7 @@
  * Initialize the radiobutton and link it into the group's linked list
 */
 Radiobutton::Radiobutton(
-   Panel* const parent, Point const p, const Image* pic, Radiogroup& group, int32_t const id)
+   Panel* const parent, Vector2i const p, const Image* pic, Radiogroup& group, int32_t const id)
    : Statebox(parent, p, pic), nextbtn_(group.buttons_), group_(group), id_(id) {
 	group.buttons_ = this;
 }
@@ -86,7 +86,7 @@
  * Returns the ID of the new button.
 */
 int32_t Radiogroup::add_button(Panel* const parent,
-                               Point const p,
+                               Vector2i const p,
                                const Image* pic,
                                const std::string& tooltip,
                                Radiobutton** ret_btn) {

=== modified file 'src/ui_basic/radiobutton.h'
--- src/ui_basic/radiobutton.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/radiobutton.h	2016-10-22 18:17:28 +0000
@@ -22,7 +22,7 @@
 
 #include <stdint.h>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "ui_basic/checkbox.h"
 
 namespace UI {
@@ -34,7 +34,7 @@
 struct Radiobutton : public Statebox {
 	friend struct Radiogroup;
 
-	Radiobutton(Panel* parent, Point, const Image* pic, Radiogroup&, int32_t id);
+	Radiobutton(Panel* parent, Vector2i, const Image* pic, Radiogroup&, int32_t id);
 	~Radiobutton();
 
 	Radiobutton* next_button() {
@@ -64,7 +64,7 @@
 	boost::signals2::signal<void()> clicked;  //  clicked without things changed
 
 	int32_t add_button(Panel* parent,
-	                   Point,
+	                   Vector2i,
 	                   const Image* pic,
 	                   const std::string& tooltip = "",
 	                   Radiobutton** = nullptr);

=== modified file 'src/ui_basic/scrollbar.cc'
--- src/ui_basic/scrollbar.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/scrollbar.cc	2016-10-22 18:17:28 +0000
@@ -233,9 +233,8 @@
 	set_scrollpos(pos);
 }
 
-void Scrollbar::draw_button(RenderTarget& dst, const Area area, const Rect r) {
-
-	dst.tile(r, pic_buttons_, Point(get_x(), get_y()));
+void Scrollbar::draw_button(RenderTarget& dst, const Area area, const Rectf& r) {
+	dst.tile(r.cast<int>(), pic_buttons_, Vector2i(get_x(), get_y()));
 
 	// Draw the picture
 	const Image* pic = nullptr;
@@ -250,9 +249,10 @@
 		int blit_width = image_scale * pic->width();
 		int blit_height = image_scale * pic->height();
 
-		dst.blitrect_scale(Rect(r.origin() + Point((r.w - blit_width) / 2, (r.h - blit_height) / 2),
-		                        blit_width, blit_height),
-		                   pic, Rect(0, 0, pic->width(), pic->height()), 1., BlendMode::UseAlpha);
+		dst.blitrect_scale(Rectf(r.origin().cast<float>() +
+		                            Vector2f((r.w - blit_width) / 2.f, (r.h - blit_height) / 2.f),
+		                         blit_width, blit_height),
+		                   pic, Recti(0, 0, pic->width(), pic->height()), 1., BlendMode::UseAlpha);
 	}
 
 	// Draw border
@@ -260,32 +260,32 @@
 
 	if (area != pressed_) {
 		// top edge
-		dst.brighten_rect(Rect(r.origin(), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(r.origin(), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// left edge
-		dst.brighten_rect(Rect(r.origin() + Point(0, 2), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(r.origin() + Vector2f(0, 2), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// bottom edge
-		dst.fill_rect(Rect(r.origin() + Point(2, r.h - 2), r.w - 2, 1), black);
-		dst.fill_rect(Rect(r.origin() + Point(1, r.h - 1), r.w - 1, 1), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(2, r.h - 2), r.w - 2, 1), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(1, r.h - 1), r.w - 1, 1), black);
 		// right edge
-		dst.fill_rect(Rect(r.origin() + Point(r.w - 2, 2), 1, r.h - 2), black);
-		dst.fill_rect(Rect(r.origin() + Point(r.w - 1, 1), 1, r.h - 1), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(r.w - 2, 2), 1, r.h - 2), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(r.w - 1, 1), 1, r.h - 1), black);
 	} else {
 		// bottom edge
-		dst.brighten_rect(Rect(r.origin() + Point(0, r.h - 2), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(r.origin() + Vector2f(0, r.h - 2), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// right edge
 		dst.brighten_rect(
-		   Rect(r.origin() + Point(r.w - 2, 0), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   Rectf(r.origin() + Vector2f(r.w - 2, 0), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// top edge
-		dst.fill_rect(Rect(r.origin(), r.w - 1, 1), black);
-		dst.fill_rect(Rect(r.origin() + Point(0, 1), r.w - 2, 1), black);
+		dst.fill_rect(Rectf(r.origin(), r.w - 1, 1), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(0, 1), r.w - 2, 1), black);
 		// left edge
-		dst.fill_rect(Rect(r.origin(), 1, r.h - 1), black);
-		dst.fill_rect(Rect(r.origin() + Point(1, 0), 1, r.h - 2), black);
+		dst.fill_rect(Rectf(r.origin(), 1, r.h - 1), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(1, 0), 1, r.h - 2), black);
 	}
 }
 
-void Scrollbar::draw_area(RenderTarget& dst, const Area area, const Rect r) {
-	dst.tile(r, pic_background_, Point(get_x(), get_y()) + r.origin());
+void Scrollbar::draw_area(RenderTarget& dst, const Area area, const Rectf& r) {
+	dst.tile(r.cast<int>(), pic_background_, Vector2i(get_x(), get_y()) + r.origin().cast<int>());
 
 	if (area == pressed_)
 		dst.brighten_rect(r, BUTTON_EDGE_BRIGHT_FACTOR);
@@ -306,46 +306,46 @@
 		if ((2 * buttonsize_ + knobsize) > static_cast<uint32_t>(get_w())) {
 			// Our owner allocated too little space
 			if (static_cast<uint32_t>(get_w()) >= 2 * buttonsize_) {
-				draw_button(dst, Minus, Rect(Point(0, 0), get_w() / 2, get_h()));
-				draw_button(dst, Plus, Rect(Point(get_w() - buttonsize_, 0), get_w() / 2, get_h()));
+				draw_button(dst, Minus, Rectf(0, 0, get_w() / 2, get_h()));
+				draw_button(dst, Plus, Rectf(get_w() - buttonsize_, 0, get_w() / 2, get_h()));
 			} else {
-				draw_button(dst, Minus, Rect(Point(0, 0), get_w(), get_h()));
+				draw_button(dst, Minus, Rectf(0.f, 0.f, get_w(), get_h()));
 			}
 			return;
 		}
 
-		draw_button(dst, Minus, Rect(Point(0, 0), buttonsize_, get_h()));
-		draw_button(dst, Plus, Rect(Point(get_w() - buttonsize_, 0), buttonsize_, get_h()));
-		draw_button(dst, Knob, Rect(Point(knobpos - knobsize / 2, 0), knobsize, get_h()));
+		draw_button(dst, Minus, Rectf(0, 0, buttonsize_, get_h()));
+		draw_button(dst, Plus, Rectf(get_w() - buttonsize_, 0, buttonsize_, get_h()));
+		draw_button(dst, Knob, Rectf(knobpos - knobsize / 2.f, 0, knobsize, get_h()));
 
 		assert(buttonsize_ + knobsize / 2 <= knobpos);
-		draw_area(dst, MinusPage,
-		          Rect(Point(buttonsize_, 0), knobpos - buttonsize_ - knobsize / 2, get_h()));
+		draw_area(
+		   dst, MinusPage, Rectf(buttonsize_, 0, knobpos - buttonsize_ - knobsize / 2, get_h()));
 		assert(knobpos + knobsize / 2 + buttonsize_ <= static_cast<uint32_t>(get_w()));
-		draw_area(dst, PlusPage, Rect(Point(knobpos + knobsize / 2, 0),
-		                              get_w() - knobpos - knobsize / 2 - buttonsize_, get_h()));
+		draw_area(dst, PlusPage, Rectf(knobpos + knobsize / 2.f, 0.f,
+		                               get_w() - knobpos - knobsize / 2 - buttonsize_, get_h()));
 	} else {
 		if ((2 * buttonsize_ + knobsize) > static_cast<uint32_t>(get_h())) {
 			// Our owner allocated too little space
 			if (static_cast<uint32_t>(get_h()) >= 2 * buttonsize_) {
-				draw_button(dst, Minus, Rect(Point(0, 0), get_w(), get_h() / 2));
-				draw_button(dst, Plus, Rect(Point(0, get_h() - buttonsize_), get_w(), get_h() / 2));
+				draw_button(dst, Minus, Rectf(0.f, 0.f, get_w(), get_h() / 2.f));
+				draw_button(dst, Plus, Rectf(0.f, get_h() - buttonsize_, get_w(), get_h() / 2));
 			} else {
-				draw_button(dst, Minus, Rect(Point(0, 0), get_w(), get_h()));
+				draw_button(dst, Minus, Rectf(0.f, 0.f, get_w(), get_h()));
 			}
 			return;
 		}
 
-		draw_button(dst, Minus, Rect(Point(0, 0), get_w(), buttonsize_));
-		draw_button(dst, Plus, Rect(Point(0, get_h() - buttonsize_), get_w(), buttonsize_));
-		draw_button(dst, Knob, Rect(Point(0, knobpos - knobsize / 2), get_w(), knobsize));
+		draw_button(dst, Minus, Rectf(0, 0, get_w(), buttonsize_));
+		draw_button(dst, Plus, Rectf(0, get_h() - buttonsize_, get_w(), buttonsize_));
+		draw_button(dst, Knob, Rectf(0, knobpos - knobsize / 2.f, get_w(), knobsize));
 
 		assert(buttonsize_ + knobsize / 2 <= knobpos);
-		draw_area(dst, MinusPage,
-		          Rect(Point(0, buttonsize_), get_w(), knobpos - buttonsize_ - knobsize / 2));
+		draw_area(
+		   dst, MinusPage, Rectf(0.f, buttonsize_, get_w(), knobpos - buttonsize_ - knobsize / 2));
 		assert(knobpos + knobsize / 2 + buttonsize_ <= static_cast<uint32_t>(get_h()));
-		draw_area(dst, PlusPage, Rect(Point(0, knobpos + knobsize / 2), get_w(),
-		                              get_h() - knobpos - knobsize / 2 - buttonsize_));
+		draw_area(dst, PlusPage, Rectf(0.f, knobpos + knobsize / 2.f, get_w(),
+		                               get_h() - knobpos - knobsize / 2.f - buttonsize_));
 	}
 }
 

=== modified file 'src/ui_basic/scrollbar.h'
--- src/ui_basic/scrollbar.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/scrollbar.h	2016-10-22 18:17:28 +0000
@@ -75,8 +75,8 @@
 
 	void action(Area area);
 
-	void draw_button(RenderTarget&, Area, Rect);
-	void draw_area(RenderTarget&, Area, Rect);
+	void draw_button(RenderTarget&, Area, const Rectf&);
+	void draw_area(RenderTarget&, Area, const Rectf&);
 	void draw(RenderTarget&) override;
 	void think() override;
 

=== modified file 'src/ui_basic/slider.cc'
--- src/ui_basic/slider.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/slider.cc	2016-10-22 18:17:28 +0000
@@ -148,37 +148,37 @@
 	RGBColor black(0, 0, 0);
 
 	dst.tile  //  background
-	   (Rect(Point(x, y), w, h), pic_background_, Point(get_x(), get_y()));
+	   (Recti(Vector2i(x, y), w, h), pic_background_, Vector2i(get_x(), get_y()));
 
 	if (highlighted_)
-		dst.brighten_rect(Rect(Point(x, y), w, h), MOUSE_OVER_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(x, y, w, h), MOUSE_OVER_BRIGHT_FACTOR);
 
 	if (pressed_) {       //  draw border
 		dst.brighten_rect  //  bottom edge
-		   (Rect(Point(x, y + h - 2), w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(x, y + h - 2, w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		dst.brighten_rect  //  right edge
-		   (Rect(Point(x + w - 2, y), 2, h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(x + w - 2, y, 2, h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 
 		//  top edge
-		dst.fill_rect(Rect(Point(x, y), w - 1, 1), black);
-		dst.fill_rect(Rect(Point(x, y + 1), w - 2, 1), black);
+		dst.fill_rect(Rectf(x, y, w - 1, 1), black);
+		dst.fill_rect(Rectf(x, y + 1, w - 2, 1), black);
 
 		//  left edge
-		dst.fill_rect(Rect(Point(x, y), 1, h - 1), black);
-		dst.fill_rect(Rect(Point(x + 1, y), 1, h - 2), black);
+		dst.fill_rect(Rectf(x, y, 1, h - 1), black);
+		dst.fill_rect(Rectf(x + 1, y, 1, h - 2), black);
 	} else {
 		dst.brighten_rect  //  top edge
-		   (Rect(Point(x, y), w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(x, y, w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		dst.brighten_rect  //  left edge
-		   (Rect(Point(x, y + 2), 2, h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(x, y + 2, 2, h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 
 		//  bottom edge
-		dst.fill_rect(Rect(Point(x + 2, y + h - 2), w - 2, 1), black);
-		dst.fill_rect(Rect(Point(x + 1, y + h - 1), w - 1, 1), black);
+		dst.fill_rect(Rectf(x + 2, y + h - 2, w - 2, 1), black);
+		dst.fill_rect(Rectf(x + 1, y + h - 1, w - 1, 1), black);
 
 		//  right edge
-		dst.fill_rect(Rect(Point(x + w - 2, y + 2), 1, h - 2), black);
-		dst.fill_rect(Rect(Point(x + w - 1, y + 1), 1, h - 1), black);
+		dst.fill_rect(Rectf(x + w - 2, y + 2, 1, h - 2), black);
+		dst.fill_rect(Rectf(x + w - 1, y + 1, 1, h - 1), black);
 	}
 }
 
@@ -359,19 +359,18 @@
 
 	if (get_bar_size() > 0) {
 		dst.brighten_rect  //  bottom edge
-		   (Rect(Point(get_x_gap(), get_h() / 2), get_bar_size(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(get_x_gap(), get_h() / 2.f, get_bar_size(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		dst.brighten_rect  //  right edge
-		   (Rect(Point(get_x_gap() + get_bar_size() - 2, get_y_gap()), 2, 2),
-		    BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(get_x_gap() + get_bar_size() - 2, get_y_gap(), 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 
 		//  top edge
-		dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap()), get_bar_size() - 1, 1), black);
-		dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap() + 1), get_bar_size() - 2, 1), black);
+		dst.fill_rect(Rectf(get_x_gap(), get_y_gap(), get_bar_size() - 1, 1), black);
+		dst.fill_rect(Rectf(get_x_gap(), get_y_gap() + 1, get_bar_size() - 2, 1), black);
 	}
 
 	//  left edge
-	dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap()), 1, 4), black);
-	dst.fill_rect(Rect(Point(get_x_gap() + 1, get_y_gap()), 1, 3), black);
+	dst.fill_rect(Rectf(get_x_gap(), get_y_gap(), 1, 4), black);
+	dst.fill_rect(Rectf(get_x_gap() + 1, get_y_gap(), 1, 3), black);
 
 	draw_cursor(dst, cursor_pos_, 0, cursor_size_, get_h());
 }
@@ -432,17 +431,17 @@
 	RGBAColor black(0, 0, 0, 255);
 
 	dst.brighten_rect  //  right edge
-	   (Rect(Point(get_w() / 2, get_y_gap()), 2, get_bar_size()), BUTTON_EDGE_BRIGHT_FACTOR);
+	   (Rectf(get_w() / 2.f, get_y_gap(), 2, get_bar_size()), BUTTON_EDGE_BRIGHT_FACTOR);
 	dst.brighten_rect  //  bottom edge
-	   (Rect(Point(get_x_gap(), get_y_gap() + get_bar_size() - 2), 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+	   (Rectf(get_x_gap(), get_y_gap() + get_bar_size() - 2, 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 
 	//  left edge
-	dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap()), 1, get_bar_size() - 1), black);
-	dst.fill_rect(Rect(Point(get_x_gap() + 1, get_y_gap()), 1, get_bar_size() - 2), black);
+	dst.fill_rect(Rectf(get_x_gap(), get_y_gap(), 1, get_bar_size() - 1), black);
+	dst.fill_rect(Rectf(get_x_gap() + 1, get_y_gap(), 1, get_bar_size() - 2), black);
 
 	//  top edge
-	dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap()), 4, 1), black);
-	dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap() + 1), 3, 1), black);
+	dst.fill_rect(Rectf(get_x_gap(), get_y_gap(), 4, 1), black);
+	dst.fill_rect(Rectf(get_x_gap(), get_y_gap() + 1, 3, 1), black);
 
 	draw_cursor(dst, 0, cursor_pos_, get_w(), cursor_size_);
 }
@@ -535,7 +534,7 @@
 	uint32_t gap_n = get_w() / labels.size();
 
 	for (uint32_t i = 0; i < labels.size(); i++) {
-		dst.blit(Point(gap_1 + i * gap_n, get_h()),
+		dst.blit(Vector2f(gap_1 + i * gap_n, get_h()),
 		         UI::g_fh1->render(
 		            as_condensed(labels[i], UI::Align::kBottomCenter, UI_FONT_SIZE_SMALL - 2)),
 		         BlendMode::UseAlpha, UI::Align::kBottomCenter);
@@ -552,7 +551,7 @@
 	uint32_t w = get_w();
 	uint32_t h = get_h();
 	assert(labels.size());
-	slider.set_pos(Point(w / (2 * labels.size()) - slider.cursor_size_ / 2, 0));
+	slider.set_pos(Vector2i(w / (2 * labels.size()) - slider.cursor_size_ / 2, 0));
 	slider.set_size(w - (w / labels.size()) + slider.cursor_size_,
 	                h -
 	                   UI::g_fh1

=== modified file 'src/ui_basic/table.cc'
--- src/ui_basic/table.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/table.cc	2016-10-22 18:17:28 +0000
@@ -225,7 +225,7 @@
 	uint32_t idx = scrollpos_ / lineheight;
 	int32_t y = 1 + idx * lineheight - scrollpos_ + headerheight_;
 
-	dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), ms_darken_value);
+	dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), ms_darken_value);
 
 	while (idx < entry_records_.size()) {
 		if (y >= static_cast<int32_t>(get_h()))
@@ -235,7 +235,7 @@
 
 		if (idx == selection_) {
 			assert(2 <= get_eff_w());
-			dst.brighten_rect(Rect(Point(1, y), get_eff_w() - 2, lineheight_), -ms_darken_value);
+			dst.brighten_rect(Rectf(1.f, y, get_eff_w() - 2, lineheight_), -ms_darken_value);
 		}
 
 		Columns::size_type const nr_columns = columns_.size();
@@ -247,14 +247,14 @@
 			const Image* entry_picture = er.get_picture(i);
 			const std::string& entry_string = er.get_string(i);
 
-			Point point(curx, y);
+			Vector2f point(curx, y);
 			int picw = 0;
 
 			if (entry_picture != nullptr) {
 				picw = entry_picture->width();
 				const int pich = entry_picture->height();
 
-				int draw_x = point.x;
+				float draw_x = point.x;
 
 				// We want a bit of margin
 				int max_pic_height = lineheight - 3;
@@ -266,9 +266,9 @@
 
 					if (entry_string.empty()) {
 						if (i == nr_columns - 1 && scrollbar_->is_enabled()) {
-							draw_x = point.x + (curw - blit_width - scrollbar_->get_w()) / 2;
+							draw_x = point.x + (curw - blit_width - scrollbar_->get_w()) / 2.f;
 						} else {
-							draw_x = point.x + (curw - blit_width) / 2;
+							draw_x = point.x + (curw - blit_width) / 2.f;
 						}
 					}
 
@@ -277,22 +277,22 @@
 					}
 
 					// Create the scaled image
-					dst.blitrect_scale(Rect(draw_x, point.y + 1, blit_width, max_pic_height),
-					                   entry_picture, Rect(0, 0, picw, pich), 1., BlendMode::UseAlpha);
+					dst.blitrect_scale(Rectf(draw_x, point.y + 1.f, blit_width, max_pic_height),
+					                   entry_picture, Recti(0, 0, picw, pich), 1., BlendMode::UseAlpha);
 
 					// For text alignment below
 					picw = blit_width;
 				} else {
 					if (entry_string.empty()) {
 						if (i == nr_columns - 1 && scrollbar_->is_enabled()) {
-							draw_x = point.x + (curw - picw - scrollbar_->get_w()) / 2;
+							draw_x = point.x + (curw - picw - scrollbar_->get_w()) / 2.f;
 						} else {
-							draw_x = point.x + (curw - picw) / 2;
+							draw_x = point.x + (curw - picw) / 2.f;
 						}
 					} else if (static_cast<int>(alignment & UI::Align::kRight)) {
 						draw_x += curw - picw;
 					}
-					dst.blit(Point(draw_x, point.y + (lineheight - pich) / 2), entry_picture);
+					dst.blit(Vector2f(draw_x, point.y + (lineheight - pich) / 2.f), entry_picture);
 				}
 				point.x += picw;
 			}
@@ -308,7 +308,7 @@
 			if (static_cast<int>(alignment & UI::Align::kRight)) {
 				point.x += curw - 2 * picw;
 			} else if (static_cast<int>(alignment & UI::Align::kHCenter)) {
-				point.x += (curw - picw) / 2;
+				point.x += (curw - picw) / 2.f;
 			}
 
 			// Add an offset for rightmost column when the scrollbar is shown.
@@ -328,12 +328,12 @@
 				if (i18n::has_rtl_character(
 				       entry_string.c_str(), 20)) {  // Restrict check for efficiency
 					dst.blitrect(
-					   point, entry_text_im, Rect(text_width - curw + picw, 0, text_width, lineheight));
+					   point, entry_text_im, Recti(text_width - curw + picw, 0, text_width, lineheight));
 				} else {
-					dst.blitrect(point, entry_text_im, Rect(0, 0, curw - picw, lineheight));
+					dst.blitrect(point, entry_text_im, Recti(0, 0, curw - picw, lineheight));
 				}
 			} else {
-				dst.blitrect(point, entry_text_im, Rect(0, 0, curw - picw, lineheight));
+				dst.blitrect(point, entry_text_im, Recti(0, 0, curw - picw, lineheight));
 			}
 			curx += curw;
 		}

=== modified file 'src/ui_basic/tabpanel.cc'
--- src/ui_basic/tabpanel.cc	2016-09-08 11:59:42 +0000
+++ src/ui_basic/tabpanel.cc	2016-10-22 18:17:28 +0000
@@ -198,9 +198,9 @@
 	if (border_type_ == TabPanel::Type::kBorder) {
 		panel->set_border(kTabPanelSeparatorHeight + 1, kTabPanelSeparatorHeight + 1,
 		                  kTabPanelSeparatorHeight, kTabPanelSeparatorHeight);
-		panel->set_pos(Point(0, kTabPanelButtonHeight));
+		panel->set_pos(Vector2i(0, kTabPanelButtonHeight));
 	} else {
-		panel->set_pos(Point(0, kTabPanelButtonHeight + kTabPanelSeparatorHeight));
+		panel->set_pos(Vector2i(0, kTabPanelButtonHeight + kTabPanelSeparatorHeight));
 	}
 
 	panel->set_visible(id == active_);
@@ -259,20 +259,20 @@
 
 	if (pic_background_) {
 		if (!tabs_.empty()) {
-			dst.tile(Rect(Point(0, 0), tabs_.back()->get_x() + tabs_.back()->get_w(),
+			dst.tile(Recti(Vector2i(0, 0), tabs_.back()->get_x() + tabs_.back()->get_w(),
 			              kTabPanelButtonHeight - 2),
-			         pic_background_, Point(get_x(), get_y()));
+			         pic_background_, Vector2i(get_x(), get_y()));
 		}
 		assert(kTabPanelButtonHeight - 2 <= get_h());
 		dst.tile(
-		   Rect(Point(0, kTabPanelButtonHeight - 2), get_w(), get_h() - kTabPanelButtonHeight + 2),
-		   pic_background_, Point(get_x(), get_y() + kTabPanelButtonHeight - 2));
+		   Recti(Vector2i(0, kTabPanelButtonHeight - 2), get_w(), get_h() - kTabPanelButtonHeight + 2),
+		   pic_background_, Vector2i(get_x(), get_y() + kTabPanelButtonHeight - 2));
 	}
 
 	RGBColor black(0, 0, 0);
 
 	// draw the buttons
-	int32_t x = 0;
+	float x = 0;
 	int tab_width = 0;
 	for (size_t idx = 0; idx < tabs_.size(); ++idx) {
 		x = tabs_[idx]->get_x();
@@ -280,7 +280,7 @@
 
 		if (highlight_ == idx) {
 			dst.brighten_rect(
-			   Rect(Point(x, 0), tab_width, kTabPanelButtonHeight), MOUSE_OVER_BRIGHT_FACTOR);
+			   Rectf(x, 0, tab_width, kTabPanelButtonHeight), MOUSE_OVER_BRIGHT_FACTOR);
 		}
 
 		assert(tabs_[idx]->pic);
@@ -296,53 +296,52 @@
 			uint16_t picture_width = image_scale * tabs_[idx]->pic->width();
 			uint16_t picture_height = image_scale * tabs_[idx]->pic->height();
 			dst.blitrect_scale(
-			   Rect(x + (kTabPanelButtonHeight - picture_width) / 2,
-			        (kTabPanelButtonHeight - picture_height) / 2, picture_width, picture_height),
-			   tabs_[idx]->pic, Rect(0, 0, tabs_[idx]->pic->width(), tabs_[idx]->pic->height()), 1.,
+			   Rectf(x + (kTabPanelButtonHeight - picture_width) / 2.f,
+			        (kTabPanelButtonHeight - picture_height) / 2.f, picture_width, picture_height),
+			   tabs_[idx]->pic, Recti(0, 0, tabs_[idx]->pic->width(), tabs_[idx]->pic->height()), 1.,
 			   BlendMode::UseAlpha);
 		} else {
 			dst.blit(
-			   Point(x + kTabPanelTextMargin, (kTabPanelButtonHeight - tabs_[idx]->pic->height()) / 2),
+			   Vector2f(x + kTabPanelTextMargin, (kTabPanelButtonHeight - tabs_[idx]->pic->height()) / 2.f),
 			   tabs_[idx]->pic, BlendMode::UseAlpha, UI::Align::kLeft);
 		}
 
 		// Draw top part of border
-		dst.brighten_rect(Rect(Point(x, 0), tab_width, 2), BUTTON_EDGE_BRIGHT_FACTOR);
-		dst.brighten_rect(Rect(Point(x, 2), 2, kTabPanelButtonHeight - 4), BUTTON_EDGE_BRIGHT_FACTOR);
-		dst.fill_rect(Rect(Point(x + tab_width - 2, 2), 1, kTabPanelButtonHeight - 4), black);
-		dst.fill_rect(Rect(Point(x + tab_width - 1, 1), 1, kTabPanelButtonHeight - 3), black);
+		dst.brighten_rect(Rectf(x, 0, tab_width, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(x, 2, 2, kTabPanelButtonHeight - 4), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.fill_rect(Rectf(x + tab_width - 2, 2, 1, kTabPanelButtonHeight - 4), black);
+		dst.fill_rect(Rectf(x + tab_width - 1, 1, 1, kTabPanelButtonHeight - 3), black);
 
 		// Draw bottom part
 		if (active_ != idx)
 			dst.brighten_rect(
-			   Rect(Point(x, kTabPanelButtonHeight - 2), tab_width, 2), 2 * BUTTON_EDGE_BRIGHT_FACTOR);
+			   Rectf(x, kTabPanelButtonHeight - 2, tab_width, 2), 2 * BUTTON_EDGE_BRIGHT_FACTOR);
 		else {
 			dst.brighten_rect(
-			   Rect(Point(x, kTabPanelButtonHeight - 2), 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+			   Rectf(x, kTabPanelButtonHeight - 2, 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 
-			dst.brighten_rect(Rect(Point(x + tab_width - 2, kTabPanelButtonHeight - 2), 2, 2),
+			dst.brighten_rect(Rectf(x + tab_width - 2, kTabPanelButtonHeight - 2, 2, 2),
 			                  2 * BUTTON_EDGE_BRIGHT_FACTOR);
-			dst.fill_rect(Rect(Point(x + tab_width - 2, kTabPanelButtonHeight - 1), 1, 1), black);
-			dst.fill_rect(Rect(Point(x + tab_width - 2, kTabPanelButtonHeight - 2), 2, 1), black);
+			dst.fill_rect(Rectf(x + tab_width - 2, kTabPanelButtonHeight - 1, 1, 1), black);
+			dst.fill_rect(Rectf(x + tab_width - 2, kTabPanelButtonHeight - 2, 2, 1), black);
 		}
 	}
 
 	// draw the remaining separator
 	assert(x <= get_w());
-	dst.brighten_rect(Rect(Point(x + tab_width, kTabPanelButtonHeight - 2), get_w() - x, 2),
+	dst.brighten_rect(Rectf(x + tab_width, kTabPanelButtonHeight - 2, get_w() - x, 2),
 	                  2 * BUTTON_EDGE_BRIGHT_FACTOR);
 
 	// Draw border around the main panel
 	if (border_type_ == TabPanel::Type::kBorder) {
 		//  left edge
-		dst.brighten_rect(
-		   Rect(Point(0, kTabPanelButtonHeight), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0, kTabPanelButtonHeight, 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		//  bottom edge
-		dst.fill_rect(Rect(Point(2, get_h() - 2), get_w() - 2, 1), black);
-		dst.fill_rect(Rect(Point(1, get_h() - 1), get_w() - 1, 1), black);
+		dst.fill_rect(Rectf(2, get_h() - 2, get_w() - 2, 1), black);
+		dst.fill_rect(Rectf(1, get_h() - 1, get_w() - 1, 1), black);
 		//  right edge
-		dst.fill_rect(Rect(Point(get_w() - 2, kTabPanelButtonHeight - 1), 1, get_h() - 2), black);
-		dst.fill_rect(Rect(Point(get_w() - 1, kTabPanelButtonHeight - 2), 1, get_h() - 1), black);
+		dst.fill_rect(Rectf(get_w() - 2, kTabPanelButtonHeight - 1, 1, get_h() - 2), black);
+		dst.fill_rect(Rectf(get_w() - 1, kTabPanelButtonHeight - 2, 1, get_h() - 1), black);
 	}
 }
 

=== modified file 'src/ui_basic/textarea.cc'
--- src/ui_basic/textarea.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/textarea.cc	2016-10-22 18:17:28 +0000
@@ -125,13 +125,12 @@
  */
 void Textarea::draw(RenderTarget& dst) {
 	if (!text_.empty()) {
-		Point anchor(static_cast<int>(align_ & UI::Align::kHCenter) ?
-		                get_w() / 2 :
-		                static_cast<int>(align_ & UI::Align::kRight) ? get_w() : 0,
+		Vector2f anchor(static_cast<int>(align_ & UI::Align::kHCenter) ?
+		                get_w() / 2.f :
+		                static_cast<int>(align_ & UI::Align::kRight) ? get_w() : 0.f,
 		             static_cast<int>(align_ & UI::Align::kVCenter) ?
-		                get_h() / 2 :
-		                static_cast<int>(align_ & UI::Align::kBottom) ? get_h() : 0);
-
+		                get_h() / 2.f :
+		                static_cast<int>(align_ & UI::Align::kBottom) ? get_h() : 0.f);
 		dst.blit(anchor, rendered_text_, BlendMode::UseAlpha, align_);
 	}
 }
@@ -155,7 +154,7 @@
 	else if (static_cast<int>(align_ & UI::Align::kBottom))
 		y += h;
 
-	set_pos(Point(x, y));
+	set_pos(Vector2i(x, y));
 	set_size(0, 0);
 }
 
@@ -180,7 +179,7 @@
 	else if (static_cast<int>(align_ & UI::Align::kBottom))
 		y -= h;
 
-	set_pos(Point(x, y));
+	set_pos(Vector2i(x, y));
 	set_size(w, h);
 }
 

=== modified file 'src/ui_basic/unique_window.cc'
--- src/ui_basic/unique_window.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/unique_window.cc	2016-10-22 18:17:28 +0000
@@ -80,7 +80,7 @@
 
 		registry_->window = this;
 		if (registry_->valid_pos) {
-			set_pos(Point(registry_->x, registry_->y));
+			set_pos(Vector2i(registry_->x, registry_->y));
 			usedefaultpos_ = false;
 		}
 		if (registry_->on_create) {

=== modified file 'src/ui_basic/window.cc'
--- src/ui_basic/window.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/window.cc	2016-10-22 18:17:28 +0000
@@ -141,7 +141,7 @@
  */
 void Window::layout() {
 	if (center_panel_ && !is_minimal_) {
-		center_panel_->set_pos(Point(0, 0));
+		center_panel_->set_pos(Vector2i(0, 0));
 		center_panel_->set_size(get_inner_w(), get_inner_h());
 	}
 }
@@ -152,9 +152,9 @@
 void Window::move_out_of_the_way() {
 	center_to_parent();
 
-	const Point mouse = get_mouse_position();
+	const Vector2i mouse = get_mouse_position();
 	if (0 <= mouse.x && mouse.x < get_w() && 0 <= mouse.y && mouse.y < get_h()) {
-		set_pos(Point(get_x(), get_y()) + Point(0, (mouse.y < get_h() / 2 ? 1 : -1) * get_h()));
+		set_pos(Vector2i(get_x(), get_y()) + Vector2i(0, (mouse.y < get_h() / 2 ? 1 : -1) * get_h()));
 		move_inside_parent();
 	}
 }
@@ -164,7 +164,7 @@
  */
 void Window::warp_mouse_to_fastclick_panel() {
 	if (fastclick_panel_) {
-		Point pt(fastclick_panel_->get_w() / 2, fastclick_panel_->get_h() / 2);
+		Vector2i pt(fastclick_panel_->get_w() / 2, fastclick_panel_->get_h() / 2);
 		UI::Panel* p = fastclick_panel_;
 
 		while (p->get_parent() && p != this) {
@@ -215,7 +215,7 @@
 			if (docked_bottom_)
 				py += BT_B_PIXMAP_THICKNESS;
 		}
-		set_pos(Point(px, py));
+		set_pos(Vector2i(px, py));
 	}
 }
 
@@ -225,7 +225,7 @@
 void Window::center_to_parent() {
 	Panel& parent = *get_parent();
 
-	set_pos(Point((static_cast<int32_t>(parent.get_inner_w()) - get_w()) / 2,
+	set_pos(Vector2i((static_cast<int32_t>(parent.get_inner_w()) - get_w()) / 2,
 	              (static_cast<int32_t>(parent.get_inner_h()) - get_h()) / 2));
 }
 
@@ -234,7 +234,7 @@
  */
 void Window::draw(RenderTarget& dst) {
 	if (!is_minimal()) {
-		dst.tile(Rect(Point(0, 0), get_inner_w(), get_inner_h()), pic_background_, Point(0, 0));
+		dst.tile(Recti(Vector2i(0, 0), get_inner_w(), get_inner_h()), pic_background_, Vector2i(0, 0));
 	}
 }
 
@@ -252,25 +252,25 @@
 		int32_t pos = HZ_B_CORNER_PIXMAP_LEN;
 
 		dst.blitrect  //  top left corner
-		   (Point(0, 0), pic_top_, Rect(Point(0, 0), pos, TP_B_PIXMAP_THICKNESS));
+		   (Vector2f(0.f, 0.f), pic_top_, Recti(Vector2i(0, 0), pos, TP_B_PIXMAP_THICKNESS));
 
 		//  top bar
 		static_assert(0 <= HZ_B_CORNER_PIXMAP_LEN, "assert(0 <= HZ_B_CORNER_PIXMAP_LEN) failed.");
 		for (; pos < hz_bar_end_minus_middle; pos += HZ_B_MIDDLE_PIXMAP_LEN)
-			dst.blitrect(Point(pos, 0), pic_top_, Rect(Point(HZ_B_CORNER_PIXMAP_LEN, 0),
+			dst.blitrect(Vector2f(pos, 0), pic_top_, Recti(Vector2i(HZ_B_CORNER_PIXMAP_LEN, 0),
 			                                           HZ_B_MIDDLE_PIXMAP_LEN, TP_B_PIXMAP_THICKNESS));
 
 		// odd pixels of top bar and top right corner
 		const int32_t width = hz_bar_end - pos + HZ_B_CORNER_PIXMAP_LEN;
 		assert(0 <= HZ_B_TOTAL_PIXMAP_LEN - width);
-		dst.blitrect(Point(pos, 0), pic_top_,
-		             Rect(Point(HZ_B_TOTAL_PIXMAP_LEN - width, 0), width, TP_B_PIXMAP_THICKNESS));
+		dst.blitrect(Vector2f(pos, 0), pic_top_,
+		             Recti(Vector2i(HZ_B_TOTAL_PIXMAP_LEN - width, 0), width, TP_B_PIXMAP_THICKNESS));
 	}
 
 	// draw the title if we have one
 	if (!title_.empty()) {
 		// The title shouldn't be richtext, but we escape it just to make sure.
-		dst.blit(Point(get_lborder() + get_inner_w() / 2, TP_B_PIXMAP_THICKNESS / 2),
+		dst.blit(Vector2f(get_lborder() + get_inner_w() / 2, TP_B_PIXMAP_THICKNESS / 2),
 		         autofit_ui_text(richtext_escape(title_), get_inner_w(), UI_FONT_CLR_FG, 13),
 		         BlendMode::UseAlpha, UI::Align::kCenter);
 	}
@@ -284,8 +284,8 @@
 
 			static_assert(0 <= VT_B_PIXMAP_THICKNESS, "assert(0 <= VT_B_PIXMAP_THICKNESS) failed.");
 			dst.blitrect  // left top thingy
-			   (Point(0, TP_B_PIXMAP_THICKNESS), pic_lborder_,
-			    Rect(Point(0, 0), VT_B_PIXMAP_THICKNESS, VT_B_THINGY_PIXMAP_LEN));
+			   (Vector2f(0, TP_B_PIXMAP_THICKNESS), pic_lborder_,
+			    Recti(Vector2i(0, 0), VT_B_PIXMAP_THICKNESS, VT_B_THINGY_PIXMAP_LEN));
 
 			int32_t pos = TP_B_PIXMAP_THICKNESS + VT_B_THINGY_PIXMAP_LEN;
 
@@ -293,13 +293,13 @@
 			static_assert(0 <= VT_B_THINGY_PIXMAP_LEN, "assert(0 <= VT_B_THINGY_PIXMAP_LEN) failed.");
 			for (; pos < vt_bar_end_minus_middle; pos += VT_B_MIDDLE_PIXMAP_LEN)
 				dst.blitrect(
-				   Point(0, pos), pic_lborder_, Rect(Point(0, VT_B_THINGY_PIXMAP_LEN),
+				   Vector2f(0, pos), pic_lborder_, Recti(Vector2i(0, VT_B_THINGY_PIXMAP_LEN),
 				                                     VT_B_PIXMAP_THICKNESS, VT_B_MIDDLE_PIXMAP_LEN));
 
 			//  odd pixels of left bar and left bottom thingy
 			const int32_t height = vt_bar_end - pos + VT_B_THINGY_PIXMAP_LEN;
 			assert(0 <= VT_B_TOTAL_PIXMAP_LEN - height);
-			dst.blitrect(Point(0, pos), pic_lborder_, Rect(Point(0, VT_B_TOTAL_PIXMAP_LEN - height),
+			dst.blitrect(Vector2f(0, pos), pic_lborder_, Recti(Vector2i(0, VT_B_TOTAL_PIXMAP_LEN - height),
 			                                               VT_B_PIXMAP_THICKNESS, height));
 		}
 
@@ -307,42 +307,42 @@
 			const int32_t right_border_x = get_w() - VT_B_PIXMAP_THICKNESS;
 
 			dst.blitrect  // right top thingy
-			   (Point(right_border_x, TP_B_PIXMAP_THICKNESS), pic_rborder_,
-			    Rect(Point(0, 0), VT_B_PIXMAP_THICKNESS, VT_B_THINGY_PIXMAP_LEN));
+			   (Vector2f(right_border_x, TP_B_PIXMAP_THICKNESS), pic_rborder_,
+			    Recti(Vector2i(0, 0), VT_B_PIXMAP_THICKNESS, VT_B_THINGY_PIXMAP_LEN));
 
 			int32_t pos = TP_B_PIXMAP_THICKNESS + VT_B_THINGY_PIXMAP_LEN;
 
 			//  right bar
 			static_assert(0 <= VT_B_THINGY_PIXMAP_LEN, "assert(0 <= VT_B_THINGY_PIXMAP_LEN) failed.");
 			for (; pos < vt_bar_end_minus_middle; pos += VT_B_MIDDLE_PIXMAP_LEN)
-				dst.blitrect(Point(right_border_x, pos), pic_rborder_,
-				             Rect(Point(0, VT_B_THINGY_PIXMAP_LEN), VT_B_PIXMAP_THICKNESS,
+				dst.blitrect(Vector2f(right_border_x, pos), pic_rborder_,
+				             Recti(Vector2i(0, VT_B_THINGY_PIXMAP_LEN), VT_B_PIXMAP_THICKNESS,
 				                  VT_B_MIDDLE_PIXMAP_LEN));
 
 			// odd pixels of right bar and right bottom thingy
 			const int32_t height = vt_bar_end - pos + VT_B_THINGY_PIXMAP_LEN;
 			dst.blitrect(
-			   Point(right_border_x, pos), pic_rborder_,
-			   Rect(Point(0, VT_B_TOTAL_PIXMAP_LEN - height), VT_B_PIXMAP_THICKNESS, height));
+			   Vector2f(right_border_x, pos), pic_rborder_,
+			   Recti(Vector2i(0, VT_B_TOTAL_PIXMAP_LEN - height), VT_B_PIXMAP_THICKNESS, height));
 		}
 
 		{  // Bottom border
 			int32_t pos = HZ_B_CORNER_PIXMAP_LEN;
 
 			dst.blitrect  //  bottom left corner
-			   (Point(0, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
-			    Rect(Point(0, 0), pos, BT_B_PIXMAP_THICKNESS));
+			   (Vector2f(0, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
+			    Recti(Vector2i(0, 0), pos, BT_B_PIXMAP_THICKNESS));
 
 			//  bottom bar
 			for (; pos < hz_bar_end_minus_middle; pos += HZ_B_MIDDLE_PIXMAP_LEN)
-				dst.blitrect(Point(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
-				             Rect(Point(HZ_B_CORNER_PIXMAP_LEN, 0), HZ_B_MIDDLE_PIXMAP_LEN,
+				dst.blitrect(Vector2f(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
+				             Recti(Vector2i(HZ_B_CORNER_PIXMAP_LEN, 0), HZ_B_MIDDLE_PIXMAP_LEN,
 				                  BT_B_PIXMAP_THICKNESS));
 
 			// odd pixels of bottom bar and bottom right corner
 			const int32_t width = hz_bar_end - pos + HZ_B_CORNER_PIXMAP_LEN;
-			dst.blitrect(Point(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
-			             Rect(Point(HZ_B_TOTAL_PIXMAP_LEN - width, 0), width, BT_B_PIXMAP_THICKNESS));
+			dst.blitrect(Vector2f(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
+			             Recti(Vector2i(HZ_B_TOTAL_PIXMAP_LEN - width, 0), width, BT_B_PIXMAP_THICKNESS));
 		}
 	}
 }
@@ -427,7 +427,7 @@
 	is_minimal_ = true;
 	set_border(get_lborder(), get_rborder(), get_tborder(), 0);
 	set_size(get_w(), TP_B_PIXMAP_THICKNESS);
-	set_pos(Point(x, y));  // If on border, this feels more natural
+	set_pos(Vector2i(x, y));  // If on border, this feels more natural
 }
 
 /**
@@ -574,7 +574,7 @@
 				}
 			}
 		}
-		set_pos(Point(new_left, new_top));
+		set_pos(Vector2i(new_left, new_top));
 	}
 	return true;
 }

=== modified file 'src/ui_basic/window.h'
--- src/ui_basic/window.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/window.h	2016-10-22 18:17:28 +0000
@@ -52,7 +52,7 @@
  */
 class Window : public NamedPanel {
 public:
-	/// Do not use richtext for the \param title.
+	/// Do not use richtext for 'title'.
 	Window(Panel* parent,
 	       const std::string& name,
 	       int32_t x,
@@ -61,7 +61,7 @@
 	       uint32_t h,
 	       const std::string& title);
 
-	/// This will set the window title. Do not use richtext for the \param text.
+	/// This will set the window title. Do not use richtext for 'text'.
 	void set_title(const std::string& text);
 	const std::string& get_title() const {
 		return title_;

=== modified file 'src/ui_fsmenu/about.cc'
--- src/ui_fsmenu/about.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/about.cc	2016-10-22 18:17:28 +0000
@@ -56,7 +56,7 @@
            g_gr->images().get("images/ui_basic/but1.png"),
            UI::TabPanel::Type::kBorder) {
 	title_.set_fontsize(UI_FONT_SIZE_BIG);
-	tabs_.set_pos(Point(hmargin_, tab_panel_y_));
+	tabs_.set_pos(Vector2i(hmargin_, tab_panel_y_));
 
 	tabs_.add_tab("txts/README.lua");
 	tabs_.add_tab("txts/LICENSE.lua");

=== modified file 'src/ui_fsmenu/base.cc'
--- src/ui_fsmenu/base.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/base.cc	2016-10-22 18:17:28 +0000
@@ -58,7 +58,7 @@
 */
 void FullscreenMenuBase::draw(RenderTarget& dst) {
 	const Image* bg = g_gr->images().get(background_image_);
-	dst.blitrect_scale(Rect(0, 0, get_w(), get_h()), bg, Rect(0, 0, bg->width(), bg->height()), 1.,
+	dst.blitrect_scale(Rectf(0, 0, get_w(), get_h()), bg, Recti(0, 0, bg->width(), bg->height()), 1.,
 	                   BlendMode::UseAlpha);
 }
 

=== modified file 'src/ui_fsmenu/helpwindow.cc'
--- src/ui_fsmenu/helpwindow.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/helpwindow.cc	2016-10-22 18:17:28 +0000
@@ -53,7 +53,7 @@
 	              g_gr->images().get("images/ui_basic/but5.png"), _("OK"), "", true, false);
 
 	btn->sigclicked.connect(boost::bind(&FullscreenHelpWindow::clicked_ok, boost::ref(*this)));
-	btn->set_pos(Point(btn->get_x(), height - margin - btn->get_h()));
+	btn->set_pos(Vector2i(btn->get_x(), height - margin - btn->get_h()));
 
 	std::string helptext;
 	try {

=== modified file 'src/ui_fsmenu/launch_mpg.cc'
--- src/ui_fsmenu/launch_mpg.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/launch_mpg.cc	2016-10-22 18:17:28 +0000
@@ -662,7 +662,7 @@
 	suggested_teams_box_->hide();
 	suggested_teams_box_->show(map.get_suggested_teams());
 	suggested_teams_box_->set_pos(
-	   Point(suggested_teams_box_->get_x(),
+	   Vector2i(suggested_teams_box_->get_x(),
 	         back_.get_y() - padding_ - suggested_teams_box_->get_h() - padding_));
 }
 

=== modified file 'src/ui_fsmenu/loadgame.cc'
--- src/ui_fsmenu/loadgame.cc	2016-09-25 12:27:22 +0000
+++ src/ui_fsmenu/loadgame.cc	2016-10-22 18:17:28 +0000
@@ -409,7 +409,7 @@
 					}
 
 					minimap_icon_.set_size(w, h);
-					minimap_icon_.set_pos(Point(xpos, ypos));
+					minimap_icon_.set_pos(Vector2i(xpos, ypos));
 					minimap_icon_.set_frame(UI_FONT_CLR_FG);
 					minimap_icon_.set_visible(true);
 					minimap_icon_.set_icon(minimap_image_.get());

=== modified file 'src/ui_fsmenu/mapselect.cc'
--- src/ui_fsmenu/mapselect.cc	2016-09-25 12:27:22 +0000
+++ src/ui_fsmenu/mapselect.cc	2016-10-22 18:17:28 +0000
@@ -81,7 +81,7 @@
 	   new UI::Box(this, tablex_, checkboxes_y_, UI::Box::Horizontal, checkbox_space_, get_w());
 
 	// Must be initialized before tag checkboxes
-	cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Point(0, 0), _("Show original map names"));
+	cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Vector2i(0, 0), _("Show original map names"));
 	cb_dont_localize_mapnames_->set_state(false);
 	cb_dont_localize_mapnames_->changedto.connect(
 	   boost::bind(&FullscreenMenuMapSelect::fill_table, boost::ref(*this)));
@@ -290,7 +290,7 @@
 	int32_t id = tags_ordered_.size();
 	tags_ordered_.push_back(tag);
 
-	UI::Checkbox* cb = new UI::Checkbox(box, Point(0, 0), displ_name);
+	UI::Checkbox* cb = new UI::Checkbox(box, Vector2i(0, 0), displ_name);
 	cb->changedto.connect(boost::bind(&FullscreenMenuMapSelect::tagbox_changed, this, id, _1));
 
 	box->add(cb, UI::Align::kLeft, true);

=== modified file 'src/ui_fsmenu/options.cc'
--- src/ui_fsmenu/options.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/options.cc	2016-10-22 18:17:28 +0000
@@ -159,8 +159,8 @@
      label_resolution_(&box_interface_, _("In-game resolution"), UI::Align::kLeft),
      resolution_list_(&box_interface_, 0, 0, column_width_ / 2, 80, true),
 
-     fullscreen_(&box_interface_, Point(0, 0), _("Fullscreen"), "", column_width_),
-     inputgrab_(&box_interface_, Point(0, 0), _("Grab Input"), "", column_width_),
+     fullscreen_(&box_interface_, Vector2i(0, 0), _("Fullscreen"), "", column_width_),
+     inputgrab_(&box_interface_, Vector2i(0, 0), _("Grab Input"), "", column_width_),
 
      sb_maxfps_(&box_interface_,
                 0,
@@ -174,9 +174,9 @@
 
      // Windows options
      snap_win_overlap_only_(
-        &box_windows_, Point(0, 0), _("Snap windows only when overlapping"), "", column_width_),
+        &box_windows_, Vector2i(0, 0), _("Snap windows only when overlapping"), "", column_width_),
      dock_windows_to_edges_(
-        &box_windows_, Point(0, 0), _("Dock windows to edges"), "", column_width_),
+        &box_windows_, Vector2i(0, 0), _("Dock windows to edges"), "", column_width_),
 
      sb_dis_panel_(&box_windows_,
                    0,
@@ -201,10 +201,10 @@
                     UI::SpinBox::Units::kPixels),
 
      // Sound options
-     music_(&box_sound_, Point(0, 0), _("Enable Music"), "", column_width_),
-     fx_(&box_sound_, Point(0, 0), _("Enable Sound Effects"), "", column_width_),
+     music_(&box_sound_, Vector2i(0, 0), _("Enable Music"), "", column_width_),
+     fx_(&box_sound_, Vector2i(0, 0), _("Enable Sound Effects"), "", column_width_),
      message_sound_(
-        &box_sound_, Point(0, 0), _("Play a sound at message arrival"), "", column_width_),
+        &box_sound_, Vector2i(0, 0), _("Play a sound at message arrival"), "", column_width_),
 
      // Saving options
      sb_autosave_(&box_saving_,
@@ -234,28 +234,28 @@
                           UI::SpinBox::Type::kBig),
 
      zip_(&box_saving_,
-          Point(0, 0),
+          Vector2i(0, 0),
           _("Compress widelands data files (maps, replays and savegames)"),
           "",
           column_width_),
      write_syncstreams_(&box_saving_,
-                        Point(0, 0),
+                        Vector2i(0, 0),
                         _("Write syncstreams in network games to debug desyncs"),
                         "",
                         column_width_),
 
      // Game options
-     auto_roadbuild_mode_(&box_game_, Point(0, 0), _("Start building road after placing a flag")),
-     show_workarea_preview_(&box_game_, Point(0, 0), _("Show buildings area preview")),
+     auto_roadbuild_mode_(&box_game_, Vector2i(0, 0), _("Start building road after placing a flag")),
+     show_workarea_preview_(&box_game_, Vector2i(0, 0), _("Show buildings area preview")),
      transparent_chat_(&box_game_,
-                       Point(0, 0),
+                       Vector2i(0, 0),
                        _("Show in-game chat with transparent background"),
                        "",
                        column_width_),
 
      /** TRANSLATORS: A watchwindow is a window where you keep watching an object or a map region,*/
      /** TRANSLATORS: and it also lets you jump to it on the map. */
-     single_watchwin_(&box_game_, Point(0, 0), _("Use single watchwindow mode")),
+     single_watchwin_(&box_game_, Vector2i(0, 0), _("Use single watchwindow mode")),
 
      // Language options
      label_language_(&box_language_, _("Language"), UI::Align::kLeft),
@@ -282,7 +282,7 @@
 		tabs_.activate(os_.active_tab);
 	}
 
-	tabs_.set_pos(Point(hmargin_, tab_panel_y_));
+	tabs_.set_pos(Vector2i(hmargin_, tab_panel_y_));
 
 	box_interface_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());
 	box_windows_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());

=== modified file 'src/website/map_info.cc'
--- src/website/map_info.cc	2016-08-04 15:49:05 +0000
+++ src/website/map_info.cc	2016-10-22 18:17:28 +0000
@@ -88,8 +88,8 @@
 		ml->preload_map(true);
 		ml->load_map_complete(egbase, Widelands::MapLoader::LoadType::kScenario);
 
-		std::unique_ptr<Texture> minimap(
-		   draw_minimap(egbase, nullptr, Point(0, 0), MiniMapLayer::Terrain));
+		std::unique_ptr<Texture> minimap(draw_minimap(
+		   egbase, nullptr, Rectf(), MiniMapType::kStaticMap, MiniMapLayer::Terrain));
 
 		// Write minimap
 		{

=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc	2016-09-16 16:54:11 +0000
+++ src/wlapplication.cc	2016-10-22 18:17:28 +0000
@@ -465,7 +465,7 @@
 	case SDL_MOUSEMOTION:
 		ev.motion.xrel += mouse_compensate_warp_.x;
 		ev.motion.yrel += mouse_compensate_warp_.y;
-		mouse_compensate_warp_ = Point(0, 0);
+		mouse_compensate_warp_ = Vector2i(0, 0);
 
 		if (mouse_locked_) {
 			warp_mouse(mouse_position_);
@@ -576,7 +576,7 @@
 			}
 			break;
 		case SDL_MOUSEMOTION:
-			mouse_position_ = Point(ev.motion.x, ev.motion.y);
+			mouse_position_ = Vector2i(ev.motion.x, ev.motion.y);
 
 			if ((ev.motion.xrel || ev.motion.yrel) && cb && cb->mouse_move)
 				cb->mouse_move(
@@ -654,10 +654,10 @@
 /// eliminate the motion event in poll_event()
 ///
 /// \param position The new mouse position
-void WLApplication::warp_mouse(const Point position) {
+void WLApplication::warp_mouse(const Vector2i position) {
 	mouse_position_ = position;
 
-	Point cur_position;
+	Vector2i cur_position;
 	SDL_GetMouseState(&cur_position.x, &cur_position.y);
 	if (cur_position != position) {
 		mouse_compensate_warp_ += cur_position - position;

=== modified file 'src/wlapplication.h'
--- src/wlapplication.h	2016-08-13 12:16:14 +0000
+++ src/wlapplication.h	2016-10-22 18:17:28 +0000
@@ -36,7 +36,7 @@
 #include <SDL_events.h>
 #include <SDL_keyboard.h>
 
-#include "base/point.h"
+#include "base/vector.h"
 
 namespace Widelands {
 class Game;
@@ -152,11 +152,11 @@
 	}
 
 	// @{
-	void warp_mouse(Point);
+	void warp_mouse(Vector2i);
 	void set_input_grab(bool grab);
 
 	/// The mouse's current coordinates
-	Point get_mouse_position() const {
+	Vector2i get_mouse_position() const {
 		return mouse_position_;
 	}
 	//
@@ -239,15 +239,15 @@
 	bool faking_middle_mouse_button_;
 
 	/// The current position of the mouse pointer
-	Point mouse_position_;
+	Vector2i mouse_position_;
 
 	/// If true, the mouse cursor will \e not move with a mousemotion event:
 	/// instead, the map will be scrolled
 	bool mouse_locked_;
 
-	/// If the mouse needs to be moved in warp_mouse(), this Point is
+	/// If the mouse needs to be moved in warp_mouse(), this Vector2i is
 	/// used to cancel the resulting SDL_MouseMotionEvent.
-	Point mouse_compensate_warp_;
+	Vector2i mouse_compensate_warp_;
 
 	/// true if an external entity wants us to quit
 	bool should_die_;

=== modified file 'src/wui/CMakeLists.txt'
--- src/wui/CMakeLists.txt	2016-04-15 17:23:00 +0000
+++ src/wui/CMakeLists.txt	2016-10-22 18:17:28 +0000
@@ -48,7 +48,6 @@
     mapviewpixelconstants.h
     mapviewpixelfunctions.cc
     mapviewpixelfunctions.h
-    vector.h
   DEPENDS
     base_geometry
     logic
@@ -185,6 +184,7 @@
     base_i18n
     base_log
     base_macros
+    base_math
     base_time_string
     chat
     economy

=== modified file 'src/wui/building_statistics_menu.cc'
--- src/wui/building_statistics_menu.cc	2016-08-04 15:49:05 +0000
+++ src/wui/building_statistics_menu.cc	2016-10-22 18:17:28 +0000
@@ -481,7 +481,7 @@
 
 	if (found) {
 		validate_pointer(&last_building_index_, stats_vector.size());
-		iplayer().move_view_to(stats_vector[last_building_index_].pos);
+		iplayer().center_view_on_coords(stats_vector[last_building_index_].pos);
 	}
 	low_production_reset_focus();
 	update();
@@ -501,7 +501,7 @@
 		tab_panel_.set_size(kWindowWidth, tab_height);
 		set_size(
 		   get_w(), tab_height + kMargin + 4 * kButtonRowHeight + get_tborder() + get_bborder());
-		navigation_panel_.set_pos(Point(0, tab_height + kMargin));
+		navigation_panel_.set_pos(Vector2i(0, tab_height + kMargin));
 	}
 
 	// Update statistics

=== modified file 'src/wui/building_ui.cc'
--- src/wui/building_ui.cc	2016-08-04 15:49:05 +0000
+++ src/wui/building_ui.cc	2016-10-22 18:17:28 +0000
@@ -31,7 +31,7 @@
  * Create the building's options window if necessary and bring it to
  * the top to be seen by the player.
  */
-void Building::show_options(InteractiveGameBase& igbase, bool avoid_fastclick, Point pos) {
+void Building::show_options(InteractiveGameBase& igbase, bool avoid_fastclick, Vector2i pos) {
 	if (optionswindow_) {
 		if (optionswindow_->is_minimal())
 			optionswindow_->restore();
@@ -66,7 +66,7 @@
 void Building::refresh_options(InteractiveGameBase& igb) {
 	// Only do something if there is actually a window
 	if (optionswindow_) {
-		Point window_position = optionswindow_->get_pos();
+		Vector2i window_position = optionswindow_->get_pos();
 		hide_options();
 		show_options(igb, true);
 		optionswindow_->set_pos(window_position);

=== modified file 'src/wui/buildingwindow.cc'
--- src/wui/buildingwindow.cc	2016-08-04 15:49:05 +0000
+++ src/wui/buildingwindow.cc	2016-10-22 18:17:28 +0000
@@ -110,9 +110,10 @@
 	// TODO(sirver): chang this to directly blit the animation. This needs support for or removal of
 	// RenderTarget.
 	const Image* image = building().representative_image();
-	dst.blitrect_scale(Rect((get_inner_w() - image->width()) / 2,
-	                        (get_inner_h() - image->height()) / 2, image->width(), image->height()),
-	                   image, Rect(0, 0, image->width(), image->height()), 0.5, BlendMode::UseAlpha);
+	dst.blitrect_scale(
+	   Rectf((get_inner_w() - image->width()) / 2.f, (get_inner_h() - image->height()) / 2.f,
+	         image->width(), image->height()),
+	   image, Recti(0, 0, image->width(), image->height()), 0.5, BlendMode::UseAlpha);
 }
 
 /*
@@ -460,7 +461,7 @@
  * for the corresponding button.
  */
 void BuildingWindow::clicked_goto() {
-	igbase().move_view_to(building().get_position());
+	igbase().center_view_on_coords(building().get_position());
 }
 
 void BuildingWindow::update_expedition_button(bool expedition_was_canceled) {

=== modified file 'src/wui/chatoverlay.cc'
--- src/wui/chatoverlay.cc	2016-08-04 15:49:05 +0000
+++ src/wui/chatoverlay.cc	2016-10-22 18:17:28 +0000
@@ -183,12 +183,10 @@
 	const int width = std::min<int>(get_w(), im->width());
 
 	if (!m->transparent_) {
-		Rect rect(0, top, width, height);
-		dst.fill_rect(rect, RGBAColor(50, 50, 50, 128), BlendMode::Default);
+		dst.fill_rect(Rectf(0, top, width, height), RGBAColor(50, 50, 50, 128), BlendMode::Default);
 	}
 	int32_t topcrop = im->height() - height;
-	Rect cropRect(0, topcrop, width, height);
+	Recti cropRect(0, topcrop, width, height);
 
-	Point pt(0, top);
-	dst.blitrect(pt, im, cropRect);
+	dst.blitrect(Vector2f(0, top), im, cropRect);
 }

=== modified file 'src/wui/field_overlay_manager.cc'
--- src/wui/field_overlay_manager.cc	2016-08-04 15:49:05 +0000
+++ src/wui/field_overlay_manager.cc	2016-10-22 18:17:28 +0000
@@ -36,7 +36,7 @@
 	//  Special case for flag, which has a different formula for hotspot_y.
 	buildhelp_info->pic = g_gr->images().get(*filename);
 	buildhelp_info->hotspot =
-	   Point(buildhelp_info->pic->width() / 2, buildhelp_info->pic->height() - 1);
+	   Vector2i(buildhelp_info->pic->width() / 2, buildhelp_info->pic->height() - 1);
 
 	const OverlayInfo* const buildhelp_infos_end = buildhelp_info + Widelands::Field::Buildhelp_None;
 	for (;;) {  // The other buildhelp overlays.
@@ -45,7 +45,7 @@
 			break;
 		buildhelp_info->pic = g_gr->images().get(*filename);
 		buildhelp_info->hotspot =
-		   Point(buildhelp_info->pic->width() / 2, buildhelp_info->pic->height() / 2);
+		   Vector2i(buildhelp_info->pic->width() / 2, buildhelp_info->pic->height() / 2);
 	}
 }
 
@@ -113,13 +113,13 @@
 void FieldOverlayManager::register_overlay(const Widelands::TCoords<>& c,
                                            const Image* pic,
                                            int32_t const level,
-                                           Point hotspot,
+                                           Vector2i hotspot,
                                            OverlayId const overlay_id) {
 	assert(c.t <= 2);
 	assert(level != 5);  //  level == 5 is undefined behavior
 
-	if (hotspot == Point::invalid()) {
-		hotspot = Point(pic->width() / 2, pic->height() / 2);
+	if (hotspot == Vector2i::invalid()) {
+		hotspot = Vector2i(pic->width() / 2, pic->height() / 2);
 	}
 
 	RegisteredOverlaysMap& overlay_map = overlays_[c.t];

=== modified file 'src/wui/field_overlay_manager.h'
--- src/wui/field_overlay_manager.h	2016-08-04 15:49:05 +0000
+++ src/wui/field_overlay_manager.h	2016-10-22 18:17:28 +0000
@@ -25,7 +25,7 @@
 #include <set>
 #include <vector>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "logic/field.h"
 #include "logic/widelands_geometry.h"
 
@@ -55,12 +55,12 @@
 	/// A overlay as drawn onto the screen.
 	struct OverlayInfo {
 		OverlayInfo() = default;
-		OverlayInfo(const Image* init_pic, const Point& init_hotspot)
+		OverlayInfo(const Image* init_pic, const Vector2i& init_hotspot)
 		   : pic(init_pic), hotspot(init_hotspot) {
 		}
 
 		const Image* pic;
-		Point hotspot;
+		Vector2i hotspot;
 	};
 
 	/// A function returning Field::nodecaps() for the build overlay. This can be
@@ -84,11 +84,11 @@
 
 	/// Register an overlay at a location (node or triangle). hotspot is the point
 	/// of the picture that will be exactly over the location. If hotspot is
-	/// Point::invalid(), the center of the picture will be used as hotspot.
+	/// Vector2i::invalid(), the center of the picture will be used as hotspot.
 	void register_overlay(const Widelands::TCoords<>& coords,
 	                      const Image* pic,
 	                      int32_t level,
-	                      Point hotspot = Point::invalid(),
+	                      Vector2i hotspot = Vector2i::invalid(),
 	                      OverlayId overlay_id = 0);
 
 	/// removes all overlays when pic is nullptr.
@@ -111,14 +111,14 @@
 	struct RegisteredOverlays {
 		RegisteredOverlays(const OverlayId init_overlay_id,
 		                   const Image* init_pic,
-		                   const Point init_hotspot,
+		                   const Vector2i init_hotspot,
 		                   const int init_level)
 		   : pic(init_pic), hotspot(init_hotspot), level(init_level) {
 			overlay_ids.insert(init_overlay_id);
 		}
 		std::set<OverlayId> overlay_ids;
 		const Image* pic;
-		Point hotspot;
+		Vector2i hotspot;
 		int level;
 	};
 

=== modified file 'src/wui/fieldaction.cc'
--- src/wui/fieldaction.cc	2016-08-04 15:49:05 +0000
+++ src/wui/fieldaction.cc	2016-10-22 18:17:28 +0000
@@ -282,7 +282,7 @@
 	move_out_of_the_way();
 
 	// Now force the mouse onto the first button
-	set_mouse_pos(Point(17 + kBuildGridCellSize * best_tab_, fastclick_ ? 51 : 17));
+	set_mouse_pos(Vector2i(17 + kBuildGridCellSize * best_tab_, fastclick_ ? 51 : 17));
 
 	// Will only do something if we explicitly set another fast click panel
 	// than the first button

=== modified file 'src/wui/game_message_menu.cc'
--- src/wui/game_message_menu.cc	2016-09-16 10:32:40 +0000
+++ src/wui/game_message_menu.cc	2016-10-22 18:17:28 +0000
@@ -445,7 +445,7 @@
 	if (Message const* const message =
 	       iplayer().player().messages()[MessageId((*list)[selection])]) {
 		assert(message->position());
-		iplayer().move_view_to(message->position());
+		iplayer().center_view_on_coords(message->position());
 	}
 }
 

=== modified file 'src/wui/game_options_sound_menu.cc'
--- src/wui/game_options_sound_menu.cc	2016-08-04 15:49:05 +0000
+++ src/wui/game_options_sound_menu.cc	2016-10-22 18:17:28 +0000
@@ -25,9 +25,9 @@
 GameOptionsSoundMenu::GameOptionsSoundMenu(InteractiveGameBase& gb,
                                            UI::UniqueWindow::Registry& registry)
    : UI::UniqueWindow(&gb, "sound_options_menu", &registry, 160, 160, _("Sound Options")),
-     ingame_music(this, Point(hmargin(), vmargin()), _("Enable Music")),
+     ingame_music(this, Vector2i(hmargin(), vmargin()), _("Enable Music")),
      ingame_sound(
-        this, Point(hmargin(), vmargin() + kStateboxSize + vspacing()), _("Enable Sound Effects")),
+        this, Vector2i(hmargin(), vmargin() + kStateboxSize + vspacing()), _("Enable Sound Effects")),
      ingame_music_volume_label(this,
                                hmargin(),
                                vmargin() + 2 * (kStateboxSize + vspacing()) + vbigspacing(),

=== modified file 'src/wui/game_tips.cc'
--- src/wui/game_tips.cc	2016-08-04 15:49:05 +0000
+++ src/wui/game_tips.cc	2016-10-22 18:17:28 +0000
@@ -104,15 +104,15 @@
 	assert(pic_background);
 
 	RenderTarget& rt = *g_gr->get_render_target();
-	Rect tips_area;
 
 	uint16_t w = pic_background->width();
 	uint16_t h = pic_background->height();
-	Point pt((g_gr->get_xres() - w) / 2, (g_gr->get_yres() - h) / 2);
-	tips_area = Rect(pt, w, h);
+	Vector2f pt((g_gr->get_xres() - w) / 2, (g_gr->get_yres() - h) / 2);
+	Rectf tips_area(pt, w, h);
 	rt.blit(pt, pic_background);
 
-	Point center(tips_area.x + tips_area.w / 2, tips_area.y + tips_area.h / 2);
 	const Image* rendered_text = UI::g_fh1->render(as_game_tip(tips_[index].text), tips_area.w);
-	rt.blit(center - Point(rendered_text->width() / 2, rendered_text->height() / 2), rendered_text);
+	rt.blit(
+	   tips_area.center() - Vector2f(rendered_text->width() / 2.f, rendered_text->height() / 2.f),
+	   rendered_text);
 }

=== modified file 'src/wui/general_statistics_menu.cc'
--- src/wui/general_statistics_menu.cc	2016-08-04 15:49:05 +0000
+++ src/wui/general_statistics_menu.cc	2016-10-22 18:17:28 +0000
@@ -137,63 +137,63 @@
 
 	UI::Radiobutton* btn;
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_landsize.png"), _("Land"),
 	                       &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_nrworkers.png"),
 	                       _("Workers"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_nrbuildings.png"),
 	                       _("Buildings"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_nrwares.png"), _("Wares"),
 	                       &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_productivity.png"),
 	                       _("Productivity"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_casualties.png"),
 	                       _("Casualties"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_kills.png"), _("Kills"),
 	                       &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_msites_lost.png"),
 	                       _("Military buildings lost"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_msites_defeated.png"),
 	                       _("Military buildings defeated"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_civil_blds_lost.png"),
 	                       _("Civilian buildings lost"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_militarystrength.png"),
 	                       _("Military"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
 	if (hook) {
-		radiogroup_.add_button(hbox2, Point(0, 0), g_gr->images().get(cs_pic), cs_name.c_str(), &btn);
+		radiogroup_.add_button(hbox2, Vector2i(0, 0), g_gr->images().get(cs_pic), cs_name.c_str(), &btn);
 		hbox2->add(btn, UI::Align::kLeft, false, true);
 	}
 

=== modified file 'src/wui/interactive_base.cc'
--- src/wui/interactive_base.cc	2016-09-25 16:45:37 +0000
+++ src/wui/interactive_base.cc	2016-10-22 18:17:28 +0000
@@ -119,7 +119,7 @@
 	m->quicknavigation->set_setview(boost::bind(&MapView::set_viewpoint, this, _1, true));
 	set_changeview(boost::bind(&QuickNavigation::view_changed, m->quicknavigation.get(), _1, _2));
 
-	changeview.connect(boost::bind(&InteractiveBase::mainview_move, this, _1, _2));
+	changeview.connect(boost::bind(&InteractiveBase::mainview_move, this, _1));
 
 	set_border_snap_distance(global_s.get_int("border_snap_distance", 0));
 	set_panel_snap_distance(global_s.get_int("panel_snap_distance", 10));
@@ -161,13 +161,13 @@
 		Widelands::MapTriangleRegion<> mr(map, Area<TCoords<>>(center.triangle, sel_.radius));
 		do
 			field_overlay_manager_->register_overlay(
-			   mr.location(), sel_.pic, 7, Point::invalid(), jobid);
+			   mr.location(), sel_.pic, 7, Vector2i::invalid(), jobid);
 		while (mr.advance(map));
 	} else {
 		Widelands::MapRegion<> mr(map, Area<>(center.node, sel_.radius));
 		do
 			field_overlay_manager_->register_overlay(
-			   mr.location(), sel_.pic, 7, Point::invalid(), jobid);
+			   mr.location(), sel_.pic, 7, Vector2i::invalid(), jobid);
 		while (mr.advance(map));
 		if (upcast(InteractiveGameBase const, igbase, this))
 			if (upcast(Widelands::ProductionSite, productionsite, map[center.node].get_immovable())) {
@@ -255,7 +255,7 @@
 		Widelands::MapHollowRegion<> mr(map, hollow_area);
 		do
 			field_overlay_manager_->register_overlay(
-			   mr.location(), workarea_pics_[wa_index], 0, Point::invalid(), overlay_id);
+			   mr.location(), workarea_pics_[wa_index], 0, Vector2i::invalid(), overlay_id);
 		while (mr.advance(map));
 		wa_index++;
 		hollow_area.hole_radius = hollow_area.radius;
@@ -288,19 +288,19 @@
 	if (keyboard_free() && Panel::allow_user_input()) {
 		if (get_key_state(SDL_SCANCODE_UP) ||
 		    (get_key_state(SDL_SCANCODE_KP_8) && (SDL_GetModState() ^ KMOD_NUM))) {
-			set_rel_viewpoint(Point(0, -scrollval), false);
+			pan_by(Vector2i(0, -scrollval));
 		}
 		if (get_key_state(SDL_SCANCODE_DOWN) ||
 		    (get_key_state(SDL_SCANCODE_KP_2) && (SDL_GetModState() ^ KMOD_NUM))) {
-			set_rel_viewpoint(Point(0, scrollval), false);
+			pan_by(Vector2i(0, scrollval));
 		}
 		if (get_key_state(SDL_SCANCODE_LEFT) ||
 		    (get_key_state(SDL_SCANCODE_KP_4) && (SDL_GetModState() ^ KMOD_NUM))) {
-			set_rel_viewpoint(Point(-scrollval, 0), false);
+			pan_by(Vector2i(-scrollval, 0));
 		}
 		if (get_key_state(SDL_SCANCODE_RIGHT) ||
 		    (get_key_state(SDL_SCANCODE_KP_6) && (SDL_GetModState() ^ KMOD_NUM))) {
-			set_rel_viewpoint(Point(scrollval, 0), false);
+			pan_by(Vector2i(scrollval, 0));
 		}
 	}
 	egbase().think();  // Call game logic here. The game advances.
@@ -330,7 +330,7 @@
 		if (is_game) {
 			const std::string gametime(gametimestring(egbase().get_gametime(), true));
 			const std::string gametime_text = as_condensed(gametime);
-			dst.blit(Point(5, 5), UI::g_fh1->render(gametime_text), BlendMode::UseAlpha,
+			dst.blit(Vector2f(5.f, 5.f), UI::g_fh1->render(gametime_text), BlendMode::UseAlpha,
 			         UI::Align::kTopLeft);
 
 			static boost::format node_format("(%i, %i)");
@@ -341,8 +341,8 @@
 			node_text = as_condensed((node_format % sel_.pos.node.x % sel_.pos.node.y % height).str());
 		}
 
-		dst.blit(Point(get_w() - 5, get_h() - 5), UI::g_fh1->render(node_text), BlendMode::UseAlpha,
-		         UI::Align::kBottomRight);
+		dst.blit(Vector2f(get_w() - 5.f, get_h() - 5.f), UI::g_fh1->render(node_text),
+		         BlendMode::UseAlpha, UI::Align::kBottomRight);
 	}
 
 	// Blit FPS when playing a game in debug mode.
@@ -350,100 +350,32 @@
 		static boost::format fps_format("%5.1f fps (avg: %5.1f fps)");
 		const Image* rendered_text = UI::g_fh1->render(as_condensed(
 		   (fps_format % (1000.0 / frametime_) % (1000.0 / (avg_usframetime_ / 1000))).str()));
-		dst.blit(Point((get_w() - rendered_text->width()) / 2, 5), rendered_text, BlendMode::UseAlpha,
-		         UI::Align::kLeft);
+		dst.blit(Vector2f((get_w() - rendered_text->width()) / 2.f, 5.f), rendered_text,
+		         BlendMode::UseAlpha, UI::Align::kLeft);
 	}
 }
 
-/** InteractiveBase::mainview_move(int32_t x, int32_t y)
- *
- * Signal handler for the main view's warpview updates the mini map's
- * viewpos marker position
- */
-void InteractiveBase::mainview_move(int32_t x, int32_t y) {
+void InteractiveBase::mainview_move(const Rectf& map_view) {
 	if (m->minimap.window) {
-		const Map& map = egbase().map();
-		const int32_t maxx = MapviewPixelFunctions::get_map_end_screen_x(map);
-		const int32_t maxy = MapviewPixelFunctions::get_map_end_screen_y(map);
-
-		x += get_w() >> 1;
-		if (x >= maxx)
-			x -= maxx;
-		y += get_h() >> 1;
-		if (y >= maxy)
-			y -= maxy;
-
-		m->mm->set_view_pos(x, y);
+		m->mm->set_view(map_view);
 	}
 }
 
-/*
-===============
-Called whenever the player clicks on a location on the minimap.
-Warps the main mapview position to the clicked location.
-===============
-*/
-void InteractiveBase::minimap_warp(int32_t x, int32_t y) {
-	x -= get_w() >> 1;
-	y -= get_h() >> 1;
-	const Map& map = egbase().map();
-	if (x < 0)
-		x += map.get_width() * kTriangleWidth;
-	if (y < 0)
-		y += map.get_height() * kTriangleHeight;
-	set_viewpoint(Point(x, y), true);
-}
-
-/*
-===============
-Move the mainview to the given position (in node coordinates)
-===============
-*/
-void InteractiveBase::move_view_to(const Coords c) {
-	assert(0 <= c.x);
-	assert(c.x < egbase().map().get_width());
-	assert(0 <= c.y);
-	assert(c.y < egbase().map().get_height());
-
-	const Map& map = egbase().map();
-	uint32_t const x = (c.x + (c.y & 1) * 0.5) * kTriangleWidth;
-	uint32_t const y = c.y * kTriangleHeight - map[c].get_height() * kHeightFactor;
-	if (m->minimap.window)
-		m->mm->set_view_pos(x, y);
-	minimap_warp(x, y);
-}
-
-/*
-===============
-Center the mainview on the given position (in pixels)
-===============
-*/
-void InteractiveBase::move_view_to_point(Point pos) {
-	if (m->minimap.window)
-		m->mm->set_view_pos(pos.x, pos.y);
-
-	set_viewpoint(pos - Point(get_w() / 2, get_h() / 2), true);
-}
-
 // Open the minimap or close it if it's open
 void InteractiveBase::toggle_minimap() {
 	if (m->minimap.window) {
 		delete m->minimap.window;
 	} else {
 		m->mm = new MiniMap(*this, &m->minimap);
-		m->mm->warpview.connect(boost::bind(&InteractiveBase::minimap_warp, this, _1, _2));
-
-		// make sure the viewpos marker is at the right pos to start with
-		const Point p = get_viewpoint();
-
-		mainview_move(p.x, p.y);
+		m->mm->warpview.connect(boost::bind(&InteractiveBase::center_view_on_map_pixel, this, _1));
+		mainview_move(get_view_area());
 	}
 }
 
 const std::vector<QuickNavigation::Landmark>& InteractiveBase::landmarks() {
 	return m->quicknavigation->landmarks();
 }
-void InteractiveBase::set_landmark(size_t key, const Point& point) {
+void InteractiveBase::set_landmark(size_t key, const Vector2i& point) {
 	m->quicknavigation->set_landmark(key, point);
 }
 
@@ -461,7 +393,7 @@
 Exposes the Registry object of the minimap to derived classes
 ===========
 */
-UI::UniqueWindow::Registry& InteractiveBase::minimap_registry() {
+MiniMap::Registry& InteractiveBase::minimap_registry() {
 	return m->minimap;
 }
 
@@ -742,7 +674,7 @@
 			name = "images/wui/overlays/roadb_red.png";
 
 		field_overlay_manager_->register_overlay(
-		   neighb, g_gr->images().get(name), 7, Point::invalid(), road_buildhelp_overlay_jobid_);
+		   neighb, g_gr->images().get(name), 7, Vector2i::invalid(), road_buildhelp_overlay_jobid_);
 	}
 }
 

=== modified file 'src/wui/interactive_base.h'
--- src/wui/interactive_base.h	2016-08-04 15:49:05 +0000
+++ src/wui/interactive_base.h	2016-10-22 18:17:28 +0000
@@ -37,6 +37,7 @@
 #include "wui/edge_overlay_manager.h"
 #include "wui/field_overlay_manager.h"
 #include "wui/mapview.h"
+#include "wui/minimap.h"
 #include "wui/quicknavigation.h"
 
 namespace Widelands {
@@ -117,9 +118,6 @@
 	}
 	void set_sel_radius(uint32_t);
 
-	void move_view_to(Widelands::Coords);
-	void move_view_to_point(Point pos);
-
 	//  display flags
 	uint32_t get_display_flags() const;
 	void set_display_flags(uint32_t flags);
@@ -167,7 +165,7 @@
 	// Returns the list of landmarks that have been mapped to the keys 0-9
 	const std::vector<QuickNavigation::Landmark>& landmarks();
 	// Sets the landmark for the keyboard 'key' to 'point'
-	void set_landmark(size_t key, const Point& point);
+	void set_landmark(size_t key, const Vector2i& point);
 
 protected:
 	// Will be called whenever the buildhelp is changed with the new 'value'.
@@ -176,10 +174,9 @@
 	void toggle_buildhelp();
 	void hide_minimap();
 
-	UI::UniqueWindow::Registry& minimap_registry();
+	MiniMap::Registry& minimap_registry();
 
-	void mainview_move(int32_t x, int32_t y);
-	void minimap_warp(int32_t x, int32_t y);
+	void mainview_move(const Rectf&);
 
 	void draw_overlay(RenderTarget&) override;
 	bool handle_key(bool down, SDL_Keysym) override;
@@ -187,7 +184,7 @@
 	void unset_sel_picture();
 	void set_sel_picture(const char* const);
 	void adjust_toolbar_position() {
-		toolbar_.set_pos(Point((get_inner_w() - toolbar_.get_w()) >> 1, get_inner_h() - 34));
+		toolbar_.set_pos(Vector2i((get_inner_w() - toolbar_.get_w()) >> 1, get_inner_h() - 34));
 	}
 
 	// TODO(sirver): why are these protected?

=== modified file 'src/wui/interactive_gamebase.cc'
--- src/wui/interactive_gamebase.cc	2016-08-04 15:49:05 +0000
+++ src/wui/interactive_gamebase.cc	2016-10-22 18:17:28 +0000
@@ -107,7 +107,7 @@
 		}
 
 		if (!game_speed.empty()) {
-			dst.blit(Point(get_w() - 5, 5), UI::g_fh1->render(game_speed), BlendMode::UseAlpha,
+			dst.blit(Vector2f(get_w() - 5.f, 5.f), UI::g_fh1->render(game_speed), BlendMode::UseAlpha,
 			         UI::Align::kTopRight);
 		}
 	}

=== modified file 'src/wui/interactive_player.cc'
--- src/wui/interactive_player.cc	2016-08-04 15:49:05 +0000
+++ src/wui/interactive_player.cc	2016-10-22 18:17:28 +0000
@@ -322,7 +322,7 @@
 				break;
 		/* no break */
 		case SDLK_HOME:
-			move_view_to(game().map().get_starting_pos(player_number_));
+			center_view_on_coords(game().map().get_starting_pos(player_number_));
 			return true;
 
 		case SDLK_KP_ENTER:

=== modified file 'src/wui/itemwaresdisplay.cc'
--- src/wui/itemwaresdisplay.cc	2016-08-04 15:49:05 +0000
+++ src/wui/itemwaresdisplay.cc	2016-10-22 18:17:28 +0000
@@ -98,7 +98,7 @@
 void ItemWaresDisplay::draw(RenderTarget& dst) {
 	const Widelands::TribeDescr& tribe(player().tribe());
 
-	dst.fill_rect(Rect(Point(0, 0), get_w(), get_h()), RGBAColor(0, 0, 0, 0));
+	dst.fill_rect(Rectf(0, 0, get_w(), get_h()), RGBAColor(0, 0, 0, 0));
 
 	for (uint32_t idx = 0; idx < items_.size(); ++idx) {
 		const Item& it = items_[idx];
@@ -110,13 +110,14 @@
 
 		if (it.worker) {
 			y += IWD_WorkerBaseline;
-			dst.blit_animation(Point(x + (IWD_ItemWidth / 2), y + (IWD_ItemHeight / 2)),
-			                   tribe.get_worker_descr(it.index)->main_animation(), 0,
+			constexpr float kZoom = 1.f;
+			dst.blit_animation(Vector2f(x + (IWD_ItemWidth / 2.f), y + (IWD_ItemHeight / 2.f)),
+			                   kZoom, tribe.get_worker_descr(it.index)->main_animation(), 0,
 			                   player().get_playercolor());
 		} else {
 			y += IWD_WareBaseLine;
 			if (tribe.get_ware_descr(it.index)->icon())
-				dst.blit(Point(x, y), tribe.get_ware_descr(it.index)->icon());
+				dst.blit(Vector2f(x, y), tribe.get_ware_descr(it.index)->icon());
 		}
 	}
 }

=== modified file 'src/wui/login_box.cc'
--- src/wui/login_box.cc	2016-08-07 08:18:51 +0000
+++ src/wui/login_box.cc	2016-10-22 18:17:28 +0000
@@ -42,9 +42,9 @@
 	                                        _("WARNING: Password will be shown and saved readable!"),
 	                                        UI::Align::kLeft);
 
-	cb_register = new UI::Checkbox(this, Point(margin, 110), _("Log in to a registered account"), "",
+	cb_register = new UI::Checkbox(this, Vector2i(margin, 110), _("Log in to a registered account"), "",
 	                               get_inner_w() - 2 * margin);
-	cb_auto_log = new UI::Checkbox(this, Point(margin, 135),
+	cb_auto_log = new UI::Checkbox(this, Vector2i(margin, 135),
 	                               _("Automatically use this login information from now on."), "",
 	                               get_inner_w() - 2 * margin);
 

=== modified file 'src/wui/mapdetails.cc'
--- src/wui/mapdetails.cc	2016-08-04 15:49:05 +0000
+++ src/wui/mapdetails.cc	2016-10-22 18:17:28 +0000
@@ -111,7 +111,7 @@
 void MapDetails::update_layout() {
 	// Adjust sizes for show / hide suggested teams
 	if (suggested_teams_box_->is_visible()) {
-		suggested_teams_box_->set_pos(Point(0, max_h_ - suggested_teams_box_->get_h()));
+		suggested_teams_box_->set_pos(Vector2i(0, max_h_ - suggested_teams_box_->get_h()));
 		main_box_.set_size(main_box_.get_w(), max_h_ - suggested_teams_box_->get_h() - padding_);
 	} else {
 		main_box_.set_size(main_box_.get_w(), max_h_);

=== modified file 'src/wui/mapview.cc'
--- src/wui/mapview.cc	2016-08-04 15:49:05 +0000
+++ src/wui/mapview.cc	2016-10-22 18:17:28 +0000
@@ -20,58 +20,120 @@
 #include "wui/mapview.h"
 
 #include "base/macros.h"
+#include "base/math.h"
 #include "graphic/game_renderer.h"
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 #include "logic/map.h"
+#include "logic/map_objects/draw_text.h"
 #include "logic/player.h"
 #include "wlapplication.h"
 #include "wui/interactive_base.h"
 #include "wui/interactive_player.h"
 #include "wui/mapviewpixelfunctions.h"
 
+namespace {
+
+// Returns the shortest distance between two points on a wrapping line of
+// length width.
+float shortest_distance_on_torus(float x1, float x2, const float width) {
+	if (x1 > x2) {
+		std::swap(x1, x2);
+	}
+	while (x2 - x1 > width / 2.f) {
+		x1 += width;
+	}
+	return x2 - x1;
+}
+
+// Given 'p' on a torus of dimension ('h', 'h') and 'r' that contains this
+// point, change 'p' so that r.x < p.x < r.x + r.w and similar for y.
+// Containing is defined as such that the shortest distance between the center
+// of 'r' is smaller than (r.w / 2, r.h / 2). If 'p' is NOT contained in 'r'
+// this method will loop forever.
+Vector2f move_inside(Vector2f p, const Rectf& r, float w, float h) {
+	while (p.x < r.x && r.x < r.x + r.w) {
+		p.x += w;
+	}
+	while (p.x > r.x && r.x > r.x + r.w) {
+		p.x -= w;
+	}
+	while (p.y < r.y && r.y < r.y + r.y) {
+		p.y += h;
+	}
+	while (p.y > r.y && r.y > r.y + r.y) {
+		p.y -= h;
+	}
+	return p;
+}
+
+}  // namespace
+
 MapView::MapView(
    UI::Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, InteractiveBase& player)
    : UI::Panel(parent, x, y, w, h),
      renderer_(new GameRenderer()),
      intbase_(player),
-     viewpoint_(Point(0, 0)),
+     viewpoint_(0.f, 0.f),
+     zoom_(1.f),
      dragging_(false) {
 }
 
 MapView::~MapView() {
-	// explicit destructor so that smart pointer destructors
-	// with forward-declared types are properly instantiated
+}
+
+Vector2i MapView::get_viewpoint() const {
+	return round(viewpoint_);
+}
+
+Vector2f MapView::to_panel(const Vector2f& map_pixel) const {
+	return MapviewPixelFunctions::map_to_panel(viewpoint_, zoom_, map_pixel);
+}
+
+Vector2f MapView::to_map(const Vector2f& panel_pixel) const {
+	return MapviewPixelFunctions::panel_to_map(viewpoint_, zoom_, panel_pixel);
 }
 
 /// Moves the mouse cursor so that it is directly above the given node
 void MapView::warp_mouse_to_node(Widelands::Coords const c) {
+	// This problem is surprisingly hard: We want to figure out if the
+	// 'minimap_pixel' is currently visible on screen and if so, what pixel it
+	// has. Since Wideland's map is a torus, the current 'view_area' could span
+	// the origin. Without loss of generality we only discuss x - y follows
+	// accordingly.
+	// Depending on the interpretation, the area spanning the origin means:
+	// 1) either view_area.x + view_area.w < view_area.x - which would be surprising to
+	//    the rest of Widelands.
+	// 2) map_pixel.x > get_map_end_screen_x(map).
+	//
+	// We are dealing with the problem in two steps: first we figure out if
+	// 'map_pixel' is visible on screen. To do this, we calculate the shortest
+	// distance to 'view_area.center()' on a torus. If the distance is less than
+	// 'view_area.w / 2', the point is visible.
+	// If that is the case, we move the point by adding or substracting
+	// 'get_map_end_screen_x()' such that the point is contained inside of
+	// 'view_area'. If we now convert to panel pixels, we are guaranteed that
+	// the pixel we get back is inside the panel.
+
 	const Widelands::Map& map = intbase().egbase().map();
-	Point p;
-	MapviewPixelFunctions::get_save_pix(map, c, p.x, p.y);
-	p -= viewpoint_;
-
-	//  If the user has scrolled the node outside the viewable area, he most
-	//  surely doesn't want to jump there.
-	if (p.x < get_w() && p.y < get_h()) {
-		if (p.x <= 0)
-			warp_mouse_to_node(Widelands::Coords(c.x + map.get_width(), c.y));
-		else if (p.y <= 0)
-			warp_mouse_to_node(Widelands::Coords(c.x, c.y + map.get_height()));
-		else {
-			set_mouse_pos(p);
-			track_sel(p);
-		}
+	const Vector2f map_pixel = MapviewPixelFunctions::to_map_pixel_with_normalization(map, c);
+	const Rectf view_area = get_view_area();
+
+	const Vector2f view_center = view_area.center();
+	const int w = MapviewPixelFunctions::get_map_end_screen_x(map);
+	const int h = MapviewPixelFunctions::get_map_end_screen_y(map);
+	const float dist_x = shortest_distance_on_torus(view_center.x, map_pixel.x, w);
+	const float dist_y = shortest_distance_on_torus(view_center.y, map_pixel.y, h);
+
+	// Check if the point is visible on screen.
+	if (dist_x > view_area.w / 2.f || dist_y > view_area.h / 2.f) {
+		return;
 	}
+	const Vector2i in_panel = round(to_panel(move_inside(map_pixel, view_area, w, h)));
+	set_mouse_pos(in_panel);
+	track_sel(in_panel);
 }
 
-/*
-===============
-This is the guts!! this function draws the whole
-map the user can see. we spend a lot of time
-in this function
-===============
-*/
 void MapView::draw(RenderTarget& dst) {
 	Widelands::EditorGameBase& egbase = intbase().egbase();
 
@@ -82,10 +144,20 @@
 			return;
 	}
 
+	int draw_text = DrawText::kNone;
+	auto display_flags = intbase().get_display_flags();
+	if (display_flags & InteractiveBase::dfShowCensus) {
+		draw_text |= DrawText::kCensus;
+	}
+	if (display_flags & InteractiveBase::dfShowStatistics) {
+		draw_text |= DrawText::kStatistics;
+	}
+
 	if (upcast(InteractivePlayer const, interactive_player, &intbase())) {
-		renderer_->rendermap(dst, egbase, viewpoint_, interactive_player->player());
+		renderer_->rendermap(egbase, viewpoint_, zoom_, interactive_player->player(),
+		                     static_cast<DrawText>(draw_text), &dst);
 	} else {
-		renderer_->rendermap(dst, egbase, viewpoint_);
+		renderer_->rendermap(egbase, viewpoint_, zoom_, static_cast<DrawText>(draw_text), &dst);
 	}
 }
 
@@ -93,21 +165,54 @@
 	changeview_ = fn;
 }
 
+float MapView::get_zoom() const {
+	return zoom_;
+}
+
+void MapView::set_zoom(const float zoom) {
+	zoom_ = zoom;
+}
+
 /*
 ===============
 Set the viewpoint to the given pixel coordinates
 ===============
 */
-void MapView::set_viewpoint(Point vp, bool jump) {
-	if (vp == viewpoint_)
-		return;
-
-	MapviewPixelFunctions::normalize_pix(intbase().egbase().map(), vp);
-	viewpoint_ = vp;
-
-	if (changeview_)
+void MapView::set_viewpoint(Vector2i vp, bool jump) {
+	const Widelands::Map& map = intbase().egbase().map();
+	MapviewPixelFunctions::normalize_pix(map, &vp);
+
+	viewpoint_ = vp.cast<float>();
+
+	// NOCOM(#sirver): why are there 2 callback functions?
+	if (changeview_) {
 		changeview_(vp, jump);
-	changeview(viewpoint_.x, viewpoint_.y);
+	}
+	changeview(get_view_area());
+}
+
+void MapView::center_view_on_coords(const Widelands::Coords& c) {
+	const Widelands::Map& map = intbase().egbase().map();
+	assert(0 <= c.x);
+	assert(c.x < map.get_width());
+	assert(0 <= c.y);
+	assert(c.y < map.get_height());
+
+	const Vector2i in_mappixel = round(MapviewPixelFunctions::to_map_pixel(map.get_fcoords(c)));
+	center_view_on_map_pixel(in_mappixel);
+}
+
+void MapView::center_view_on_map_pixel(const Vector2i& pos) {
+	const Rectf view_area = get_view_area();
+	set_viewpoint(pos - Vector2i(view_area.w / 2.f, view_area.h / 2.f), true);
+}
+
+Rectf MapView::get_view_area() const {
+	return Rectf(viewpoint_, get_w() * zoom_, get_h() * zoom_);
+}
+
+void MapView::pan_by(Vector2i delta_pixels) {
+	set_viewpoint(get_viewpoint() + delta_pixels * zoom_, false);
 }
 
 void MapView::stop_dragging() {
@@ -125,7 +230,7 @@
 bool MapView::handle_mousepress(uint8_t const btn, int32_t const x, int32_t const y) {
 	if (btn == SDL_BUTTON_LEFT) {
 		stop_dragging();
-		track_sel(Point(x, y));
+		track_sel(Vector2i(x, y));
 
 		fieldclicked();
 	} else if (btn == SDL_BUTTON_RIGHT) {
@@ -135,28 +240,52 @@
 	}
 	return true;
 }
+
 bool MapView::handle_mouserelease(const uint8_t btn, int32_t, int32_t) {
 	if (btn == SDL_BUTTON_RIGHT && dragging_)
 		stop_dragging();
 	return true;
 }
 
-/*
-===============
-Scroll the view according to mouse movement.
-===============
-*/
 bool MapView::handle_mousemove(
    uint8_t const state, int32_t x, int32_t y, int32_t xdiff, int32_t ydiff) {
+	last_mouse_pos_.x = x;
+	last_mouse_pos_.y = y;
+
 	if (dragging_) {
-		if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
-			set_rel_viewpoint(Point(xdiff, ydiff), false);
-		else
+		if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
+			pan_by(Vector2i(xdiff, ydiff));
+		} else {
 			stop_dragging();
+		}
 	}
 
 	if (!intbase().get_sel_freeze())
-		track_sel(Point(x, y));
+		track_sel(Vector2i(x, y));
+	return true;
+}
+
+bool MapView::handle_mousewheel(uint32_t which, int32_t /* x */, int32_t y) {
+	if (which != 0) {
+		return false;
+	}
+
+	constexpr float kPercentPerMouseWheelTick = 0.02f;
+	float zoom = zoom_ * static_cast<float>(
+	                        std::pow(1.f - math::sign(y) * kPercentPerMouseWheelTick, std::abs(y)));
+
+	// Somewhat arbitrarily we limit the zoom to a reasonable value. This is for
+	// performance and to avoid numeric glitches with more extreme values.
+	constexpr float kMaxZoom = 4.f;
+	zoom = math::clamp(zoom, 1.f / kMaxZoom, kMaxZoom);
+
+	// Zoom around the current mouse position. See
+	// http://stackoverflow.com/questions/2916081/zoom-in-on-a-point-using-scale-and-translate
+	// for a good explanation of this math.
+	const Vector2f offset = -last_mouse_pos_.cast<float>() * (zoom - zoom_);
+
+	zoom_ = zoom;
+	set_viewpoint(round(viewpoint_ + offset), false);
 	return true;
 }
 
@@ -168,8 +297,8 @@
 Does not honour sel freeze.
 ===============
 */
-void MapView::track_sel(Point m) {
-	m += viewpoint_;
-	intbase_.set_sel_pos(
-	   MapviewPixelFunctions::calc_node_and_triangle(intbase().egbase().map(), m.x, m.y));
+void MapView::track_sel(Vector2i p) {
+	Vector2f p_in_map = to_map(p.cast<float>());
+	intbase_.set_sel_pos(MapviewPixelFunctions::calc_node_and_triangle(
+	   intbase().egbase().map(), p_in_map.x, p_in_map.y));
 }

=== modified file 'src/wui/mapview.h'
--- src/wui/mapview.h	2016-08-04 15:49:05 +0000
+++ src/wui/mapview.h	2016-10-22 18:17:28 +0000
@@ -25,6 +25,7 @@
 #include <boost/function.hpp>
 #include <boost/signals2.hpp>
 
+#include "base/rect.h"
 #include "logic/widelands_geometry.h"
 #include "ui_basic/panel.h"
 
@@ -41,7 +42,7 @@
 	 * Parameters are x/y screen coordinates and whether the change should
 	 * be considered a "jump" or a smooth scrolling event.
 	 */
-	using ChangeViewFn = boost::function<void(Point, bool)>;
+	using ChangeViewFn = boost::function<void(Vector2i, bool)>;
 
 	MapView(UI::Panel* const parent,
 	        const int32_t x,
@@ -53,25 +54,24 @@
 
 	void set_changeview(const ChangeViewFn& fn);
 
-	/**
-	 * Called whenever the view position changes, for whatever reason.
-	 *
-	 * Parameters are x/y position in screen coordinates.
-	 */
-	boost::signals2::signal<void(int32_t, int32_t)> changeview;
+	boost::signals2::signal<void(const Rectf&)> changeview;
 
 	boost::signals2::signal<void()> fieldclicked;
 
 	void warp_mouse_to_node(Widelands::Coords);
 
-	void set_viewpoint(Point vp, bool jump);
-	void set_rel_viewpoint(Point r, bool jump) {
-		set_viewpoint(viewpoint_ + r, jump);
-	}
-
-	Point get_viewpoint() const {
-		return viewpoint_;
-	}
+	void set_viewpoint(Vector2i vp, bool jump);
+	void center_view_on_coords(const Widelands::Coords& coords);
+	void center_view_on_map_pixel(const Vector2i& pos);
+
+	Vector2i get_viewpoint() const;
+	Rectf get_view_area() const;
+	float get_zoom() const;
+
+	// Set the zoom to the new value without changing view_point. For the user
+	// the view will perceivably jump.
+	void set_zoom(float zoom);
+
 	bool is_dragging() const {
 		return dragging_;
 	}
@@ -84,21 +84,31 @@
 	bool handle_mouserelease(uint8_t btn, int32_t x, int32_t y) override;
 	bool
 	handle_mousemove(uint8_t state, int32_t x, int32_t y, int32_t xdiff, int32_t ydiff) override;
+	bool
+	handle_mousewheel(uint32_t which, int32_t x, int32_t y) override;
 
-	void track_sel(Point m);
+	void track_sel(Vector2i m);
 
 protected:
 	InteractiveBase& intbase() const {
 		return intbase_;
 	}
 
+	// Move the view by 'delta_pixels'.
+	void pan_by(Vector2i delta_pixels);
+
 private:
 	void stop_dragging();
 
+	Vector2f to_panel(const Vector2f& map_pixel) const;
+	Vector2f to_map(const Vector2f& panel_pixel) const;
+
 	std::unique_ptr<GameRenderer> renderer_;
 	InteractiveBase& intbase_;
 	ChangeViewFn changeview_;
-	Point viewpoint_;
+	Vector2f viewpoint_;
+	float zoom_;
+	Vector2i last_mouse_pos_;
 	bool dragging_;
 };
 

=== modified file 'src/wui/mapviewpixelconstants.h'
--- src/wui/mapviewpixelconstants.h	2016-08-04 15:49:05 +0000
+++ src/wui/mapviewpixelconstants.h	2016-10-22 18:17:28 +0000
@@ -20,7 +20,11 @@
 #ifndef WL_WUI_MAPVIEWPIXELCONSTANTS_H
 #define WL_WUI_MAPVIEWPIXELCONSTANTS_H
 
-//  These are constants with the unit pixel.
+// These are constants with the unit map pixel, i.e. at zoom = 1 a triangle on
+// screen is kTriangleWidth pixels wide. Map pixelspace is used in many places
+// when the hexagonal fields coordinate space is insufficient. For example draw
+// calculations first figure out where something needs to be drawn in map pixel
+// space, then this is converted into screen space taking zoom into account.
 constexpr int kTriangleWidth = 64;
 constexpr int kTriangleHeight = 32;
 constexpr int kHeightFactor = 5;

=== modified file 'src/wui/mapviewpixelfunctions.cc'
--- src/wui/mapviewpixelfunctions.cc	2016-08-04 15:49:05 +0000
+++ src/wui/mapviewpixelfunctions.cc	2016-10-22 18:17:28 +0000
@@ -21,7 +21,7 @@
 
 #include <cstdlib>
 
-#include "wui/vector.h"
+#include "base/vector.h"
 
 using namespace Widelands;
 
@@ -39,16 +39,14 @@
 	constexpr float kSin60 = 0.86603f;
 	constexpr float kLightFactor = -75.0f;
 
-	static Vector sun_vect = Vector(kVectorThird, -kVectorThird, -kVectorThird);  //  |sun_vect| = 1
-
-	Vector normal;
+	static Vector3f sun_vect = Vector3f(kVectorThird, -kVectorThird, -kVectorThird);  //  |sun_vect| = 1
 
 	// find normal
 	// more guessed than thought about
 	// but hey, results say I am good at guessing :)
 	// perhaps I will paint an explanation for this someday
 	// florian
-	normal = Vector(0, 0, kTriangleWidth);
+	Vector3f normal(0, 0, kTriangleWidth);
 	normal.x -= l * kHeightFactor;
 	normal.x += r * kHeightFactor;
 	normal.x -= tl * kHeightFactorFloat * kCos60;
@@ -61,17 +59,17 @@
 	normal.y += br * kHeightFactorFloat * kSin60;
 	normal.normalize();
 
-	return normal * sun_vect * kLightFactor;
+	return normal.dot(sun_vect) * kLightFactor;
 }
 
 /**
  * Compute a - b, taking care to handle wrap-around effects properly.
  */
-Point MapviewPixelFunctions::calc_pix_difference(const Map& map, Point a, Point b) {
-	normalize_pix(map, a);
-	normalize_pix(map, b);
+Vector2i MapviewPixelFunctions::calc_pix_difference(const Map& map, Vector2i a, Vector2i b) {
+	normalize_pix(map, &a);
+	normalize_pix(map, &b);
 
-	Point diff = a - b;
+	Vector2i diff = a - b;
 
 	int32_t map_end_screen_x = get_map_end_screen_x(map);
 	if (diff.x > map_end_screen_x / 2)
@@ -92,9 +90,9 @@
  * Calculate the pixel (currently Manhattan) distance between the two points,
  * taking wrap-arounds into account.
 */
-uint32_t MapviewPixelFunctions::calc_pix_distance(const Map& map, Point a, Point b) {
-	normalize_pix(map, a);
-	normalize_pix(map, b);
+uint32_t MapviewPixelFunctions::calc_pix_distance(const Map& map, Vector2i a, Vector2i b) {
+	normalize_pix(map, &a);
+	normalize_pix(map, &b);
 	uint32_t dx = abs(a.x - b.x), dy = abs(a.y - b.y);
 	{
 		const uint32_t map_end_screen_x = get_map_end_screen_x(map);
@@ -262,19 +260,27 @@
 /**
  * Normalize pixel points of the map.
 */
-void MapviewPixelFunctions::normalize_pix(const Map& map, Point& p) {
-	{
-		const int32_t map_end_screen_x = get_map_end_screen_x(map);
-		while (p.x >= map_end_screen_x)
-			p.x -= map_end_screen_x;
-		while (p.x < 0)
-			p.x += map_end_screen_x;
-	}
-	{
-		const int32_t map_end_screen_y = get_map_end_screen_y(map);
-		while (p.y >= map_end_screen_y)
-			p.y -= map_end_screen_y;
-		while (p.y < 0)
-			p.y += map_end_screen_y;
-	}
+void MapviewPixelFunctions::normalize_pix(const Map& map, Vector2i* p) {
+	float x = p->x;
+	float y = p->y;
+	{
+		const float map_end_screen_x = get_map_end_screen_x(map);
+		while (x >= map_end_screen_x) {
+			x -= map_end_screen_x;
+		}
+		while (x < 0) {
+			x += map_end_screen_x;
+		}
+	}
+	{
+		const float map_end_screen_y = get_map_end_screen_y(map);
+		while (y >= map_end_screen_y) {
+			y -= map_end_screen_y;
+		}
+		while (y < 0) {
+			y += map_end_screen_y;
+		}
+	}
+	p->x = std::lround(x);
+	p->y = std::lround(y);
 }

=== modified file 'src/wui/mapviewpixelfunctions.h'
--- src/wui/mapviewpixelfunctions.h	2016-08-04 15:49:05 +0000
+++ src/wui/mapviewpixelfunctions.h	2016-10-22 18:17:28 +0000
@@ -20,7 +20,8 @@
 #ifndef WL_WUI_MAPVIEWPIXELFUNCTIONS_H
 #define WL_WUI_MAPVIEWPIXELFUNCTIONS_H
 
-#include "base/point.h"
+#include "base/vector.h"
+#include "base/vector.h"
 #include "logic/field.h"
 #include "logic/map.h"
 #include "logic/widelands_geometry.h"
@@ -34,8 +35,8 @@
 
 float calc_brightness(int32_t l, int32_t r, int32_t tl, int32_t tr, int32_t bl, int32_t br);
 
-Point calc_pix_difference(const Widelands::Map&, Point, Point);
-uint32_t calc_pix_distance(const Widelands::Map&, Point, Point);
+Vector2i calc_pix_difference(const Widelands::Map&, Vector2i, Vector2i);
+uint32_t calc_pix_distance(const Widelands::Map&, Vector2i, Vector2i);
 
 inline uint32_t get_map_end_screen_x(const Widelands::Map& map) {
 	return map.get_width() * kTriangleWidth;
@@ -45,6 +46,16 @@
 	return map.get_height() * kTriangleHeight;
 }
 
+inline Vector2f
+map_to_panel(const Vector2f& viewpoint, const float zoom, const Vector2f& map_pixel) {
+	return map_pixel / zoom - viewpoint / zoom;
+}
+
+inline Vector2f
+panel_to_map(const Vector2f& viewpoint, const float zoom, const Vector2f& panel_pixel) {
+	return panel_pixel * zoom + viewpoint;
+}
+
 /**
  * Calculate the coordinates of the triangle the given point in pixels is in.
  *
@@ -56,39 +67,39 @@
  */
 Widelands::NodeAndTriangle<> calc_node_and_triangle(const Widelands::Map&, uint32_t x, uint32_t y);
 
-void normalize_pix(const Widelands::Map&, Point& p);
+void normalize_pix(const Widelands::Map& map, Vector2i* p);
 
 // Calculate the on-screen position of the node without taking height into
 // account.
-inline void get_basepix(const Widelands::Coords& c, int32_t& px, int32_t& py) {
-	py = c.y * kTriangleHeight;
-	px = c.x * kTriangleWidth + (c.y & 1) * (kTriangleWidth / 2);
+inline Vector2f to_map_pixel_ignoring_height(const Widelands::Coords& c) {
+	return Vector2f(
+	   c.x * kTriangleWidth + (c.y & 1) * (kTriangleWidth / 2.f), c.y * kTriangleHeight);
 }
 
 /**
  * Calculate the on-screen position of the node.
  */
-inline void get_pix(const Widelands::FCoords& fc, int32_t& px, int32_t& py) {
-	get_basepix(fc, px, py);
-	py -= fc.field->get_height() * kHeightFactor;
+inline Vector2f to_map_pixel(const Widelands::FCoords& fc) {
+	Vector2f p = to_map_pixel_ignoring_height(fc);
+	p.y -= fc.field->get_height() * kHeightFactor;
+	return p;
 }
 
-inline void
-get_pix(const Widelands::Map& map, const Widelands::Coords& c, int32_t& px, int32_t& py) {
-	get_pix(map.get_fcoords(c), px, py);
+inline Vector2f to_map_pixel(const Widelands::Map& map, const Widelands::Coords& c) {
+	return to_map_pixel(map.get_fcoords(c));
 }
 
 // fx and fy might be out of range, must be normalized for the field
 // theres no need for such a function for FCoords, since x, y out of range
 // but field valid doesn't make sense
-inline void
-get_save_pix(const Widelands::Map& map, const Widelands::Coords& c, int32_t& px, int32_t& py) {
+inline Vector2f to_map_pixel_with_normalization(const Widelands::Map& map,
+                                                  const Widelands::Coords& c) {
 	Widelands::Coords c1 = c;
 	map.normalize_coords(c1);
 	Widelands::FCoords fc = map.get_fcoords(c1);
 	fc.x = c.x;
 	fc.y = c.y;
-	get_pix(fc, px, py);
+	return to_map_pixel(fc);
 }
 
 }  // namespace MapviewPixelFunctions

=== modified file 'src/wui/minimap.cc'
--- src/wui/minimap.cc	2016-08-04 15:49:05 +0000
+++ src/wui/minimap.cc	2016-10-22 18:17:28 +0000
@@ -32,6 +32,7 @@
 
 MiniMap::View::View(UI::Panel& parent,
                     MiniMapLayer* flags,
+                    MiniMapType* type,
                     int32_t const x,
                     int32_t const y,
                     uint32_t const,
@@ -39,30 +40,20 @@
                     InteractiveBase& ibase)
    : UI::Panel(&parent, x, y, 10, 10),
      ibase_(ibase),
-     viewx_(0),
-     viewy_(0),
      pic_map_spot_(g_gr->images().get("images/wui/overlays/map_spot.png")),
-     flags_(flags) {
+     minimap_layers_(flags),
+     minimap_type_(type) {
 }
 
-/** MiniMap::View::set_view_pos(int32_t x, int32_t y)
- *
- * Set the view point marker to a new position.
- *
- * Args: x, y  new view point coordinates, in screen coordinates
- */
-void MiniMap::View::set_view_pos(const int32_t x, const int32_t y) {
-	viewx_ = x / kTriangleWidth;
-	viewy_ = y / kTriangleHeight;
+void MiniMap::View::set_view(const Rectf& view_area) {
+	view_area_ = view_area;
 }
 
 void MiniMap::View::draw(RenderTarget& dst) {
-	minimap_image_ = draw_minimap(ibase_.egbase(), ibase_.get_player(),
-	                              (*flags_) & (MiniMapLayer::Zoom2) ?
-	                                 Point((viewx_ - get_w() / 4), (viewy_ - get_h() / 4)) :
-	                                 Point((viewx_ - get_w() / 2), (viewy_ - get_h() / 2)),
-	                              *flags_ | MiniMapLayer::ViewWindow);
-	dst.blit(Point(), minimap_image_.get());
+	minimap_image_ =
+	   draw_minimap(ibase_.egbase(), ibase_.get_player(), view_area_, *minimap_type_,
+	                *minimap_layers_ | MiniMapLayer::ViewWindow);
+	dst.blit(Vector2f(), minimap_image_.get());
 }
 
 /*
@@ -74,19 +65,12 @@
 	if (btn != SDL_BUTTON_LEFT)
 		return false;
 
-	//  calculates the coordinates corresponding to the mouse position
-	Widelands::Coords c;
-	if (*flags_ & MiniMapLayer::Zoom2)
-		c = Widelands::Coords(viewx_ + 1 - (get_w() / 2 - x) / 2, viewy_ + 1 - (get_h() / 2 - y) / 2);
-	else
-		c = Widelands::Coords(viewx_ + 1 - get_w() / 2 + x, viewy_ + 1 - get_h() / 2 + y);
-
-	ibase_.egbase().map().normalize_coords(c);
-
-	dynamic_cast<MiniMap&>(*get_parent()).warpview(c.x * kTriangleWidth, c.y * kTriangleHeight);
-
+	dynamic_cast<MiniMap&>(*get_parent())
+	   .warpview(minimap_pixel_to_mappixel(ibase_.egbase().map(), Vector2i(x, y), view_area_,
+	                                       *minimap_type_, *minimap_layers_ & MiniMapLayer::Zoom2));
 	return true;
 }
+
 bool MiniMap::View::handle_mouserelease(uint8_t const btn, int32_t, int32_t) {
 	return btn == SDL_BUTTON_LEFT;
 }
@@ -129,7 +113,7 @@
 }
 MiniMap::MiniMap(InteractiveBase& ibase, Registry* const registry)
    : UI::UniqueWindow(&ibase, "minimap", registry, 0, 0, _("Map")),
-     view_(*this, &registry->flags, 0, 0, 0, 0, ibase),
+     view_(*this, &registry->minimap_layers, &registry->minimap_type, 0, 0, 0, 0, ibase),
 
      button_terrn(this,
                   "terrain",
@@ -225,36 +209,35 @@
 }
 
 void MiniMap::toggle(MiniMapLayer const button) {
-	*view_.flags_ = MiniMapLayer(*view_.flags_ ^ button);
+	*view_.minimap_layers_ = MiniMapLayer(*view_.minimap_layers_ ^ button);
 	if (button == MiniMapLayer::Zoom2)
 		resize();
 	update_button_permpressed();
 }
 
 void MiniMap::resize() {
-	view_.set_zoom(*view_.flags_ & MiniMapLayer::Zoom2 ? 2 : 1);
+	view_.set_zoom(*view_.minimap_layers_ & MiniMapLayer::Zoom2 ? 2 : 1);
 	set_inner_size(view_.get_w(), view_.get_h() + number_of_button_rows() * but_h());
-	button_terrn.set_pos(Point(but_w() * 0, view_.get_h() + but_h() * 0));
+	button_terrn.set_pos(Vector2i(but_w() * 0, view_.get_h() + but_h() * 0));
 	button_terrn.set_size(but_w(), but_h());
-	button_owner.set_pos(Point(but_w() * 1, view_.get_h() + but_h() * 0));
+	button_owner.set_pos(Vector2i(but_w() * 1, view_.get_h() + but_h() * 0));
 	button_owner.set_size(but_w(), but_h());
-	button_flags.set_pos(Point(but_w() * 2, view_.get_h() + but_h() * 0));
+	button_flags.set_pos(Vector2i(but_w() * 2, view_.get_h() + but_h() * 0));
 	button_flags.set_size(but_w(), but_h());
-	button_roads.set_pos(Point(but_w() * 0, view_.get_h() + but_h() * 1));
+	button_roads.set_pos(Vector2i(but_w() * 0, view_.get_h() + but_h() * 1));
 	button_roads.set_size(but_w(), but_h());
-	button_bldns.set_pos(Point(but_w() * 1, view_.get_h() + but_h() * 1));
+	button_bldns.set_pos(Vector2i(but_w() * 1, view_.get_h() + but_h() * 1));
 	button_bldns.set_size(but_w(), but_h());
-	button_zoom.set_pos(Point(but_w() * 2, view_.get_h() + but_h() * 1));
+	button_zoom.set_pos(Vector2i(but_w() * 2, view_.get_h() + but_h() * 1));
 	button_zoom.set_size(but_w(), but_h());
 	move_inside_parent();
 }
 
-// Makes the buttons reflect the selected layers
 void MiniMap::update_button_permpressed() {
-	button_terrn.set_perm_pressed(*view_.flags_ & MiniMapLayer::Terrain);
-	button_owner.set_perm_pressed(*view_.flags_ & MiniMapLayer::Owner);
-	button_flags.set_perm_pressed(*view_.flags_ & MiniMapLayer::Flag);
-	button_roads.set_perm_pressed(*view_.flags_ & MiniMapLayer::Road);
-	button_bldns.set_perm_pressed(*view_.flags_ & MiniMapLayer::Building);
-	button_zoom.set_perm_pressed(*view_.flags_ & MiniMapLayer::Zoom2);
+	button_terrn.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Terrain);
+	button_owner.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Owner);
+	button_flags.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Flag);
+	button_roads.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Road);
+	button_bldns.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Building);
+	button_zoom.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Zoom2);
 }

=== modified file 'src/wui/minimap.h'
--- src/wui/minimap.h	2016-08-04 15:49:05 +0000
+++ src/wui/minimap.h	2016-10-22 18:17:28 +0000
@@ -30,22 +30,25 @@
 
 class InteractiveBase;
 
-struct MiniMap : public UI::UniqueWindow {
+class MiniMap : public UI::UniqueWindow {
+public:
 	struct Registry : public UI::UniqueWindow::Registry {
-		MiniMapLayer flags; /**< Combination of \ref MiniMapLayer flags */
+		MiniMapLayer minimap_layers;
+		MiniMapType minimap_type;
 
 		Registry()
-		   : flags(MiniMapLayer::Terrain | MiniMapLayer::Owner | MiniMapLayer::Flag |
-		           MiniMapLayer::Road | MiniMapLayer::Building) {
+		   : minimap_layers(MiniMapLayer::Terrain | MiniMapLayer::Owner | MiniMapLayer::Flag |
+		                    MiniMapLayer::Road | MiniMapLayer::Building),
+		     minimap_type(MiniMapType::kStaticViewWindow) {
 		}
 	};
 
 	MiniMap(InteractiveBase& parent, Registry*);
 
-	boost::signals2::signal<void(int32_t, int32_t)> warpview;
+	boost::signals2::signal<void(const Vector2i&)> warpview;
 
-	void set_view_pos(int32_t const x, int32_t const y) {
-		view_.set_view_pos(x, y);
+	void set_view(const Rectf& rect) {
+		view_.set_view(rect);
 	}
 
 private:
@@ -56,22 +59,19 @@
 	/**
 	 * MiniMap::View is the panel that represents the pure representation of the
 	 * map, without any borders or gadgets.
-	 *
-	 * If the size of MiniMapView is not the same as the size of the map itself,
-	 * it will either show a subset of the map, or it will show the map more than
-	 * once.
-	 * The minimap always centers around the current viewpoint.
 	 */
 	struct View : public UI::Panel {
 		View(UI::Panel& parent,
-		     MiniMapLayer* flags,
+		     MiniMapLayer* minimap_layers,
+			  MiniMapType* minimap_type,
 		     int32_t x,
 		     int32_t y,
 		     uint32_t w,
 		     uint32_t h,
 		     InteractiveBase&);
 
-		void set_view_pos(int32_t x, int32_t y);
+		// Set the currently viewed area in map pixel space.
+		void set_view(const Rectf&);
 
 		void draw(RenderTarget&) override;
 
@@ -82,7 +82,7 @@
 
 	private:
 		InteractiveBase& ibase_;
-		int32_t viewx_, viewy_;
+		Rectf view_area_;
 		const Image* pic_map_spot_;
 
 		// This needs to be owned since it will be rendered by the RenderQueue
@@ -90,7 +90,8 @@
 		std::unique_ptr<Texture> minimap_image_;
 
 	public:
-		MiniMapLayer* flags_;
+		MiniMapLayer* minimap_layers_;
+		MiniMapType* minimap_type_;
 	};
 
 	uint32_t number_of_buttons_per_row() const;

=== modified file 'src/wui/playerdescrgroup.cc'
--- src/wui/playerdescrgroup.cc	2016-08-04 15:49:05 +0000
+++ src/wui/playerdescrgroup.cc	2016-10-22 18:17:28 +0000
@@ -64,7 +64,7 @@
 	int32_t xplayertribe = w * 80 / 125;
 	int32_t xplayerinit = w * 55 / 125;
 	d->plr_name = new UI::Textarea(this, xplrname, 0, xplayertype - xplrname, h);
-	d->btnEnablePlayer = new UI::Checkbox(this, Point(xplayertype - 23, 0), "");
+	d->btnEnablePlayer = new UI::Checkbox(this, Vector2i(xplayertype - 23, 0), "");
 	d->btnEnablePlayer->changedto.connect(
 	   boost::bind(&PlayerDescriptionGroup::enable_player, this, _1));
 	d->btnPlayerType = new UI::Button(

=== modified file 'src/wui/plot_area.cc'
--- src/wui/plot_area.cc	2016-08-04 15:49:05 +0000
+++ src/wui/plot_area.cc	2016-10-22 18:17:28 +0000
@@ -168,7 +168,7 @@
 /**
  * print the string into the RenderTarget.
  */
-void draw_value(const string& value, const RGBColor& color, const Point& pos, RenderTarget& dst) {
+void draw_value(const string& value, const RGBColor& color, const Vector2f& pos, RenderTarget& dst) {
 	const Image* pic = UI::g_fh1->render(ytick_text_style(value, color));
 	dst.blit(pos, pic, BlendMode::UseAlpha, UI::Align::kCenterRight);
 }
@@ -209,25 +209,25 @@
 	how_many_ticks = std::max(how_many_ticks, 1u);
 
 	// first, tile the background
-	dst.tile(Rect(Point(0, 0), inner_w, inner_h), g_gr->images().get(BG_PIC), Point(0, 0));
+	dst.tile(Recti(Vector2i(0, 0), inner_w, inner_h), g_gr->images().get(BG_PIC), Vector2i(0, 0));
 
 	// Draw coordinate system
 	// X Axis
-	dst.draw_line_strip({FloatPoint(kSpacing, inner_h - kSpaceBottom),
-	                     FloatPoint(inner_w - kSpaceRight, inner_h - kSpaceBottom)},
+	dst.draw_line_strip({Vector2f(kSpacing, inner_h - kSpaceBottom),
+	                     Vector2f(inner_w - kSpaceRight, inner_h - kSpaceBottom)},
 	                    kAxisLineColor, kAxisLinesWidth);
 	// Arrow
 	dst.draw_line_strip(
 	   {
-	      FloatPoint(kSpacing + 5, inner_h - kSpaceBottom - 3),
-	      FloatPoint(kSpacing, inner_h - kSpaceBottom),
-	      FloatPoint(kSpacing + 5, inner_h - kSpaceBottom + 3),
+	      Vector2f(kSpacing + 5, inner_h - kSpaceBottom - 3),
+	      Vector2f(kSpacing, inner_h - kSpaceBottom),
+	      Vector2f(kSpacing + 5, inner_h - kSpaceBottom + 3),
 	   },
 	   kAxisLineColor, kAxisLinesWidth);
 
 	//  Y Axis
-	dst.draw_line_strip({FloatPoint(inner_w - kSpaceRight, kSpacing),
-	                     FloatPoint(inner_w - kSpaceRight, inner_h - kSpaceBottom)},
+	dst.draw_line_strip({Vector2f(inner_w - kSpaceRight, kSpacing),
+	                     Vector2f(inner_w - kSpaceRight, inner_h - kSpaceBottom)},
 	                    kAxisLineColor, kAxisLinesWidth);
 	//  No Arrow here, since this doesn't continue.
 
@@ -235,32 +235,32 @@
 	float posx = inner_w - kSpaceRight;
 
 	for (uint32_t i = 0; i <= how_many_ticks; ++i) {
-		dst.draw_line_strip({FloatPoint(static_cast<int32_t>(posx), inner_h - kSpaceBottom),
-		                     FloatPoint(static_cast<int32_t>(posx), inner_h - kSpaceBottom + 3)},
+		dst.draw_line_strip({Vector2f(static_cast<int32_t>(posx), inner_h - kSpaceBottom),
+		                     Vector2f(static_cast<int32_t>(posx), inner_h - kSpaceBottom + 3)},
 		                    kAxisLineColor, kAxisLinesWidth);
 
 		// The space at the end is intentional to have the tick centered
 		// over the number, not to the left
 		const Image* xtick = UI::g_fh1->render(
 		   xtick_text_style((boost::format("-%u ") % (max_x / how_many_ticks * i)).str()));
-		dst.blit(Point(static_cast<int32_t>(posx), inner_h - kSpaceBottom + 10), xtick,
-		         BlendMode::UseAlpha, UI::Align::kCenter);
+		dst.blit(Vector2f(posx, inner_h - kSpaceBottom + 10), xtick, BlendMode::UseAlpha,
+		         UI::Align::kCenter);
 
 		posx -= sub;
 	}
 
 	//  draw yticks, one at full, one at half
-	dst.draw_line_strip({FloatPoint(inner_w - kSpaceRight, kSpacing),
-	                     FloatPoint(inner_w - kSpaceRight - 3, kSpacing)},
+	dst.draw_line_strip({Vector2f(inner_w - kSpaceRight, kSpacing),
+	                     Vector2f(inner_w - kSpaceRight - 3, kSpacing)},
 	                    kAxisLineColor, kAxisLinesWidth);
 	dst.draw_line_strip(
-	   {FloatPoint(inner_w - kSpaceRight, kSpacing + ((inner_h - kSpaceBottom) - kSpacing) / 2),
-	    FloatPoint(inner_w - kSpaceRight - 3, kSpacing + ((inner_h - kSpaceBottom) - kSpacing) / 2)},
+	   {Vector2f(inner_w - kSpaceRight, kSpacing + ((inner_h - kSpaceBottom) - kSpacing) / 2),
+	    Vector2f(inner_w - kSpaceRight - 3, kSpacing + ((inner_h - kSpaceBottom) - kSpacing) / 2)},
 	   kAxisLineColor, kAxisLinesWidth);
 
 	//  print the used unit
 	const Image* xtick = UI::g_fh1->render(xtick_text_style(get_generic_unit_name(unit)));
-	dst.blit(Point(2, kSpacing + 2), xtick, BlendMode::UseAlpha, UI::Align::kCenterLeft);
+	dst.blit(Vector2f(2.f, kSpacing + 2), xtick, BlendMode::UseAlpha, UI::Align::kCenterLeft);
 }
 
 }  // namespace
@@ -446,7 +446,7 @@
 
 	//  print the maximal value into the top right corner
 	draw_value(yscale_label, RGBColor(60, 125, 0),
-	           Point(get_inner_w() - kSpaceRight - 2, kSpacing + 2), dst);
+	           Vector2f(get_inner_w() - kSpaceRight - 2, kSpacing + 2), dst);
 
 	//  plot the pixels
 	for (uint32_t plot = 0; plot < plotdata_.size(); ++plot) {
@@ -480,7 +480,7 @@
 			ly -= static_cast<int32_t>(scale_value(yline_length_, highest_scale, value));
 		}
 
-		std::vector<FloatPoint> points;
+		std::vector<Vector2f> points;
 		points.emplace_back(lx, ly);
 
 		for (int32_t i = dataset->size() - 1; i > 0 && posx > kSpacing; --i) {
@@ -632,11 +632,11 @@
 
 	// Print the min value
 	draw_value((boost::format("-%u") % (highest_scale_)).str(), RGBColor(125, 0, 0),
-	           Point(get_inner_w() - kSpaceRight - 2, get_inner_h() - kSpacing - 15), dst);
+	           Vector2f(get_inner_w() - kSpaceRight - 2, get_inner_h() - kSpacing - 15), dst);
 
 	// draw zero line
-	dst.draw_line_strip({FloatPoint(get_inner_w() - kSpaceRight, yoffset),
-	                     FloatPoint(get_inner_w() - kSpaceRight - xline_length_, yoffset)},
+	dst.draw_line_strip({Vector2f(get_inner_w() - kSpaceRight, yoffset),
+	                     Vector2f(get_inner_w() - kSpaceRight - xline_length_, yoffset)},
 	                    kZeroLineColor, kPlotLinesWidth);
 }
 

=== modified file 'src/wui/quicknavigation.cc'
--- src/wui/quicknavigation.cc	2016-08-04 15:49:05 +0000
+++ src/wui/quicknavigation.cc	2016-10-22 18:17:28 +0000
@@ -41,16 +41,16 @@
 	setview_ = fn;
 }
 
-void QuickNavigation::setview(Point where) {
+void QuickNavigation::setview(Vector2i where) {
 	update_ = false;
 	setview_(where);
 	update_ = true;
 }
 
-void QuickNavigation::view_changed(Point newpos, bool jump) {
+void QuickNavigation::view_changed(Vector2i newpos, bool jump) {
 	if (havefirst_ && update_) {
 		if (!jump) {
-			Point delta = MapviewPixelFunctions::calc_pix_difference(egbase_.map(), newpos, anchor_);
+			Vector2i delta = MapviewPixelFunctions::calc_pix_difference(egbase_.map(), newpos, anchor_);
 
 			if (static_cast<uint32_t>(abs(delta.x)) > screenwidth_ ||
 			    static_cast<uint32_t>(abs(delta.y)) > screenheight_)
@@ -75,7 +75,7 @@
 	havefirst_ = true;
 }
 
-void QuickNavigation::set_landmark(size_t index, const Point& point) {
+void QuickNavigation::set_landmark(size_t index, const Vector2i& point) {
 	assert(index < landmarks_.size());
 	landmarks_[index].point = point;
 	landmarks_[index].set = true;

=== modified file 'src/wui/quicknavigation.h'
--- src/wui/quicknavigation.h	2016-08-04 15:49:05 +0000
+++ src/wui/quicknavigation.h	2016-10-22 18:17:28 +0000
@@ -26,7 +26,7 @@
 #include <boost/function.hpp>
 #include <stdint.h>
 
-#include "base/point.h"
+#include "base/vector.h"
 
 namespace Widelands {
 class EditorGameBase;
@@ -40,14 +40,14 @@
  */
 struct QuickNavigation {
 	struct Landmark {
-		Point point;
+		Vector2i point;
 		bool set;
 
 		Landmark() : set(false) {
 		}
 	};
 
-	using SetViewFn = boost::function<void(Point)>;
+	using SetViewFn = boost::function<void(Vector2i)>;
 
 	QuickNavigation(const Widelands::EditorGameBase& egbase,
 	                uint32_t screenwidth,
@@ -55,10 +55,10 @@
 
 	void set_setview(const SetViewFn& fn);
 
-	void view_changed(Point point, bool jump);
+	void view_changed(Vector2i point, bool jump);
 
 	// Set the landmark for 'index' to 'point'. 'index' must be < 10.
-	void set_landmark(size_t index, const Point& point);
+	void set_landmark(size_t index, const Vector2i& point);
 
 	// Returns a pointer to the first element in the landmarks array
 	const std::vector<Landmark>& landmarks() const {
@@ -68,7 +68,7 @@
 	bool handle_key(bool down, SDL_Keysym key);
 
 private:
-	void setview(Point where);
+	void setview(Vector2i where);
 
 	const Widelands::EditorGameBase& egbase_;
 	uint32_t screenwidth_;
@@ -81,16 +81,16 @@
 
 	bool havefirst_;
 	bool update_;
-	Point anchor_;
-	Point current_;
+	Vector2i anchor_;
+	Vector2i current_;
 
 	/**
 	 * Keeps track of what the player has looked at to allow jumping back and forth
 	 * in the history.
 	 */
 	/*@{*/
-	std::vector<Point> history_;
-	std::vector<Point>::size_type history_index_;
+	std::vector<Vector2i> history_;
+	std::vector<Vector2i>::size_type history_index_;
 	/*@}*/
 
 	/**

=== modified file 'src/wui/shipwindow.cc'
--- src/wui/shipwindow.cc	2016-09-07 09:30:49 +0000
+++ src/wui/shipwindow.cc	2016-10-22 18:17:28 +0000
@@ -273,13 +273,13 @@
 
 /// Move the main view towards the current ship location
 void ShipWindow::act_goto() {
-	igbase_.move_view_to(ship_.get_position());
+	igbase_.center_view_on_coords(ship_.get_position());
 }
 
 /// Move the main view towards the current destination of the ship
 void ShipWindow::act_destination() {
 	if (PortDock* destination = ship_.get_destination(igbase_.egbase())) {
-		igbase_.move_view_to(destination->get_warehouse()->get_position());
+		igbase_.center_view_on_coords(destination->get_warehouse()->get_position());
 	}
 }
 
@@ -373,7 +373,7 @@
 void Ship::refresh_window(InteractiveGameBase& igb) {
 	// Only do something if there is actually a window
 	if (window_) {
-		Point window_position = window_->get_pos();
+		Vector2i window_position = window_->get_pos();
 		close_window();
 		show_window(igb, true);
 		// show window could theoretically fail if refresh_window was called at the very same moment

=== modified file 'src/wui/soldierlist.cc'
--- src/wui/soldierlist.cc	2016-08-04 15:49:05 +0000
+++ src/wui/soldierlist.cc	2016-10-22 18:17:28 +0000
@@ -75,14 +75,14 @@
 	bool handle_mousepress(uint8_t btn, int32_t x, int32_t y) override;
 
 private:
-	Point calc_pos(uint32_t row, uint32_t col) const;
+	Vector2i calc_pos(uint32_t row, uint32_t col) const;
 	const Soldier* find_soldier(int32_t x, int32_t y) const;
 
 	struct Icon {
 		Widelands::OPtr<Soldier> soldier;
 		uint32_t row;
 		uint32_t col;
-		Point pos;
+		Vector2i pos;
 
 		/**
 		 * Keep track of how we last rendered this soldier,
@@ -242,8 +242,8 @@
 	last_animate_time_ = curtime;
 
 	for (Icon& icon : icons_) {
-		Point goal = calc_pos(icon.row, icon.col);
-		Point dp = goal - icon.pos;
+		Vector2i goal = calc_pos(icon.row, icon.col);
+		Vector2i dp = goal - icon.pos;
 
 		dp.x = std::min(std::max(dp.x, -maxdist), maxdist);
 		dp.y = std::min(std::max(dp.y, -maxdist), maxdist);
@@ -270,7 +270,7 @@
 	}
 
 	if (changes) {
-		Point mousepos = get_mouse_position();
+		Vector2i mousepos = get_mouse_position();
 		mouseover_fn_(find_soldier(mousepos.x, mousepos.y));
 	}
 }
@@ -280,12 +280,14 @@
 	uint32_t capacity = soldiers_.soldier_capacity();
 	uint32_t fullrows = capacity / kMaxColumns;
 
-	if (fullrows)
-		dst.fill_rect(Rect(Point(0, 0), get_w(), icon_height_ * fullrows), RGBAColor(0, 0, 0, 0));
-	if (capacity % kMaxColumns)
-		dst.fill_rect(Rect(Point(0, icon_height_ * fullrows), icon_width_ * (capacity % kMaxColumns),
-		                   icon_height_),
-		              RGBAColor(0, 0, 0, 0));
+	if (fullrows) {
+		dst.fill_rect(Rectf(0.f, 0.f, get_w(), icon_height_ * fullrows), RGBAColor(0, 0, 0, 0));
+	}
+	if (capacity % kMaxColumns) {
+		dst.fill_rect(
+		   Rectf(0.f, icon_height_ * fullrows, icon_width_ * (capacity % kMaxColumns), icon_height_),
+		   RGBAColor(0, 0, 0, 0));
+	}
 
 	// Draw icons
 	for (const Icon& icon : icons_) {
@@ -293,12 +295,14 @@
 		if (!soldier)
 			continue;
 
-		soldier->draw_info_icon(dst, icon.pos + Point(kIconBorder, kIconBorder), false);
+		constexpr float kNoZoom = 1.f;
+		soldier->draw_info_icon(
+		   icon.pos.cast<float>() + Vector2f(kIconBorder, kIconBorder), kNoZoom, false, &dst);
 	}
 }
 
-Point SoldierPanel::calc_pos(uint32_t row, uint32_t col) const {
-	return Point(col * icon_width_, row * icon_height_);
+Vector2i SoldierPanel::calc_pos(uint32_t row, uint32_t col) const {
+	return Vector2i(col * icon_width_, row * icon_height_);
 }
 
 /**
@@ -306,8 +310,8 @@
  */
 const Soldier* SoldierPanel::find_soldier(int32_t x, int32_t y) const {
 	for (const Icon& icon : icons_) {
-		Rect r(icon.pos, icon_width_, icon_height_);
-		if (r.contains(Point(x, y))) {
+		Recti r(icon.pos, icon_width_, icon_height_);
+		if (r.contains(Vector2i(x, y))) {
 			return icon.soldier.get(egbase());
 		}
 	}
@@ -394,10 +398,10 @@
 
 	bool can_act = igbase_.can_act(building_.owner().player_number());
 	if (upcast(Widelands::MilitarySite, ms, &building)) {
-		soldier_preference_.add_button(buttons, Point(0, 0),
+		soldier_preference_.add_button(buttons, Vector2i(0, 0),
 		                               g_gr->images().get("images/wui/buildings/prefer_rookies.png"),
 		                               _("Prefer Rookies"));
-		soldier_preference_.add_button(buttons, Point(32, 0),
+		soldier_preference_.add_button(buttons, Vector2i(32, 0),
 		                               g_gr->images().get("images/wui/buildings/prefer_heroes.png"),
 		                               _("Prefer Heroes"));
 		UI::Radiobutton* button = soldier_preference_.get_first_button();

=== modified file 'src/wui/story_message_box.cc'
--- src/wui/story_message_box.cc	2016-08-04 15:49:05 +0000
+++ src/wui/story_message_box.cc	2016-10-22 18:17:28 +0000
@@ -64,9 +64,9 @@
 	center_to_parent();
 
 	if (gposx != -1)
-		set_pos(Point(gposx, get_y()));
+		set_pos(Vector2i(gposx, get_y()));
 	if (gposy != -1)
-		set_pos(Point(get_x(), gposy));
+		set_pos(Vector2i(get_x(), gposy));
 
 	move_inside_parent();
 }

=== modified file 'src/wui/transport_draw.cc'
--- src/wui/transport_draw.cc	2016-08-04 15:49:05 +0000
+++ src/wui/transport_draw.cc	2016-10-22 18:17:28 +0000
@@ -26,27 +26,35 @@
 
 namespace Widelands {
 
-void Flag::draw(const EditorGameBase& game, RenderTarget& dst, const FCoords&, const Point& pos) {
+void Flag::draw(uint32_t gametime,
+                const DrawText,
+                const Vector2f& point_on_dst,
+                float scale,
+                RenderTarget* dst) {
 	static struct {
-		int32_t x, y;
-	} ware_offsets[8] = {{-5, 1}, {-1, 3}, {3, 3}, {7, 1}, {-6, -3}, {-1, -2}, {3, -2}, {8, -3}};
+		float x, y;
+	} ware_offsets[8] = {{-5.f, 1.f},  {-1.f, 3.f},  {3.f, 3.f},  {7.f, 1.f},
+	                     {-6.f, -3.f}, {-1.f, -2.f}, {3.f, -2.f}, {8.f, -3.f}};
 
 	const RGBColor& player_color = owner().get_playercolor();
-	dst.blit_animation(
-	   pos, owner().tribe().flag_animation(), game.get_gametime() - animstart_, player_color);
+	dst->blit_animation(
+	   point_on_dst, scale, owner().tribe().flag_animation(), gametime - animstart_, player_color);
 
 	for (int32_t i = 0; i < ware_filled_; ++i) {  //  draw wares
-		Point warepos = pos;
+		Vector2f warepos = point_on_dst;
 		if (i < 8) {
-			warepos.x += ware_offsets[i].x;
-			warepos.y += ware_offsets[i].y;
-		} else
-			warepos.y -= 6 + (i - 8) * 3;
-		dst.blit_animation(warepos, wares_[i].ware->descr().get_animation("idle"), 0, player_color);
+			warepos.x += ware_offsets[i].x * scale;
+			warepos.y += ware_offsets[i].y * scale;
+		} else {
+			warepos.y -= (6.f + (i - 8.f) * 3.f) * scale;
+		}
+		dst->blit_animation(
+		   warepos, scale, wares_[i].ware->descr().get_animation("idle"), 0, player_color);
 	}
 }
 
 /** The road is drawn by the terrain renderer via marked fields. */
-void Road::draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) {
+void Road::draw(uint32_t, const DrawText, const Vector2f&, float, RenderTarget*) {
 }
+
 }

=== modified file 'src/wui/warehousewindow.cc'
--- src/wui/warehousewindow.cc	2016-08-04 15:59:26 +0000
+++ src/wui/warehousewindow.cc	2016-10-22 18:17:28 +0000
@@ -93,7 +93,7 @@
 	}
 	assert(pic != nullptr);
 
-	dst.blit(ware_position(ware), pic);
+	dst.blit(ware_position(ware).cast<float>(), pic);
 }
 
 /**

=== modified file 'src/wui/waresdisplay.cc'
--- src/wui/waresdisplay.cc	2016-08-04 15:49:05 +0000
+++ src/wui/waresdisplay.cc	2016-10-22 18:17:28 +0000
@@ -196,7 +196,7 @@
 		in_selection_[resetme.first] = false;
 	}
 
-	Point anchor_pos = ware_position(selection_anchor_);
+	Vector2i anchor_pos = ware_position(selection_anchor_);
 	// Add an offset to make sure the anchor line and column will be
 	// selected when selecting in topleft direction
 	int32_t anchor_x = anchor_pos.x + WARE_MENU_PIC_WIDTH / 2;
@@ -245,7 +245,7 @@
 }
 
 void AbstractWaresDisplay::layout() {
-	curware_.set_pos(Point(0, get_inner_h() - 25));
+	curware_.set_pos(Vector2i(0, get_inner_h() - 25));
 	curware_.set_size(get_inner_w(), 20);
 }
 
@@ -281,8 +281,8 @@
 	NEVER_HERE();
 }
 
-Point AbstractWaresDisplay::ware_position(Widelands::DescriptionIndex id) const {
-	Point p(2, 2);
+Vector2i AbstractWaresDisplay::ware_position(Widelands::DescriptionIndex id) const {
+	Vector2i p(2, 2);
 	if (horizontal_) {
 		p.x += icons_order_coords()[id].second * (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
 		p.y += icons_order_coords()[id].first *
@@ -303,8 +303,6 @@
 ===============
 */
 void AbstractWaresDisplay::draw_ware(RenderTarget& dst, Widelands::DescriptionIndex id) {
-	Point p = ware_position(id);
-
 	bool draw_selected = selected_[id];
 	if (selection_anchor_ != Widelands::INVALID_INDEX) {
 		// Draw the temporary selected wares as if they were
@@ -322,20 +320,21 @@
 	                                                        "images/wui/ware_list_bg.png");
 	uint16_t w = bgpic->width();
 
+	const Vector2f p = ware_position(id).cast<float>();
 	dst.blit(p, bgpic);
 
 	const Image* icon = type_ == Widelands::wwWORKER ? tribe_.get_worker_descr(id)->icon() :
 	                                                   tribe_.get_ware_descr(id)->icon();
 
-	dst.blit(p + Point((w - WARE_MENU_PIC_WIDTH) / 2, 1), icon);
+	dst.blit(p + Vector2f((w - WARE_MENU_PIC_WIDTH) / 2.f, 1.f), icon);
 
 	dst.fill_rect(
-	   Rect(p + Point(0, WARE_MENU_PIC_HEIGHT), w, WARE_MENU_INFO_SIZE), info_color_for_ware(id));
+	   Rectf(p + Vector2f(0.f, WARE_MENU_PIC_HEIGHT), w, WARE_MENU_INFO_SIZE), info_color_for_ware(id));
 
 	const Image* text = UI::g_fh1->render(as_waresinfo(info_for_ware(id)));
 	if (text)  // might be zero when there is no info text.
-		dst.blit(p + Point(w - text->width() - 1,
-		                   WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + 1 - text->height()),
+		dst.blit(p + Vector2f(w - text->width() - 1.f,
+		                      WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + 1 - text->height()),
 		         text);
 }
 

=== modified file 'src/wui/waresdisplay.h'
--- src/wui/waresdisplay.h	2016-08-04 15:49:05 +0000
+++ src/wui/waresdisplay.h	2016-10-22 18:17:28 +0000
@@ -83,7 +83,7 @@
 
 	const Widelands::TribeDescr::WaresOrder& icons_order() const;
 	const Widelands::TribeDescr::WaresOrderCoords& icons_order_coords() const;
-	virtual Point ware_position(Widelands::DescriptionIndex) const;
+	virtual Vector2i ware_position(Widelands::DescriptionIndex) const;
 	void draw(RenderTarget&) override;
 	virtual void draw_ware(RenderTarget&, Widelands::DescriptionIndex);
 

=== modified file 'src/wui/waresqueuedisplay.cc'
--- src/wui/waresqueuedisplay.cc	2016-08-04 15:49:05 +0000
+++ src/wui/waresqueuedisplay.cc	2016-10-22 18:17:28 +0000
@@ -124,17 +124,17 @@
 	uint32_t nr_wares_to_draw = std::min(queue_->get_filled(), cache_size_);
 	uint32_t nr_empty_to_draw = cache_size_ - nr_wares_to_draw;
 
-	Point point;
+	Vector2f point;
 	point.x = Border + (show_only_ ? 0 : CellWidth + CellSpacing);
 	point.y = Border + (total_height_ - 2 * Border - WARE_MENU_PIC_HEIGHT) / 2;
 
 	for (; nr_wares_to_draw; --nr_wares_to_draw, point.x += CellWidth + CellSpacing) {
-		dst.blitrect_scale(Rect(point.x, point.y, icon_->width(), icon_->height()), icon_,
-		                   Rect(0, 0, icon_->width(), icon_->height()), 1.0, BlendMode::UseAlpha);
+		dst.blitrect(Vector2f(point.x, point.y), icon_, Recti(0, 0, icon_->width(), icon_->height()),
+		             BlendMode::UseAlpha);
 	}
 	for (; nr_empty_to_draw; --nr_empty_to_draw, point.x += CellWidth + CellSpacing) {
-		dst.blitrect_scale_monochrome(Rect(point.x, point.y, icon_->width(), icon_->height()), icon_,
-		                              Rect(0, 0, icon_->width(), icon_->height()),
+		dst.blitrect_scale_monochrome(Rectf(point.x, point.y, icon_->width(), icon_->height()), icon_,
+		                              Recti(0, 0, icon_->width(), icon_->height()),
 		                              RGBAColor(166, 166, 166, 127));
 	}
 
@@ -156,7 +156,7 @@
 		priority_radiogroup_ = nullptr;
 	}
 
-	Point pos = Point(cache_size_ * CellWidth + Border, 0);
+	Vector2i pos = Vector2i(cache_size_ * CellWidth + Border, 0);
 	pos.x = (cache_size_ + 2) * (CellWidth + CellSpacing) + Border;
 	pos.y = Border + (total_height_ - 2 * Border - 3 * PriorityButtonSize) / 2;
 

=== modified file 'src/wui/watchwindow.cc'
--- src/wui/watchwindow.cc	2016-08-04 15:49:05 +0000
+++ src/wui/watchwindow.cc	2016-10-22 18:17:28 +0000
@@ -24,6 +24,7 @@
 
 #include "base/i18n.h"
 #include "base/macros.h"
+#include "base/rect.h"
 #include "graphic/graphic.h"
 #include "logic/game.h"
 #include "logic/map.h"
@@ -43,7 +44,8 @@
 
 // Holds information for a view
 struct WatchWindowView {
-	Point view_point;
+	Vector2i viewpoint;
+	float zoom;
 	Widelands::ObjectPointer tracking;  //  if non-null, we're tracking a Bob
 };
 
@@ -53,27 +55,24 @@
 	            int32_t y,
 	            uint32_t w,
 	            uint32_t h,
-	            Widelands::Coords,
-	            bool single_window = false);
+	            bool single_window_ = false);
 	~WatchWindow();
 
 	Widelands::Game& game() const {
 		return dynamic_cast<InteractiveGameBase&>(*get_parent()).game();
 	}
 
-	boost::signals2::signal<void(Point)> warp_mainview;
+	boost::signals2::signal<void(Vector2i)> warp_mainview;
 
 	void add_view(Widelands::Coords);
 	void next_view();
-	void show_view();
-	Point calc_coords(Widelands::Coords);
 	void save_coords();
 	void close_cur_view();
 	void toggle_buttons();
 
 protected:
 	void think() override;
-	void stop_tracking_by_drag(int32_t x, int32_t y);
+	void stop_tracking_by_drag(const Rectf&);
 
 private:
 	void do_follow();
@@ -81,12 +80,12 @@
 	void view_button_clicked(uint8_t index);
 	void set_current_view(uint8_t idx, bool save_previous = true);
 
-	MapView mapview;
-	uint32_t last_visit;
-	bool single_window;
-	uint8_t cur_index;
-	UI::Button* view_btns[NUM_VIEWS];
-	std::vector<WatchWindowView> views;
+	MapView mapview_;
+	uint32_t last_visit_;
+	bool single_window_;
+	uint8_t cur_index_;
+	UI::Button* view_btns_[NUM_VIEWS];
+	std::vector<WatchWindowView> views_;
 };
 
 static WatchWindow* g_watch_window = nullptr;
@@ -96,13 +95,12 @@
                          int32_t const y,
                          uint32_t const w,
                          uint32_t const h,
-                         Widelands::Coords const coords,
                          bool const init_single_window)
    : UI::Window(&parent, "watch", x, y, w, h, _("Watch")),
-     mapview(this, 0, 0, 200, 166, parent),
-     last_visit(game().get_gametime()),
-     single_window(init_single_window),
-     cur_index(0) {
+     mapview_(this, 0, 0, 200, 166, parent),
+     last_visit_(game().get_gametime()),
+     single_window_(init_single_window),
+     cur_index_(0) {
 	UI::Button* followbtn = new UI::Button(
 	   this, "follow", 0, h - 34, 34, 34, g_gr->images().get("images/ui_basic/but0.png"),
 	   g_gr->images().get("images/wui/menus/menu_watch_follow.png"), _("Follow"));
@@ -116,10 +114,10 @@
 
 	if (init_single_window) {
 		for (uint8_t i = 0; i < NUM_VIEWS; ++i) {
-			view_btns[i] = new UI::Button(this, "view", 74 + (17 * i), 200 - 34, 17, 34,
+			view_btns_[i] = new UI::Button(this, "view", 74 + (17 * i), 200 - 34, 17, 34,
 			                              g_gr->images().get("images/ui_basic/but0.png"), "-",
 			                              std::string(), false);
-			view_btns[i]->sigclicked.connect(boost::bind(&WatchWindow::view_button_clicked, this, i));
+			view_btns_[i]->sigclicked.connect(boost::bind(&WatchWindow::view_button_clicked, this, i));
 		}
 
 		UI::Button* closebtn = new UI::Button(
@@ -128,11 +126,9 @@
 		closebtn->sigclicked.connect(boost::bind(&WatchWindow::close_cur_view, this));
 	}
 
-	mapview.fieldclicked.connect(boost::bind(&InteractiveGameBase::node_action, &parent));
-	mapview.changeview.connect(boost::bind(&WatchWindow::stop_tracking_by_drag, this, _1, _2));
-	warp_mainview.connect(boost::bind(&InteractiveBase::move_view_to_point, &parent, _1));
-
-	add_view(coords);
+	mapview_.fieldclicked.connect(boost::bind(&InteractiveGameBase::node_action, &parent));
+	mapview_.changeview.connect(boost::bind(&WatchWindow::stop_tracking_by_drag, this, _1));
+	warp_mainview.connect(boost::bind(&InteractiveBase::center_view_on_map_pixel, &parent, _1));
 }
 
 /**
@@ -141,71 +137,61 @@
  * This also resets the view cycling timer.
  */
 void WatchWindow::add_view(Widelands::Coords const coords) {
-	if (views.size() >= NUM_VIEWS)
+	if (views_.size() >= NUM_VIEWS)
 		return;
 	WatchWindowView view;
 
+	mapview_.center_view_on_coords(coords);
+
 	view.tracking = nullptr;
-	view.view_point = calc_coords(coords);
-	last_visit = game().get_gametime();
+	view.viewpoint = mapview_.get_viewpoint();
+	view.zoom = mapview_.get_zoom();
+	last_visit_ = game().get_gametime();
 
-	views.push_back(view);
-	set_current_view(views.size() - 1, views.size() > 1);
-	if (single_window)
+	views_.push_back(view);
+	set_current_view(views_.size() - 1, views_.size() > 1);
+	if (single_window_)
 		toggle_buttons();
 }
 
-// Calc point on map from coords
-Point WatchWindow::calc_coords(Widelands::Coords const coords) {
-	// Initial positioning
-	int32_t vx = (coords.x + (coords.y & 1) * 0.5) * kTriangleWidth;
-	int32_t vy = (coords.y) * kTriangleHeight;
-	Widelands::Map& map = game().map();
-	uint8_t height = map[coords].get_height() * kHeightFactor;
-
-	return Point(vx - mapview.get_w() / 2, vy - height - mapview.get_h() / 2);
-}
-
 // Switch to next view
 void WatchWindow::next_view() {
-	set_current_view((cur_index + 1) % views.size());
+	set_current_view((cur_index_ + 1) % views_.size());
 }
 
 // Saves the coordinates of a view if it was already shown (and possibly moved)
 void WatchWindow::save_coords() {
-	views[cur_index].view_point = mapview.get_viewpoint();
+	auto& view = views_[cur_index_];
+	view.viewpoint = mapview_.get_viewpoint();
+	view.zoom = mapview_.get_zoom();
 }
 
-// Enables/Disables buttons for views
+// Enables/Disables buttons for views_
 void WatchWindow::toggle_buttons() {
 	for (uint32_t i = 0; i < NUM_VIEWS; ++i) {
-		if (i < views.size()) {
-			view_btns[i]->set_title(std::to_string(i + 1));
-			view_btns[i]->set_enabled(true);
+		if (i < views_.size()) {
+			view_btns_[i]->set_title(std::to_string(i + 1));
+			view_btns_[i]->set_enabled(true);
 		} else {
-			view_btns[i]->set_title("-");
-			view_btns[i]->set_enabled(false);
+			view_btns_[i]->set_title("-");
+			view_btns_[i]->set_enabled(false);
 		}
 	}
 }
 
 void WatchWindow::set_current_view(uint8_t idx, bool save_previous) {
-	assert(idx < views.size());
+	assert(idx < views_.size());
 
 	if (save_previous)
 		save_coords();
 
-	if (single_window) {
-		view_btns[cur_index]->set_perm_pressed(false);
-		view_btns[idx]->set_perm_pressed(true);
+	if (single_window_) {
+		view_btns_[cur_index_]->set_perm_pressed(false);
+		view_btns_[idx]->set_perm_pressed(true);
 	}
-	cur_index = idx;
-	show_view();
-}
-
-// Draws the current view
-void WatchWindow::show_view() {
-	mapview.set_viewpoint(views[cur_index].view_point, true);
+	cur_index_ = idx;
+	mapview_.set_zoom(views_[cur_index_].zoom);
+	mapview_.set_viewpoint(views_[cur_index_].viewpoint, true);
 }
 
 WatchWindow::~WatchWindow() {
@@ -214,46 +200,45 @@
 
 /*
 ===============
-Update the mapview if we're tracking something.
+Update the mapview_ if we're tracking something.
 ===============
 */
 void WatchWindow::think() {
 	UI::Window::think();
 
-	if ((game().get_gametime() - last_visit) > REFRESH_TIME) {
-		last_visit = game().get_gametime();
+	if ((game().get_gametime() - last_visit_) > REFRESH_TIME) {
+		last_visit_ = game().get_gametime();
 		next_view();
 		return;
 	}
 
-	if (upcast(Widelands::Bob, bob, views[cur_index].tracking.get(game()))) {
-		Point pos;
-
-		MapviewPixelFunctions::get_pix(game().map(), bob->get_position(), pos.x, pos.y);
-		pos = bob->calc_drawpos(game(), pos);
+	if (upcast(Widelands::Bob, bob, views_[cur_index_].tracking.get(game()))) {
+		const Vector2f field_position =
+		   MapviewPixelFunctions::to_map_pixel(game().map(), bob->get_position());
+		const Vector2f pos = bob->calc_drawpos(game(), field_position, 1.f);
 
 		Widelands::Map& map = game().map();
 		// Drop the tracking if it leaves our vision range
 		InteractivePlayer* ipl = game().get_ipl();
 		if (ipl && 1 >= ipl->player().vision(map.get_index(bob->get_position(), map.get_width()))) {
 			// Not in sight
-			views[cur_index].tracking = nullptr;
+			views_[cur_index_].tracking = nullptr;
 		} else {
-			mapview.set_viewpoint(pos - Point(mapview.get_w() / 2, mapview.get_h() / 2), false);
+			mapview_.center_view_on_map_pixel(round(pos));
 		}
 	}
 }
 
 /*
 ===============
-When the user drags the mapview, we stop tracking.
+When the user drags the mapview_, we stop tracking.
 ===============
 */
-void WatchWindow::stop_tracking_by_drag(int32_t, int32_t) {
+void WatchWindow::stop_tracking_by_drag(const Rectf&) {
 	// Disable switching while dragging
-	if (mapview.is_dragging()) {
-		last_visit = game().get_gametime();
-		views[cur_index].tracking = nullptr;
+	if (mapview_.is_dragging()) {
+		last_visit_ = game().get_gametime();
+		views_[cur_index_].tracking = nullptr;
 	}
 }
 
@@ -265,14 +250,14 @@
  */
 void WatchWindow::do_follow() {
 	Widelands::Game& g = game();
-	if (views[cur_index].tracking.get(g)) {
-		views[cur_index].tracking = nullptr;
+	if (views_[cur_index_].tracking.get(g)) {
+		views_[cur_index_].tracking = nullptr;
 	} else {
 		//  Find the nearest bob. Other object types can not move and are
 		//  therefore not of interest.
-		Point pos(mapview.get_viewpoint() + Point(mapview.get_w() / 2, mapview.get_h() / 2));
+		Vector2i pos(mapview_.get_viewpoint() + Vector2i(mapview_.get_w() / 2, mapview_.get_h() / 2));
 		Widelands::Map& map = g.map();
-		MapviewPixelFunctions::normalize_pix(map, pos);
+		MapviewPixelFunctions::normalize_pix(map, &pos);
 		std::vector<Widelands::Bob*> bobs;
 		//  Scan progressively larger circles around the given position for
 		//  suitable bobs.
@@ -288,10 +273,9 @@
 		Widelands::Bob* closest = nullptr;
 		for (uint32_t i = 0; i < bobs.size(); ++i) {
 			Widelands::Bob* const bob = bobs[i];
-			Point p;
-			MapviewPixelFunctions::get_pix(map, bob->get_position(), p.x, p.y);
-			p = bob->calc_drawpos(g, p);
-			uint32_t const dist = MapviewPixelFunctions::calc_pix_distance(map, p, pos);
+			const Vector2f field_position = MapviewPixelFunctions::to_map_pixel(map, bob->get_position());
+			const Vector2f p = bob->calc_drawpos(g, field_position, 1.f);
+			uint32_t const dist = MapviewPixelFunctions::calc_pix_distance(map, p.cast<int>(), pos);
 			InteractivePlayer* ipl = game().get_ipl();
 			if ((!closest || closest_dist > dist) &&
 			    (!ipl ||
@@ -300,17 +284,17 @@
 				closest_dist = dist;
 			}
 		}
-		views[cur_index].tracking = closest;
+		views_[cur_index_].tracking = closest;
 	}
 }
 
 /**
  * Called when the "go to" button is clicked.
  *
- * Cause the main mapview to jump to our current position.
+ * Cause the main mapview_ to jump to our current position.
  */
 void WatchWindow::do_goto() {
-	warp_mainview(mapview.get_viewpoint() + Point(mapview.get_w() / 2, mapview.get_h() / 2));
+	warp_mainview(mapview_.get_viewpoint() + Vector2i(mapview_.get_w() / 2, mapview_.get_h() / 2));
 }
 
 /**
@@ -318,7 +302,7 @@
  */
 void WatchWindow::view_button_clicked(uint8_t index) {
 	set_current_view(index);
-	last_visit = game().get_gametime();
+	last_visit_ = game().get_gametime();
 }
 
 /**
@@ -328,13 +312,13 @@
  * If there is only one view remaining, the window itself is closed.
  */
 void WatchWindow::close_cur_view() {
-	if (views.size() == 1) {
+	if (views_.size() == 1) {
 		die();
 		return;
 	}
 
-	views.erase(views.begin() + cur_index);
-	set_current_view(cur_index % views.size(), false);
+	views_.erase(views_.begin() + cur_index_);
+	set_current_view(cur_index_ % views_.size(), false);
 	toggle_buttons();
 }
 
@@ -347,10 +331,12 @@
 */
 void show_watch_window(InteractiveGameBase& parent, const Widelands::Coords& coords) {
 	if (g_options.pull_section("global").get_bool("single_watchwin", false)) {
-		if (g_watch_window)
-			g_watch_window->add_view(coords);
-		else
-			g_watch_window = new WatchWindow(parent, 250, 150, 200, 200, coords, true);
-	} else
-		new WatchWindow(parent, 250, 150, 200, 200, coords, false);
+		if (!g_watch_window) {
+			g_watch_window = new WatchWindow(parent, 250, 150, 200, 200, true);
+		}
+		g_watch_window->add_view(coords);
+	} else {
+		auto* window = new WatchWindow(parent, 250, 150, 200, 200, false);
+		window->add_view(coords);
+	}
 }