diff --git a/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/utils/Tessellator.java b/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/utils/Tessellator.java index e2f04c87..a22a93de 100644 --- a/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/utils/Tessellator.java +++ b/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/utils/Tessellator.java @@ -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)/*-{ diff --git a/vtm/jni/tessellate/TessellateJni.c b/vtm/jni/tessellate/TessellateJni.c index bfa0a776..928ddd3e 100644 --- a/vtm/jni/tessellate/TessellateJni.c +++ b/vtm/jni/tessellate/TessellateJni.c @@ -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; diff --git a/vtm/jni/tessellate/tessellate.c b/vtm/jni/tessellate/tessellate.c index 7bedfcc4..33c0f4e9 100644 --- a/vtm/jni/tessellate/tessellate.c +++ b/vtm/jni/tessellate/tessellate.c @@ -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; } diff --git a/vtm/jni/tessellate/tessellate.h b/vtm/jni/tessellate/tessellate.h index 0a2d5148..58849e47 100644 --- a/vtm/jni/tessellate/tessellate.h +++ b/vtm/jni/tessellate/tessellate.h @@ -14,6 +14,7 @@ typedef struct Vertex { typedef struct TessContext { Triangle *latest_t; int n_tris; + int reversed; Vertex *v_prev; Vertex *v_prevprev; diff --git a/vtm/src/org/oscim/renderer/elements/ExtrusionLayer.java b/vtm/src/org/oscim/renderer/elements/ExtrusionLayer.java index e6a5a01b..8dc65d39 100644 --- a/vtm/src/org/oscim/renderer/elements/ExtrusionLayer.java +++ b/vtm/src/org/oscim/renderer/elements/ExtrusionLayer.java @@ -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); diff --git a/vtm/src/org/oscim/utils/Tessellator.java b/vtm/src/org/oscim/utils/Tessellator.java index 3d16db4e..68ec3cfe 100644 --- a/vtm/src/org/oscim/utils/Tessellator.java +++ b/vtm/src/org/oscim/utils/Tessellator.java @@ -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); }