refactor: MapTile et al

- cleanup proxy draw logic in VectorTileRenderer
- fixes upload of child proxies in TileRenderer
This commit is contained in:
Hannes Janetzek 2014-09-16 05:13:45 +02:00
parent 7779e30635
commit 0c245f4f6d
4 changed files with 322 additions and 242 deletions

View File

@ -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;
}
} }

View File

@ -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;
} }
} }

View File

@ -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);
}
} }
} }
} }

View File

@ -58,4 +58,9 @@ public class TreeNode<T extends TreeNode<T, E>, E> {
} }
return null; return null;
} }
public boolean isRoot() {
return this == parent;
}
} }