MarkerLayer: render items in z-order
This commit is contained in:
parent
fccf3212e6
commit
eb9194fe73
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -80,6 +80,10 @@ public class Inlist<T extends Inlist<T>> {
|
||||
cur = null;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public T getHead() {
|
||||
return head;
|
||||
}
|
||||
}
|
||||
|
||||
public T next;
|
||||
|
Loading…
x
Reference in New Issue
Block a user