From a8b25d07ad19a781c7c86de38b2cb96e4d66c333 Mon Sep 17 00:00:00 2001
From: Hannes Janetzek <hannes.janetzek@gmail.com>
Date: Sat, 29 Dec 2012 23:34:48 +0100
Subject: [PATCH] keep tile loading state in JobTile.state

---
 src/org/oscim/generator/JobQueue.java     |  7 +-
 src/org/oscim/generator/JobTile.java      | 22 +++++-
 src/org/oscim/renderer/GLRenderer.java    | 95 ++++++++++++++++-------
 src/org/oscim/renderer/MapTile.java       | 18 +++--
 src/org/oscim/renderer/TileGenerator.java | 18 ++---
 src/org/oscim/renderer/TileManager.java   | 45 ++++++-----
 6 files changed, 137 insertions(+), 68 deletions(-)

diff --git a/src/org/oscim/generator/JobQueue.java b/src/org/oscim/generator/JobQueue.java
index 16ac107c..bfdb73e7 100644
--- a/src/org/oscim/generator/JobQueue.java
+++ b/src/org/oscim/generator/JobQueue.java
@@ -41,7 +41,8 @@ public class JobQueue {
 
 		for (int i = 0, n = tiles.size(); i < n; i++) {
 			JobTile tile = tiles.get(i);
-			tile.isLoading = true;
+			//tile.isLoading = true;
+			tile.state = JobTile.STATE_LOADING;
 			mPriorityQueue.offer(tile);
 		}
 	}
@@ -50,10 +51,10 @@ public class JobQueue {
 	 * Removes all jobs from this queue.
 	 */
 	public synchronized void clear() {
-
 		JobTile t;
 		while ((t = mPriorityQueue.poll()) != null)
-			t.isLoading = false;
+			t.state = JobTile.STATE_NONE;
+		//t.isLoading = false;
 
 		mPriorityQueue.clear();
 	}
diff --git a/src/org/oscim/generator/JobTile.java b/src/org/oscim/generator/JobTile.java
index 79847d19..a535b727 100644
--- a/src/org/oscim/generator/JobTile.java
+++ b/src/org/oscim/generator/JobTile.java
@@ -16,10 +16,13 @@ package org.oscim.generator;
 
 import org.oscim.core.Tile;
 
+import android.util.Log;
+
 /**
  * 
  */
 public class JobTile extends Tile implements Comparable<JobTile> {
+	private final static String TAG = JobTile.class.getName();
 	// public final static int LOADING = 1;
 	// public final static int NEWDATA = 1 << 1;
 	// public final static int READY = 1 << 2;
@@ -27,10 +30,27 @@ public class JobTile extends Tile implements Comparable<JobTile> {
 	// public final static int CANCELED = 1 << 3;
 	// public int state;
 
+	public final static int STATE_NONE = 0;
+	public final static int STATE_LOADING = 1 << 0;
+	public final static int STATE_NEW_DATA = 1 << 1;
+	public final static int STATE_READY = 1 << 2;
+
+	public void clearState() {
+		state = STATE_NONE;
+	}
+
+	public void setLoading() {
+		if (state != STATE_NONE)
+			Log.d(TAG, "wrong state: " + state);
+
+		state = STATE_LOADING;
+	}
+
 	/**
 	 * tile is in JobQueue
 	 */
-	public boolean isLoading;
+	//public boolean isLoading;
+	public byte state;
 
 	/**
 	 * distance from map center.
diff --git a/src/org/oscim/renderer/GLRenderer.java b/src/org/oscim/renderer/GLRenderer.java
index 13e7f3b7..c02cba8a 100644
--- a/src/org/oscim/renderer/GLRenderer.java
+++ b/src/org/oscim/renderer/GLRenderer.java
@@ -21,6 +21,8 @@ import static android.opengl.GLES20.GL_DYNAMIC_DRAW;
 import static android.opengl.GLES20.GL_ONE;
 import static android.opengl.GLES20.GL_ONE_MINUS_SRC_ALPHA;
 import static android.opengl.GLES20.GL_POLYGON_OFFSET_FILL;
+import static org.oscim.generator.JobTile.STATE_NEW_DATA;
+import static org.oscim.generator.JobTile.STATE_READY;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -166,6 +168,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 				holder = new MapTile(x, y, mZoom);
 				holder.isVisible = true;
 				holder.holder = tile;
+				tile.isVisible = true;
 				tiles[cnt + mHolderCount++] = holder;
 			}
 		}
@@ -281,20 +284,19 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		return true;
 	}
 
-	private static boolean uploadTileData(MapTile tile) {
-		if (tile.layers != null) {
-			tile.isReady = uploadLayers(tile.layers, tile.vbo, true);
-
-			if (!tile.isReady) {
-				Log.d(TAG, "uploadTileData " + tile + " is empty!");
-				tile.layers.clear();
-				tile.layers = null;
-			}
+	private static void uploadTileData(MapTile tile) {
+		if (tile.layers == null) {
+			BufferObject.release(tile.vbo);
+			tile.vbo = null;
+		} else if (!uploadLayers(tile.layers, tile.vbo, true)) {
+			Log.d(TAG, "uploadTileData " + tile + " failed!");
+			tile.layers.clear();
+			tile.layers = null;
+			BufferObject.release(tile.vbo);
+			tile.vbo = null;
 		}
-		tile.newData = false;
-		// Log.d(TAG, "uploaded " + tile.isReady + " " + tile);
 
-		return tile.isReady;
+		tile.state = STATE_READY;
 	}
 
 	private static boolean uploadOverlayData(RenderOverlay renderOverlay) {
@@ -307,10 +309,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		return renderOverlay.isReady;
 	}
 
-	private static void checkBufferUsage() {
+	private static void checkBufferUsage(boolean force) {
 		// try to clear some unused vbo when exceding limit
 
-		if (mBufferMemoryUsage < LIMIT_BUFFERS) {
+		if (!force && mBufferMemoryUsage < LIMIT_BUFFERS) {
 			if (CACHE_TILES < CACHE_TILES_MAX)
 				CACHE_TILES += 50;
 			return;
@@ -457,23 +459,23 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 			if (!tile.isVisible)
 				continue;
 
-			if (tile.newData) {
+			if (tile.state == STATE_NEW_DATA) {
 				uploadTileData(tile);
 				continue;
 			}
 
 			if (tile.holder != null) {
 				// load tile that is referenced by this holder
-				if (tile.holder.newData)
+				if (tile.holder.state == STATE_NEW_DATA)
 					uploadTileData(tile.holder);
 
-				tile.isReady = tile.holder.isReady;
+				tile.state = tile.holder.state;
 
-			} else if (!tile.isReady) {
+			} else if (tile.state != STATE_READY) {
 				// check near relatives than can serve as proxy
 				if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
 					MapTile rel = tile.rel.parent.tile;
-					if (rel.newData)
+					if (rel.state == STATE_NEW_DATA)
 						uploadTileData(rel);
 
 					continue;
@@ -483,14 +485,14 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 						continue;
 
 					MapTile rel = tile.rel.child[c].tile;
-					if (rel != null && rel.newData)
+					if (rel != null && rel.state == STATE_NEW_DATA)
 						uploadTileData(rel);
 				}
 			}
 		}
 
 		if (uploadCnt > 0)
-			checkBufferUsage();
+			checkBufferUsage(false);
 
 		tilesChanged |= (uploadCnt > 0);
 
@@ -507,7 +509,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 
 		for (int i = 0; i < tileCnt; i++) {
 			MapTile t = tiles[i];
-			if (t.isVisible && t.isReady)
+			if (t.isVisible && t.state == STATE_READY)
 				drawTile(t);
 		}
 
@@ -517,7 +519,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		// TODO draw proxies for placeholder...
 		for (int i = 0; i < tileCnt; i++) {
 			MapTile t = tiles[i];
-			if (t.isVisible && !t.isReady && (t.holder == null))
+			if (t.isVisible && (t.state != STATE_READY) && (t.holder == null))
 				drawProxyTile(t);
 		}
 
@@ -577,6 +579,11 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 					mapPosition.viewMatrix, 0);
 			PolygonRenderer.debugDraw(mMVPMatrix, mDebugCoords, 1);
 		}
+
+		if (GlUtils.checkGlOutOfMemory("finish")) {
+			checkBufferUsage(true);
+			// TODO also throw out some textures etc
+		}
 	}
 
 	// used to not draw a tile twice per frame.
@@ -598,6 +605,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		if (tile.holder != null)
 			tile = tile.holder;
 
+		if (tile.layers == null)
+			return;
+
 		GLES20.glPolygonOffset(0, mDrawCount++);
 
 		// seems there are not infinite offset units possible
@@ -652,7 +662,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 
 			MapTile c = tile.rel.child[i].tile;
 
-			if (c.isReady) {
+			if (c.state == STATE_READY) {
 				drawTile(c);
 				drawn++;
 			}
@@ -669,7 +679,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 			if (!drawProxyChild(tile)) {
 				if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
 					MapTile t = tile.rel.parent.tile;
-					if (t.isReady) {
+					if (t.state == STATE_READY) {
 						drawTile(t);
 						drawn = true;
 					}
@@ -677,7 +687,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 
 				if (!drawn && (tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
 					MapTile t = tile.rel.parent.parent.tile;
-					if (t.isReady)
+					if (t.state == STATE_READY)
 						drawTile(t);
 
 				}
@@ -686,14 +696,14 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 			// prefer drawing parent
 			MapTile t = tile.rel.parent.tile;
 
-			if (t != null && t.isReady) {
+			if (t != null && t.state == STATE_READY) {
 				drawTile(t);
 
 			} else if (!drawProxyChild(tile)) {
 
 				if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
 					t = tile.rel.parent.parent.tile;
-					if (t.isReady)
+					if (t.state == STATE_READY)
 						drawTile(t);
 				}
 			}
@@ -789,4 +799,33 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 	void clearBuffer() {
 		mNewSurface = true;
 	}
+
+	public static void enableVertexArrays(int va1, int va2) {
+		if (va1 > 1 || va2 > 1)
+			Log.d(TAG, "FIXME: enableVertexArrays...");
+
+		if ((va1 == 0 || va2 == 0)) {
+			if (!vertexArray[0]) {
+				GLES20.glEnableVertexAttribArray(0);
+				vertexArray[0] = true;
+			}
+		} else {
+			if (vertexArray[0]) {
+				GLES20.glDisableVertexAttribArray(0);
+				vertexArray[0] = false;
+			}
+		}
+
+		if ((va1 == 1 || va2 == 1)) {
+			if (!vertexArray[1]) {
+				GLES20.glEnableVertexAttribArray(1);
+				vertexArray[1] = true;
+			}
+		} else {
+			if (vertexArray[1]) {
+				GLES20.glDisableVertexAttribArray(1);
+				vertexArray[1] = false;
+			}
+		}
+	}
 }
diff --git a/src/org/oscim/renderer/MapTile.java b/src/org/oscim/renderer/MapTile.java
index 68f7ee0d..8409c93d 100644
--- a/src/org/oscim/renderer/MapTile.java
+++ b/src/org/oscim/renderer/MapTile.java
@@ -37,12 +37,12 @@ public final class MapTile extends JobTile {
 	/**
 	 * tile has new data to upload to gl
 	 */
-	boolean newData;
+	//boolean newData;
 
 	/**
 	 * tile is loaded and ready for drawing.
 	 */
-	boolean isReady;
+	//boolean isReady;
 
 	/**
 	 * tile is in view region.
@@ -80,7 +80,7 @@ public final class MapTile extends JobTile {
 	}
 
 	boolean isActive() {
-		return isLoading || newData || isReady;
+		return state != 0;
 	}
 
 	boolean isLocked() {
@@ -91,18 +91,22 @@ public final class MapTile extends JobTile {
 
 		locked++;
 
-		if (locked > 1 || isReady || newData)
+		if (locked > 1)
 			return;
 
+		//if (isReady || newData)
+		// return;
+
 		MapTile p = rel.parent.tile;
 
-		if (p != null && (p.isReady || p.newData || p.isLoading)) {
+		if (p != null && (p.state != 0)) {
 			proxies |= PROXY_PARENT;
 			p.refs++;
 		}
 
+		// FIXME handle root-tile case?
 		p = rel.parent.parent.tile;
-		if (p != null && (p.isReady || p.newData || p.isLoading)) {
+		if (p != null && (p.state != 0)) {
 			proxies |= PROXY_GRAMPA;
 			p.refs++;
 		}
@@ -110,7 +114,7 @@ public final class MapTile extends JobTile {
 		for (int j = 0; j < 4; j++) {
 			if (rel.child[j] != null) {
 				p = rel.child[j].tile;
-				if (p != null && (p.isReady || p.newData || p.isLoading)) {
+				if (p != null && (p.state != 0)) {
 					proxies |= (1 << j);
 					p.refs++;
 				}
diff --git a/src/org/oscim/renderer/TileGenerator.java b/src/org/oscim/renderer/TileGenerator.java
index b967220a..f398e805 100644
--- a/src/org/oscim/renderer/TileGenerator.java
+++ b/src/org/oscim/renderer/TileGenerator.java
@@ -14,6 +14,8 @@
  */
 package org.oscim.renderer;
 
+import static org.oscim.generator.JobTile.STATE_NONE;
+
 import org.oscim.core.MercatorProjection;
 import org.oscim.core.Tag;
 import org.oscim.core.Tile;
@@ -38,7 +40,6 @@ import org.oscim.view.MapView;
 
 import android.graphics.Bitmap;
 import android.graphics.Paint;
-import android.util.FloatMath;
 import android.util.Log;
 
 /**
@@ -395,13 +396,10 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
 		mDebugDrawPolygons = !debugSettings.mDisablePolygons;
 		mDebugDrawUnmatched = debugSettings.mDrawUnmatchted;
 
-		if (tile.newData || tile.isReady || tile.layers != null) {
+		if (tile.layers != null) {
 			// should be fixed now.
 			Log.d(TAG, "XXX tile already loaded "
-					+ tile + " "
-					+ tile.newData + " "
-					+ tile.isReady + " "
-					+ tile.isLoading);
+					+ tile + " " + tile.state);
 			return false;
 		}
 
@@ -415,8 +413,8 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
 
 		// acount for area changes with latitude
 		mProjectionScaleFactor = 0.5f + 0.5f * (
-				FloatMath.sin((float) (Math.abs(MercatorProjection
-						.pixelYToLatitude(tile.pixelY, tile.zoomLevel)) * (Math.PI / 180))));
+				(float) Math.sin(Math.abs(MercatorProjection
+						.pixelYToLatitude(tile.pixelY, tile.zoomLevel)) * (Math.PI / 180)));
 
 		mLayers = new Layers();
 
@@ -426,7 +424,9 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
 			mLayers = null;
 			mLabels = null;
 			mCurLineLayer = null;
-			tile.isLoading = false;
+
+			// FIXME add STATE_FAILED?
+			tile.state = STATE_NONE;
 			return false;
 		}
 
diff --git a/src/org/oscim/renderer/TileManager.java b/src/org/oscim/renderer/TileManager.java
index 7a19f858..1bdab9f0 100644
--- a/src/org/oscim/renderer/TileManager.java
+++ b/src/org/oscim/renderer/TileManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Hannes Janetzek
+ * Copyright 2012 OpenScienceMap
  *
  * This program is free software: you can redistribute it and/or modify it under the
  * terms of the GNU Lesser General Public License as published by the Free Software
@@ -12,8 +12,14 @@
  * You should have received a copy of the GNU Lesser General Public License along with
  * this program. If not, see <http://www.gnu.org/licenses/>.
  */
+
 package org.oscim.renderer;
 
+import static org.oscim.generator.JobTile.STATE_LOADING;
+import static org.oscim.generator.JobTile.STATE_NEW_DATA;
+import static org.oscim.generator.JobTile.STATE_NONE;
+import static org.oscim.generator.JobTile.STATE_READY;
+
 import java.util.ArrayList;
 import java.util.Collections;
 
@@ -25,9 +31,11 @@ import org.oscim.renderer.layer.VertexPool;
 import org.oscim.view.MapView;
 import org.oscim.view.MapViewPosition;
 
-import android.util.FloatMath;
 import android.util.Log;
 
+/**
+ * @author Hannes Janetzek
+ */
 public class TileManager {
 	static final String TAG = TileManager.class.getSimpleName();
 
@@ -266,11 +274,7 @@ public class TileManager {
 				td = new TileSet(newTiles.length);
 				mTileSets.add(td);
 			}
-			// else if (td.serial > mUpdateCnt) {
-			// Log.d(TAG, "ignore previous tile data " + td.cnt);
-			// // tile data was cleared, ignore tiles
-			// td.cnt = 0;
-			// }
+
 			nextTiles = td.tiles;
 
 			// unlock previously active tiles
@@ -442,9 +446,7 @@ public class TileManager {
 
 	private static void clearTile(MapTile t) {
 
-		t.newData = false;
-		t.isLoading = false;
-		t.isReady = false;
+		t.state = STATE_NONE;
 
 		if (t.layers != null) {
 			t.layers.clear();
@@ -486,7 +488,7 @@ public class TileManager {
 				dx %= center;
 				dy %= center;
 				//t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) * 0.25f;
-				t.distance = FloatMath.sqrt((dx * dx + dy * dy)) * 0.25f;
+				t.distance = (float) Math.sqrt((dx * dx + dy * dy)) * 0.25f;
 			} else if (diff > 0) {
 				// tile zoom level is child of current
 
@@ -501,7 +503,7 @@ public class TileManager {
 				dx %= center;
 				dy %= center;
 				//t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy));
-				t.distance = FloatMath.sqrt((dx * dx + dy * dy));
+				t.distance = (float) Math.sqrt((dx * dx + dy * dy));
 
 			} else {
 				// tile zoom level is parent of current
@@ -510,7 +512,7 @@ public class TileManager {
 				dx %= center;
 				dy %= center;
 				//t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) * (-diff * 0.5f);
-				t.distance = FloatMath.sqrt((dx * dx + dy * dy)) * (-diff * 0.5f);
+				t.distance = (float) Math.sqrt((dx * dx + dy * dy)) * (-diff * 0.5f);
 			}
 		}
 	}
@@ -545,7 +547,7 @@ public class TileManager {
 				// dont remove tile used by GLRenderer, or somewhere else
 				Log.d(TAG, "limitCache: tile still locked " + t + " " + t.distance);
 				mTiles.add(t);
-			} else if (t.isLoading) {
+			} else if (t.state == STATE_LOADING) {
 				// NOTE: if we add tile back and set loading=false, on next
 				// limitCache the tile will be removed. clearTile could
 				// interfere with TileGenerator. so clear in passTile()
@@ -573,8 +575,8 @@ public class TileManager {
 			// remove tiles already uploaded to vbo
 			for (int i = 0; i < size;) {
 				MapTile t = mTilesLoaded.get(i);
-				// t.rel == null means tile was removed in limitCache
-				if (!t.newData || t.rel == null) {
+				// t.rel == null means tile was removed in limitCache -- but then newdata is false anyway?
+				if (t.state == STATE_READY || t.state == STATE_NONE) {// || t.rel == null) {
 					mTilesLoaded.remove(i);
 					size--;
 					continue;
@@ -614,7 +616,7 @@ public class TileManager {
 	public synchronized boolean passTile(JobTile jobTile) {
 		MapTile tile = (MapTile) jobTile;
 
-		if (!tile.isLoading) {
+		if (tile.state != STATE_LOADING) {
 			// no one should be able to use this tile now, TileGenerator passed
 			// it, GL-Thread does nothing until newdata is set.
 			//Log.d(TAG, "passTile: failed loading " + tile);
@@ -631,12 +633,15 @@ public class TileManager {
 
 		if (tile.vbo == null) {
 			Log.d(TAG, "no VBOs left for " + tile);
-			tile.isLoading = false;
+			//tile.isLoading = false;
+			clearTile(tile);
 			return true;
 		}
 
-		tile.newData = true;
-		tile.isLoading = false;
+		tile.state = STATE_NEW_DATA;
+
+		//tile.newData = true;
+		//tile.isLoading = false;
 
 		mMapView.render();