improve Tessellator, no more 'synchronized' needed

- pass VertexItem arrays to tessGetVertices/Indices until
  everything is fetched
- re-reverse vertices in jni
This commit is contained in:
Hannes Janetzek 2013-09-25 02:50:48 +02:00
parent 768df7f6d6
commit 836f6a60e0
6 changed files with 291 additions and 71 deletions

View File

@ -1,6 +1,7 @@
package org.oscim.utils;
import org.oscim.backend.Log;
import org.oscim.core.GeometryBuffer;
import org.oscim.renderer.elements.VertexItem;
import com.google.gwt.core.client.JavaScriptException;
@ -11,7 +12,7 @@ import com.google.gwt.typedarrays.shared.Int32Array;
public class Tessellator {
public static synchronized int triangulate(float[] points, int ppos, int plen, short[] index,
public static int tessellate(float[] points, int ppos, int plen, short[] index,
int ipos, int rings, int vertexOffset, VertexItem outTris) {
//JavaScriptObject o;
@ -68,6 +69,15 @@ public class Tessellator {
return numIndices;
}
public static int tessellate(GeometryBuffer geom, GeometryBuffer out) {
return 0;
}
public static int tessellate(GeometryBuffer geom, float scale,
VertexItem outPoints, VertexItem outTris, int vertexOffset) {
return 0;
}
static native Int32Array tessellate(JsArrayNumber points, int pOffset, int pLength,
JsArrayInteger bounds, int bOffset, int bLength)/*-{

View File

@ -31,8 +31,20 @@ void Java_org_oscim_utils_Tessellator_tessFinish(JNIEnv *env, jclass c, jlong pt
free(ctx);
}
jint Java_org_oscim_utils_Tessellator_tessGetCoordinates(JNIEnv *env, jclass c,
jlong ptr_context, jshortArray obj_coords, jfloat scale) {
Vertex *reverse(Vertex *root) {
Vertex *start = 0;
while (root) {
Vertex *prev = root->prev;
root->prev = start;
start = root;
root = prev;
}
return start;
}
jint Java_org_oscim_utils_Tessellator_tessGetVerticesWO(JNIEnv *env, jclass c,
jlong ptr_context, jshortArray obj_coords, jint offset, jfloat scale) {
TessContext *ctx = CAST_CTX(ptr_context);
@ -43,23 +55,33 @@ jint Java_org_oscim_utils_Tessellator_tessGetCoordinates(JNIEnv *env, jclass c,
return 0;
}
//int n_verts = 1 + ctx->latest_v->index;
//int n_tris_copy = ctx->n_tris;
if (!ctx->reversed) {
ctx->reversed = 1;
ctx->latest_v = reverse(ctx->latest_v);
}
int cnt = 0;
for (; ctx->latest_v && cnt < length; cnt += 2) {
coords[cnt + 0] = (ctx->latest_v->pt[0] * scale) + 0.5f;
coords[cnt + 1] = (ctx->latest_v->pt[1] * scale) + 0.5f;
int pos = offset;
for (; ctx->latest_v && pos < length; pos += 2) {
coords[pos + 0] = (ctx->latest_v->pt[0] * scale) + 0.5f;
coords[pos + 1] = (ctx->latest_v->pt[1] * scale) + 0.5f;
Vertex *prev = ctx->latest_v->prev;
free(ctx->latest_v);
ctx->latest_v = prev;
}
(*env)->ReleasePrimitiveArrayCritical(env, obj_coords, coords, JNI_ABORT);
return cnt;
return pos - offset;
}
jint Java_org_oscim_utils_Tessellator_tessGetCoordinatesD(JNIEnv *env, jclass c,
jint Java_org_oscim_utils_Tessellator_tessGetVertices(JNIEnv *env, jclass c,
jlong ptr_context, jshortArray obj_coords, jfloat scale) {
return Java_org_oscim_utils_Tessellator_tessGetVerticesWO(env, c, ptr_context, obj_coords, 0,
scale);
}
jint Java_org_oscim_utils_Tessellator_tessGetVerticesD(JNIEnv *env, jclass c,
jlong ptr_context, jdoubleArray obj_coords) {
TessContext *ctx = CAST_CTX(ptr_context);
@ -71,8 +93,10 @@ jint Java_org_oscim_utils_Tessellator_tessGetCoordinatesD(JNIEnv *env, jclass c,
return 0;
}
//int n_verts = 1 + ctx->latest_v->index;
//int n_tris_copy = ctx->n_tris;
if (!ctx->reversed) {
ctx->reversed = 1;
ctx->latest_v = reverse(ctx->latest_v);
}
int cnt = 0;
for (; ctx->latest_v && cnt < length; cnt += 2) {
@ -88,8 +112,8 @@ jint Java_org_oscim_utils_Tessellator_tessGetCoordinatesD(JNIEnv *env, jclass c,
return cnt;
}
jint Java_org_oscim_utils_Tessellator_tessGetIndices(JNIEnv *env, jclass c,
jlong ptr_context, jshortArray obj_indices) {
jint Java_org_oscim_utils_Tessellator_tessGetIndicesWO(JNIEnv *env, jclass c,
jlong ptr_context, jshortArray obj_indices, int offset) {
TessContext *ctx = CAST_CTX(ptr_context);
@ -102,12 +126,12 @@ jint Java_org_oscim_utils_Tessellator_tessGetIndices(JNIEnv *env, jclass c,
int n_tris_copy = ctx->n_tris;
int cnt = 0;
int pos = offset;
for (; ctx->latest_t && cnt < length; cnt += 3) {
tris[cnt + 0] = ctx->latest_t->v[0];
tris[cnt + 1] = ctx->latest_t->v[1];
tris[cnt + 2] = ctx->latest_t->v[2];
for (; ctx->latest_t && pos < length; pos += 3) {
tris[pos + 0] = ctx->latest_t->v[0];
tris[pos + 1] = ctx->latest_t->v[1];
tris[pos + 2] = ctx->latest_t->v[2];
Triangle *prev = ctx->latest_t->prev;
free(ctx->latest_t);
@ -119,7 +143,15 @@ jint Java_org_oscim_utils_Tessellator_tessGetIndices(JNIEnv *env, jclass c,
(*env)->ReleasePrimitiveArrayCritical(env, obj_indices, tris, JNI_ABORT);
return cnt;
return pos - offset;
}
jint Java_org_oscim_utils_Tessellator_tessGetIndices(JNIEnv *env, jclass c,
jlong ptr_context, jshortArray obj_indices, int offset){
return Java_org_oscim_utils_Tessellator_tessGetIndicesWO(env, c,
ptr_context, obj_indices, 0);
}
jlong Java_org_oscim_utils_Tessellator_tessellate(JNIEnv *env, jclass c,
@ -166,7 +198,6 @@ jlong Java_org_oscim_utils_Tessellator_tessellate(JNIEnv *env, jclass c,
nverts = 1 + ctx->latest_v->index;
ntris = ctx->n_tris;
jint* out = (jint*) (*env)->GetPrimitiveArrayCritical(env, obj_out, &isCopy);
if (out == NULL) {
return 0;

View File

@ -24,6 +24,7 @@ TessContext *new_tess_context()
result->v_prev = NULL;
result->vertex_cb = &skip_vertex;
result->odd_even_strip = 0;
result->reversed = 0;
return result;
}

View File

@ -14,6 +14,7 @@ typedef struct Vertex {
typedef struct TessContext {
Triangle *latest_t;
int n_tris;
int reversed;
Vertex *v_prev;
Vertex *v_prevprev;

View File

@ -26,6 +26,7 @@ import org.oscim.renderer.BufferObject;
import org.oscim.renderer.MapRenderer;
import org.oscim.utils.LineClipper;
import org.oscim.utils.Tessellator;
import org.oscim.utils.pool.Inlist;
/**
* @author Hannes Janetzek
@ -139,7 +140,8 @@ public class ExtrusionLayer extends RenderElement {
if (simpleOutline && (ipos < n - 1) && (index[ipos + 1] > 0))
simpleOutline = false;
boolean convex = addOutline(points, ppos, len, minHeight, height, simpleOutline);
boolean convex = addOutline(points, ppos, len, minHeight,
height, simpleOutline);
if (simpleOutline && (convex || len <= 8)) {
addRoofSimple(startVertex, len);
@ -184,20 +186,14 @@ public class ExtrusionLayer extends RenderElement {
rings++;
}
int used = Tessellator.triangulate(points, ppos, len, index, ipos, rings,
startVertex + 1, mCurIndices[IND_ROOF]);
Tessellator.tessellate(points, ppos, len, index, ipos, rings,
startVertex + 1, mCurIndices[IND_ROOF]);
if (used > 0) {
// get back to the last item added..
VertexItem it = mIndices[IND_ROOF];
while (it.next != null)
it = it.next;
mCurIndices[IND_ROOF] = it;
}
mCurIndices[IND_ROOF] = Inlist.last(mCurIndices[IND_ROOF]);
}
private boolean addOutline(float[] points, int pos, int len, float minHeight, float height,
boolean convex) {
private boolean addOutline(float[] points, int pos, int len, float minHeight,
float height, boolean convex) {
// add two vertices for last face to make zigzag indices work
boolean addFace = (len % 4 != 0);

View File

@ -1,14 +1,32 @@
package org.oscim.utils;
import java.util.Arrays;
import org.oscim.backend.Log;
import org.oscim.core.GeometryBuffer;
import org.oscim.renderer.elements.VertexItem;
public class Tessellator {
private static final String TAG = Tessellator.class.getName();
private static final int RESULT_VERTICES = 0;
//private static final int RESULT_TRIANGLES = 1;
private static final int RESULT_TRIANGLES = 1;
private static final short[] coordinates = new short[720];
public static synchronized int triangulate(float[] points, int ppos, int plen, short[] index,
/**
* Special version for ExtrusionLayer to match indices with vertex
* positions.
*
* @param points
* @param ppos
* @param plen
* @param index
* @param ipos
* @param rings
* @param vertexOffset
* @param outTris
* @return
*/
public static int tessellate(float[] points, int ppos, int plen, short[] index,
int ipos, int rings, int vertexOffset, VertexItem outTris) {
int[] result = new int[2];
@ -19,27 +37,28 @@ public class Tessellator {
long ctx = Tessellator.tessellate(points, ppos, index, ipos, rings, result);
if ((numPoints / 2) < result[RESULT_VERTICES]) {
//Log.d(TAG, "nup" + Arrays.toString(result) + " " + numPoints);
Log.d(TAG, "skip poly: " + Arrays.toString(result) + " " + numPoints);
Tessellator.tessFinish(ctx);
return 0;
}
//while (Tessellator.tessGetCoordinates(ctx, coordinates, 2) > 0) {
// Log.d(TAG, Arrays.toString(coordinates));
//}
int cnt;
int numIndices = 0;
while ((cnt = Tessellator.tessGetIndices(ctx, coordinates)) > 0) {
//if (cnt > (VertexItem.SIZE - outTris.used))
// Log.d(TAG, "ok" + Arrays.toString(result));
if (outTris.used == VertexItem.SIZE) {
outTris.next = VertexItem.pool.get();
outTris = outTris.next;
}
//Log.d(TAG,Arrays.toString(coordinates));
numIndices += cnt;
while ((cnt = Tessellator.tessGetIndicesWO(ctx,
outTris.vertices,
outTris.used)) > 0) {
int start = outTris.used;
int end = start + cnt;
short[] v = outTris.vertices;
for (int j = 0; j < cnt; j++)
coordinates[j] *= 2;
for (int i = start; i < end; i++)
v[i] *= 2;
// when a ring has an odd number of points one (or rather two)
// additional vertices will be added. so the following rings
@ -52,30 +71,185 @@ public class Tessellator {
if (((index[ipos + i] >> 1) & 1) == 0)
continue;
for (int j = 0; j < cnt; j++)
if (coordinates[j] >= shift)
coordinates[j] += 2;
for (int j = start; j < end; j++)
if (v[j] >= shift)
v[j] += 2;
shift += 2;
}
for (int j = 0; j < cnt;) {
int outPos = outTris.used;
short[] v = outTris.vertices;
// shift by vertexOffset
for (int i = start; i < end; i++)
v[i] += vertexOffset;
if (outPos == VertexItem.SIZE) {
outTris.next = VertexItem.pool.get();
outTris = outTris.next;
v = outTris.vertices;
outPos = 0;
}
outTris.used += cnt;
numIndices += cnt;
// shift to vertex offset
v[outPos++] = (short) (vertexOffset + coordinates[j++]);
v[outPos++] = (short) (vertexOffset + coordinates[j++]);
v[outPos++] = (short) (vertexOffset + coordinates[j++]);
outTris.used = outPos;
if (outTris.used == VertexItem.SIZE) {
outTris.next = VertexItem.pool.get();
outTris = outTris.next;
continue;
}
// no more indices to get.
break;
}
Tessellator.tessFinish(ctx);
return numIndices;
}
/**
* Untested!
*
* @param geom
* @param out
* @return
*/
public static int tessellate(GeometryBuffer geom, GeometryBuffer out) {
int[] result = new int[2];
//int numPoints = 0;
//for (int i = 0; i < rings; i++)
// numPoints += index[ipos + i];
int numRings = 0;
int numPoints = 0;
for (int i = 0; i < geom.indexPos; i++) {
if (geom.index[i] > 0) {
numRings++;
numPoints += geom.index[i];
} else
break;
}
long ctx = Tessellator.tessellate(geom.points, 0, geom.index, 0, numRings, result);
Log.d(TAG, "got " + result[RESULT_VERTICES] + " " + result[RESULT_TRIANGLES]);
boolean verticesAdded = false;
if (numPoints < result[RESULT_VERTICES] * 2) {
Log.d(TAG, "grow vertices" + geom.pointPos);
verticesAdded = true;
}
if (out == null) {
// overwrite geom contents
out = geom;
if (verticesAdded) {
out.ensurePointSize(result[RESULT_VERTICES], false);
Tessellator.tessGetVerticesFloat(ctx, out.points);
}
} else {
out.ensurePointSize(result[RESULT_VERTICES], false);
if (verticesAdded) {
Tessellator.tessGetVerticesFloat(ctx, out.points);
} else {
System.arraycopy(geom.points, 0, out.points, 0, numPoints);
}
}
out.ensureIndexSize(result[RESULT_TRIANGLES * 3], false);
Tessellator.tessGetIndices(ctx, out.index);
Tessellator.tessFinish(ctx);
return 1;
}
/**
*
* @param geom
* @param scale
* @param outPoints
* @param outTris
* @param vertexOffset
* @return
*/
public static int tessellate(GeometryBuffer geom, float scale,
VertexItem outPoints, VertexItem outTris, int vertexOffset) {
int[] result = new int[2];
//int numPoints = 0;
//for (int i = 0; i < rings; i++)
// numPoints += index[ipos + i];
int numRings = 0;
int numPoints = 0;
for (int i = 0; i <= geom.indexPos; i++) {
if (geom.index[i] <= 0)
break;
numRings++;
numPoints += (geom.index[i]) / 2;
}
if (numRings == 0 || numPoints == 0) {
Log.d(TAG, "missing " + numPoints + ":" + numRings);
return 0;
}
long ctx = Tessellator.tessellate(geom.points, 0,
geom.index, 0,
numRings, result);
if (numPoints >= result[RESULT_VERTICES]) {
// TODO use vertices from geom.points
}
if (outPoints.used == VertexItem.SIZE) {
outPoints.next = VertexItem.pool.get();
outPoints = outPoints.next;
}
int cnt;
while ((cnt = Tessellator.tessGetVerticesWO(ctx,
outPoints.vertices,
outPoints.used,
scale)) > 0) {
outPoints.used += cnt;
if (outPoints.used == VertexItem.SIZE) {
outPoints.next = VertexItem.pool.get();
outPoints = outPoints.next;
continue;
}
// no more points to get.
break;
}
int numIndices = 0;
if (outTris.used == VertexItem.SIZE) {
outTris.next = VertexItem.pool.get();
outTris = outTris.next;
}
while ((cnt = Tessellator.tessGetIndicesWO(ctx,
outTris.vertices,
outTris.used)) > 0) {
// shift by vertexOffset
for (int pos = outTris.used, end = pos + cnt; pos < end; pos++)
outTris.vertices[pos] += vertexOffset;
outTris.used += cnt;
numIndices += cnt;
if (outTris.used == VertexItem.SIZE) {
outTris.next = VertexItem.pool.get();
outTris = outTris.next;
continue;
}
// no more indices to get.
break;
}
Tessellator.tessFinish(ctx);
@ -92,12 +266,19 @@ public class Tessellator {
* @param result contains number of vertices and number of triangles
* @return context - must be freed with tessFinish()
*/
public static native long tessellate(float[] points, int pos,
protected static native long tessellate(float[] points, int pos,
short[] index, int ipos, int numRings, int[] result);
public static native void tessFinish(long ctx);
protected static native void tessFinish(long ctx);
public static native int tessGetCoordinates(long ctx, short[] coordinates, float scale);
protected static native int tessGetVertices(long ctx, short[] coordinates, float scale);
public static native int tessGetIndices(long ctx, short[] indices);
protected static native int tessGetVerticesWO(long ctx, short[] coordinates,
int offset, float scale);
protected static native int tessGetVerticesFloat(long ctx, float[] coordinates);
protected static native int tessGetIndices(long ctx, short[] indices);
protected static native int tessGetIndicesWO(long ctx, short[] indices, int offset);
}