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