MarkerLayer: render items in z-order

This commit is contained in:
Hannes Janetzek 2014-02-09 16:59:19 +01:00
parent fccf3212e6
commit eb9194fe73
6 changed files with 134 additions and 76 deletions

View File

@ -36,6 +36,8 @@ import android.widget.Toast;
public class MarkerOverlayActivity extends BitmapTileMapActivity public class MarkerOverlayActivity extends BitmapTileMapActivity
implements OnItemGestureListener<MarkerItem> { implements OnItemGestureListener<MarkerItem> {
private MarkerSymbol mFocusMarker;
public MarkerOverlayActivity() { public MarkerOverlayActivity() {
super(new DefaultSources.StamenToner()); super(new DefaultSources.StamenToner());
} }
@ -47,6 +49,9 @@ implements OnItemGestureListener<MarkerItem> {
Drawable d = getResources().getDrawable(R.drawable.marker_poi); Drawable d = getResources().getDrawable(R.drawable.marker_poi);
MarkerSymbol symbol = AndroidGraphics.makeMarker(d, HotspotPlace.CENTER); MarkerSymbol symbol = AndroidGraphics.makeMarker(d, HotspotPlace.CENTER);
d = getResources().getDrawable(R.drawable.ic_launcher);
mFocusMarker = AndroidGraphics.makeMarker(d, HotspotPlace.BOTTOM_CENTER);
ItemizedLayer<MarkerItem> markerLayer = ItemizedLayer<MarkerItem> markerLayer =
new ItemizedLayer<MarkerItem>(mMap, new ArrayList<MarkerItem>(), new ItemizedLayer<MarkerItem>(mMap, new ArrayList<MarkerItem>(),
symbol, this); symbol, this);
@ -69,6 +74,11 @@ implements OnItemGestureListener<MarkerItem> {
@Override @Override
public boolean onItemSingleTapUp(int index, MarkerItem item) { 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 toast = Toast.makeText(this, item.getTitle(), Toast.LENGTH_SHORT);
toast.show(); toast.show();
return true; return true;

View File

@ -17,6 +17,8 @@
package org.oscim.layers.marker; package org.oscim.layers.marker;
import java.util.Comparator;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection; import org.oscim.core.MercatorProjection;
import org.oscim.core.Point; import org.oscim.core.Point;
@ -25,8 +27,8 @@ import org.oscim.renderer.ElementRenderer;
import org.oscim.renderer.MapRenderer.Matrices; import org.oscim.renderer.MapRenderer.Matrices;
import org.oscim.renderer.elements.SymbolItem; import org.oscim.renderer.elements.SymbolItem;
import org.oscim.renderer.elements.SymbolLayer; import org.oscim.renderer.elements.SymbolLayer;
import org.oscim.utils.TimSort;
import org.oscim.utils.geom.GeometryUtils; import org.oscim.utils.geom.GeometryUtils;
import org.oscim.utils.pool.Inlist;
//TODO //TODO
//- need to sort items back to front for rendering //- 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 */ /** increase view to show items that are partially visible */
protected int mExtents = 100; protected int mExtents = 100;
private boolean mUpdate; private boolean mUpdate;
private InternalItem mItems;
private InternalItem[] mItems;
private final Point mMapPoint = new Point(); private final Point mMapPoint = new Point();
static class InternalItem extends Inlist<InternalItem> { static class InternalItem {
MarkerItem item; MarkerItem item;
boolean visible; boolean visible;
boolean changes; boolean changes;
float x, y; float x, y;
double px, py; double px, py;
float dy;
@Override
public String toString() {
return "\n" + x + ":" + y + " / " + dy + " " + visible;
}
} }
public MarkerRenderer(MarkerLayer<MarkerItem> markerLayer, MarkerSymbol defaultSymbol) { public MarkerRenderer(MarkerLayer<MarkerItem> markerLayer, MarkerSymbol defaultSymbol) {
@ -72,8 +83,8 @@ public class MarkerRenderer extends ElementRenderer {
double my = pos.y; double my = pos.y;
double scale = Tile.SIZE * pos.scale; double scale = Tile.SIZE * pos.scale;
int changesInvisible = 0; //int changesInvisible = 0;
int changedVisible = 0; //int changedVisible = 0;
int numVisible = 0; int numVisible = 0;
mMarkerLayer.map().viewport().getMapExtents(mBox, mExtents); mMarkerLayer.map().viewport().getMapExtents(mBox, mExtents);
@ -88,8 +99,12 @@ public class MarkerRenderer extends ElementRenderer {
return; return;
} }
double angle = Math.toRadians(pos.angle);
float cos = (float) Math.cos(angle);
float sin = (float) Math.sin(angle);
/* check visibility */ /* check visibility */
for (InternalItem it = mItems; it != null; it = it.next) { for (InternalItem it : mItems) {
it.changes = false; it.changes = false;
it.x = (float) ((it.px - mx) * scale); it.x = (float) ((it.px - mx) * scale);
it.y = (float) ((it.py - my) * 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 (!GeometryUtils.pointInPoly(it.x, it.y, mBox, 8, 0)) {
if (it.visible) { if (it.visible) {
it.changes = true; it.changes = true;
changesInvisible++; //changesInvisible++;
} }
continue; continue;
} }
it.dy = sin * it.x + cos * it.y;
if (!it.visible) { if (!it.visible) {
it.visible = true; it.visible = true;
changedVisible++; //changedVisible++;
} }
numVisible++; numVisible++;
} }
@ -117,15 +135,21 @@ public class MarkerRenderer extends ElementRenderer {
/* only update when zoomlevel changed, new items are visible /* only update when zoomlevel changed, new items are visible
* or more than 10 of the current items became invisible */ * or more than 10 of the current items became invisible */
if ((numVisible == 0) && (changedVisible == 0 && changesInvisible < 10)) //if ((numVisible == 0) && (changedVisible == 0 && changesInvisible < 10))
return; // return;
/* keep position for current state */
mMapPosition.copy(pos);
layers.clear(); 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) if (!it.visible)
continue; continue;
@ -139,14 +163,9 @@ public class MarkerRenderer extends ElementRenderer {
marker = mDefaultMarker; marker = mDefaultMarker;
SymbolItem s = SymbolItem.pool.get(); SymbolItem s = SymbolItem.pool.get();
s.bitmap = marker.getBitmap(); s.set(it.x, it.y, marker.getBitmap(), true);
s.x = it.x;
s.y = it.y;
s.offset = marker.getHotspot(); s.offset = marker.getHotspot();
s.billboard = true; mSymbolLayer.pushSymbol(s);
mSymbolLayer.addSymbol(s);
} }
mSymbolLayer.prepare(); mSymbolLayer.prepare();
@ -155,29 +174,13 @@ public class MarkerRenderer extends ElementRenderer {
compile(); compile();
} }
@Override protected void populate(int size) {
public synchronized void compile() {
super.compile();
}
protected synchronized void populate(int size) { InternalItem[] tmp = new InternalItem[size];
InternalItem pool = mItems;
mItems = null;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
InternalItem it; InternalItem it = new InternalItem();
if (pool != null) { tmp[i] = it;
it = pool;
it.visible = false;
it.changes = false;
pool = pool.next;
} else {
it = new InternalItem();
}
it.next = mItems;
mItems = it;
it.item = mMarkerLayer.createItem(i); it.item = mMarkerLayer.createItem(i);
/* pre-project points */ /* pre-project points */
@ -185,6 +188,44 @@ public class MarkerRenderer extends ElementRenderer {
it.px = mMapPoint.x; it.px = mMapPoint.x;
it.py = mMapPoint.y; 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; mUpdate = true;
} }

View File

@ -47,7 +47,7 @@ import org.slf4j.LoggerFactory;
*/ */
public abstract class ElementRenderer extends LayerRenderer { 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; private static short[] fillCoords;

View File

@ -33,35 +33,42 @@ public final class SymbolLayer extends TextureLayer {
private final static int LBIT_MASK = 0xfffffffe; private final static int LBIT_MASK = 0xfffffffe;
private TextureItem prevTextures; private TextureItem prevTextures;
private SymbolItem symbols; private List<SymbolItem> mSymbols = new List<SymbolItem>();
public SymbolLayer() { public SymbolLayer() {
super(RenderElement.SYMBOL); super(RenderElement.SYMBOL);
fixed = true; fixed = true;
} }
// TODO move sorting items to 'prepare' /* TODO move sorting items to 'prepare' */
public void addSymbol(SymbolItem item) { public void addSymbol(SymbolItem item) {
// needed to calculate 'sbuf' size for compile /* needed to calculate 'sbuf' size for compile */
numVertices += VERTICES_PER_SPRITE; numVertices += VERTICES_PER_SPRITE;
for (SymbolItem it = symbols; it != null; it = it.next) { for (SymbolItem it : mSymbols) {
if (it.bitmap == item.bitmap) { if (it.bitmap == item.bitmap) {
// insert after same bitmap /* insert after same bitmap */
item.next = it.next; item.next = it.next;
it.next = item; it.next = item;
return; return;
} }
} }
mSymbols.push(item);
item.next = symbols; //item.next = mSymbols;
symbols = item; //mSymbols = item;
}
public void pushSymbol(SymbolItem item) {
/* needed to calculate 'sbuf' size for compile */
numVertices += VERTICES_PER_SPRITE;
mSymbols.push(item);
} }
@Override @Override
protected void compile(ShortBuffer sbuf) { protected void compile(ShortBuffer sbuf) {
// offset of layer data in vbo /* offset of layer data in vbo */
this.offset = sbuf.position() * 2; //SHORT_BYTES; this.offset = sbuf.position() * 2; //SHORT_BYTES;
short numIndices = 0; short numIndices = 0;
@ -75,18 +82,17 @@ public final class SymbolLayer extends TextureLayer {
textures = null; textures = null;
TextureItem t = null; TextureItem t = null;
for (SymbolItem it = symbols; it != null;) { for (SymbolItem it = mSymbols.getHead(); it != null;) {
int width = 0, height = 0; int width = 0, height = 0;
int x = 0; int x = 0;
int y = 0; int y = 0;
if (it.texRegion != null) { 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) { if (textures == null) {
t = it.texRegion.atlas.loadTexture(); t = it.texRegion.atlas.loadTexture();
// clone TextureItem to use same texID with /* clone TextureItem to use same texID with
// multiple TextureItem * multiple TextureItem */
t = TextureItem.clone(t); t = TextureItem.clone(t);
textures = Inlist.appendItem(textures, t); textures = Inlist.appendItem(textures, t);
} }
@ -124,7 +130,7 @@ public final class SymbolLayer extends TextureLayer {
PointF prevOffset = null; PointF prevOffset = null;
short x1 = 0, y1 = 0, x2 = 0, y2 = 0; 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) { for (SymbolItem prev = it; it != null; it = it.next) {
if (prev.bitmap != null && prev.bitmap != it.bitmap) 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 short tx = (short) ((int) (SCALE * it.x) & LBIT_MASK
| (it.billboard ? 1 : 0)); | (it.billboard ? 1 : 0));
@ -169,7 +175,7 @@ public final class SymbolLayer extends TextureLayer {
pos += TextLayer.VERTICES_PER_SPRITE * 6; 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; t.vertices += TextureLayer.INDICES_PER_SPRITE;
} }
numIndices += t.vertices; numIndices += t.vertices;
@ -201,19 +207,13 @@ public final class SymbolLayer extends TextureLayer {
} }
public void clearItems() { public void clearItems() {
symbols = SymbolItem.pool.releaseAll(symbols); SymbolItem.pool.releaseAll(mSymbols.clear());
//numVertices = 0;
} }
@Override @Override
public void clear() { public void clear() {
// release textures
super.clear(); super.clear();
clearItems(); clearItems();
//symbols = SymbolItem.pool.releaseAll(symbols);
//vertexItems = VertexItem.pool.releaseAll(vertexItems);
//numVertices = 0;
} }
@Override @Override

View File

@ -26,9 +26,13 @@ import org.oscim.renderer.GLUtils;
import org.oscim.renderer.MapRenderer; import org.oscim.renderer.MapRenderer;
import org.oscim.renderer.MapRenderer.Matrices; import org.oscim.renderer.MapRenderer.Matrices;
import org.oscim.renderer.elements.TextureItem.TexturePool; import org.oscim.renderer.elements.TextureItem.TexturePool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class TextureLayer extends RenderElement { public abstract class TextureLayer extends RenderElement {
static final Logger log = LoggerFactory.getLogger(TextureLayer.class);
public final static int INDICES_PER_SPRITE = 6; public final static int INDICES_PER_SPRITE = 6;
final static int VERTICES_PER_SPRITE = 4; final static int VERTICES_PER_SPRITE = 4;
final static int SHORTS_PER_VERTICE = 6; 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) for (TextureItem t = textures; t != null; t = t.next)
t.upload(); t.upload();
// add vertices to vbo /* add vertices to vbo */
ElementLayers.addPoolItems(this, sbuf); ElementLayers.addPoolItems(this, sbuf);
} }
@ -79,28 +83,28 @@ public abstract class TextureLayer extends RenderElement {
short u1, short v1, short u1, short v1,
short u2, short v2) { short u2, short v2) {
// top-left /* top-left */
buf[pos + 0] = tx; buf[pos + 0] = tx;
buf[pos + 1] = ty; buf[pos + 1] = ty;
buf[pos + 2] = x1; buf[pos + 2] = x1;
buf[pos + 3] = y1; buf[pos + 3] = y1;
buf[pos + 4] = u1; buf[pos + 4] = u1;
buf[pos + 5] = v2; buf[pos + 5] = v2;
// bot-left /* bot-left */
buf[pos + 6] = tx; buf[pos + 6] = tx;
buf[pos + 7] = ty; buf[pos + 7] = ty;
buf[pos + 8] = x1; buf[pos + 8] = x1;
buf[pos + 9] = y2; buf[pos + 9] = y2;
buf[pos + 10] = u1; buf[pos + 10] = u1;
buf[pos + 11] = v1; buf[pos + 11] = v1;
// top-right /* top-right */
buf[pos + 12] = tx; buf[pos + 12] = tx;
buf[pos + 13] = ty; buf[pos + 13] = ty;
buf[pos + 14] = x2; buf[pos + 14] = x2;
buf[pos + 15] = y1; buf[pos + 15] = y1;
buf[pos + 16] = u2; buf[pos + 16] = u2;
buf[pos + 17] = v2; buf[pos + 17] = v2;
// bot-right /* bot-right */
buf[pos + 18] = tx; buf[pos + 18] = tx;
buf[pos + 19] = ty; buf[pos + 19] = ty;
buf[pos + 20] = x2; buf[pos + 20] = x2;
@ -110,7 +114,6 @@ public abstract class TextureLayer extends RenderElement {
} }
public static final class Renderer { public static final class Renderer {
//static final Logger log = LoggerFactory.getLogger(TextureRenderer.class);
public final static boolean debug = false; public final static boolean debug = false;
@ -124,7 +127,6 @@ public abstract class TextureLayer extends RenderElement {
private static int hTextureSize; private static int hTextureSize;
static void init() { static void init() {
mTextureProgram = GLUtils.createProgram(textVertexShader, mTextureProgram = GLUtils.createProgram(textVertexShader,
textFragmentShader); textFragmentShader);
@ -136,7 +138,7 @@ public abstract class TextureLayer extends RenderElement {
hTextureVertex = GL.glGetAttribLocation(mTextureProgram, "vertex"); hTextureVertex = GL.glGetAttribLocation(mTextureProgram, "vertex");
hTextureTexCoord = GL.glGetAttribLocation(mTextureProgram, "tex_coord"); hTextureTexCoord = GL.glGetAttribLocation(mTextureProgram, "tex_coord");
// FIXME pool should be disposed on exit... /* FIXME pool should be disposed on exit... */
pool.init(0); pool.init(0);
} }
@ -171,9 +173,10 @@ public abstract class TextureLayer extends RenderElement {
int maxVertices = MapRenderer.maxQuads * INDICES_PER_SPRITE; 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) { 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; int off = (t.offset + i) * 8 + tl.offset;
GL.glVertexAttribPointer(hTextureVertex, 4, GL.glVertexAttribPointer(hTextureVertex, 4,

View File

@ -80,6 +80,10 @@ public class Inlist<T extends Inlist<T>> {
cur = null; cur = null;
return ret; return ret;
} }
public T getHead() {
return head;
}
} }
public T next; public T next;