diff --git a/vtm-android-example/src/org/oscim/android/test/MarkerOverlayActivity.java b/vtm-android-example/src/org/oscim/android/test/MarkerOverlayActivity.java index 1bb6187d..4f85160e 100644 --- a/vtm-android-example/src/org/oscim/android/test/MarkerOverlayActivity.java +++ b/vtm-android-example/src/org/oscim/android/test/MarkerOverlayActivity.java @@ -36,6 +36,8 @@ import android.widget.Toast; public class MarkerOverlayActivity extends BitmapTileMapActivity implements OnItemGestureListener<MarkerItem> { + private MarkerSymbol mFocusMarker; + public MarkerOverlayActivity() { super(new DefaultSources.StamenToner()); } @@ -47,6 +49,9 @@ implements OnItemGestureListener<MarkerItem> { Drawable d = getResources().getDrawable(R.drawable.marker_poi); MarkerSymbol symbol = AndroidGraphics.makeMarker(d, HotspotPlace.CENTER); + d = getResources().getDrawable(R.drawable.ic_launcher); + mFocusMarker = AndroidGraphics.makeMarker(d, HotspotPlace.BOTTOM_CENTER); + ItemizedLayer<MarkerItem> markerLayer = new ItemizedLayer<MarkerItem>(mMap, new ArrayList<MarkerItem>(), symbol, this); @@ -69,6 +74,11 @@ implements OnItemGestureListener<MarkerItem> { @Override public boolean onItemSingleTapUp(int index, MarkerItem item) { + if (item.getMarker() == null) + item.setMarker(mFocusMarker); + else + item.setMarker(null); + Toast toast = Toast.makeText(this, item.getTitle(), Toast.LENGTH_SHORT); toast.show(); return true; diff --git a/vtm/src/org/oscim/layers/marker/MarkerRenderer.java b/vtm/src/org/oscim/layers/marker/MarkerRenderer.java index be47fdff..c8f2fbb3 100644 --- a/vtm/src/org/oscim/layers/marker/MarkerRenderer.java +++ b/vtm/src/org/oscim/layers/marker/MarkerRenderer.java @@ -17,6 +17,8 @@ package org.oscim.layers.marker; +import java.util.Comparator; + import org.oscim.core.MapPosition; import org.oscim.core.MercatorProjection; import org.oscim.core.Point; @@ -25,8 +27,8 @@ import org.oscim.renderer.ElementRenderer; import org.oscim.renderer.MapRenderer.Matrices; import org.oscim.renderer.elements.SymbolItem; import org.oscim.renderer.elements.SymbolLayer; +import org.oscim.utils.TimSort; import org.oscim.utils.geom.GeometryUtils; -import org.oscim.utils.pool.Inlist; //TODO //- need to sort items back to front for rendering @@ -43,15 +45,24 @@ public class MarkerRenderer extends ElementRenderer { /** increase view to show items that are partially visible */ protected int mExtents = 100; private boolean mUpdate; - private InternalItem mItems; + + private InternalItem[] mItems; + private final Point mMapPoint = new Point(); - static class InternalItem extends Inlist<InternalItem> { + static class InternalItem { MarkerItem item; boolean visible; boolean changes; float x, y; double px, py; + + float dy; + + @Override + public String toString() { + return "\n" + x + ":" + y + " / " + dy + " " + visible; + } } public MarkerRenderer(MarkerLayer<MarkerItem> markerLayer, MarkerSymbol defaultSymbol) { @@ -72,8 +83,8 @@ public class MarkerRenderer extends ElementRenderer { double my = pos.y; double scale = Tile.SIZE * pos.scale; - int changesInvisible = 0; - int changedVisible = 0; + //int changesInvisible = 0; + //int changedVisible = 0; int numVisible = 0; mMarkerLayer.map().viewport().getMapExtents(mBox, mExtents); @@ -88,8 +99,12 @@ public class MarkerRenderer extends ElementRenderer { return; } + double angle = Math.toRadians(pos.angle); + float cos = (float) Math.cos(angle); + float sin = (float) Math.sin(angle); + /* check visibility */ - for (InternalItem it = mItems; it != null; it = it.next) { + for (InternalItem it : mItems) { it.changes = false; it.x = (float) ((it.px - mx) * scale); it.y = (float) ((it.py - my) * scale); @@ -102,13 +117,16 @@ public class MarkerRenderer extends ElementRenderer { if (!GeometryUtils.pointInPoly(it.x, it.y, mBox, 8, 0)) { if (it.visible) { it.changes = true; - changesInvisible++; + //changesInvisible++; } continue; } + + it.dy = sin * it.x + cos * it.y; + if (!it.visible) { it.visible = true; - changedVisible++; + //changedVisible++; } numVisible++; } @@ -117,15 +135,21 @@ public class MarkerRenderer extends ElementRenderer { /* only update when zoomlevel changed, new items are visible * or more than 10 of the current items became invisible */ - if ((numVisible == 0) && (changedVisible == 0 && changesInvisible < 10)) - return; - - /* keep position for current state */ - mMapPosition.copy(pos); - + //if ((numVisible == 0) && (changedVisible == 0 && changesInvisible < 10)) + // return; layers.clear(); - for (InternalItem it = mItems; it != null; it = it.next) { + if (numVisible == 0) { + compile(); + return; + } + /* keep position for current state */ + mMapPosition.copy(pos); + mMapPosition.angle = -mMapPosition.angle; + + sort(mItems, 0, mItems.length); + //log.debug(Arrays.toString(mItems)); + for (InternalItem it : mItems) { if (!it.visible) continue; @@ -139,14 +163,9 @@ public class MarkerRenderer extends ElementRenderer { marker = mDefaultMarker; SymbolItem s = SymbolItem.pool.get(); - s.bitmap = marker.getBitmap(); - - s.x = it.x; - s.y = it.y; + s.set(it.x, it.y, marker.getBitmap(), true); s.offset = marker.getHotspot(); - s.billboard = true; - - mSymbolLayer.addSymbol(s); + mSymbolLayer.pushSymbol(s); } mSymbolLayer.prepare(); @@ -155,29 +174,13 @@ public class MarkerRenderer extends ElementRenderer { compile(); } - @Override - public synchronized void compile() { - super.compile(); - } + protected void populate(int size) { - protected synchronized void populate(int size) { - - InternalItem pool = mItems; - mItems = null; + InternalItem[] tmp = new InternalItem[size]; for (int i = 0; i < size; i++) { - InternalItem it; - if (pool != null) { - it = pool; - it.visible = false; - it.changes = false; - pool = pool.next; - } else { - it = new InternalItem(); - } - it.next = mItems; - mItems = it; - + InternalItem it = new InternalItem(); + tmp[i] = it; it.item = mMarkerLayer.createItem(i); /* pre-project points */ @@ -185,6 +188,44 @@ public class MarkerRenderer extends ElementRenderer { it.px = mMapPoint.x; it.py = mMapPoint.y; } + synchronized (this) { + mUpdate = true; + mItems = tmp; + } + } + + static TimSort<InternalItem> ZSORT = new TimSort<InternalItem>(); + + public static void sort(InternalItem[] a, int lo, int hi) { + int nRemaining = hi - lo; + if (nRemaining < 2) { + return; + } + + ZSORT.doSort(a, zComparator, lo, hi); + } + + final static Comparator<InternalItem> zComparator = new Comparator<InternalItem>() { + @Override + public int compare(InternalItem a, InternalItem b) { + if (a.visible && b.visible) { + if (a.dy > b.dy) { + return -1; + } + if (a.dy < b.dy) { + return 1; + } + } else if (a.visible) { + return -1; + } else if (b.visible) { + return 1; + } + + return 0; + } + }; + + public void update() { mUpdate = true; } diff --git a/vtm/src/org/oscim/renderer/ElementRenderer.java b/vtm/src/org/oscim/renderer/ElementRenderer.java index b8ce4c9f..27650c68 100644 --- a/vtm/src/org/oscim/renderer/ElementRenderer.java +++ b/vtm/src/org/oscim/renderer/ElementRenderer.java @@ -47,7 +47,7 @@ import org.slf4j.LoggerFactory; */ public abstract class ElementRenderer extends LayerRenderer { - static final Logger log = LoggerFactory.getLogger(ElementRenderer.class); + public static final Logger log = LoggerFactory.getLogger(ElementRenderer.class); private static short[] fillCoords; diff --git a/vtm/src/org/oscim/renderer/elements/SymbolLayer.java b/vtm/src/org/oscim/renderer/elements/SymbolLayer.java index 85ae1803..7e5201c5 100644 --- a/vtm/src/org/oscim/renderer/elements/SymbolLayer.java +++ b/vtm/src/org/oscim/renderer/elements/SymbolLayer.java @@ -33,35 +33,42 @@ public final class SymbolLayer extends TextureLayer { private final static int LBIT_MASK = 0xfffffffe; private TextureItem prevTextures; - private SymbolItem symbols; + private List<SymbolItem> mSymbols = new List<SymbolItem>(); public SymbolLayer() { super(RenderElement.SYMBOL); fixed = true; } - // TODO move sorting items to 'prepare' + /* TODO move sorting items to 'prepare' */ public void addSymbol(SymbolItem item) { - // needed to calculate 'sbuf' size for compile + /* needed to calculate 'sbuf' size for compile */ numVertices += VERTICES_PER_SPRITE; - for (SymbolItem it = symbols; it != null; it = it.next) { + for (SymbolItem it : mSymbols) { if (it.bitmap == item.bitmap) { - // insert after same bitmap + /* insert after same bitmap */ item.next = it.next; it.next = item; return; } } + mSymbols.push(item); - item.next = symbols; - symbols = item; + //item.next = mSymbols; + //mSymbols = item; + } + + public void pushSymbol(SymbolItem item) { + /* needed to calculate 'sbuf' size for compile */ + numVertices += VERTICES_PER_SPRITE; + mSymbols.push(item); } @Override protected void compile(ShortBuffer sbuf) { - // offset of layer data in vbo + /* offset of layer data in vbo */ this.offset = sbuf.position() * 2; //SHORT_BYTES; short numIndices = 0; @@ -75,18 +82,17 @@ public final class SymbolLayer extends TextureLayer { textures = null; TextureItem t = null; - for (SymbolItem it = symbols; it != null;) { + for (SymbolItem it = mSymbols.getHead(); it != null;) { int width = 0, height = 0; int x = 0; int y = 0; if (it.texRegion != null) { - - // FIXME this work only with one TextureAtlas per SymbolLayer. + /* FIXME this work only with one TextureAtlas per SymbolLayer */ if (textures == null) { t = it.texRegion.atlas.loadTexture(); - // clone TextureItem to use same texID with - // multiple TextureItem + /* clone TextureItem to use same texID with + * multiple TextureItem */ t = TextureItem.clone(t); textures = Inlist.appendItem(textures, t); } @@ -124,7 +130,7 @@ public final class SymbolLayer extends TextureLayer { PointF prevOffset = null; short x1 = 0, y1 = 0, x2 = 0, y2 = 0; - // add symbol items referencing the same bitmap / + /* add symbol items referencing the same bitmap */ for (SymbolItem prev = it; it != null; it = it.next) { if (prev.bitmap != null && prev.bitmap != it.bitmap) @@ -153,7 +159,7 @@ public final class SymbolLayer extends TextureLayer { } } - // add vertices + /* add vertices */ short tx = (short) ((int) (SCALE * it.x) & LBIT_MASK | (it.billboard ? 1 : 0)); @@ -169,7 +175,7 @@ public final class SymbolLayer extends TextureLayer { pos += TextLayer.VERTICES_PER_SPRITE * 6; - // six elements used to draw the four vertices + /* six elements used to draw the four vertices */ t.vertices += TextureLayer.INDICES_PER_SPRITE; } numIndices += t.vertices; @@ -201,19 +207,13 @@ public final class SymbolLayer extends TextureLayer { } public void clearItems() { - symbols = SymbolItem.pool.releaseAll(symbols); - //numVertices = 0; + SymbolItem.pool.releaseAll(mSymbols.clear()); } @Override public void clear() { - // release textures super.clear(); clearItems(); - - //symbols = SymbolItem.pool.releaseAll(symbols); - //vertexItems = VertexItem.pool.releaseAll(vertexItems); - //numVertices = 0; } @Override diff --git a/vtm/src/org/oscim/renderer/elements/TextureLayer.java b/vtm/src/org/oscim/renderer/elements/TextureLayer.java index 225c71f7..e0aef4b9 100644 --- a/vtm/src/org/oscim/renderer/elements/TextureLayer.java +++ b/vtm/src/org/oscim/renderer/elements/TextureLayer.java @@ -26,9 +26,13 @@ import org.oscim.renderer.GLUtils; import org.oscim.renderer.MapRenderer; import org.oscim.renderer.MapRenderer.Matrices; import org.oscim.renderer.elements.TextureItem.TexturePool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class TextureLayer extends RenderElement { + static final Logger log = LoggerFactory.getLogger(TextureLayer.class); + public final static int INDICES_PER_SPRITE = 6; final static int VERTICES_PER_SPRITE = 4; final static int SHORTS_PER_VERTICE = 6; @@ -58,7 +62,7 @@ public abstract class TextureLayer extends RenderElement { for (TextureItem t = textures; t != null; t = t.next) t.upload(); - // add vertices to vbo + /* add vertices to vbo */ ElementLayers.addPoolItems(this, sbuf); } @@ -79,28 +83,28 @@ public abstract class TextureLayer extends RenderElement { short u1, short v1, short u2, short v2) { - // top-left + /* top-left */ buf[pos + 0] = tx; buf[pos + 1] = ty; buf[pos + 2] = x1; buf[pos + 3] = y1; buf[pos + 4] = u1; buf[pos + 5] = v2; - // bot-left + /* bot-left */ buf[pos + 6] = tx; buf[pos + 7] = ty; buf[pos + 8] = x1; buf[pos + 9] = y2; buf[pos + 10] = u1; buf[pos + 11] = v1; - // top-right + /* top-right */ buf[pos + 12] = tx; buf[pos + 13] = ty; buf[pos + 14] = x2; buf[pos + 15] = y1; buf[pos + 16] = u2; buf[pos + 17] = v2; - // bot-right + /* bot-right */ buf[pos + 18] = tx; buf[pos + 19] = ty; buf[pos + 20] = x2; @@ -110,7 +114,6 @@ public abstract class TextureLayer extends RenderElement { } public static final class Renderer { - //static final Logger log = LoggerFactory.getLogger(TextureRenderer.class); public final static boolean debug = false; @@ -124,7 +127,6 @@ public abstract class TextureLayer extends RenderElement { private static int hTextureSize; static void init() { - mTextureProgram = GLUtils.createProgram(textVertexShader, textFragmentShader); @@ -136,7 +138,7 @@ public abstract class TextureLayer extends RenderElement { hTextureVertex = GL.glGetAttribLocation(mTextureProgram, "vertex"); hTextureTexCoord = GL.glGetAttribLocation(mTextureProgram, "tex_coord"); - // FIXME pool should be disposed on exit... + /* FIXME pool should be disposed on exit... */ pool.init(0); } @@ -171,9 +173,10 @@ public abstract class TextureLayer extends RenderElement { int maxVertices = MapRenderer.maxQuads * INDICES_PER_SPRITE; - // draw up to maxVertices in each iteration + /* draw up to maxVertices in each iteration */ for (int i = 0; i < t.vertices; i += maxVertices) { - // to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8) + /* to.offset * (24(shorts) * 2(short-bytes) + * / 6(indices) == 8) */ int off = (t.offset + i) * 8 + tl.offset; GL.glVertexAttribPointer(hTextureVertex, 4, diff --git a/vtm/src/org/oscim/utils/pool/Inlist.java b/vtm/src/org/oscim/utils/pool/Inlist.java index d88466e4..020b67fd 100644 --- a/vtm/src/org/oscim/utils/pool/Inlist.java +++ b/vtm/src/org/oscim/utils/pool/Inlist.java @@ -80,6 +80,10 @@ public class Inlist<T extends Inlist<T>> { cur = null; return ret; } + + public T getHead() { + return head; + } } public T next;