refactor: MapTile et al
- cleanup proxy draw logic in VectorTileRenderer - fixes upload of child proxies in TileRenderer
This commit is contained in:
parent
7779e30635
commit
0c245f4f6d
@ -16,13 +16,19 @@
|
||||
*/
|
||||
package org.oscim.layers.tile;
|
||||
|
||||
import static org.oscim.layers.tile.MapTile.State.DEADBEEF;
|
||||
import static org.oscim.layers.tile.MapTile.State.NEW_DATA;
|
||||
import static org.oscim.layers.tile.MapTile.State.READY;
|
||||
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.layers.tile.vector.VectorTileLoader;
|
||||
import org.oscim.layers.tile.vector.labeling.LabelTileLoaderHook;
|
||||
import org.oscim.renderer.elements.ElementLayers;
|
||||
import org.oscim.utils.pool.Inlist;
|
||||
import org.oscim.utils.quadtree.TreeNode;
|
||||
import org.oscim.utils.quadtree.TileIndex;
|
||||
import org.oscim.utils.quadtree.TreeNode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Extends Tile class to hold state and data.
|
||||
@ -32,8 +38,9 @@ import org.oscim.utils.quadtree.TileIndex;
|
||||
*/
|
||||
public class MapTile extends Tile {
|
||||
|
||||
public static class TileNode extends TreeNode<TileNode, MapTile> {
|
||||
static final Logger log = LoggerFactory.getLogger(MapTile.class);
|
||||
|
||||
public static class TileNode extends TreeNode<TileNode, MapTile> {
|
||||
}
|
||||
|
||||
public static final class State {
|
||||
@ -43,49 +50,46 @@ public class MapTile extends Tile {
|
||||
* STATE_LOADING means the tile is about to be loaded / loading.
|
||||
* Tile belongs to TileLoader thread.
|
||||
*/
|
||||
public final static byte LOADING = 1 << 0;
|
||||
public final static byte LOADING = (1 << 0);
|
||||
|
||||
/**
|
||||
* STATE_NEW_DATA: tile data is prepared for rendering.
|
||||
* While 'locked' it belongs to GL Thread.
|
||||
*/
|
||||
public final static byte NEW_DATA = 1 << 1;
|
||||
public final static byte NEW_DATA = (1 << 1);
|
||||
|
||||
/**
|
||||
* STATE_READY: tile data is uploaded to GL.
|
||||
* While 'locked' it belongs to GL Thread.
|
||||
*/
|
||||
public final static byte READY = 1 << 2;
|
||||
public final static byte READY = (1 << 2);
|
||||
|
||||
/**
|
||||
* STATE_CANCEL: tile is removed from TileManager,
|
||||
* but may still be processed by TileLoader.
|
||||
*/
|
||||
public final static byte CANCEL = 1 << 3;
|
||||
public final static byte CANCEL = (1 << 3);
|
||||
|
||||
public final static byte DEADBEEF = (1 << 4);
|
||||
|
||||
}
|
||||
|
||||
public static abstract class TileData extends Inlist<TileData> {
|
||||
Object id;
|
||||
public final static int PROXY_CHILD00 = (1 << 0);
|
||||
public final static int PROXY_CHILD01 = (1 << 1);
|
||||
public final static int PROXY_CHILD10 = (1 << 2);
|
||||
public final static int PROXY_CHILD11 = (1 << 3);
|
||||
public final static int PROXY_PARENT = (1 << 4);
|
||||
public final static int PROXY_GRAMPA = (1 << 5);
|
||||
public final static int PROXY_HOLDER = (1 << 6);
|
||||
|
||||
protected abstract void dispose();
|
||||
}
|
||||
/** Tile state */
|
||||
byte state;
|
||||
|
||||
public MapTile(TileNode node, int tileX, int tileY, int zoomLevel) {
|
||||
super(tileX, tileY, (byte) zoomLevel);
|
||||
this.x = (double) tileX / (1 << zoomLevel);
|
||||
this.y = (double) tileY / (1 << zoomLevel);
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
protected byte state;
|
||||
|
||||
public boolean state(int testState) {
|
||||
return (state & testState) != 0;
|
||||
}
|
||||
|
||||
public byte getState() {
|
||||
return state;
|
||||
}
|
||||
/**
|
||||
* absolute tile coordinates: tileX,Y / Math.pow(2, zoomLevel)
|
||||
*/
|
||||
public final double x;
|
||||
public final double y;
|
||||
|
||||
/**
|
||||
* List of TileData for rendering. ElementLayers is always at first
|
||||
@ -95,10 +99,9 @@ public class MapTile extends Tile {
|
||||
public TileData data;
|
||||
|
||||
/**
|
||||
* absolute tile coordinates: tileX,Y / Math.pow(2, zoomLevel)
|
||||
* Pointer to access relatives in {@link TileIndex}
|
||||
*/
|
||||
public final double x;
|
||||
public final double y;
|
||||
public final TileNode node;
|
||||
|
||||
/**
|
||||
* current distance from map center
|
||||
@ -117,40 +120,50 @@ public class MapTile extends Tile {
|
||||
|
||||
/**
|
||||
* Used to avoid drawing a tile twice per frame
|
||||
* TODO remove
|
||||
*/
|
||||
int lastDraw = 0;
|
||||
|
||||
/**
|
||||
* Pointer to access relatives in {@link TileIndex}
|
||||
*/
|
||||
public final TileNode node;
|
||||
/** Keep track which tiles are locked as proxy for this tile */
|
||||
private int proxy = 0;
|
||||
|
||||
public final static int PROXY_CHILD1 = 1 << 0;
|
||||
public final static int PROXY_CHILD2 = 1 << 1;
|
||||
public final static int PROXY_CHILD3 = 1 << 2;
|
||||
public final static int PROXY_CHILD4 = 1 << 3;
|
||||
public final static int PROXY_PARENT = 1 << 4;
|
||||
public final static int PROXY_GRAMPA = 1 << 5;
|
||||
public final static int PROXY_HOLDER = 1 << 6;
|
||||
/** Tile lock counter, synced in TileManager */
|
||||
private int locked = 0;
|
||||
|
||||
/** keep track which tiles are locked as proxy for this tile */
|
||||
byte proxies;
|
||||
|
||||
/** counting the tiles that use this tile as proxy */
|
||||
private byte refs;
|
||||
|
||||
/** up to 255 Threads may lock a tile */
|
||||
private byte locked;
|
||||
private int refs = 0;
|
||||
|
||||
/**
|
||||
* only used GLRenderer when this tile sits in for another tile.
|
||||
* Only used GLRenderer when this tile sits in for another tile.
|
||||
* e.g. x:-1,y:0,z:1 for x:1,y:0
|
||||
*/
|
||||
MapTile holder;
|
||||
|
||||
public static abstract class TileData extends Inlist<TileData> {
|
||||
Object id;
|
||||
|
||||
protected abstract void dispose();
|
||||
|
||||
public TileData next() {
|
||||
return (TileData) next;
|
||||
}
|
||||
}
|
||||
|
||||
public MapTile(TileNode node, int tileX, int tileY, int zoomLevel) {
|
||||
super(tileX, tileY, (byte) zoomLevel);
|
||||
this.x = (double) tileX / (1 << zoomLevel);
|
||||
this.y = (double) tileY / (1 << zoomLevel);
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public boolean state(int testState) {
|
||||
return (state & testState) != 0;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true when tile might be referenced by render thread.
|
||||
* @return true when tile could be used by another thread.
|
||||
*/
|
||||
boolean isLocked() {
|
||||
return locked > 0 || refs > 0;
|
||||
@ -166,24 +179,34 @@ public class MapTile extends Tile {
|
||||
if (locked++ > 0)
|
||||
return;
|
||||
|
||||
MapTile p;
|
||||
/* lock all tiles that could serve as proxy */
|
||||
MapTile p = node.parent.item;
|
||||
if (p != null && (p.state != State.NONE)) {
|
||||
proxies |= PROXY_PARENT;
|
||||
p.refs++;
|
||||
}
|
||||
|
||||
p = node.parent.parent.item;
|
||||
if (p != null && (p.state != State.NONE)) {
|
||||
proxies |= PROXY_GRAMPA;
|
||||
p.refs++;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if ((p = node.child(j)) == null || p.state == 0)
|
||||
for (int i = 0; i < 4; i++) {
|
||||
p = node.child(i);
|
||||
if (p == null)
|
||||
continue;
|
||||
|
||||
proxies |= (1 << j);
|
||||
if (p.state(READY | NEW_DATA)) {
|
||||
proxy |= (1 << i);
|
||||
p.refs++;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.isRoot())
|
||||
return;
|
||||
|
||||
p = node.parent();
|
||||
if (p != null && p.state(READY | NEW_DATA)) {
|
||||
proxy |= PROXY_PARENT;
|
||||
p.refs++;
|
||||
}
|
||||
|
||||
if (node.parent.isRoot())
|
||||
return;
|
||||
|
||||
p = node.parent.parent();
|
||||
if (p != null && p.state(READY | NEW_DATA)) {
|
||||
proxy |= PROXY_GRAMPA;
|
||||
p.refs++;
|
||||
}
|
||||
}
|
||||
@ -192,25 +215,28 @@ public class MapTile extends Tile {
|
||||
* Unlocks this tile when it cannot be used by render-thread.
|
||||
*/
|
||||
void unlock() {
|
||||
if (--locked > 0 || proxies == 0)
|
||||
if (--locked > 0)
|
||||
return;
|
||||
|
||||
if ((proxies & PROXY_PARENT) != 0)
|
||||
node.parent.item.refs--;
|
||||
|
||||
if ((proxies & PROXY_GRAMPA) != 0)
|
||||
node.parent.parent.item.refs--;
|
||||
TileNode parent = node.parent;
|
||||
if ((proxy & PROXY_PARENT) != 0)
|
||||
parent.item.refs--;
|
||||
|
||||
if ((proxy & PROXY_GRAMPA) != 0) {
|
||||
parent = parent.parent;
|
||||
parent.item.refs--;
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((proxies & (1 << i)) != 0)
|
||||
if ((proxy & (1 << i)) != 0)
|
||||
node.child(i).refs--;
|
||||
}
|
||||
proxies = 0;
|
||||
|
||||
/* removed all proxy references for this tile */
|
||||
proxy = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if tile is loading, has new data or is ready
|
||||
* for rendering
|
||||
* @return true if tile is state is not NONE.
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return state > State.NONE;
|
||||
@ -221,7 +247,7 @@ public class MapTile extends Tile {
|
||||
* through this.node.*
|
||||
*/
|
||||
public boolean hasProxy(int proxy) {
|
||||
return (proxies & proxy) != 0;
|
||||
return (this.proxy & proxy) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -233,9 +259,7 @@ public class MapTile extends Tile {
|
||||
data.dispose();
|
||||
data = data.next;
|
||||
}
|
||||
|
||||
// still needed?
|
||||
state = State.NONE;
|
||||
state = DEADBEEF;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -257,7 +281,7 @@ public class MapTile extends Tile {
|
||||
}
|
||||
|
||||
public void addData(Object id, TileData td) {
|
||||
// keeping ElementLayers at position 0!
|
||||
/* keeping ElementLayers at position 0! */
|
||||
td.id = id;
|
||||
if (data != null) {
|
||||
td.next = data.next;
|
||||
@ -267,7 +291,80 @@ public class MapTile extends Tile {
|
||||
}
|
||||
}
|
||||
|
||||
public TileData removeData(Object id) {
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
TileData prev = data;
|
||||
if (data.id == id) {
|
||||
data = data.next;
|
||||
return prev;
|
||||
}
|
||||
for (TileData d = data.next; d != null; d = d.next) {
|
||||
if (d.id == id) {
|
||||
prev.next = d.next;
|
||||
return d;
|
||||
}
|
||||
prev = d;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int depthOffset(MapTile t) {
|
||||
return ((t.tileX % 4) + (t.tileY % 4 * 4) + 1);
|
||||
}
|
||||
|
||||
public MapTile getProxyChild(int id, byte state) {
|
||||
if ((proxy & (1 << id)) == 0)
|
||||
return null;
|
||||
|
||||
MapTile child = node.child(id);
|
||||
if (child == null || (child.state & state) == 0)
|
||||
return null;
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
public MapTile getParent() {
|
||||
if ((proxy & PROXY_PARENT) == 0)
|
||||
return null;
|
||||
|
||||
return node.parent.item;
|
||||
}
|
||||
|
||||
public MapTile getProxy(int proxy, byte state) {
|
||||
|
||||
if ((this.proxy & proxy) == 0)
|
||||
return null;
|
||||
|
||||
MapTile p = null;
|
||||
switch (proxy) {
|
||||
case PROXY_CHILD00:
|
||||
p = node.child(0);
|
||||
break;
|
||||
case PROXY_CHILD01:
|
||||
p = node.child(1);
|
||||
break;
|
||||
case PROXY_CHILD10:
|
||||
p = node.child(2);
|
||||
break;
|
||||
case PROXY_CHILD11:
|
||||
p = node.child(3);
|
||||
break;
|
||||
case PROXY_PARENT:
|
||||
p = node.parent();
|
||||
break;
|
||||
case PROXY_GRAMPA:
|
||||
p = node.parent.parent();
|
||||
break;
|
||||
case PROXY_HOLDER:
|
||||
p = holder;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == null || (p.state & state) == 0)
|
||||
return null;
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,13 @@
|
||||
*/
|
||||
package org.oscim.layers.tile;
|
||||
|
||||
import static org.oscim.layers.tile.MapTile.PROXY_PARENT;
|
||||
import static org.oscim.layers.tile.MapTile.State.NEW_DATA;
|
||||
import static org.oscim.layers.tile.MapTile.State.READY;
|
||||
|
||||
import org.oscim.backend.GL20;
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.layers.tile.MapTile.TileNode;
|
||||
import org.oscim.renderer.BufferObject;
|
||||
import org.oscim.renderer.ElementRenderer;
|
||||
import org.oscim.renderer.GLViewport;
|
||||
@ -36,7 +38,7 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
|
||||
/** fade-in time */
|
||||
protected static final float FADE_TIME = 500;
|
||||
protected static final int MAX_TILE_LOAD = 1;
|
||||
protected static final int MAX_TILE_LOAD = 8;
|
||||
|
||||
private TileManager mTileManager;
|
||||
|
||||
@ -46,8 +48,8 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
private int mOverdraw = 0;
|
||||
private float mAlpha = 1;
|
||||
|
||||
protected int mRenderOverdraw;
|
||||
protected float mRenderAlpha;
|
||||
protected int mOverdrawColor;
|
||||
protected float mLayerAlpha;
|
||||
|
||||
private int mUploadSerial;
|
||||
|
||||
@ -60,12 +62,6 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
mTileManager = tileManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current number of frames drawn, used to not draw a
|
||||
* tile twice per frame.
|
||||
*/
|
||||
protected int mDrawSerial;
|
||||
|
||||
/**
|
||||
* Threadsafe
|
||||
*/
|
||||
@ -101,8 +97,8 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
return;
|
||||
|
||||
/* keep constant while rendering frame */
|
||||
mRenderAlpha = mAlpha;
|
||||
mRenderOverdraw = mOverdraw;
|
||||
mLayerAlpha = mAlpha;
|
||||
mOverdrawColor = mOverdraw;
|
||||
|
||||
int tileCnt = mDrawTiles.cnt;
|
||||
MapTile[] tiles = mDrawTiles.tiles;
|
||||
@ -118,8 +114,6 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
mUploadSerial++;
|
||||
BufferObject.checkBufferUsage(false);
|
||||
}
|
||||
|
||||
mDrawSerial++;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -153,36 +147,30 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tile.holder != null) {
|
||||
/* load tile that is referenced by this holder */
|
||||
if (tile.holder.state == NEW_DATA)
|
||||
uploadCnt += uploadTileData(tile.holder);
|
||||
|
||||
tile.state = tile.holder.state;
|
||||
/* load tile that is referenced by this holder */
|
||||
MapTile proxy = tile.holder;
|
||||
if (proxy != null && proxy.state == NEW_DATA) {
|
||||
uploadCnt += uploadTileData(proxy);
|
||||
tile.state = proxy.state;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check near relatives than can serve as proxy */
|
||||
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||
MapTile t = tile.node.parent.item;
|
||||
if (t.state == NEW_DATA)
|
||||
uploadCnt += uploadTileData(t);
|
||||
|
||||
proxy = tile.getProxy(PROXY_PARENT, NEW_DATA);
|
||||
if (proxy != null) {
|
||||
uploadCnt += uploadTileData(proxy);
|
||||
/* dont load child proxies */
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int c = 0; c < 4; c++) {
|
||||
if ((tile.proxies & 1 << c) == 0)
|
||||
continue;
|
||||
proxy = tile.getProxyChild(c, NEW_DATA);
|
||||
if (proxy != null)
|
||||
uploadCnt += uploadTileData(proxy);
|
||||
}
|
||||
|
||||
MapTile t = tile.node.child(i);
|
||||
if (t != null && t.state == NEW_DATA)
|
||||
uploadCnt += uploadTileData(t);
|
||||
}
|
||||
if (uploadCnt >= MAX_TILE_LOAD) {
|
||||
if (uploadCnt >= MAX_TILE_LOAD)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return uploadCnt;
|
||||
}
|
||||
@ -295,9 +283,9 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
protected void setVisible(int y, int x1, int x2) {
|
||||
|
||||
MapTile[] tiles = mDrawTiles.tiles;
|
||||
int cnt = mDrawTiles.cnt;
|
||||
int proxyOffset = mDrawTiles.cnt;
|
||||
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
for (int i = 0; i < proxyOffset; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if (t.tileY == y && t.tileX >= x1 && t.tileX < x2)
|
||||
t.isVisible = true;
|
||||
@ -322,12 +310,12 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
if (xx < 0 || xx >= xmax)
|
||||
continue;
|
||||
|
||||
for (int i = cnt; i < cnt + mProxyTileCnt; i++)
|
||||
for (int i = proxyOffset; i < proxyOffset + mProxyTileCnt; i++)
|
||||
if (tiles[i].tileX == x && tiles[i].tileY == y)
|
||||
continue O;
|
||||
|
||||
MapTile tile = null;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
for (int i = 0; i < proxyOffset; i++)
|
||||
if (tiles[i].tileX == xx && tiles[i].tileY == y) {
|
||||
tile = tiles[i];
|
||||
break;
|
||||
@ -336,24 +324,31 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
if (tile == null)
|
||||
continue;
|
||||
|
||||
if (cnt + mProxyTileCnt >= tiles.length) {
|
||||
if (proxyOffset + mProxyTileCnt >= tiles.length) {
|
||||
//log.error(" + mNumTileHolder");
|
||||
break;
|
||||
}
|
||||
|
||||
MapTile holder = new MapTile(null, x, y, (byte) mZoom);
|
||||
holder.isVisible = true;
|
||||
holder.holder = tile;
|
||||
holder.state = tile.state;
|
||||
tile.isVisible = true;
|
||||
tiles[cnt + mProxyTileCnt++] = holder;
|
||||
tiles[proxyOffset + mProxyTileCnt++] = holder;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected long getMinFade(MapTile t, int proxyLevel) {
|
||||
/**
|
||||
* @param proxyLevel zoom-level of tile relative to current TileSet
|
||||
*/
|
||||
public static long getMinFade(MapTile tile, int proxyLevel) {
|
||||
long minFade = MapRenderer.frametime - 50;
|
||||
|
||||
/* check children for grandparent, parent or current */
|
||||
if (proxyLevel <= 0) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
MapTile ci = t.node.child(c);
|
||||
MapTile ci = tile.node.child(c);
|
||||
if (ci == null)
|
||||
continue;
|
||||
|
||||
@ -363,27 +358,27 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
/* when drawing the parent of the current level
|
||||
* we also check if the children of current level
|
||||
* are visible */
|
||||
if (proxyLevel > -2) {
|
||||
if (proxyLevel >= -1) {
|
||||
long m = getMinFade(ci, proxyLevel - 1);
|
||||
if (m < minFade)
|
||||
minFade = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (proxyLevel >= -1) {
|
||||
MapTile p = t.node.parent();
|
||||
if (p != null) {
|
||||
if (p.fadeTime > 0 && p.fadeTime < minFade)
|
||||
minFade = p.fadeTime;
|
||||
|
||||
if (proxyLevel >= 0) {
|
||||
if ((p = p.node.parent()) != null) {
|
||||
if (p.fadeTime > 0 && p.fadeTime < minFade)
|
||||
minFade = p.fadeTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* check parents for child, current or parent */
|
||||
TileNode p = tile.node.parent;
|
||||
|
||||
for (int i = proxyLevel; i >= -1; i--) {
|
||||
if (p == null)
|
||||
break;
|
||||
|
||||
if (p.item != null && p.item.fadeTime > 0 && p.item.fadeTime < minFade)
|
||||
minFade = p.item.fadeTime;
|
||||
|
||||
p = p.parent;
|
||||
}
|
||||
|
||||
return minFade;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package org.oscim.layers.tile;
|
||||
|
||||
import static org.oscim.layers.tile.MapTile.PROXY_GRAMPA;
|
||||
import static org.oscim.layers.tile.MapTile.PROXY_PARENT;
|
||||
import static org.oscim.layers.tile.MapTile.State.READY;
|
||||
import static org.oscim.renderer.elements.RenderElement.BITMAP;
|
||||
import static org.oscim.renderer.elements.RenderElement.LINE;
|
||||
@ -11,7 +13,6 @@ import org.oscim.backend.GL20;
|
||||
import org.oscim.backend.canvas.Color;
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.layers.tile.MapTile.TileNode;
|
||||
import org.oscim.renderer.GLMatrix;
|
||||
import org.oscim.renderer.GLViewport;
|
||||
import org.oscim.renderer.MapRenderer;
|
||||
@ -32,6 +33,12 @@ public class VectorTileRenderer extends TileRenderer {
|
||||
|
||||
protected GLMatrix mViewProj = new GLMatrix();
|
||||
|
||||
/**
|
||||
* Current number of frames drawn, used to not draw a
|
||||
* tile twice per frame.
|
||||
*/
|
||||
protected int mDrawSerial;
|
||||
|
||||
@Override
|
||||
protected synchronized void update(GLViewport v) {
|
||||
super.update(v);
|
||||
@ -45,12 +52,14 @@ public class VectorTileRenderer extends TileRenderer {
|
||||
|
||||
mClipMode = PolygonLayer.CLIP_STENCIL;
|
||||
|
||||
/* */
|
||||
int tileCnt = mDrawTiles.cnt + mProxyTileCnt;
|
||||
|
||||
MapTile[] tiles = mDrawTiles.tiles;
|
||||
|
||||
boolean drawProxies = false;
|
||||
|
||||
mDrawSerial++;
|
||||
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if (t.isVisible && t.state != READY) {
|
||||
@ -71,47 +80,60 @@ public class VectorTileRenderer extends TileRenderer {
|
||||
MapTile t = tiles[i];
|
||||
if (t.isVisible && t.state == READY)
|
||||
drawTile(t, v, 0);
|
||||
|
||||
}
|
||||
|
||||
/* draw parent or children as proxy for visibile tiles that dont
|
||||
* have data yet. Proxies are clipped to the region where nothing
|
||||
* was drawn to depth buffer.
|
||||
* TODO draw proxies for placeholder */
|
||||
if (drawProxies) {
|
||||
/* only draw where no other tile is drawn */
|
||||
GL.glDepthFunc(GL20.GL_LESS);
|
||||
if (!drawProxies)
|
||||
return;
|
||||
|
||||
/* draw child or parent proxies */
|
||||
boolean preferParent = (v.pos.getZoomScale() < 1.5)
|
||||
|| (v.pos.zoomLevel < tiles[0].zoomLevel);
|
||||
/* only draw where no other tile is drawn */
|
||||
GL.glDepthFunc(GL20.GL_LESS);
|
||||
|
||||
/* draw child or parent proxies */
|
||||
boolean preferParent = (v.pos.getZoomScale() < 1.5)
|
||||
|| (v.pos.zoomLevel < tiles[0].zoomLevel);
|
||||
|
||||
if (preferParent) {
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if (t.isVisible
|
||||
&& (t.state != READY)
|
||||
&& (t.holder == null)) {
|
||||
drawProxyTile(t, v, true, preferParent);
|
||||
}
|
||||
if ((!t.isVisible) || (t.lastDraw == mDrawSerial))
|
||||
continue;
|
||||
if (!drawParent(t, v))
|
||||
drawChildren(t, v);
|
||||
}
|
||||
|
||||
/* draw grandparents */
|
||||
} else {
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if (t.isVisible
|
||||
&& (t.state != READY)
|
||||
&& (t.holder == null))
|
||||
drawProxyTile(t, v, false, false);
|
||||
if ((!t.isVisible) || (t.lastDraw == mDrawSerial))
|
||||
continue;
|
||||
drawChildren(t, v);
|
||||
}
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if ((!t.isVisible) || (t.lastDraw == mDrawSerial))
|
||||
continue;
|
||||
drawParent(t, v);
|
||||
}
|
||||
GL.glDepthMask(false);
|
||||
}
|
||||
|
||||
/* make sure stencil buffer write is disabled */
|
||||
GL.glStencilMask(0x00);
|
||||
/* draw grandparents */
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if ((!t.isVisible) || (t.lastDraw == mDrawSerial))
|
||||
continue;
|
||||
drawGrandParent(t, v);
|
||||
}
|
||||
GL.glDepthMask(false);
|
||||
|
||||
/* make sure stencil buffer write is disabled */
|
||||
//GL.glStencilMask(0x00);
|
||||
}
|
||||
|
||||
private void drawTile(MapTile tile, GLViewport v, int proxyLevel) {
|
||||
|
||||
/* ensure to draw parents only once */
|
||||
if (tile.lastDraw == mDrawSerial)
|
||||
return;
|
||||
@ -119,12 +141,11 @@ public class VectorTileRenderer extends TileRenderer {
|
||||
tile.lastDraw = mDrawSerial;
|
||||
|
||||
/* use holder proxy when it is set */
|
||||
MapTile t = tile.holder == null ? tile : tile.holder;
|
||||
|
||||
ElementLayers layers = t.getLayers();
|
||||
ElementLayers layers = (tile.holder == null)
|
||||
? tile.getLayers()
|
||||
: tile.holder.getLayers();
|
||||
|
||||
if (layers == null || layers.vbo == null)
|
||||
//throw new IllegalStateException(t + "no data " + (t.layers == null));
|
||||
return;
|
||||
|
||||
layers.vbo.bind();
|
||||
@ -181,19 +202,16 @@ public class VectorTileRenderer extends TileRenderer {
|
||||
clipped = true;
|
||||
}
|
||||
if (l.type == BITMAP) {
|
||||
l = BitmapLayer.Renderer.draw(l, v, 1, mRenderAlpha);
|
||||
l = BitmapLayer.Renderer.draw(l, v, 1, mLayerAlpha);
|
||||
continue;
|
||||
}
|
||||
l = l.next;
|
||||
}
|
||||
|
||||
if (t.fadeTime == 0)
|
||||
t.fadeTime = getMinFade(t, proxyLevel);
|
||||
|
||||
if (debugOverdraw) {
|
||||
if (t.zoomLevel > pos.zoomLevel)
|
||||
if (tile.zoomLevel > pos.zoomLevel)
|
||||
PolygonLayer.Renderer.drawOver(v, Color.BLUE, 0.5f);
|
||||
else if (t.zoomLevel < pos.zoomLevel)
|
||||
else if (tile.zoomLevel < pos.zoomLevel)
|
||||
PolygonLayer.Renderer.drawOver(v, Color.RED, 0.5f);
|
||||
else
|
||||
PolygonLayer.Renderer.drawOver(v, Color.GREEN, 0.5f);
|
||||
@ -201,92 +219,57 @@ public class VectorTileRenderer extends TileRenderer {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRenderOverdraw != 0 && MapRenderer.frametime - t.fadeTime < FADE_TIME) {
|
||||
float fade = 1 - (MapRenderer.frametime - t.fadeTime) / FADE_TIME;
|
||||
PolygonLayer.Renderer.drawOver(v, mRenderOverdraw, fade * fade);
|
||||
MapRenderer.animate();
|
||||
} else {
|
||||
PolygonLayer.Renderer.drawOver(v, 0, 1);
|
||||
if (tile.fadeTime == 0) {
|
||||
/* need to use original tile to get the fade */
|
||||
MapTile t = (tile.holder == null) ? tile : tile.holder;
|
||||
tile.fadeTime = getMinFade(t, proxyLevel);
|
||||
}
|
||||
|
||||
long dTime = MapRenderer.frametime - tile.fadeTime;
|
||||
|
||||
if (mOverdrawColor == 0 || dTime > FADE_TIME) {
|
||||
PolygonLayer.Renderer.drawOver(v, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
float fade = 1 - dTime / FADE_TIME;
|
||||
PolygonLayer.Renderer.drawOver(v, mOverdrawColor, fade * fade);
|
||||
|
||||
MapRenderer.animate();
|
||||
}
|
||||
|
||||
private int drawProxyChild(MapTile tile, GLViewport v) {
|
||||
protected boolean drawChildren(MapTile t, GLViewport v) {
|
||||
int drawn = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((tile.proxies & 1 << i) == 0)
|
||||
MapTile c = t.getProxyChild(i, READY);
|
||||
if (c == null)
|
||||
continue;
|
||||
|
||||
MapTile c = tile.node.child(i);
|
||||
|
||||
if (c.state == READY) {
|
||||
drawTile(c, v, 1);
|
||||
drawn++;
|
||||
}
|
||||
drawTile(c, v, 1);
|
||||
drawn++;
|
||||
}
|
||||
return drawn;
|
||||
if (drawn == 4) {
|
||||
t.lastDraw = mDrawSerial;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void drawProxyTile(MapTile tile, GLViewport v,
|
||||
boolean parent, boolean preferParent) {
|
||||
protected boolean drawParent(MapTile t, GLViewport v) {
|
||||
MapTile proxy = t.getProxy(PROXY_PARENT, READY);
|
||||
if (proxy != null) {
|
||||
drawTile(proxy, v, -1);
|
||||
t.lastDraw = mDrawSerial;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TileNode r = tile.node;
|
||||
MapTile proxy;
|
||||
|
||||
if (!preferParent) {
|
||||
/* prefer drawing children */
|
||||
if (drawProxyChild(tile, v) == 4)
|
||||
return;
|
||||
|
||||
if (parent) {
|
||||
/* draw parent proxy */
|
||||
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||
proxy = r.parent.item;
|
||||
if (proxy.state == READY) {
|
||||
//log.debug("1. draw parent " + proxy);
|
||||
drawTile(proxy, v, -1);
|
||||
}
|
||||
}
|
||||
} else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
|
||||
/* check if parent was already drawn */
|
||||
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||
proxy = r.parent.item;
|
||||
if (proxy.state == READY)
|
||||
return;
|
||||
}
|
||||
|
||||
proxy = r.parent.parent.item;
|
||||
if (proxy.state == READY)
|
||||
drawTile(proxy, v, -2);
|
||||
}
|
||||
} else {
|
||||
/* prefer drawing parent */
|
||||
if (parent) {
|
||||
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||
proxy = r.parent.item;
|
||||
if (proxy != null && proxy.state == READY) {
|
||||
//log.debug("2. draw parent " + proxy);
|
||||
drawTile(proxy, v, -1);
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
drawProxyChild(tile, v);
|
||||
|
||||
} else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
|
||||
/* check if parent was already drawn */
|
||||
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||
proxy = r.parent.item;
|
||||
if (proxy.state == READY)
|
||||
return;
|
||||
}
|
||||
/* this will do nothing, just to check */
|
||||
if (drawProxyChild(tile, v) > 0)
|
||||
return;
|
||||
|
||||
proxy = r.parent.parent.item;
|
||||
if (proxy.state == READY)
|
||||
drawTile(proxy, v, -2);
|
||||
}
|
||||
protected void drawGrandParent(MapTile t, GLViewport v) {
|
||||
MapTile proxy = t.getProxy(PROXY_GRAMPA, READY);
|
||||
if (proxy != null) {
|
||||
drawTile(proxy, v, -2);
|
||||
t.lastDraw = mDrawSerial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,4 +58,9 @@ public class TreeNode<T extends TreeNode<T, E>, E> {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isRoot() {
|
||||
return this == parent;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user