unify ExtrusionLayer vertex ids - TODO reduce allocations

This commit is contained in:
Hannes Janetzek 2014-03-15 05:54:33 +01:00
parent 6b388c12d1
commit 37ab92534a

View File

@ -17,6 +17,7 @@
package org.oscim.renderer.elements;
import java.nio.ShortBuffer;
import java.util.HashMap;
import org.oscim.backend.GL20;
import org.oscim.backend.GLAdapter;
@ -50,7 +51,7 @@ public class ExtrusionLayer extends RenderElement {
/** indices for: 0. even sides, 1. odd sides, 2. roof, 3. roof outline */
public int numIndices[] = { 0, 0, 0, 0, 0 };
public int sumIndices = 0;
//public int sumIndices = 0;
public int sumVertices = 0;
public BufferObject vboIndices;
@ -109,6 +110,46 @@ public class ExtrusionLayer extends RenderElement {
mIndices[4] = mCurIndices[4] = VertexItem.pool.get();
}
static class Vertex {
short x, y, z, n;
@Override
public boolean equals(Object obj) {
Vertex o = (Vertex) obj;
return x == o.x && y == o.y && z == o.z && n == o.n;
}
@Override
public int hashCode() {
int hash = 31;
hash *= x * 31;
hash *= y * 31;
hash *= n * 31;
return hash;
}
public void set(short x, short y, short z, short n) {
this.x = x;
this.y = y;
this.z = z;
this.n = n;
}
public Vertex() {
}
public Vertex(Vertex v) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
this.n = v.n;
}
}
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;
@ -116,36 +157,19 @@ public class ExtrusionLayer extends RenderElement {
short[] index = element.index;
float[] points = element.points;
// roof indices for convex shapes
int i = mCurIndices[IND_MESH].used;
short[] indices = mCurIndices[IND_MESH].vertices;
int first = sumVertices;
int vertexCnt = sumVertices;
short[] vertices = mCurVertices.vertices;
int v = mCurVertices.used;
int vertexCnt = 0;
Vertex key = mTmpVertex;
double scale = S * Tile.SIZE / 4096;
for (int k = 0, n = index.length; k < n;) {
if (index[k] < 0)
break;
// FIXME: workaround: dont overflow max index id.
if (sumVertices + vertexCnt >= 1 << 16)
if (vertexCnt >= 1 << 16)
break;
if (i == VertexItem.SIZE) {
mCurIndices[IND_MESH].used = VertexItem.SIZE;
mCurIndices[IND_MESH].next = VertexItem.pool.get();
mCurIndices[IND_MESH] = mCurIndices[IND_MESH].next;
indices = mCurIndices[IND_MESH].vertices;
i = 0;
}
indices[i++] = (short) (first + vertexCnt);
indices[i++] = (short) (first + vertexCnt + 1);
indices[i++] = (short) (first + vertexCnt + 2);
int vtx1 = index[k++] * 3;
int vtx2 = index[k++] * 3;
int vtx3 = index[k++] * 3;
@ -177,46 +201,92 @@ public class ExtrusionLayer extends RenderElement {
double len = Math.sqrt(cx * cx + cy * cy + cz * cz);
// packing the normal in two bytes
// int mx = FastMath.clamp(127 + (int) ((cx / len) * 128), 0, 0xff);
// int my = FastMath.clamp(127 + (int) ((cy / len) * 128), 0, 0xff);
// short normal = (short) ((my << 8) | (mx & NORMAL_DIR_MASK) | (cz > 0 ? 1 : 0));
double p = Math.sqrt((cz / len) * 8.0 + 8.0);
int mx = FastMath.clamp(127 + (int) ((cx / len / p) * 128), 0, 255);
int my = FastMath.clamp(127 + (int) ((cy / len / p) * 128), 0, 255);
short normal = (short) ((my << 8) | mx);
// int mx = FastMath.clamp(127 + (int) ((cx / len) * 128), 0, 0xff);
// int my = FastMath.clamp(127 + (int) ((cy / len) * 128), 0, 0xff);
// short normal = (short) ((my << 8) | (mx & NORMAL_DIR_MASK) | (cz > 0 ? 1 : 0));
key.set((short) (vx1 * scale),
(short) (vy1 * scale),
(short) (vz1 * scale),
(short) normal);
if (v == VertexItem.SIZE) {
mCurVertices.used = VertexItem.SIZE;
mCurVertices.next = VertexItem.pool.get();
mCurVertices = mCurVertices.next;
vertices = mCurVertices.vertices;
v = 0;
Integer vertexId = mVertexMap.get(key);
if (vertexId == null) {
addVertex(key);
addIndex(vertexCnt);
mVertexMap.put(new Vertex(key), vertexCnt++);
} else {
numIndexHits++;
addIndex(vertexId.intValue());
}
double s = S * Tile.SIZE / 4096;
key.set((short) (vx2 * scale),
(short) (vy2 * scale),
(short) (vz2 * scale),
(short) normal);
vertices[v++] = (short) (vx1 * s);
vertices[v++] = (short) (vy1 * s);
vertices[v++] = (short) (vz1 * s);
vertices[v++] = (short) normal;
vertexId = mVertexMap.get(key);
if (vertexId == null) {
addVertex(key);
addIndex(vertexCnt);
mVertexMap.put(new Vertex(key), vertexCnt++);
} else {
numIndexHits++;
addIndex(vertexId.intValue());
}
vertices[v++] = (short) (vx2 * s);
vertices[v++] = (short) (vy2 * s);
vertices[v++] = (short) (vz2 * s);
vertices[v++] = (short) normal;
key.set((short) (vx3 * scale),
(short) (vy3 * scale),
(short) (vz3 * scale),
(short) normal);
vertices[v++] = (short) (vx3 * s);
vertices[v++] = (short) (vy3 * s);
vertices[v++] = (short) (vz3 * s);
vertices[v++] = (short) normal;
vertexCnt += 3;
vertexId = mVertexMap.get(key);
if (vertexId == null) {
addVertex(key);
addIndex(vertexCnt);
mVertexMap.put(new Vertex(key), vertexCnt++);
} else {
numIndexHits++;
addIndex(vertexId.intValue());
}
}
mCurIndices[IND_MESH].used = i;
mCurVertices.used = v;
sumVertices += vertexCnt; //(vertexCnt / 3);
sumVertices = vertexCnt;
}
private void addVertex(Vertex vertex) {
VertexItem vi = mCurVertices;
if (vi.used == VertexItem.SIZE) {
mCurVertices.used = VertexItem.SIZE;
mCurVertices.next = VertexItem.pool.get();
mCurVertices = mCurVertices.next;
vi = mCurVertices;
}
vi.vertices[vi.used++] = vertex.x;
vi.vertices[vi.used++] = vertex.y;
vi.vertices[vi.used++] = vertex.z;
vi.vertices[vi.used++] = vertex.n;
}
private void addIndex(int id) {
VertexItem vi = mCurIndices[IND_MESH];
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;
vi = mCurIndices[IND_MESH];
//indices = mCurIndices[IND_MESH].vertices;
//i = 0;
}
vi.vertices[vi.used++] = (short) id;
}
// private void encodeNormal(float v[], int offset) {
@ -568,11 +638,11 @@ public class ExtrusionLayer extends RenderElement {
@Override
public void compile(ShortBuffer sbuf) {
mVertexMap.clear();
if (sumVertices == 0 || compiled)
return;
sumIndices = 0;
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);
@ -581,7 +651,7 @@ public class ExtrusionLayer extends RenderElement {
sumIndices += numIndices[i];
}
//log.debug("compile" + mNumIndices + " / " + mNumVertices);
//log.debug("INDEX HITS " + numIndexHits + " / " + sumVertices + " / " + sumIndices);
int size = sumIndices * 2;
vboIndices = BufferObject.get(GL20.GL_ELEMENT_ARRAY_BUFFER, size);