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

View File

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

View File

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

View File

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