From 0c245f4f6d2c9dd50a732540323d9c9203a73158 Mon Sep 17 00:00:00 2001 From: Hannes Janetzek Date: Tue, 16 Sep 2014 05:13:45 +0200 Subject: [PATCH] refactor: MapTile et al - cleanup proxy draw logic in VectorTileRenderer - fixes upload of child proxies in TileRenderer --- vtm/src/org/oscim/layers/tile/MapTile.java | 259 ++++++++++++------ .../org/oscim/layers/tile/TileRenderer.java | 101 ++++--- .../oscim/layers/tile/VectorTileRenderer.java | 199 ++++++-------- .../org/oscim/utils/quadtree/TreeNode.java | 5 + 4 files changed, 322 insertions(+), 242 deletions(-) diff --git a/vtm/src/org/oscim/layers/tile/MapTile.java b/vtm/src/org/oscim/layers/tile/MapTile.java index 999b9ebd..00f56d2c 100644 --- a/vtm/src/org/oscim/layers/tile/MapTile.java +++ b/vtm/src/org/oscim/layers/tile/MapTile.java @@ -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 { + static final Logger log = LoggerFactory.getLogger(MapTile.class); + public static class TileNode extends TreeNode { } 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 { - 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 { + 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; + } } diff --git a/vtm/src/org/oscim/layers/tile/TileRenderer.java b/vtm/src/org/oscim/layers/tile/TileRenderer.java index bb631aa2..8e01f60b 100644 --- a/vtm/src/org/oscim/layers/tile/TileRenderer.java +++ b/vtm/src/org/oscim/layers/tile/TileRenderer.java @@ -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; } } diff --git a/vtm/src/org/oscim/layers/tile/VectorTileRenderer.java b/vtm/src/org/oscim/layers/tile/VectorTileRenderer.java index c9ee7c2a..aacaffb1 100644 --- a/vtm/src/org/oscim/layers/tile/VectorTileRenderer.java +++ b/vtm/src/org/oscim/layers/tile/VectorTileRenderer.java @@ -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; } } } diff --git a/vtm/src/org/oscim/utils/quadtree/TreeNode.java b/vtm/src/org/oscim/utils/quadtree/TreeNode.java index 85f0276c..0e86e125 100644 --- a/vtm/src/org/oscim/utils/quadtree/TreeNode.java +++ b/vtm/src/org/oscim/utils/quadtree/TreeNode.java @@ -58,4 +58,9 @@ public class TreeNode, E> { } return null; } + + public boolean isRoot() { + return this == parent; + } + }