package org.oscim.layers.tile.buildings;
import static java.lang.System.currentTimeMillis;
import static org.oscim.layers.tile.MapTile.State.NEW_DATA;
import static org.oscim.layers.tile.MapTile.State.READY;
import static org.oscim.utils.FastMath.clamp;
import org.oscim.layers.tile.MapTile;
import org.oscim.layers.tile.TileDistanceSort;
import org.oscim.layers.tile.TileRenderer;
import org.oscim.layers.tile.TileSet;
import org.oscim.renderer.ExtrusionRenderer;
import org.oscim.renderer.GLViewport;
import org.oscim.renderer.MapRenderer;
import org.oscim.renderer.bucket.ExtrusionBuckets;
import org.oscim.renderer.bucket.RenderBuckets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BuildingRenderer extends ExtrusionRenderer {
static final Logger log = LoggerFactory.getLogger(BuildingRenderer.class);
private final TileRenderer mTileRenderer;
private final TileSet mTileSet;
private final int mZoomMin;
private final int mZoomMax;
private final float mFadeInTime = 250;
private final float mFadeOutTime = 400;
private long mAnimTime;
private boolean mShow;
public BuildingRenderer(TileRenderer tileRenderer, int zoomMin, int zoomMax,
boolean mesh, boolean alpha) {
super(mesh, alpha);
mZoomMax = zoomMax;
mZoomMin = zoomMin;
mTileRenderer = tileRenderer;
mTileSet = new TileSet();
}
@Override
public boolean setup() {
mAlpha = 0;
return super.setup();
}
@Override
public void update(GLViewport v) {
int diff = (v.pos.zoomLevel - mZoomMin);
/* if below min zoom or already faded out */
if (diff < -1) {
mAlpha = 0;
mShow = false;
setReady(false);
return;
}
if (diff >= 0) {
if (mAlpha < 1) {
long now = currentTimeMillis();
if (!mShow)
mAnimTime = now - (long) (mAlpha * mFadeInTime);
mShow = true;
mAlpha = clamp((now - mAnimTime) / mFadeInTime, 0, 1);
MapRenderer.animate();
}
} else {
if (mAlpha > 0) {
long now = currentTimeMillis();
if (mShow)
mAnimTime = now - (long) ((1 - mAlpha) * mFadeOutTime);
mShow = false;
mAlpha = clamp(1 - (now - mAnimTime) / mFadeOutTime, 0, 1);
MapRenderer.animate();
}
}
if (mAlpha == 0) {
setReady(false);
return;
}
mTileRenderer.getVisibleTiles(mTileSet);
if (mTileSet.cnt == 0) {
mTileRenderer.releaseTiles(mTileSet);
setReady(false);
return;
}
MapTile[] tiles = mTileSet.tiles;
TileDistanceSort.sort(tiles, 0, mTileSet.cnt);
/* keep a list of tiles available for rendering */
int maxTiles = mTileSet.cnt * 4;
if (mExtrusionBucketSet.length < maxTiles)
mExtrusionBucketSet = new ExtrusionBuckets[maxTiles];
/* compile one tile max per frame */
boolean compiled = false;
int activeTiles = 0;
int zoom = tiles[0].zoomLevel;
if (zoom >= mZoomMin && zoom <= mZoomMax) {
/* TODO - if tile is not available try parent or children */
for (int i = 0; i < mTileSet.cnt; i++) {
ExtrusionBuckets ebs = getBuckets(tiles[i]);
if (ebs == null)
continue;
if (ebs.compiled)
mExtrusionBucketSet[activeTiles++] = ebs;
else if (!compiled && ebs.compile()) {
mExtrusionBucketSet[activeTiles++] = ebs;
compiled = true;
}
}
} else if (zoom == mZoomMax + 1) {
/* special case for s3db: render from parent tiles */
for (int i = 0; i < mTileSet.cnt; i++) {
MapTile t = tiles[i].node.parent();
if (t == null)
continue;
// for (MapTile c : mTiles)
// if (c == t)
// continue O;
ExtrusionBuckets ebs = getBuckets(t);
if (ebs == null)
continue;
if (ebs.compiled)
mExtrusionBucketSet[activeTiles++] = ebs;
else if (!compiled && ebs.compile()) {
mExtrusionBucketSet[activeTiles++] = ebs;
compiled = true;
}
}
} else if (zoom == mZoomMin - 1) {
/* check if proxy children are ready */
for (int i = 0; i < mTileSet.cnt; i++) {
MapTile t = tiles[i];
for (byte j = 0; j < 4; j++) {
if (!t.hasProxy(1 << j))
continue;
MapTile c = t.node.child(j);
ExtrusionBuckets eb = getBuckets(c);
if (eb == null || !eb.compiled)
continue;
mExtrusionBucketSet[activeTiles++] = eb;
}
}
}
/* load more tiles on next frame */
if (compiled)
MapRenderer.animate();
mBucketsCnt = activeTiles;
//log.debug("active tiles: {}", mExtrusionLayerCnt);
if (activeTiles == 0) {
mTileRenderer.releaseTiles(mTileSet);
setReady(false);
return;
}
setReady(true);
}
@Override
public void render(GLViewport v) {
super.render(v);
/* release lock on tile data */
mTileRenderer.releaseTiles(mTileSet);
}
private static ExtrusionBuckets getBuckets(MapTile t) {
RenderBuckets buckets = t.getBuckets();
if (buckets != null && !t.state(READY | NEW_DATA))
return null;
return BuildingLayer.get(t);
}
}