more work on building layer

This commit is contained in:
Hannes Janetzek
2013-01-03 18:29:13 +01:00
parent 74ca621de0
commit eb278585fa
22 changed files with 1105 additions and 79 deletions

View File

@@ -0,0 +1,475 @@
/*
* Copyright 2012, 2013 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
* Foundation, either version 3 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 Lesser General Public License for more details.
*
* 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.layer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.oscim.renderer.GLRenderer;
import org.oscim.view.MapView;
import org.quake.triangle.TriangleJNI;
import android.opengl.GLES20;
import android.util.Log;
/**
* @author Hannes Janetzek
*/
public class ExtrusionLayer extends Layer {
private final static String TAG = ExtrusionLayer.class.getName();
private static final float S = GLRenderer.COORD_MULTIPLIER;
public int mIndicesBufferID;
public int mVertexBufferID;
public int mNumIndices = 0;
private int mNumVertices = 0;
private VertexPoolItem mVertices, mCurVertices;
private VertexPoolItem mIndices[], mCurIndices[];
public int mIndiceCnt[] = { 0, 0, 0 };
public ExtrusionLayer(int level) {
this.type = Layer.EXTRUSION;
this.layer = level;
mVertices = mCurVertices = VertexPool.get();
mIndices = new VertexPoolItem[3];
mCurIndices = new VertexPoolItem[3];
mIndices[0] = mCurIndices[0] = VertexPool.get();
mIndices[1] = mCurIndices[1] = VertexPool.get();
mIndices[2] = mCurIndices[2] = VertexPool.get();
}
public void addBuildings(float[] points, short[] index, int height) {
int complex = 0;
boolean simple = true;
if (height == 0)
height = 400;
else
height *= 40;
for (int i = 0, pos = 0, n = index.length; i < n; i++) {
int length = index[i];
// end marker
if (length < 0)
break;
// start next polygon
if (length == 0) {
complex = i + 1;
simple = true;
continue;
}
// need at least three points
if (length < 6) {
pos += length;
continue;
}
// check if polygon contains inner rings
//if (simple && ((i < n - 1) && (index[i + 1] > 0)))
// simple = false;
addOutline(points, pos, length, height, simple);
pos += length;
}
}
private void addOutline(float[] points, int pos, int len, float height, boolean simple) {
if (!MapView.enableClosePolygons)
len -= 2;
// add two vertices for last face to make zigzag indices work
boolean addFace = (len % 4 != 0);
// Log.d(TAG, "add: " + addFace + " " + len + " (" + pos + ")");
int vertexCnt = len + (addFace ? 2 : 0);
int indicesCnt = (len >> 1) * 6;
short h = (short) height;
float cx = points[pos + len - 2];
float cy = points[pos + len - 1];
float nx = points[pos + 0];
float ny = points[pos + 1];
float vx = nx - cx;
float vy = ny - cy;
float ca = (float) Math.sqrt(vx * vx + vy * vy);
float pa = ca;
float ux = vx;
float uy = vy;
float vlight = vx > 0 ? (vx / ca) : -(vx / ca) - 0.1f;
short color1 = (short) (200 + (50 * vlight));
short fcolor = color1;
short color2 = 0;
boolean even = true;
short[] vertices = mCurVertices.vertices;
int v = mCurVertices.used;
int convex = 0;
for (int i = 0; i < len; i += 2, v += 8) {
cx = nx;
cy = ny;
if (v == VertexPoolItem.SIZE) {
mCurVertices.used = VertexPoolItem.SIZE;
mCurVertices.next = VertexPool.get();
mCurVertices = mCurVertices.next;
vertices = mCurVertices.vertices;
v = 0;
}
vertices[v + 0] = vertices[v + 4] = (short) (cx * S);
vertices[v + 1] = vertices[v + 5] = (short) (cy * S);
vertices[v + 2] = 0;
vertices[v + 6] = h;
if (i < len - 2) {
nx = points[pos + i + 2];
ny = points[pos + i + 3];
vx = nx - cx;
vy = ny - cy;
ca = (float) Math.sqrt(vx * vx + vy * vy);
if (convex > -1) {
// TODO fix for straight line...
double dir = (vx * ux + vy * uy) / (ca * pa);
if (convex == 0)
convex = dir > 0 ? 1 : 2;
else if (convex == 1)
convex = dir > 0 ? 1 : -1;
else
convex = dir > 0 ? -1 : 2;
}
vlight = vx > 0 ? (vx / ca) : -(vx / ca) - 0.1f;
color2 = (short) (200 + (50 * vlight));
} else {
color2 = fcolor;
}
short c;
if (even)
c = (short) (color1 | color2 << 8);
else
c = (short) (color2 | color1 << 8);
vertices[v + 3] = vertices[v + 7] = c;
pa = ca;
ux = vx;
uy = vy;
color1 = color2;
even = !even;
}
if (addFace) {
if (v == VertexPoolItem.SIZE) {
mCurVertices.used = VertexPoolItem.SIZE;
mCurVertices.next = VertexPool.get();
mCurVertices = mCurVertices.next;
vertices = mCurVertices.vertices;
v = 0;
}
cx = points[pos + 0];
cy = points[pos + 1];
vertices[v + 0] = vertices[v + 4] = (short) (cx * S);
vertices[v + 1] = vertices[v + 5] = (short) (cy * S);
vertices[v + 2] = 0;
vertices[v + 6] = h;
short c = (short) (color1 | fcolor << 8);
vertices[v + 3] = vertices[v + 7] = c;
v += 8;
}
mCurVertices.used = v;
// fill ZigZagQuadIndices(tm)
for (int j = 0; j < 2; j++) {
short[] indices = mCurIndices[j].vertices;
// index id relative to mCurIndices
int i = mCurIndices[j].used;
// vertex id
v = mNumVertices + (j * 2);
for (int k = j * 2; k < len; k += 4) {
short s0 = (short) (v++);
short s1 = (short) (v++);
short s2 = (short) (v++);
short s3 = (short) (v++);
if (i == VertexPoolItem.SIZE) {
mCurIndices[j].used = VertexPoolItem.SIZE;
mCurIndices[j].next = VertexPool.get();
mCurIndices[j] = mCurIndices[j].next;
indices = mCurIndices[j].vertices;
i = 0;
}
if (k + 2 == len) {
// connect last to first (when number of faces is even)
if (!addFace) {
//Log.d(TAG, "connect last " + vertexCnt + " " + len);
s2 -= len;
s3 -= len;
}
}
indices[i++] = s0;
indices[i++] = s1;
indices[i++] = s2;
indices[i++] = s1;
indices[i++] = s3;
indices[i++] = s2;
//System.out.println(" i:" + (mNumIndices + (k * 6))
// + "\t(" + s0 + "," + s1 + "," + s2
// + ")\t(" + s1 + "," + s3 + "," + s2 + ")");
}
mCurIndices[j].used = i;
}
if (simple && (len <= 8 || convex > 0)) {
//Log.d(TAG, len + " is simple " + convex);
// roof indices for convex shapes
int i = mCurIndices[2].used;
short[] indices = mCurIndices[2].vertices;
short first = (short) (mNumVertices + 1);
for (int k = 0; k < len - 4; k += 2) {
if (i == VertexPoolItem.SIZE) {
mCurIndices[2].used = VertexPoolItem.SIZE;
mCurIndices[2].next = VertexPool.get();
mCurIndices[2] = mCurIndices[2].next;
indices = mCurIndices[2].vertices;
i = 0;
}
indices[i++] = first;
//if (convex != 2) {
// cw ?
indices[i++] = (short) (first + k + 4);
indices[i++] = (short) (first + k + 2);
// } else {
// indices[i++] = (short) (first + k + 2);
// indices[i++] = (short) (first + k + 4);
// }
// System.out.println("indice:" + k + "\t" + indices[cnt - 3] + ","
// + indices[cnt - 2]+ "," + indices[cnt - 1]);
indicesCnt += 3;
}
mCurIndices[2].used = i;
} else if (len < 400) {
// triangulate up to 200 points
short first = (short) (mNumVertices + 1);
int used = triangulate(points, pos, len, mCurIndices[2], first);
if (used > 0) {
indicesCnt += used;
// find the last item added..
VertexPoolItem it = mIndices[2];
while (it.next != null)
it = it.next;
mCurIndices[2] = it;
}
// mCurIndices[2].next = VertexPool.get();
// mCurIndices[2] = mCurIndices[2].next;
// short[] indices = mCurIndices[2].vertices;
// int used = triangulate(points, pos, len, indices);
// if (used > 0) {
// short first = (short) (mNumVertices + 1);
// for (int i = 0; i < used; i += 3) {
// indices[i] = (short) (indices[i] * 2 + first);
// short tmp = indices[i + 1];
// indices[i + 1] = (short) (indices[i + 2] * 2 + first);
// indices[i + 2] = (short) (tmp * 2 + first);
// }
// mCurIndices[2].used = used;
// indicesCnt += used;
// }
} else
Log.d(TAG, "skip >>>>>>>>>> : " + len + " <<<<<<<<<<<<<");
//Log.d(TAG, "add building: " + vertexCnt);
mNumVertices += vertexCnt;
mNumIndices += indicesCnt;
}
public void compile(ShortBuffer sbuf) {
if (mNumVertices == 0 || compiled)
return;
mVboIds = new int[2];
GLES20.glGenBuffers(2, mVboIds, 0);
mIndicesBufferID = mVboIds[0];
mVertexBufferID = mVboIds[1];
// upload indices
sbuf.clear();
for (int i = 0; i < 3; i++) {
for (VertexPoolItem vi = mIndices[i]; vi != null; vi = vi.next) {
//System.out.println("put indices: " + vi.used + " " + mNumIndices);
sbuf.put(vi.vertices, 0, vi.used);
mIndiceCnt[i] += vi.used;
}
}
// Log.d(TAG,"put indices: " + mNumIndices + "=="
// + (mIndiceCnt[0] + mIndiceCnt[1] + mIndiceCnt[2])
// + " " + mIndiceCnt[0] + " " + mIndiceCnt[1] + " " + mIndiceCnt[2]);
mNumIndices = mIndiceCnt[0] + mIndiceCnt[1] + mIndiceCnt[2];
sbuf.flip();
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferID);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER,
mNumIndices * 2, sbuf, GLES20.GL_DYNAMIC_DRAW);
sbuf.clear();
// upload vertices
for (VertexPoolItem vi = mVertices; vi != null; vi = vi.next) {
//System.out.println("put vertices: " + vi.used + " " + mNumVertices);
sbuf.put(vi.vertices, 0, vi.used);
}
sbuf.flip();
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferID);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
mNumVertices * 4 * 2, sbuf, GLES20.GL_DYNAMIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
for (VertexPoolItem i : mIndices)
VertexPool.release(i);
VertexPool.release(mVertices);
compiled = true;
}
public boolean compiled = false;
int[] mVboIds;
public boolean ready;
@Override
protected void clear() {
if (compiled) {
GLES20.glDeleteBuffers(2, mVboIds, 0);
}
}
public void render() {
}
private static boolean initialized = false;
private static ShortBuffer sBuf;
private static FloatBuffer fBuf;
public static synchronized int triangulate(float[] points, int pos, int len,
VertexPoolItem item, int first) {
int numRings = 1;
if (!initialized) {
// FIXME also cleanup on shutdown!
fBuf = ByteBuffer.allocateDirect(360 * 4).order(ByteOrder.nativeOrder())
.asFloatBuffer();
sBuf = ByteBuffer.allocateDirect(720 * 2).order(ByteOrder.nativeOrder())
.asShortBuffer();
initialized = true;
}
fBuf.clear();
fBuf.put(points, pos, len);
sBuf.clear();
sBuf.put((short) (len >> 1)); // all points
sBuf.put((short) (len >> 1)); // outer ring
//sBuf.put((short)4); // inner ring
int numTris = TriangleJNI.triangulate(fBuf, numRings, sBuf, first);
int numIndices = numTris * 3;
sBuf.limit(numIndices);
sBuf.position(0);
for (int k = 0, cnt = 0; k < numIndices; k += cnt) {
cnt = VertexPoolItem.SIZE - item.used;
if (item.used == VertexPoolItem.SIZE) {
item.next = VertexPool.get();
item = item.next;
}
if (k + cnt > numIndices)
cnt = numIndices - k;
sBuf.get(item.vertices, item.used, cnt);
item.used += cnt;
}
// sBuf.get(sIndices, 0, numIndices);
//
// short[] indices = item.vertices;
// int i = item.used;
//
// for (int k = 0; k < numIndices; k += 3) {
// if (i == VertexPoolItem.SIZE) {
// item.used = VertexPoolItem.SIZE;
// item.next = VertexPool.get();
// item = item.next;
// indices = item.vertices;
// i = 0;
// }
// indices[i++] = sIndices[k + 0];
// indices[i++] = sIndices[k + 1];
// indices[i++] = sIndices[k + 2];
// }
// item.used = i;
return numIndices;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 Hannes Janetzek
* Copyright 2012, 2013 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
@@ -14,6 +14,9 @@
*/
package org.oscim.renderer.layer;
/**
* @authorHannes Janetzek
*/
public abstract class Layer {
public final static byte LINE = 0;
public final static byte POLYGON = 1;
@@ -21,15 +24,21 @@ public abstract class Layer {
public final static byte POITEXT = 3;
public final static byte SYMBOL = 4;
public final static byte BITMAP = 5;
public final static byte TEXLINE = 6;
public final static byte EXTRUSION = 7;
public byte type;
public byte type = -1;
public Layer next;
int layer;
// number of vertices this layer holds
// number of vertices for this layer
public int verticesCnt;
// vertices offset of this layer in VBO
// in case of line and polygon layer:
// - number of VERTICES offset for this layertype in VBO
// otherwise:
// - offset in byte in VBO
public int offset;
VertexPoolItem pool;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 Hannes Janetzek
* Copyright 2012, 2013 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
@@ -18,13 +18,22 @@ import java.nio.ShortBuffer;
import android.util.Log;
/**
* @author Hannes Janetzek
*/
public class Layers {
// mixed Polygon and Line layers
public Layer layers;
public int lineOffset;
public Layer textureLayers;
public int texOffset;
public Layer extrusionLayers;
// To not need to switch VertexAttribPointer positions all the time:
// 1. polygons are packed in VBO at offset 0
// 2. lines afterwards at lineOffset
// 3. other layers keep their byte offset in Layer.offset
public int lineOffset;
private Layer mCurLayer;
@@ -78,10 +87,78 @@ public class Layers {
return ret;
}
// public boolean uploadLayers(BufferObject vbo, boolean addFill, boolean limit) {
//
// int newSize = getSize();
// if (newSize == 0) {
// // Log.d(TAG, "empty");
// return true;
// }
//
// GLES20.glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
//
// // use multiple buffers to avoid overwriting buffer while current
// // data is uploaded (or rather the blocking which is probably done to
// // avoid overwriting)
// int curBuffer = uploadCnt++ % rotateBuffers;
//
// ShortBuffer sbuf = shortBuffer[curBuffer];
//
// // add fill coordinates
// if (addFill)
// newSize += 8;
//
// if (sbuf.capacity() < newSize) {
// sbuf = ByteBuffer
// .allocateDirect(newSize * SHORT_BYTES)
// .order(ByteOrder.nativeOrder())
// .asShortBuffer();
//
// shortBuffer[curBuffer] = sbuf;
// } else {
// sbuf.clear();
// // if (addFill)
// // sbuf.position(8);
// }
//
// if (addFill)
// sbuf.put(mFillCoords, 0, 8);
//
// compile(sbuf, addFill);
//
// sbuf.flip();
//
// if (newSize != sbuf.remaining()) {
// Log.d(TAG, "wrong size: "
// + newSize + " "
// + sbuf.position() + " "
// + sbuf.limit() + " "
// + sbuf.remaining());
// return false;
// }
// newSize *= SHORT_BYTES;
//
// // reuse memory allocated for vbo when possible and allocated
// // memory is less then four times the new data
// if (vbo.size > newSize && vbo.size < newSize * 4
// && !limit) {
// GLES20.glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, sbuf);
// } else {
// //mBufferMemoryUsage += newSize - vbo.size;
// vbo.size = newSize;
// GLES20.glBufferData(GL_ARRAY_BUFFER, vbo.size, sbuf, GL_DYNAMIC_DRAW);
// //mBufferMemoryUsage += vbo.size;
// }
//
// return true;
// }
private static int LINE_VERTEX_SHORTS = 4;
private static int POLY_VERTEX_SHORTS = 2;
private static int TEXTURE_VERTEX_SHORTS = 6;
//private static int EXTRUSION_VERTEX_SHORTS = 4;
public int getSize() {
int size = 0;
@@ -91,12 +168,13 @@ public class Layers {
size += l.verticesCnt * LINE_VERTEX_SHORTS;
else
size += l.verticesCnt * POLY_VERTEX_SHORTS;
}
for (Layer l = textureLayers; l != null; l = l.next) {
for (Layer l = textureLayers; l != null; l = l.next)
size += l.verticesCnt * TEXTURE_VERTEX_SHORTS;
}
//for (Layer l = extrusionLayers; l != null; l = l.next)
// size += l.verticesCnt * EXTRUSION_VERTEX_SHORTS;
return size;
}
@@ -113,18 +191,18 @@ public class Layers {
lineOffset = sbuf.position() * 2; // * short-bytes
addLayerItems(sbuf, layers, Layer.LINE, 0);
texOffset = sbuf.position() * 2; // * short-bytes
for (Layer l = textureLayers; l != null; l = l.next) {
TextureLayer sl = (TextureLayer) l;
sl.compile(sbuf);
TextureLayer tl = (TextureLayer) l;
tl.compile(sbuf);
}
// FIXME
addLayerItems(sbuf, textureLayers, Layer.SYMBOL, 0);
// for (Layer l = extrusionLayers; l != null; l = l.next) {
// ExtrusionLayer tl = (ExtrusionLayer) l;
// tl.compile(sbuf);
// }
}
// optimization for lines and polygon: collect all pool items and add back in one go
private static void addLayerItems(ShortBuffer sbuf, Layer l, byte type, int pos) {
VertexPoolItem last = null, items = null;
@@ -136,7 +214,8 @@ public class Layers {
if (it.next == null)
sbuf.put(it.vertices, 0, it.used);
else
sbuf.put(it.vertices);
sbuf.put(it.vertices, 0, VertexPoolItem.SIZE);
last = it;
}
if (last == null)
@@ -155,8 +234,22 @@ public class Layers {
VertexPool.release(items);
}
public void clear() {
static void addPoolItems(Layer l, ShortBuffer sbuf) {
l.offset = sbuf.position() * 2; // (* short-bytes)
for (VertexPoolItem it = l.pool; it != null; it = it.next) {
if (it.next == null)
sbuf.put(it.vertices, 0, it.used);
else
sbuf.put(it.vertices, 0, VertexPoolItem.SIZE);
}
VertexPool.release(l.pool);
l.pool = null;
}
// cleanup only when layers are not used by tile or overlay anymore!
public void clear() {
while (layers != null) {
Layer l = layers;
if (l.pool != null) {
@@ -181,5 +274,20 @@ public class Layers {
l = l.next;
}
textureLayers = null;
l = extrusionLayers;
while (l != null) {
l.clear();
if (l.pool != null) {
VertexPool.release(l.pool);
l.pool = null;
l.curItem = null;
}
l = l.next;
}
extrusionLayers = null;
}
}

View File

@@ -14,8 +14,6 @@
*/
package org.oscim.renderer.layer;
import java.nio.ShortBuffer;
import org.oscim.renderer.TextureObject;
import org.oscim.renderer.TextureRenderer;
@@ -85,14 +83,16 @@ public final class SymbolLayer extends TextureLayer {
symbols = item;
}
@Override
void compile(ShortBuffer sbuf) {
if (TextureRenderer.debug)
Log.d("...", "compile");
for (TextureObject to = textures; to != null; to = to.next)
TextureObject.uploadTexture(to);
}
// @Override
// void compile(ShortBuffer sbuf) {
// if (TextureRenderer.debug)
// Log.d("...", "compile");
//
// for (TextureObject to = textures; to != null; to = to.next)
// TextureObject.uploadTexture(to);
//
// Layers.addPoolItems(this, sbuf);
// }
private final static int LBIT_MASK = 0xfffffffe;

View File

@@ -14,13 +14,10 @@
*/
package org.oscim.renderer.layer;
import java.nio.ShortBuffer;
import org.oscim.renderer.TextureObject;
import org.oscim.renderer.TextureRenderer;
import android.graphics.Canvas;
import android.util.FloatMath;
import android.util.Log;
public final class TextLayer extends TextureLayer {
@@ -92,15 +89,6 @@ public final class TextLayer extends TextureLayer {
labels = item;
}
@Override
void compile(ShortBuffer sbuf) {
if (TextureRenderer.debug)
Log.d("...", "compile");
for (TextureObject to = textures; to != null; to = to.next)
TextureObject.uploadTexture(to);
}
@Override
public boolean prepare() {
if (TextureRenderer.debug)
@@ -189,7 +177,7 @@ public final class TextLayer extends TextureLayer {
} else {
float vx = it.x1 - it.x2;
float vy = it.y1 - it.y2;
float a = FloatMath.sqrt(vx * vx + vy * vy);
float a = (float) Math.sqrt(vx * vx + vy * vy);
vx = vx / a;
vy = vy / a;

View File

@@ -17,6 +17,9 @@ package org.oscim.renderer.layer;
import java.nio.ShortBuffer;
import org.oscim.renderer.TextureObject;
import org.oscim.renderer.TextureRenderer;
import android.util.Log;
public abstract class TextureLayer extends Layer {
public TextureObject textures;
@@ -26,7 +29,15 @@ public abstract class TextureLayer extends Layer {
* @param sbuf
* buffer to add vertices
*/
abstract void compile(ShortBuffer sbuf);
void compile(ShortBuffer sbuf) {
if (TextureRenderer.debug)
Log.d("...", "compile");
for (TextureObject to = textures; to != null; to = to.next)
TextureObject.uploadTexture(to);
Layers.addPoolItems(this, sbuf);
}
abstract public boolean prepare();
}

View File

@@ -29,6 +29,15 @@ public class VertexPool {
pool = null;
}
// public static VertexPoolItem get(VertexPoolItem prev) {
// VertexPoolItem it = get();
// if (prev != null) {
// prev.next = it;
// prev.used = VertexPoolItem.SIZE;
// }
// return it;
// }
public static synchronized VertexPoolItem get() {
if (pool == null && count > 0) {