From 55030c116694a1ecfc7307ef5ad520361f5d4cc3 Mon Sep 17 00:00:00 2001
From: Hannes Janetzek <hannes.janetzek@gmail.com>
Date: Fri, 15 Feb 2013 16:56:13 +0100
Subject: [PATCH] refactor: dont pass matrices with MapPosition -> use
 GLRender.Matrices

---
 src/org/oscim/core/MapPosition.java           |  15 --
 src/org/oscim/overlay/ItemizedOverlay.java    |  11 +-
 src/org/oscim/overlay/PathOverlay.java        |  10 +-
 src/org/oscim/renderer/BaseMap.java           |   5 +-
 src/org/oscim/renderer/GLRenderer.java        |  64 +++----
 src/org/oscim/renderer/TileManager.java       |  10 +-
 .../oscim/renderer/overlays/BasicOverlay.java |  32 ++--
 .../renderer/overlays/BuildingOverlay.java    |  29 ++-
 .../renderer/overlays/CustomOverlay.java      |  12 +-
 .../renderer/overlays/ExtrusionOverlay.java   |  41 ++--
 .../oscim/renderer/overlays/ModelOverlay.java |  26 +--
 .../renderer/overlays/RenderOverlay.java      |  37 ++--
 .../renderer/overlays/TestLineOverlay.java    |  77 ++++----
 .../oscim/renderer/overlays/TextOverlay.java  |  11 +-
 .../renderer/overlays/TextOverlayExp.java     | 178 +++++++++++-------
 src/org/oscim/utils/FastMath.java             |   6 +
 src/org/oscim/view/MapViewPosition.java       |  70 ++++---
 17 files changed, 362 insertions(+), 272 deletions(-)

diff --git a/src/org/oscim/core/MapPosition.java b/src/org/oscim/core/MapPosition.java
index c2169ba1..59ece2e7 100644
--- a/src/org/oscim/core/MapPosition.java
+++ b/src/org/oscim/core/MapPosition.java
@@ -15,7 +15,6 @@
  */
 package org.oscim.core;
 
-import android.opengl.Matrix;
 
 /** A MapPosition Container. */
 public class MapPosition {
@@ -31,11 +30,6 @@ public class MapPosition {
 	public double x;
 	public double y;
 
-	public float[] viewMatrix;
-
-	//	// DO NOT MODIFY! shared with MapViewPosition
-	//	public float[] projMatrix;
-
 	public MapPosition() {
 		this.zoomLevel = (byte) 1;
 		this.scale = 1;
@@ -46,15 +40,6 @@ public class MapPosition {
 		this.y = MercatorProjection.latitudeToPixelY(this.lat, zoomLevel);
 	}
 
-	// FIXME remove this here
-	public void init() {
-		viewMatrix = new float[16];
-		Matrix.setIdentityM(viewMatrix, 0);
-		//
-		//		rotateMatrix = new float[16];
-		//		Matrix.setIdentityM(rotateMatrix, 0);
-	}
-
 	//	public Point geopointToMap(GeoPoint in, Point reuse) {
 	//		Point out = reuse == null ? new Point() : reuse;
 	//		out.x = (int) (MercatorProjection.longitudeToPixelX(in.getLongitude(), zoomLevel) - x);
diff --git a/src/org/oscim/overlay/ItemizedOverlay.java b/src/org/oscim/overlay/ItemizedOverlay.java
index 19ae72b8..6ac3665c 100644
--- a/src/org/oscim/overlay/ItemizedOverlay.java
+++ b/src/org/oscim/overlay/ItemizedOverlay.java
@@ -73,9 +73,9 @@ public abstract class ItemizedOverlay<Item extends OverlayItem> extends Overlay
 
 	class ItemOverlay extends BasicOverlay {
 
-		private SymbolLayer mSymbolLayer;
-		private float[] mMvp = new float[16];
-		private float[] mVec = new float[4];
+		private final SymbolLayer mSymbolLayer;
+		private final float[] mMvp = new float[16];
+		private final float[] mVec = new float[4];
 
 		public ItemOverlay(MapView mapView) {
 			super(mapView);
@@ -84,7 +84,8 @@ public abstract class ItemizedOverlay<Item extends OverlayItem> extends Overlay
 
 		// note: this is called from GL-Thread. so check your syncs!
 		@Override
-		public synchronized void update(MapPosition curPos, boolean positionChanged,
+		public synchronized void update(MapPosition curPos, 
+				boolean positionChanged,
 				boolean tilesChanged) {
 
 			if (!tilesChanged && !mUpdate)
@@ -97,7 +98,7 @@ public abstract class ItemizedOverlay<Item extends OverlayItem> extends Overlay
 			int my = (int) curPos.y;
 
 			// TODO could pass mvp as param
-			mMapView.getMapViewPosition().getMVP(mMvp);
+			mMapView.getMapViewPosition().getMatrix(null, null, mMvp);
 
 			float[] matrix = mMvp;
 			float[] vec = mVec;
diff --git a/src/org/oscim/overlay/PathOverlay.java b/src/org/oscim/overlay/PathOverlay.java
index 2df6a023..7723b1c7 100644
--- a/src/org/oscim/overlay/PathOverlay.java
+++ b/src/org/oscim/overlay/PathOverlay.java
@@ -25,6 +25,7 @@ import org.oscim.renderer.layer.Layer;
 import org.oscim.renderer.layer.LineLayer;
 import org.oscim.renderer.overlays.BasicOverlay;
 import org.oscim.theme.renderinstruction.Line;
+import org.oscim.utils.FastMath;
 import org.oscim.view.MapView;
 
 import android.content.Context;
@@ -52,10 +53,10 @@ public class PathOverlay extends Overlay {
 
 		// projected points
 		private float[] mPPoints;
-		private short[] mIndex;
+		private final short[] mIndex;
 		private int mSize;
 
-		private Line mLine;
+		private final Line mLine;
 
 		// limit coords
 		private final int max = 2048;
@@ -70,7 +71,8 @@ public class PathOverlay extends Overlay {
 		// note: this is called from GL-Thread. so check your syncs!
 		// TODO use an Overlay-Thread to build up layers (like for Labeling)
 		@Override
-		public synchronized void update(MapPosition curPos, boolean positionChanged,
+		public synchronized void update(MapPosition curPos,
+				boolean positionChanged,
 				boolean tilesChanged) {
 
 			if (!tilesChanged && !mUpdatePoints)
@@ -144,7 +146,7 @@ public class PathOverlay extends Overlay {
 				// skip too near points
 				int dx = x - px;
 				int dy = y - py;
-				if ((i == 0) || dx > MIN_DIST || dx < -MIN_DIST || dy > MIN_DIST || dy < -MIN_DIST) {
+				if ((i == 0) || FastMath.absMaxCmp(dx, dy, MIN_DIST)) {
 					projected[i + 0] = px = x;
 					projected[i + 1] = py = y;
 					i += 2;
diff --git a/src/org/oscim/renderer/BaseMap.java b/src/org/oscim/renderer/BaseMap.java
index effc8715..2ad3a1c6 100644
--- a/src/org/oscim/renderer/BaseMap.java
+++ b/src/org/oscim/renderer/BaseMap.java
@@ -19,6 +19,7 @@ import static android.opengl.GLES20.glStencilMask;
 import static org.oscim.generator.JobTile.STATE_READY;
 
 import org.oscim.core.MapPosition;
+import org.oscim.renderer.GLRenderer.Matrices;
 import org.oscim.renderer.layer.Layer;
 import org.oscim.utils.FastMath;
 import org.oscim.utils.GlUtils;
@@ -49,10 +50,10 @@ public class BaseMap {
 		mfProjMatrix[14] = 0;
 	}
 
-	static void draw(MapTile[] tiles, int tileCnt, MapPosition pos) {
+	static void draw(MapTile[] tiles, int tileCnt, MapPosition pos, Matrices m) {
 		mDrawCnt = 0;
 
-		Matrix.multiplyMM(mVPMatrix, 0, mfProjMatrix, 0, pos.viewMatrix, 0);
+		Matrix.multiplyMM(mVPMatrix, 0, mfProjMatrix, 0, m.view, 0);
 
 		GLES20.glDepthFunc(GLES20.GL_LESS);
 
diff --git a/src/org/oscim/renderer/GLRenderer.java b/src/org/oscim/renderer/GLRenderer.java
index e87c5045..7a33b55a 100644
--- a/src/org/oscim/renderer/GLRenderer.java
+++ b/src/org/oscim/renderer/GLRenderer.java
@@ -74,12 +74,21 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 	// bytes currently loaded in VBOs
 	private static int mBufferMemoryUsage;
 
-	private static float[] mMVPMatrix = new float[16];
-	private static float[] mProjMatrix = new float[16];
-	private static float[] mTmpMatrix = new float[16];
+
 	private static float[] mTileCoords = new float[8];
 	private static float[] mDebugCoords = new float[8];
 
+	public class Matrices {
+		public final float[] viewproj = new float[16];
+		public final float[] proj = new float[16];
+		public final float[] view = new float[16];
+
+		// for temporary use by callee
+		public final float[] mvp = new float[16];
+	}
+
+	private static Matrices mMatrices;
+
 	//private
 	static float[] mClearColor = null;
 	private static boolean mUpdateColor = false;
@@ -171,9 +180,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		mMapView = mapView;
 		mMapViewPosition = mapView.getMapViewPosition();
 		mMapPosition = new MapPosition();
-		mMapPosition.init();
 
-		Matrix.setIdentityM(mMVPMatrix, 0);
+		//Matrix.setIdentityM(mMVPMatrix, 0);
+		mMatrices = new Matrices();
 
 		// add half pixel to tile clip/fill coordinates to avoid rounding issues
 		short min = -4;
@@ -366,7 +375,12 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		// coordinates)
 		MapPosition pos = mMapPosition;
 		float[] coords = mTileCoords;
-		boolean changed = mMapViewPosition.getMapPosition(pos, coords);
+		boolean changed;
+		synchronized(mMapViewPosition){
+			changed = mMapViewPosition.getMapPosition(pos);
+			mMapViewPosition.getMapViewProjection(coords);
+			mMapViewPosition.getMatrix(mMatrices.view, null, mMatrices.viewproj);
+		}
 
 		int tileCnt = mDrawTiles.cnt;
 		MapTile[] tiles = mDrawTiles.tiles;
@@ -455,7 +469,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 			overlays.get(i).update(mMapPosition, changed, tilesChanged);
 
 		/* draw base layer */
-		BaseMap.draw(tiles, tileCnt, pos);
+		BaseMap.draw(tiles, tileCnt, pos, mMatrices);
 
 		/* draw overlays */
 		for (int i = 0, n = overlays.size(); i < n; i++) {
@@ -466,7 +480,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 				renderOverlay.newData = false;
 			}
 			if (renderOverlay.isReady)
-				renderOverlay.render(mMapPosition, mMVPMatrix, mProjMatrix);
+				renderOverlay.render(mMapPosition, mMatrices);
 		}
 
 		if (MapView.debugFrameTime) {
@@ -490,15 +504,12 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 			mDebugCoords[6] = max;
 			mDebugCoords[7] = -ymax;
 
-			PolygonRenderer.debugDraw(mProjMatrix, mDebugCoords, 0);
+			PolygonRenderer.debugDraw(mMatrices.proj, mDebugCoords, 0);
 
 			pos.zoomLevel = -1;
-			mMapViewPosition.getMapPosition(pos, mDebugCoords);
+			mMapViewPosition.getMapViewProjection(mDebugCoords);
 
-			Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0,
-					pos.viewMatrix, 0);
-
-			PolygonRenderer.debugDraw(mMVPMatrix, mDebugCoords, 1);
+			PolygonRenderer.debugDraw(mMatrices.viewproj, mDebugCoords, 1);
 
 		}
 
@@ -560,32 +571,21 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		mWidth = width;
 		mHeight = height;
 
-		GLES20.glScissor(0, 0, mWidth, mHeight);
-
-		float s = MapViewPosition.VIEW_SCALE;
-		float aspect = mHeight / (float) mWidth;
-
-		Matrix.frustumM(mProjMatrix, 0, -s, s,
-				aspect * s, -aspect * s, MapViewPosition.VIEW_NEAR,
-				MapViewPosition.VIEW_FAR);
-
-		Matrix.setIdentityM(mTmpMatrix, 0);
-		Matrix.translateM(mTmpMatrix, 0, 0, 0, -MapViewPosition.VIEW_DISTANCE);
-		Matrix.multiplyMM(mProjMatrix, 0, mProjMatrix, 0, mTmpMatrix, 0);
+		mMapViewPosition.getMatrix(null, mMatrices.proj, null);
 
 		if (debugView) {
 			// modify this to scale only the view, to see better which tiles are
 			// rendered
-			Matrix.setIdentityM(mMVPMatrix, 0);
-			Matrix.scaleM(mMVPMatrix, 0, 0.5f, 0.5f, 1);
-			Matrix.multiplyMM(mProjMatrix, 0, mMVPMatrix, 0, mProjMatrix, 0);
+			Matrix.setIdentityM(mMatrices.mvp, 0);
+			Matrix.scaleM(mMatrices.mvp, 0, 0.5f, 0.5f, 1);
+			Matrix.multiplyMM(mMatrices.proj, 0, mMatrices.mvp, 0, mMatrices.proj, 0);
 		}
 
-		BaseMap.setProjection(mProjMatrix);
+		BaseMap.setProjection(mMatrices.proj);
 
 		GLES20.glViewport(0, 0, width, height);
-		//GLES20.glScissor(0, 0, width, height);
-		//GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
+		GLES20.glScissor(0, 0, width, height);
+		GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
 
 		GLES20.glClearStencil(0x00);
 
diff --git a/src/org/oscim/renderer/TileManager.java b/src/org/oscim/renderer/TileManager.java
index 551e16a1..58a09f66 100644
--- a/src/org/oscim/renderer/TileManager.java
+++ b/src/org/oscim/renderer/TileManager.java
@@ -29,6 +29,7 @@ import org.oscim.generator.TileDistanceSort;
 import org.oscim.renderer.layer.TextItem;
 import org.oscim.renderer.layer.VertexPool;
 import org.oscim.view.MapView;
+import org.oscim.view.MapViewPosition;
 
 import android.util.Log;
 
@@ -49,6 +50,7 @@ public class TileManager {
 	private static final int CACHE_THRESHOLD = 30;
 
 	private final MapView mMapView;
+	private final MapViewPosition mMapViewPosition;
 	private final MapPosition mMapPosition;
 	private boolean mInitialized;
 	private int mWidth = 0;
@@ -82,7 +84,7 @@ public class TileManager {
 
 	public TileManager(MapView mapView) {
 		mMapView = mapView;
-
+		mMapViewPosition = mapView.getMapViewPosition();
 		mMapPosition = new MapPosition();
 		mJobs = new ArrayList<JobTile>();
 		mTiles = new MapTile[GLRenderer.CACHE_TILES];
@@ -159,7 +161,11 @@ public class TileManager {
 
 		MapPosition mapPosition = mMapPosition;
 		float[] coords = mTileCoords;
-		changedPos = mMapView.getMapViewPosition().getMapPosition(mapPosition, coords);
+
+		synchronized(mMapViewPosition){
+			changedPos = mMapViewPosition.getMapPosition(mapPosition);
+			mMapViewPosition.getMapViewProjection(coords);
+		}
 
 		if (changedPos) {
 			mMapView.render();
diff --git a/src/org/oscim/renderer/overlays/BasicOverlay.java b/src/org/oscim/renderer/overlays/BasicOverlay.java
index fd980b18..33d84ee4 100644
--- a/src/org/oscim/renderer/overlays/BasicOverlay.java
+++ b/src/org/oscim/renderer/overlays/BasicOverlay.java
@@ -17,6 +17,7 @@ package org.oscim.renderer.overlays;
 import org.oscim.core.MapPosition;
 import org.oscim.renderer.BufferObject;
 import org.oscim.renderer.GLRenderer;
+import org.oscim.renderer.GLRenderer.Matrices;
 import org.oscim.renderer.GLState;
 import org.oscim.renderer.LineRenderer;
 import org.oscim.renderer.PolygonRenderer;
@@ -27,7 +28,6 @@ import org.oscim.utils.FastMath;
 import org.oscim.view.MapView;
 
 import android.opengl.GLES20;
-import android.opengl.Matrix;
 
 // Base class to use the Layers drawing 'API'
 public abstract class BasicOverlay extends RenderOverlay {
@@ -47,25 +47,33 @@ public abstract class BasicOverlay extends RenderOverlay {
 	 * use synchronized when modifying layers
 	 */
 	@Override
-	public synchronized void render(MapPosition pos, float[] mv, float[] proj) {
-		setMatrix(pos, mv);
-		float div = FastMath.pow(mMapPosition.zoomLevel - pos.zoomLevel);
+	public synchronized void render(MapPosition pos, Matrices m) {
 
-		Matrix.multiplyMM(mvp, 0, proj, 0, mv, 0);
+		float div = FastMath.pow(mMapPosition.zoomLevel - pos.zoomLevel);
 
 		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo.id);
 		GLState.test(false, false);
 
-		for (Layer l = layers.layers; l != null;) {
-			if (l.type == Layer.POLYGON) {
-				l = PolygonRenderer.draw(pos, l, mvp, true, false);
-			} else {
-				l = LineRenderer.draw(pos, l, mvp, div, 0, layers.lineOffset);
+		if (layers.layers != null) {
+			setMatrix(pos, m, true);
+
+			for (Layer l = layers.layers; l != null;) {
+				if (l.type == Layer.POLYGON) {
+					l = PolygonRenderer.draw(pos, l, m.mvp, true, false);
+				} else {
+					l = LineRenderer.draw(pos, l, m.mvp, div, 0, layers.lineOffset);
+				}
 			}
 		}
 
-		for (Layer l = layers.textureLayers; l != null;) {
-			l = TextureRenderer.draw(l, (mMapPosition.scale / pos.scale) * div, proj, mv);
+		if (layers.textureLayers != null) {
+			setMatrix(pos, m, false);
+
+			float scale = (mMapPosition.scale / pos.scale) * div;
+
+			for (Layer l = layers.textureLayers; l != null;) {
+				l = TextureRenderer.draw(l, scale, m.proj, m.mvp);
+			}
 		}
 	}
 
diff --git a/src/org/oscim/renderer/overlays/BuildingOverlay.java b/src/org/oscim/renderer/overlays/BuildingOverlay.java
index c443c24c..87fb68f3 100644
--- a/src/org/oscim/renderer/overlays/BuildingOverlay.java
+++ b/src/org/oscim/renderer/overlays/BuildingOverlay.java
@@ -21,6 +21,7 @@ import java.nio.ShortBuffer;
 import org.oscim.core.MapPosition;
 import org.oscim.core.Tile;
 import org.oscim.renderer.GLRenderer;
+import org.oscim.renderer.GLRenderer.Matrices;
 import org.oscim.renderer.GLState;
 import org.oscim.renderer.layer.VertexPool;
 import org.oscim.renderer.layer.VertexPoolItem;
@@ -58,7 +59,7 @@ public class BuildingOverlay extends RenderOverlay {
 	private VertexPoolItem mVertices, mCurVertices;
 	private VertexPoolItem mIndices[], mCurIndices[];
 
-	private int mIndiceCnt[] = { 0, 0, 0 };
+	private final int mIndiceCnt[] = { 0, 0, 0 };
 
 	private void addOutline(float[] points, float height) {
 		int len = points.length;
@@ -338,21 +339,19 @@ public class BuildingOverlay extends RenderOverlay {
 				mNumVertices * 4 * 2, sbuf, GLES20.GL_STATIC_DRAW);
 		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
 
-		mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
+		mMapView.getMapViewPosition().getMapPosition(mMapPosition);
 
 		// tell GLRenderer to call 'render'
 		isReady = true;
 	}
 
 	@Override
-	public synchronized void render(MapPosition pos, float[] mv, float[] proj) {
-
-		setMatrix(pos, mv);
-		Matrix.multiplyMM(mv, 0, proj, 0, mv, 0);
+	public synchronized void render(MapPosition pos, Matrices m) {
+		setMatrix(pos, m);
 
 		GLState.useProgram(buildingProgram);
 
-		GLES20.glUniformMatrix4fv(hBuildingMatrix, 1, false, mv, 0);
+		GLES20.glUniformMatrix4fv(hBuildingMatrix, 1, false, m.mvp, 0);
 		GLES20.glUniform4f(hBuildingColor, 0.5f, 0.5f, 0.5f, 0.7f);
 
 		GLState.enableVertexArrays(hBuildingVertexPosition, hBuildingLightPosition);
@@ -413,7 +412,7 @@ public class BuildingOverlay extends RenderOverlay {
 	}
 
 	@Override
-	protected void setMatrix(MapPosition curPos, float[] matrix) {
+	protected void setMatrix(MapPosition curPos, Matrices m) {
 
 		MapPosition oPos = mMapPosition;
 
@@ -432,19 +431,19 @@ public class BuildingOverlay extends RenderOverlay {
 
 		float scale = curPos.scale / div;
 
-		Matrix.setIdentityM(matrix, 0);
+		Matrix.setIdentityM(m.mvp, 0);
 
 		// translate relative to map center
-		matrix[12] = x * scale;
-		matrix[13] = y * scale;
+		m.mvp[12] = x * scale;
+		m.mvp[13] = y * scale;
 		// scale to current tile world coordinates
 		scale = (curPos.scale / oPos.scale) / div;
 		scale /= GLRenderer.COORD_MULTIPLIER;
-		matrix[0] = scale;
-		matrix[5] = scale;
-		matrix[10] = scale / 1000f;
+		m.mvp[0] = scale;
+		m.mvp[5] = scale;
+		m.mvp[10] = scale / 1000f;
 
-		Matrix.multiplyMM(matrix, 0, curPos.viewMatrix, 0, matrix, 0);
+		Matrix.multiplyMM(m.mvp, 0, m.viewproj, 0, m.mvp, 0);
 	}
 
 	final static String buildingVertexShader = ""
diff --git a/src/org/oscim/renderer/overlays/CustomOverlay.java b/src/org/oscim/renderer/overlays/CustomOverlay.java
index c048dd2d..14371ddd 100644
--- a/src/org/oscim/renderer/overlays/CustomOverlay.java
+++ b/src/org/oscim/renderer/overlays/CustomOverlay.java
@@ -19,12 +19,12 @@ import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
 
 import org.oscim.core.MapPosition;
+import org.oscim.renderer.GLRenderer.Matrices;
 import org.oscim.renderer.GLState;
 import org.oscim.utils.GlUtils;
 import org.oscim.view.MapView;
 
 import android.opengl.GLES20;
-import android.opengl.Matrix;
 
 /*
  * This is an example how to integrate custom OpenGL drawing routines as map overlay
@@ -84,7 +84,7 @@ public class CustomOverlay extends RenderOverlay {
 	}
 
 	@Override
-	public void render(MapPosition pos, float[] tmp, float[] proj) {
+	public void render(MapPosition pos, Matrices m) {
 
 		// Use the program object
 		GLState.useProgram(mProgramObject);
@@ -106,12 +106,14 @@ public class CustomOverlay extends RenderOverlay {
 		/* apply view and projection matrices */
 		// set mvp (tmp) matrix relative to mMapPosition
 		// i.e. fixed on the map
-		setMatrix(pos, tmp);
-		Matrix.multiplyMM(tmp, 0, proj, 0, tmp, 0);
+		setMatrix(pos, m);
+
+		//Matrix.multiplyMM(tmp, 0, proj, 0, tmp, 0);
+
 		// or set mvp matrix fixed on screen center
 		// Matrix.multiplyMM(tmp, 0, proj, 0, pos.viewMatrix, 0);
 
-		GLES20.glUniformMatrix4fv(hMatrixPosition, 1, false, tmp, 0);
+		GLES20.glUniformMatrix4fv(hMatrixPosition, 1, false, m.mvp, 0);
 
 		// Draw the triangle
 		GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
diff --git a/src/org/oscim/renderer/overlays/ExtrusionOverlay.java b/src/org/oscim/renderer/overlays/ExtrusionOverlay.java
index f281186a..b7c9f868 100644
--- a/src/org/oscim/renderer/overlays/ExtrusionOverlay.java
+++ b/src/org/oscim/renderer/overlays/ExtrusionOverlay.java
@@ -21,6 +21,7 @@ import java.nio.ShortBuffer;
 import org.oscim.core.MapPosition;
 import org.oscim.generator.JobTile;
 import org.oscim.renderer.GLRenderer;
+import org.oscim.renderer.GLRenderer.Matrices;
 import org.oscim.renderer.GLState;
 import org.oscim.renderer.MapTile;
 import org.oscim.renderer.TileSet;
@@ -54,7 +55,7 @@ public class ExtrusionOverlay extends RenderOverlay {
 	private boolean initialized = false;
 
 	// FIXME sum up size used while filling layer only up to:
-	private int BUFFERSIZE = 65536 * 2;
+	private final int BUFFERSIZE = 65536 * 2;
 	private TileSet mTileSet;
 	private ShortBuffer mShortBuffer;
 	private MapTile[] mTiles;
@@ -64,7 +65,7 @@ public class ExtrusionOverlay extends RenderOverlay {
 	public void update(MapPosition curPos, boolean positionChanged,
 			boolean tilesChanged) {
 
-		mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
+		mMapView.getMapViewPosition().getMapPosition(mMapPosition);
 
 		if (!initialized) {
 			initialized = true;
@@ -155,16 +156,16 @@ public class ExtrusionOverlay extends RenderOverlay {
 		return null;
 	}
 
-	private boolean debug = false;
-	private final float[] mVPMatrix = new float[16];
+	private final boolean debug = false;
+	//private final float[] mVPMatrix = new float[16];
 
 	@Override
-	public void render(MapPosition pos, float[] mv, float[] proj) {
+	public void render(MapPosition pos, Matrices m) {
 		// TODO one could render in one pass to texture and then draw the texture
 		// with alpha... might be faster.
 
-		Matrix.multiplyMM(mVPMatrix, 0, proj, 0, pos.viewMatrix, 0);
-		proj = mVPMatrix;
+		//Matrix.multiplyMM(mVPMatrix, 0, proj, 0, pos.viewMatrix, 0);
+		//proj = mVPMatrix;
 
 		MapTile[] tiles = mTiles;
 
@@ -190,8 +191,8 @@ public class ExtrusionOverlay extends RenderOverlay {
 			for (int i = 0; i < mTileCnt; i++) {
 				ExtrusionLayer el = (ExtrusionLayer) tiles[i].layers.extrusionLayers;
 
-				setMatrix(pos, mv, proj, tiles[i], div, 0);
-				GLES20.glUniformMatrix4fv(uExtMatrix, 1, false, mv, 0);
+				setMatrix(pos, m, tiles[i], div, 0);
+				GLES20.glUniformMatrix4fv(uExtMatrix, 1, false, m.mvp, 0);
 
 				GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, el.mIndicesBufferID);
 				GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, el.mVertexBufferID);
@@ -242,8 +243,8 @@ public class ExtrusionOverlay extends RenderOverlay {
 			MapTile t = tiles[i];
 			ExtrusionLayer el = (ExtrusionLayer) t.layers.extrusionLayers;
 			int d = GLRenderer.depthOffset(t) * 10;
-			setMatrix(pos, mv, proj, t, div, d);
-			GLES20.glUniformMatrix4fv(uExtMatrix, 1, false, mv, 0);
+			setMatrix(pos, m, t, div, d);
+			GLES20.glUniformMatrix4fv(uExtMatrix, 1, false, m.mvp, 0);
 
 			GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, el.mIndicesBufferID);
 			GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, el.mVertexBufferID);
@@ -268,8 +269,8 @@ public class ExtrusionOverlay extends RenderOverlay {
 
 			GLES20.glDepthFunc(GLES20.GL_EQUAL);
 			int d = GLRenderer.depthOffset(t) * 10;
-			setMatrix(pos, mv, proj, t, div, d);
-			GLES20.glUniformMatrix4fv(uExtMatrix, 1, false, mv, 0);
+			setMatrix(pos, m, t, div, d);
+			GLES20.glUniformMatrix4fv(uExtMatrix, 1, false, m.mvp, 0);
 
 			GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, el.mIndicesBufferID);
 			GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, el.mVertexBufferID);
@@ -298,8 +299,8 @@ public class ExtrusionOverlay extends RenderOverlay {
 			// drawing gl_lines with the same coordinates does not result in
 			// same depth values as polygons, so add offset and draw gl_lequal:
 			GLES20.glDepthFunc(GLES20.GL_LEQUAL);
-			GlUtils.addOffsetM(mv, 100);
-			GLES20.glUniformMatrix4fv(uExtMatrix, 1, false, mv, 0);
+			GlUtils.addOffsetM(m.mvp, 100);
+			GLES20.glUniformMatrix4fv(uExtMatrix, 1, false, m.mvp, 0);
 
 			GLES20.glUniform1i(uExtMode, 3);
 			GLES20.glDrawElements(GLES20.GL_LINES, el.mIndiceCnt[3],
@@ -315,20 +316,20 @@ public class ExtrusionOverlay extends RenderOverlay {
 		GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
 	}
 
-	private static void setMatrix(MapPosition mapPosition, float[] matrix, float[] proj,
+	private static void setMatrix(MapPosition mapPosition, Matrices m,
 			MapTile tile, float div, int delta) {
 
 		float x = (float) (tile.pixelX - mapPosition.x * div);
 		float y = (float) (tile.pixelY - mapPosition.y * div);
 		float scale = mapPosition.scale / div;
 
-		GlUtils.setTileMatrix(matrix, x, y, scale);
+		GlUtils.setTileMatrix(m.mvp, x, y, scale);
 		// scale height
-		matrix[10] = scale / (1000f * GLRenderer.COORD_MULTIPLIER);
+		m.mvp[10] = scale / (1000f * GLRenderer.COORD_MULTIPLIER);
 
-		Matrix.multiplyMM(matrix, 0, proj, 0, matrix, 0);
+		Matrix.multiplyMM(m.mvp, 0, m.viewproj, 0, m.mvp, 0);
 
-		GlUtils.addOffsetM(matrix, delta);
+		GlUtils.addOffsetM(m.mvp, delta);
 	}
 
 	private final float _a = 0.86f;
diff --git a/src/org/oscim/renderer/overlays/ModelOverlay.java b/src/org/oscim/renderer/overlays/ModelOverlay.java
index 25202e08..c658bb12 100644
--- a/src/org/oscim/renderer/overlays/ModelOverlay.java
+++ b/src/org/oscim/renderer/overlays/ModelOverlay.java
@@ -22,6 +22,7 @@ import java.nio.ShortBuffer;
 import org.oscim.core.MapPosition;
 import org.oscim.core.Tile;
 import org.oscim.renderer.GLRenderer;
+import org.oscim.renderer.GLRenderer.Matrices;
 import org.oscim.renderer.GLState;
 import org.oscim.utils.FastMath;
 import org.oscim.utils.GlUtils;
@@ -160,17 +161,16 @@ public class ModelOverlay extends RenderOverlay {
 		GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 64 * 4, fbuf, GLES20.GL_STATIC_DRAW);
 		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
 
-		mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
+		mMapView.getMapViewPosition().getMapPosition(mMapPosition);
 
 		// tell GLRenderer to call 'render'
 		isReady = true;
 	}
 
 	@Override
-	public synchronized void render(MapPosition pos, float[] mv, float[] proj) {
+	public synchronized void render(MapPosition pos, Matrices m) {
 
-		setMatrix(pos, mv);
-		Matrix.multiplyMM(mv, 0, proj, 0, mv, 0);
+		setMatrix(pos, m);
 
 		GLState.useProgram(polygonProgram);
 
@@ -182,7 +182,7 @@ public class ModelOverlay extends RenderOverlay {
 		GLES20.glVertexAttribPointer(hPolygonVertexPosition, 3, GLES20.GL_FLOAT, false, 16, 0);
 		GLES20.glVertexAttribPointer(hPolygonLightPosition, 1, GLES20.GL_FLOAT, false, 16, 12);
 
-		GLES20.glUniformMatrix4fv(hPolygonMatrix, 1, false, mv, 0);
+		GLES20.glUniformMatrix4fv(hPolygonMatrix, 1, false, m.mvp, 0);
 		GLES20.glUniform4f(hPolygonColor, 0.5f, 0.5f, 0.5f, 0.7f);
 
 		// draw to depth buffer
@@ -211,7 +211,7 @@ public class ModelOverlay extends RenderOverlay {
 	}
 
 	@Override
-	protected void setMatrix(MapPosition curPos, float[] matrix) {
+	protected void setMatrix(MapPosition curPos, Matrices m) {
 		// TODO if oPos == curPos this could be simplified
 
 		MapPosition oPos = mMapPosition;
@@ -231,19 +231,19 @@ public class ModelOverlay extends RenderOverlay {
 
 		float scale = curPos.scale / div;
 
-		Matrix.setIdentityM(matrix, 0);
+		Matrix.setIdentityM(m.mvp, 0);
 
 		// translate relative to map center
-		matrix[12] = x * scale;
-		matrix[13] = y * scale;
+		m.mvp[12] = x * scale;
+		m.mvp[13] = y * scale;
 		// scale to current tile world coordinates
 		scale = (curPos.scale / oPos.scale) / div;
 		scale /= GLRenderer.COORD_MULTIPLIER;
-		matrix[0] = scale;
-		matrix[5] = scale;
-		matrix[10] = scale; // 1000f;
+		m.mvp[0] = scale;
+		m.mvp[5] = scale;
+		m.mvp[10] = scale; // 1000f;
 
-		Matrix.multiplyMM(matrix, 0, curPos.viewMatrix, 0, matrix, 0);
+		Matrix.multiplyMM(m.mvp, 0, m.viewproj, 0, m.mvp, 0);
 	}
 
 	@Override
diff --git a/src/org/oscim/renderer/overlays/RenderOverlay.java b/src/org/oscim/renderer/overlays/RenderOverlay.java
index a9f3e6f0..4bf93e80 100644
--- a/src/org/oscim/renderer/overlays/RenderOverlay.java
+++ b/src/org/oscim/renderer/overlays/RenderOverlay.java
@@ -17,6 +17,7 @@ package org.oscim.renderer.overlays;
 import org.oscim.core.MapPosition;
 import org.oscim.core.Tile;
 import org.oscim.renderer.GLRenderer;
+import org.oscim.renderer.GLRenderer.Matrices;
 import org.oscim.utils.FastMath;
 import org.oscim.utils.GlUtils;
 import org.oscim.view.MapView;
@@ -65,21 +66,21 @@ public abstract class RenderOverlay {
 	 *
 	 * @param pos
 	 *            current MapPosition
-	 * @param mv
-	 *            current model-view matrix
-	 * @param proj
-	 *            current projection matrix
+	 * @param m
+	 *            current render matrices + matrix for temporary use
 	 */
-	public abstract void render(MapPosition pos, float[] mv, float[] proj);
+	public abstract void render(MapPosition pos, Matrices m);
 
 	/**
-	 * Utility: set matrix relative to the difference of current MapPosition
+	 * Utility: set m.mvp matrix relative to the difference of current MapPosition
 	 * and the last updated Overlay MapPosition
 	 *
 	 * @param curPos ...
-	 * @param matrix ...
+	 * @param m ...
+	 * @param project
+	 *  apply view and projection, or just view otherwise
 	 */
-	protected void setMatrix(MapPosition curPos, float[] matrix) {
+	protected void setMatrix(MapPosition curPos, Matrices m, boolean project) {
 		MapPosition oPos = mMapPosition;
 
 		float div = FastMath.pow(oPos.zoomLevel - curPos.zoomLevel);
@@ -101,10 +102,24 @@ public abstract class RenderOverlay {
 		// set scale to be relative to current scale
 		float s = (curPos.scale / oPos.scale) / div;
 
-		GlUtils.setMatrix(matrix, x * scale, y * scale,
+		GlUtils.setMatrix(m.mvp, x * scale, y * scale,
 				s / GLRenderer.COORD_MULTIPLIER);
 
-		Matrix.multiplyMM(matrix, 0, curPos.viewMatrix, 0, matrix, 0);
+		if (project)
+			Matrix.multiplyMM(m.mvp, 0, m.viewproj, 0, m.mvp, 0);
+		else
+			Matrix.multiplyMM(m.mvp, 0, m.view, 0, m.mvp, 0);
+	}
+
+	/**
+	 * Utility: set m.mvp matrix relative to the difference of current MapPosition
+	 * and the last updated Overlay MapPosition and add m.viewproj
+	 *
+	 * @param curPos ...
+	 * @param m ...
+	 */
+	protected void setMatrix(MapPosition curPos, Matrices m) {
+		setMatrix(curPos, m, true);
 	}
 
 	/**
@@ -113,6 +128,6 @@ public abstract class RenderOverlay {
 	 * @return true if position has changed
 	 */
 	protected boolean updateMapPosition() {
-		return mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
+		return mMapView.getMapViewPosition().getMapPosition(mMapPosition);
 	}
 }
diff --git a/src/org/oscim/renderer/overlays/TestLineOverlay.java b/src/org/oscim/renderer/overlays/TestLineOverlay.java
index 6a0a7f9e..9c5fb502 100644
--- a/src/org/oscim/renderer/overlays/TestLineOverlay.java
+++ b/src/org/oscim/renderer/overlays/TestLineOverlay.java
@@ -21,6 +21,7 @@ import java.nio.ShortBuffer;
 import org.oscim.core.MapPosition;
 import org.oscim.core.Tile;
 import org.oscim.renderer.GLRenderer;
+import org.oscim.renderer.GLRenderer.Matrices;
 import org.oscim.renderer.GLState;
 import org.oscim.utils.FastMath;
 import org.oscim.utils.GlUtils;
@@ -73,31 +74,31 @@ public class TestLineOverlay extends RenderOverlay {
 	//   -> max line length is 2^12/4=1024
 	// - texture 'end' is 'length'-'start'
 
-	private final short[] box = {
-			//  '-' start
-			0, 0, 0, 0,
-			// 0.
-			-800, 0, 255, 0,
-			// 2.
-			100, 0, 255, 0,
-			// 1.
-			0, 0, 255, 1,
-			// 3.
-			800, 0, 255, 1,
-
-			-800, 200, 127, 0,
-			0, 200, 127, 0,
-			0, 200, 127, 1,
-			800, 200, 127, 1,
-
-			-800, 400, 255, 0,
-			0, 400, 255, 0,
-			0, 400, 255, 1,
-			800, 400, 255, 1,
-
-			// '-' end
-			0, 0, 0, 0,
-	};
+	//	private final short[] box = {
+	//			//  '-' start
+	//			0, 0, 0, 0,
+	//			// 0.
+	//			-800, 0, 255, 0,
+	//			// 2.
+	//			100, 0, 255, 0,
+	//			// 1.
+	//			0, 0, 255, 1,
+	//			// 3.
+	//			800, 0, 255, 1,
+	//
+	//			-800, 200, 127, 0,
+	//			0, 200, 127, 0,
+	//			0, 200, 127, 1,
+	//			800, 200, 127, 1,
+	//
+	//			-800, 400, 255, 0,
+	//			0, 400, 255, 0,
+	//			0, 400, 255, 1,
+	//			800, 400, 255, 1,
+	//
+	//			// '-' end
+	//			0, 0, 0, 0,
+	//	};
 
 	private short[] indices = {
 			0, 1, 2,
@@ -298,17 +299,17 @@ public class TestLineOverlay extends RenderOverlay {
 				GLES20.GL_STATIC_DRAW);
 		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
 
-		mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
+		mMapView.getMapViewPosition().getMapPosition(mMapPosition);
 
 		// tell GLRenderer to call 'render'
 		isReady = true;
 	}
 
 	@Override
-	public synchronized void render(MapPosition pos, float[] mv, float[] proj) {
+	public synchronized void render(MapPosition pos, Matrices m) {
 
-		setMatrix(pos, mv);
-		Matrix.multiplyMM(mv, 0, proj, 0, mv, 0);
+		setMatrix(pos, m);
+		//Matrix.multiplyMM(mv, 0, proj, 0, mv, 0);
 
 		GLState.useProgram(testProgram);
 		GLES20.glDisable(GLES20.GL_CULL_FACE);
@@ -319,7 +320,7 @@ public class TestLineOverlay extends RenderOverlay {
 
 		GLES20.glEnableVertexAttribArray(htestVertexFlip);
 
-		GLES20.glUniformMatrix4fv(htestMatrix, 1, false, mv, 0);
+		GLES20.glUniformMatrix4fv(htestMatrix, 1, false, m.mvp, 0);
 
 		GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferID);
 
@@ -355,7 +356,7 @@ public class TestLineOverlay extends RenderOverlay {
 	}
 
 	@Override
-	protected void setMatrix(MapPosition curPos, float[] matrix) {
+	protected void setMatrix(MapPosition curPos, Matrices m) {
 		MapPosition oPos = mMapPosition;
 
 		byte z = oPos.zoomLevel;
@@ -373,19 +374,19 @@ public class TestLineOverlay extends RenderOverlay {
 
 		float scale = curPos.scale / div;
 
-		Matrix.setIdentityM(matrix, 0);
+		Matrix.setIdentityM(m.mvp, 0);
 
 		// translate relative to map center
-		matrix[12] = x * scale;
-		matrix[13] = y * scale;
+		m.mvp[12] = x * scale;
+		m.mvp[13] = y * scale;
 		// scale to current tile world coordinates
 		scale = (curPos.scale / oPos.scale) / div;
 		scale /= GLRenderer.COORD_MULTIPLIER;
-		matrix[0] = scale;
-		matrix[5] = scale;
-		matrix[10] = 1; //scale; // 1000f;
+		m.mvp[0] = scale;
+		m.mvp[5] = scale;
+		m.mvp[10] = 1; //scale; // 1000f;
 
-		Matrix.multiplyMM(matrix, 0, curPos.viewMatrix, 0, matrix, 0);
+		Matrix.multiplyMM(m.mvp, 0, m.viewproj, 0, m.mvp, 0);
 	}
 
 	@Override
diff --git a/src/org/oscim/renderer/overlays/TextOverlay.java b/src/org/oscim/renderer/overlays/TextOverlay.java
index bf2ffd92..8ba9c341 100644
--- a/src/org/oscim/renderer/overlays/TextOverlay.java
+++ b/src/org/oscim/renderer/overlays/TextOverlay.java
@@ -18,6 +18,7 @@ package org.oscim.renderer.overlays;
 import org.oscim.core.MapPosition;
 import org.oscim.core.Tile;
 import org.oscim.renderer.GLRenderer;
+import org.oscim.renderer.GLRenderer.Matrices;
 import org.oscim.renderer.MapTile;
 import org.oscim.renderer.TileSet;
 import org.oscim.renderer.layer.Layer;
@@ -45,7 +46,7 @@ public class TextOverlay extends BasicOverlay {
 	private final static String TAG = TextOverlay.class.getName();
 
 	private TileSet mTiles;
-	private LabelThread mThread;
+	private final LabelThread mThread;
 
 	private MapPosition mWorkPos;
 
@@ -170,7 +171,7 @@ public class TextOverlay extends BasicOverlay {
 		if (mTiles.cnt == 0)
 			return;
 
-		mMapView.getMapViewPosition().getMapPosition(mWorkPos, null);
+		mMapView.getMapViewPosition().getMapPosition(mWorkPos);
 
 		TextLayer tl = mWorkLayer;
 
@@ -415,7 +416,7 @@ public class TextOverlay extends BasicOverlay {
 	}
 
 	@Override
-	protected void setMatrix(MapPosition curPos, float[] matrix) {
+	protected void setMatrix(MapPosition curPos, Matrices m) {
 		MapPosition oPos = mMapPosition;
 
 		float div = FastMath.pow(oPos.zoomLevel - curPos.zoomLevel);
@@ -424,10 +425,10 @@ public class TextOverlay extends BasicOverlay {
 
 		float scale = curPos.scale / div;
 
-		GlUtils.setMatrix(matrix, x * scale, y * scale,
+		GlUtils.setMatrix(m.mvp, x * scale, y * scale,
 				scale / GLRenderer.COORD_MULTIPLIER);
 
-		Matrix.multiplyMM(matrix, 0, curPos.viewMatrix, 0, matrix, 0);
+		Matrix.multiplyMM(m.mvp, 0, m.view, 0, m.mvp, 0);
 	}
 
 	private boolean mHolding;
diff --git a/src/org/oscim/renderer/overlays/TextOverlayExp.java b/src/org/oscim/renderer/overlays/TextOverlayExp.java
index e72c60e1..11c112bc 100644
--- a/src/org/oscim/renderer/overlays/TextOverlayExp.java
+++ b/src/org/oscim/renderer/overlays/TextOverlayExp.java
@@ -17,12 +17,13 @@ package org.oscim.renderer.overlays;
 
 // TODO
 // 1. rewrite :)
+// 1.1 test if label is actually visible
 // 2. compare previous to current state
 // 2.1 test for new labels to be placed
 // 2.2 handle collisions
 // 3 join segments that belong to one feature
 // 4 handle zoom-level changes
-// 5 3D-Tree might be handy
+// 5 R-Tree might be handy
 //
 
 import java.util.HashMap;
@@ -32,6 +33,7 @@ import org.oscim.core.Tile;
 import org.oscim.generator.JobTile;
 import org.oscim.renderer.BufferObject;
 import org.oscim.renderer.GLRenderer;
+import org.oscim.renderer.GLRenderer.Matrices;
 import org.oscim.renderer.GLState;
 import org.oscim.renderer.LineRenderer;
 import org.oscim.renderer.MapTile;
@@ -49,6 +51,7 @@ import org.oscim.utils.GlUtils;
 import org.oscim.utils.OBB2D;
 import org.oscim.utils.PausableThread;
 import org.oscim.view.MapView;
+import org.oscim.view.MapViewPosition;
 
 import android.graphics.Color;
 import android.graphics.Paint.Cap;
@@ -60,6 +63,7 @@ import android.util.Log;
 public class TextOverlayExp extends BasicOverlay {
 	private final static String TAG = TextOverlayExp.class.getName();
 
+	private final MapViewPosition mMapViewPosition;
 	private TileSet mTileSet;
 	private final LabelThread mThread;
 
@@ -70,6 +74,8 @@ public class TextOverlayExp extends BasicOverlay {
 	// TextLayer that is ready to be added to 'layers'
 	private TextLayer mNextLayer;
 
+	private final float[] mTmpCoords = new float[8];
+
 	/* package */boolean mRun;
 
 	class LabelThread extends PausableThread {
@@ -102,6 +108,7 @@ public class TextOverlayExp extends BasicOverlay {
 
 	public TextOverlayExp(MapView mapView) {
 		super(mapView);
+		mMapViewPosition = mapView.getMapViewPosition();
 
 		layers.textureLayers = new TextLayer();
 		mTmpLayer = new TextLayer();
@@ -145,10 +152,6 @@ public class TextOverlayExp extends BasicOverlay {
 	private byte checkOverlap(TextLayer tl, TextItem ti) {
 
 		for (TextItem lp = tl.labels; lp != null;) {
-			if (lp.text.caption) {
-				lp = lp.next;
-				continue;
-			}
 
 			// check bounding box
 			if (!TextItem.bboxOverlaps(ti, lp, 100)) {
@@ -186,11 +189,12 @@ public class TextOverlayExp extends BasicOverlay {
 
 			if (ti.bbox == null) {
 				ti.bbox = new OBB2D(ti.x, ti.y, ti.x1, ti.y1,
-						ti.width + 10, ti.text.fontHeight + 10);
+						ti.width + 5, ti.text.fontHeight + 5);
 			}
+
 			if (lp.bbox == null) {
 				lp.bbox = new OBB2D(lp.x, lp.y, lp.x1, lp.y1,
-						lp.width + 10, lp.text.fontHeight + 10);
+						lp.width + 5, lp.text.fontHeight + 5);
 			}
 
 			boolean intersect = ti.bbox.overlaps(lp.bbox);
@@ -203,9 +207,8 @@ public class TextOverlayExp extends BasicOverlay {
 				//Log.d(TAG, "intersection " + lp.string + " <> " + ti.string
 				//		+ " at " + ti.x + ":" + ti.y);
 
-				if (lp.text.priority > ti.text.priority || lp.length < ti.length) {
-					//if (lp.length > ti.length) {
-					//Log.d(TAG, "drop " + lp.string);
+				if (!lp.text.caption
+						&& (lp.text.priority > ti.text.priority || lp.length < ti.length)) {
 					TextItem tmp = lp;
 					lp = lp.next;
 
@@ -241,35 +244,50 @@ public class TextOverlayExp extends BasicOverlay {
 		return 0;
 	}
 
+	private int mMinX;
+	private int mMinY;
+	private int mMaxX;
+	private int mMaxY;
+
+	private boolean isVisible(TextItem ti) {
+
+		return true;
+	}
+
 	private Layers mDebugLayer;
+	private final float[] mMVP = new float[16];
 
 	boolean updateLabels() {
 		if (mTmpLayer == null)
 			return false;
 
+		// get current tiles
 		mTileSet = GLRenderer.getVisibleTiles(mTileSet);
 
 		if (mTileSet.cnt == 0)
 			return false;
 
+		// reuse text layer
 		TextLayer tl = mTmpLayer;
 		mTmpLayer = null;
 
-		Layers dbg = null;//new Layers();
+		Layers dbg = null; //new Layers();
+
+		float[] coords = mTmpCoords;
+		synchronized (mMapViewPosition) {
+			mMapViewPosition.getMapPosition(mTmpPos);
+			mMapViewPosition.getMapViewProjection(coords);
+			mMapViewPosition.getMatrix(null, null, mMVP);
+		}
 
 		// mTiles might be from another zoomlevel than the current:
 		// this scales MapPosition to the zoomlevel of mTiles...
 		// TODO create a helper function in MapPosition
-		mMapView.getMapViewPosition().getMapPosition(mTmpPos, null);
-		// capture current state
-
 		MapTile[] tiles = mTileSet.tiles;
-
 		int diff = tiles[0].zoomLevel - mTmpPos.zoomLevel;
-
 		float div = FastMath.pow(diff);
-
 		float scale = mTmpPos.scale * div;
+
 		double angle = Math.toRadians(mTmpPos.angle);
 		float cos = (float) Math.cos(angle);
 		float sin = (float) Math.sin(angle);
@@ -301,9 +319,6 @@ public class TextOverlayExp extends BasicOverlay {
 			if (t.state == JobTile.STATE_NONE || t.state == JobTile.STATE_LOADING)
 				continue;
 
-			//if (t.joined != MapTile.JOINED)
-			//	joinTile()
-
 			float dx = (float) (t.pixelX - mTmpPos.x);
 			float dy = (float) (t.pixelY - mTmpPos.y);
 
@@ -329,33 +344,70 @@ public class TextOverlayExp extends BasicOverlay {
 					}
 				}
 
-				if (ti.text.caption) {
-					ti2.move(ti, dx, dy, scale);
-					ti2.setAxisAlignedBBox();
-					ti2.bbox = new OBB2D(ti2.x, ti2.y, cos, -sin, ti2.width + 6,
-							ti2.text.fontHeight + 6, true);
-
-					boolean overlaps = false;
-					for (TextItem lp = tl.labels; lp != null; lp = lp.next) {
-						if (!lp.text.caption)
-							continue;
-
-						if (ti2.bbox.overlaps(lp.bbox)) {
-							Log.d(TAG, "overlap > " + ti2.string + " " + lp.string);
-							//if (TextItem.bboxOverlaps(ti2, lp, 4)) {
-							overlaps = true;
-							break;
-						}
-					}
-					if (!overlaps) {
-						tl.addText(ti2);
-						ti2 = null;
-					}
-
+				if (!ti.text.caption)
 					continue;
+
+				ti2.move(ti, dx, dy, scale);
+				ti2.setAxisAlignedBBox();
+
+				ti2.bbox = new OBB2D(ti2.x, ti2.y, cos, -sin, ti2.width + 6,
+						ti2.text.fontHeight + 6, true);
+
+				boolean overlaps = false;
+				for (TextItem lp = tl.labels; lp != null; lp = lp.next) {
+					if (!lp.text.caption)
+						continue;
+
+					if (ti2.bbox.overlaps(lp.bbox)) {
+						Log.d(TAG, "overlap > " + ti2.string + " " + lp.string);
+						//if (TextItem.bboxOverlaps(ti2, lp, 4)) {
+						overlaps = true;
+						break;
+					}
+				}
+				if (!overlaps) {
+					tl.addText(ti2);
+					ti2 = null;
 				}
 
-				/* text is way label */
+			}
+		}
+
+		/* add way labels */
+		for (int i = 0, n = mTileSet.cnt; i < n; i++) {
+
+			MapTile t = tiles[i];
+
+			if (t.state == JobTile.STATE_NONE || t.state == JobTile.STATE_LOADING)
+				continue;
+
+			float dx = (float) (t.pixelX - mTmpPos.x);
+			float dy = (float) (t.pixelY - mTmpPos.y);
+
+			// flip around date-line
+			if (dx > maxx) {
+				dx = dx - maxx * 2;
+			} else if (dx < -maxx) {
+				dx = dx + maxx * 2;
+			}
+			dx *= scale;
+			dy *= scale;
+
+			for (TextItem ti = t.labels; ti != null; ti = ti.next) {
+
+				if (ti.text.caption)
+					continue;
+
+				// acquire a TextItem to add to TextLayer
+				if (ti2 == null) {
+					if (mPool == null)
+						ti2 = TextItem.get();
+					else {
+						ti2 = mPool;
+						mPool = mPool.next;
+						ti2.next = null;
+					}
+				}
 
 				// check if path at current scale is long enough for text
 				if (dbg == null && ti.width > ti.length * scale)
@@ -423,6 +475,7 @@ public class TextOverlayExp extends BasicOverlay {
 				}
 			}
 		}
+
 		for (TextItem ti = tl.labels; ti != null; ti = ti.next) {
 			// scale back to fixed zoom-level. could be done in setMatrix
 			ti.x /= scale;
@@ -457,9 +510,7 @@ public class TextOverlayExp extends BasicOverlay {
 		tl.setScale(scale);
 		tl.prepare();
 
-		//TextItem.printPool();
-		//Log.d(TAG, "new labels: " + count);
-
+		// remove tile locks
 		GLRenderer.releaseTiles(mTileSet);
 
 		// pass new labels for rendering
@@ -514,12 +565,8 @@ public class TextOverlayExp extends BasicOverlay {
 	@Override
 	public void compile() {
 		int newSize = layers.getSize();
-		//if (newSize == 0)
-		//	Log.d(TAG, "text layer size " + newSize);
 
 		if (newSize == 0) {
-			//BufferObject.release(vbo);
-			//vbo = null;
 			isReady = false;
 			return;
 		}
@@ -535,31 +582,34 @@ public class TextOverlayExp extends BasicOverlay {
 	}
 
 	@Override
-	public synchronized void render(MapPosition pos, float[] mv, float[] proj) {
-		setMatrix(pos, mv);
+	public synchronized void render(MapPosition pos, Matrices m) {
 		float div = FastMath.pow(mMapPosition.zoomLevel - pos.zoomLevel);
 
-		Matrix.multiplyMM(mvp, 0, proj, 0, mv, 0);
-
 		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo.id);
 		GLState.test(false, false);
 
-		for (Layer l = layers.layers; l != null;) {
-			if (l.type == Layer.POLYGON) {
-				l = PolygonRenderer.draw(pos, l, mvp, true, false);
-			} else {
-				l = LineRenderer.draw(pos, l, mvp, div, 0, layers.lineOffset);
+		if (layers.layers != null) {
+			setMatrix(pos, m);
+			Matrix.multiplyMM(m.mvp, 0, m.proj, 0, m.mvp,0);
+			for (Layer l = layers.layers; l != null;) {
+				if (l.type == Layer.POLYGON) {
+					l = PolygonRenderer.draw(pos, l, m.mvp, true, false);
+				} else {
+					l = LineRenderer.draw(pos, l, m.mvp, div, 0, layers.lineOffset);
+				}
 			}
 		}
 
+		setMatrix(pos, m);
 		for (Layer l = layers.textureLayers; l != null;) {
-			l = TextureRenderer.draw(l, (mMapPosition.scale / pos.scale) * div, proj, mv);
+			float scale = (mMapPosition.scale / pos.scale) * div;
+			l = TextureRenderer.draw(l, scale, m.proj, m.mvp);
 		}
 
 	}
 
 	@Override
-	protected void setMatrix(MapPosition curPos, float[] matrix) {
+	protected void setMatrix(MapPosition curPos, Matrices m) {
 		MapPosition oPos = mMapPosition;
 
 		float div = FastMath.pow(oPos.zoomLevel - curPos.zoomLevel);
@@ -568,10 +618,10 @@ public class TextOverlayExp extends BasicOverlay {
 
 		float scale = curPos.scale / div;
 
-		GlUtils.setMatrix(matrix, x * scale, y * scale,
+		GlUtils.setMatrix(m.mvp, x * scale, y * scale,
 				scale / GLRenderer.COORD_MULTIPLIER);
 
-		Matrix.multiplyMM(matrix, 0, curPos.viewMatrix, 0, matrix, 0);
+		Matrix.multiplyMM(m.mvp, 0, m.view, 0, m.mvp, 0);
 	}
 
 	private boolean mHolding;
diff --git a/src/org/oscim/utils/FastMath.java b/src/org/oscim/utils/FastMath.java
index b8b257d7..e5bb1bd6 100644
--- a/src/org/oscim/utils/FastMath.java
+++ b/src/org/oscim/utils/FastMath.java
@@ -65,7 +65,13 @@ public class FastMath {
 		return a2 < a1 ? a1 : a2;
 	}
 
+	// test if any absolute value is greater than 'cmp'
 	public static boolean absMaxCmp(float value1, float value2, float cmp){
 		return value1 < -cmp || value1 > cmp || value2 < -cmp || value2 > cmp;
 	}
+
+	// test if any absolute value is greater than 'cmp'
+	public static boolean absMaxCmp(int value1, int value2, int cmp){
+		return value1 < -cmp || value1 > cmp || value2 < -cmp || value2 > cmp;
+	}
 }
diff --git a/src/org/oscim/view/MapViewPosition.java b/src/org/oscim/view/MapViewPosition.java
index c75ef901..c3444d80 100644
--- a/src/org/oscim/view/MapViewPosition.java
+++ b/src/org/oscim/view/MapViewPosition.java
@@ -66,7 +66,7 @@ public class MapViewPosition {
 	private double mPosX;
 	private double mPosY;
 
-	private AnimationHandler mHandler;
+	private final AnimationHandler mHandler;
 
 	MapViewPosition(MapView mapView) {
 		mMapView = mapView;
@@ -81,18 +81,19 @@ public class MapViewPosition {
 		mHandler = new AnimationHandler(this);
 	}
 
-	private float[] mProjMatrix = new float[16];
-	private float[] mProjMatrixI = new float[16];
-	private float[] mUnprojMatrix = new float[16];
-	private float[] mViewMatrix = new float[16];
-	private float[] mRotMatrix = new float[16];
-	private float[] mTmpMatrix = new float[16];
+	private final float[] mProjMatrix = new float[16];
+	private final float[] mProjMatrixI = new float[16];
+	private final float[] mUnprojMatrix = new float[16];
+	private final float[] mViewMatrix = new float[16];
+	private final float[] mVPMatrix = new float[16];
+	private final float[] mRotMatrix = new float[16];
+	private final float[] mTmpMatrix = new float[16];
 
 	// temporary vars: only use in synchronized functions!
-	private Point2D mMovePoint = new Point2D();
-	private float[] mv = { 0, 0, 0, 1 };
-	private float[] mu = { 0, 0, 0, 1 };
-	private float[] mBBoxCoords = new float[8];
+	private final Point2D mMovePoint = new Point2D();
+	private final float[] mv = { 0, 0, 0, 1 };
+	private final float[] mu = { 0, 0, 0, 1 };
+	private final float[] mBBoxCoords = new float[8];
 
 	private float mHeight, mWidth;
 
@@ -120,8 +121,7 @@ public class MapViewPosition {
 		updateMatrix();
 	}
 
-	public synchronized boolean getMapPosition(final MapPosition mapPosition,
-			final float[] projection) {
+	public synchronized boolean getMapPosition(final MapPosition mapPosition) {
 		// if (!isValid())
 		// return false;
 
@@ -145,21 +145,34 @@ public class MapViewPosition {
 		mapPosition.x = mPosX;
 		mapPosition.y = mPosY;
 
-		if (mapPosition.viewMatrix != null)
-			System.arraycopy(mViewMatrix, 0, mapPosition.viewMatrix, 0, 16);
+		return true;
+	}
 
-		if (projection == null)
-			return true;
+	/**
+	 * get a copy of current matrices
+	 * @param view ...
+	 * @param proj ...
+	 * @param vp view and projection
+	 */
+	public synchronized void getMatrix(float[] view, float[] proj, float[] vp) {
+		if (view != null)
+			System.arraycopy(mViewMatrix, 0, view, 0, 16);
 
+		if (proj!= null)
+			System.arraycopy(mProjMatrix, 0, proj, 0, 16);
+
+		if (vp != null)
+			System.arraycopy(mVPMatrix, 0, vp, 0, 16);
+	}
+
+	public synchronized void getMapViewProjection(float[] box) {
 		float t = getZ(1);
 		float t2 = getZ(-1);
 
-		unproject(1, -1, t, projection, 0); // top-right
-		unproject(-1, -1, t, projection, 2); // top-left
-		unproject(-1, 1, t2, projection, 4); // bottom-left
-		unproject(1, 1, t2, projection, 6); // bottom-right
-
-		return true;
+		unproject(1, -1, t, box, 0); // top-right
+		unproject(-1, -1, t, box, 2); // top-left
+		unproject(-1, 1, t2, box, 4); // bottom-left
+		unproject(1, 1, t2, box, 6); // bottom-right
 	}
 
 	// get the z-value of the map-plane for a point on screen
@@ -365,8 +378,9 @@ public class MapViewPosition {
 		mv[2] = 0;
 		mv[3] = 1;
 
-		Matrix.multiplyMV(mv, 0, mViewMatrix, 0, mv, 0);
-		Matrix.multiplyMV(mv, 0, mProjMatrix, 0, mv, 0);
+		//	Matrix.multiplyMV(mv, 0, mViewMatrix, 0, mv, 0);
+		//	Matrix.multiplyMV(mv, 0, mProjMatrix, 0, mv, 0);
+		Matrix.multiplyMV(mv, 0, mVPMatrix, 0, mv, 0);
 
 		out.x = (int) (mv[0] / mv[3] * mWidth / 2);
 		out.y = (int) (mv[1] / mv[3] * mHeight / 2);
@@ -376,10 +390,6 @@ public class MapViewPosition {
 		return out;
 	}
 
-	public synchronized void getMVP(float[] matrix) {
-		Matrix.multiplyMM(matrix, 0, mProjMatrix, 0, mViewMatrix, 0);
-	}
-
 	//	public static Point project(float x, float y, float[] matrix, float[] tmpVec, Point reuse) {
 	//		Point out = reuse == null ? new Point() : reuse;
 	//
@@ -420,6 +430,8 @@ public class MapViewPosition {
 
 		Matrix.multiplyMM(mViewMatrix, 0, mRotMatrix, 0, mTmpMatrix, 0);
 
+		Matrix.multiplyMM(mVPMatrix, 0, mProjMatrix, 0, mViewMatrix, 0);
+
 		//--- unproject matrix:
 		// Matrix.multiplyMM(mTmpMatrix, 0, mProjMatrix, 0, mViewMatrix, 0);
 		// Matrix.invertM(mUnprojMatrix, 0, mTmpMatrix, 0);