From bda73374ca50798a145fd262c8b247e4eba58534 Mon Sep 17 00:00:00 2001
From: Hannes Janetzek <hannes.janetzek@gmail.com>
Date: Mon, 17 Mar 2014 00:27:26 +0100
Subject: [PATCH] compile extrusion layers into one vbo

---
 .../org/oscim/renderer/ExtrusionRenderer.java | 85 +++++++++++++----
 .../renderer/elements/ElementLayers.java      | 12 ++-
 .../renderer/elements/ExtrusionLayer.java     | 95 ++++++++++++-------
 .../renderer/elements/RenderElement.java      | 18 ++--
 4 files changed, 142 insertions(+), 68 deletions(-)

diff --git a/vtm/src/org/oscim/renderer/ExtrusionRenderer.java b/vtm/src/org/oscim/renderer/ExtrusionRenderer.java
index 7eded407..8055b77f 100644
--- a/vtm/src/org/oscim/renderer/ExtrusionRenderer.java
+++ b/vtm/src/org/oscim/renderer/ExtrusionRenderer.java
@@ -19,6 +19,8 @@ package org.oscim.renderer;
 import static org.oscim.layers.tile.MapTile.State.NEW_DATA;
 import static org.oscim.layers.tile.MapTile.State.READY;
 
+import java.nio.ShortBuffer;
+
 import org.oscim.backend.GL20;
 import org.oscim.core.Tile;
 import org.oscim.layers.tile.MapTile;
@@ -191,15 +193,47 @@ public class ExtrusionRenderer extends LayerRenderer {
 			return true;
 
 		boolean compiled = false;
-		for (; el != null; el = (ExtrusionLayer) el.next) {
-			if (!el.compiled) {
-				int numShorts = el.sumVertices * 8;
-				el.compile(MapRenderer.getShortBuffer(numShorts));
-				GLUtils.checkGlError("...");
-			}
-			compiled |= el.compiled;
+
+		int sumIndices = 0;
+		int sumVertices = 0;
+		for (ExtrusionLayer l = el; l != null; l = (ExtrusionLayer) l.next) {
+			sumIndices += l.sumIndices;
+			sumVertices += l.sumVertices;
 		}
 
+		ShortBuffer vbuf = MapRenderer.getShortBuffer(sumVertices * 4);
+		ShortBuffer ibuf = MapRenderer.getShortBuffer(sumIndices);
+
+		for (ExtrusionLayer l = el; l != null; l = (ExtrusionLayer) l.next)
+			l.compile(vbuf, ibuf);
+
+		int size = sumIndices * 2;
+		if (ibuf.position() != sumIndices) {
+			int pos = ibuf.position();
+			log.error("invalid indice size: {} {}", sumIndices, pos);
+			size = pos * 2;
+		}
+		el.vboIndices = BufferObject.get(GL20.GL_ELEMENT_ARRAY_BUFFER, size);
+		el.vboIndices.loadBufferData(ibuf.flip(), size);
+		el.vboIndices.unbind();
+
+		//GL.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0);
+
+		size = sumVertices * 4 * 2;
+		if (vbuf.position() != sumVertices * 4) {
+			int pos = vbuf.position();
+			log.error("invalid vertex size: {} {}", sumVertices, pos);
+			size = pos * 2;
+		}
+
+		el.vboVertices = BufferObject.get(GL20.GL_ARRAY_BUFFER, size);
+		el.vboVertices.loadBufferData(vbuf.flip(), size);
+		el.vboVertices.unbind();
+
+		//GL.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);
+
+		GLUtils.checkGlError("compile extrusion layer");
+
 		return compiled;
 	}
 
@@ -238,7 +272,6 @@ public class ExtrusionRenderer extends LayerRenderer {
 				int offset = sumIndices * 2;
 				GL.glDrawElements(GL20.GL_TRIANGLES, el.numIndices[4],
 				                  GL20.GL_UNSIGNED_SHORT, offset);
-
 			}
 		}
 	}
@@ -337,6 +370,9 @@ public class ExtrusionRenderer extends LayerRenderer {
 			if (el == null)
 				continue;
 
+			if (el.vboIndices == null)
+				continue;
+
 			int d = 1;
 			if (drawAlpha) {
 				GL.glDepthFunc(GL20.GL_EQUAL);
@@ -346,10 +382,10 @@ public class ExtrusionRenderer extends LayerRenderer {
 			setMatrix(v, t, d);
 			v.mvp.setAsUniform(uExtMatrix);
 
-			for (; el != null; el = (ExtrusionLayer) el.next) {
+			el.vboIndices.bind();
+			el.vboVertices.bind();
 
-				if (el.vboIndices == null)
-					continue;
+			for (; el != null; el = (ExtrusionLayer) el.next) {
 
 				if (el.colors != currentColor) {
 					currentColor = el.colors;
@@ -357,14 +393,16 @@ public class ExtrusionRenderer extends LayerRenderer {
 					                     el.colors);
 				}
 
-				el.vboIndices.bind();
-				el.vboVertices.bind();
+				/* indices offset */
+				int indexOffset = el.indexOffset;
+				/* vertex byte offset */
+				int vertexOffset = el.getOffset();
 
 				GL.glVertexAttribPointer(uExtVertexPosition, 3,
-				                         GL20.GL_SHORT, false, 8, 0);
+				                         GL20.GL_SHORT, false, 8, vertexOffset);
 
 				GL.glVertexAttribPointer(uExtLightPosition, 2,
-				                         GL20.GL_UNSIGNED_BYTE, false, 8, 6);
+				                         GL20.GL_UNSIGNED_BYTE, false, 8, vertexOffset + 6);
 
 				/* draw extruded outlines */
 				if (el.numIndices[0] > 0) {
@@ -395,16 +433,23 @@ public class ExtrusionRenderer extends LayerRenderer {
 					v.mvp.setAsUniform(uExtMatrix);
 
 					GL.glUniform1i(uExtMode, 3);
+
+					int offset = 2 * (indexOffset
+					        + el.numIndices[0]
+					        + el.numIndices[1]
+					        + el.numIndices[2]);
+
 					GL.glDrawElements(GL20.GL_LINES, el.numIndices[3],
-					                  GL20.GL_UNSIGNED_SHORT,
-					                  (el.numIndices[0] + el.numIndices[1]
-					                  + el.numIndices[2]) * 2);
+					                  GL20.GL_UNSIGNED_SHORT, offset);
 				}
 
 				/* draw triangle meshes */
 				if (el.numIndices[4] > 0) {
-					int offset = (el.numIndices[0] + el.numIndices[1]
-					        + el.numIndices[2] + el.numIndices[3]) * 2;
+					int offset = 2 * (indexOffset
+					        + el.numIndices[0]
+					        + el.numIndices[1]
+					        + el.numIndices[2]
+					        + el.numIndices[3]);
 
 					GL.glUniform1i(uExtMode, 4);
 					GL.glDrawElements(GL20.GL_TRIANGLES, el.numIndices[4],
diff --git a/vtm/src/org/oscim/renderer/elements/ElementLayers.java b/vtm/src/org/oscim/renderer/elements/ElementLayers.java
index 9179ef49..7b2ba56b 100644
--- a/vtm/src/org/oscim/renderer/elements/ElementLayers.java
+++ b/vtm/src/org/oscim/renderer/elements/ElementLayers.java
@@ -269,16 +269,18 @@ public class ElementLayers extends TileData {
 		return layer;
 	}
 
-	private final static int[] VERTEX_SHORT_CNT = {
-	        4, // LINE_VERTEX_SHORTS
-	        6, // TEXLINE_VERTEX_SHORTS
-	        2, // POLY_VERTEX_SHORTS
-	        2, // MESH_VERTEX_SHORTS
+	public final static int[] VERTEX_SHORT_CNT = {
+	        4, // LINE_VERTEX
+	        6, // TEXLINE_VERTEX
+	        2, // POLY_VERTEX
+	        2, // MESH_VERTEX
+	        4, // EXTRUSION_VERTEX
 	};
 
 	private final static int TEXTURE_VERTEX_SHORTS = 6;
 	private final static int SHORT_BYTES = 2;
 
+	// TODO move to specific layer implementation
 	public int getSize() {
 		int size = 0;
 
diff --git a/vtm/src/org/oscim/renderer/elements/ExtrusionLayer.java b/vtm/src/org/oscim/renderer/elements/ExtrusionLayer.java
index 4d818a42..3a3613ea 100644
--- a/vtm/src/org/oscim/renderer/elements/ExtrusionLayer.java
+++ b/vtm/src/org/oscim/renderer/elements/ExtrusionLayer.java
@@ -19,8 +19,6 @@ package org.oscim.renderer.elements;
 import java.nio.ShortBuffer;
 import java.util.HashMap;
 
-import org.oscim.backend.GL20;
-import org.oscim.backend.GLAdapter;
 import org.oscim.backend.canvas.Color;
 import org.oscim.core.GeometryBuffer;
 import org.oscim.core.GeometryBuffer.GeometryType;
@@ -53,6 +51,7 @@ public class ExtrusionLayer extends RenderElement {
 	public int numIndices[] = { 0, 0, 0, 0, 0 };
 	//public int sumIndices = 0;
 	public int sumVertices = 0;
+	public int sumIndices = 0;
 
 	public BufferObject vboIndices;
 	public BufferObject vboVertices;
@@ -60,6 +59,8 @@ public class ExtrusionLayer extends RenderElement {
 	//private final static int IND_EVEN_SIDE = 0;
 	//private final static int IND_ODD_SIDE = 1;
 	private final static int IND_ROOF = 2;
+
+	// FIXME flip OUTLINE / MESH!
 	private final static int IND_OUTLINE = 3;
 	private final static int IND_MESH = 4;
 
@@ -68,8 +69,18 @@ public class ExtrusionLayer extends RenderElement {
 	public boolean compiled = false;
 	private final float mGroundResolution;
 
-	boolean filled;
+	private HashMap<Vertex, Integer> mVertexMap = new HashMap<Vertex, Integer>();
+	private Vertex mTmpVertex = new Vertex();
 
+	public int indexOffset;
+
+	//private int numIndexHits = 0;
+
+	//boolean filled;
+
+	/**
+	 * ExtrusionLayer for polygon geometries.
+	 */
 	public ExtrusionLayer(int level, float groundResolution, float[] colors) {
 		super(RenderElement.EXTRUSION);
 		this.level = level;
@@ -88,7 +99,7 @@ public class ExtrusionLayer extends RenderElement {
 	}
 
 	/**
-	 * ExtrusionLayer for Mesh elements only.
+	 * ExtrusionLayer for triangle geometries.
 	 */
 	public ExtrusionLayer(int level, float groundResolution, int color) {
 		super(RenderElement.EXTRUSION);
@@ -146,10 +157,6 @@ public class ExtrusionLayer extends RenderElement {
 		}
 	}
 
-	private HashMap<Vertex, Integer> mVertexMap = new HashMap<Vertex, Integer>();
-	private Vertex mTmpVertex = new Vertex();
-	private int numIndexHits = 0;
-
 	public void add(MapElement element) {
 		if (element.type != GeometryType.TRIS)
 			return;
@@ -221,7 +228,7 @@ public class ExtrusionLayer extends RenderElement {
 				addIndex(vertexCnt);
 				mVertexMap.put(new Vertex(key), vertexCnt++);
 			} else {
-				numIndexHits++;
+				//numIndexHits++;
 				addIndex(vertexId.intValue());
 			}
 
@@ -236,7 +243,7 @@ public class ExtrusionLayer extends RenderElement {
 				addIndex(vertexCnt);
 				mVertexMap.put(new Vertex(key), vertexCnt++);
 			} else {
-				numIndexHits++;
+				//numIndexHits++;
 				addIndex(vertexId.intValue());
 			}
 
@@ -251,7 +258,7 @@ public class ExtrusionLayer extends RenderElement {
 				addIndex(vertexCnt);
 				mVertexMap.put(new Vertex(key), vertexCnt++);
 			} else {
-				numIndexHits++;
+				//numIndexHits++;
 				addIndex(vertexId.intValue());
 			}
 		}
@@ -264,8 +271,9 @@ public class ExtrusionLayer extends RenderElement {
 
 		if (vi.used == VertexItem.SIZE) {
 			mCurVertices.used = VertexItem.SIZE;
-			mCurVertices.next = VertexItem.pool.get();
-			mCurVertices = mCurVertices.next;
+			mCurVertices = VertexItem.pool.getNext(vi);
+			//mCurVertices.next = VertexItem.pool.get();
+			//mCurVertices = mCurVertices.next;
 			vi = mCurVertices;
 		}
 
@@ -280,12 +288,16 @@ public class ExtrusionLayer extends RenderElement {
 
 		if (vi.used == VertexItem.SIZE) {
 			mCurIndices[IND_MESH].used = VertexItem.SIZE;
-			mCurIndices[IND_MESH].next = VertexItem.pool.get();
-			mCurIndices[IND_MESH] = mCurIndices[IND_MESH].next;
+			mCurIndices[IND_MESH] = VertexItem.pool.getNext(vi);
 			vi = mCurIndices[IND_MESH];
+
+			//mCurIndices[IND_MESH].next = VertexItem.pool.get();
+			//mCurIndices[IND_MESH] = mCurIndices[IND_MESH].next;
+			//vi = mCurIndices[IND_MESH];
 			//indices = mCurIndices[IND_MESH].vertices;
 			//i = 0;
 		}
+		sumIndices++;
 		vi.vertices[vi.used++] = (short) id;
 	}
 
@@ -436,9 +448,11 @@ public class ExtrusionLayer extends RenderElement {
 				indices = mCurIndices[IND_ROOF].vertices;
 				i = 0;
 			}
+
 			indices[i++] = first;
 			indices[i++] = (short) (first + k + 2);
 			indices[i++] = (short) (first + k + 4);
+			sumIndices += 3;
 		}
 		mCurIndices[IND_ROOF].used = i;
 	}
@@ -456,8 +470,8 @@ public class ExtrusionLayer extends RenderElement {
 			rings++;
 		}
 
-		Tessellator.tessellate(points, ppos, len, index, ipos, rings,
-		                       startVertex + 1, mCurIndices[IND_ROOF]);
+		sumIndices += Tessellator.tessellate(points, ppos, len, index, ipos, rings,
+		                                     startVertex + 1, mCurIndices[IND_ROOF]);
 
 		mCurIndices[IND_ROOF] = Inlist.last(mCurIndices[IND_ROOF]);
 	}
@@ -617,6 +631,7 @@ public class ExtrusionLayer extends RenderElement {
 			indices[ind + 3] = s1;
 			indices[ind + 4] = s2;
 			indices[ind + 5] = s3;
+			sumIndices += 6;
 
 			mCurIndices[even].used += 6;
 			even = (even == 0 ? 1 : 0);
@@ -636,44 +651,52 @@ public class ExtrusionLayer extends RenderElement {
 		return convex;
 	}
 
-	@Override
-	public void compile(ShortBuffer sbuf) {
+	public void complete() {
 		mVertexMap.clear();
+	}
+
+	@Override
+	public void compile(ShortBuffer vertexBuffer, ShortBuffer indexBuffer) {
+		mVertexMap.clear();
+
 		if (sumVertices == 0 || compiled)
 			return;
 
-		int sumIndices = 0;
+		indexOffset = indexBuffer.position();
+
+		//int sumIndices = 0;
 		for (int i = 0; i <= IND_MESH; i++) {
 			for (VertexItem vi = mIndices[i]; vi != null; vi = vi.next) {
-				sbuf.put(vi.vertices, 0, vi.used);
+				indexBuffer.put(vi.vertices, 0, vi.used);
 				numIndices[i] += vi.used;
 			}
-			sumIndices += numIndices[i];
+			//sumIndices += numIndices[i];
 		}
 
 		//log.debug("INDEX HITS " + numIndexHits + " / " + sumVertices + " / " + sumIndices);
 
-		int size = sumIndices * 2;
-		vboIndices = BufferObject.get(GL20.GL_ELEMENT_ARRAY_BUFFER, size);
-		vboIndices.loadBufferData(sbuf.flip(), size);
-
-		GL20 GL = GLAdapter.get();
-		GL.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0);
+		//int size = sumIndices * 2;
+		//vboIndices = BufferObject.get(GL20.GL_ELEMENT_ARRAY_BUFFER, size);
+		//vboIndices.loadBufferData(vertexBuffer.flip(), size);
+		//
+		//GL.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0);
 
 		// upload vertices
-		sbuf.clear();
+		//vertexBuffer.clear();
+
+		offset = vertexBuffer.position() * 2;
+
 		for (VertexItem vi = mVertices; vi != null; vi = vi.next)
-			sbuf.put(vi.vertices, 0, vi.used);
+			vertexBuffer.put(vi.vertices, 0, vi.used);
 
-		size = sumVertices * 4 * 2;
-		vboVertices = BufferObject.get(GL20.GL_ARRAY_BUFFER, size);
-		vboVertices.loadBufferData(sbuf.flip(), size);
-
-		GL.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);
+		//		size = sumVertices * 4 * 2;
+		//		vboVertices = BufferObject.get(GL20.GL_ARRAY_BUFFER, size);
+		//		vboVertices.loadBufferData(vertexBuffer.flip(), size);
+		//
+		//		GL.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);
 
 		clear();
 		compiled = true;
-
 		mClipper = null;
 	}
 
diff --git a/vtm/src/org/oscim/renderer/elements/RenderElement.java b/vtm/src/org/oscim/renderer/elements/RenderElement.java
index cfab11b9..ecd8d2e8 100644
--- a/vtm/src/org/oscim/renderer/elements/RenderElement.java
+++ b/vtm/src/org/oscim/renderer/elements/RenderElement.java
@@ -28,9 +28,9 @@ public abstract class RenderElement extends Inlist<RenderElement> {
 	public final static int TEXLINE = 1;
 	public final static int POLYGON = 2;
 	public final static int MESH = 3;
-	public final static int SYMBOL = 4;
-	public final static int BITMAP = 5;
-	public final static int EXTRUSION = 6;
+	public final static int EXTRUSION = 4;
+	public final static int SYMBOL = 5;
+	public final static int BITMAP = 6;
 
 	public final int type;
 
@@ -60,12 +60,12 @@ public abstract class RenderElement extends Inlist<RenderElement> {
 	}
 
 	public int getOffset() {
-	    return offset;
-    }
+		return offset;
+	}
 
 	public void setOffset(int offset) {
-	    this.offset = offset;
-    }
+		this.offset = offset;
+	}
 
 	/**
 	 * For line- and polygon-layers this is the offset
@@ -73,4 +73,8 @@ public abstract class RenderElement extends Inlist<RenderElement> {
 	 * For all other types it is the byte offset in vbo.
 	 */
 	protected int offset;
+
+	protected void compile(ShortBuffer vertexBuffer, ShortBuffer indexBuffer) {
+
+	}
 }