package org.oscim.test.gdx.poi3d;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import org.oscim.core.MapElement;
import org.oscim.core.MapPosition;
import org.oscim.core.PointF;
import org.oscim.core.Tag;
import org.oscim.core.Tile;
import org.oscim.event.Event;
import org.oscim.layers.Layer;
import org.oscim.layers.tile.MapTile;
import org.oscim.layers.tile.MapTile.TileData;
import org.oscim.layers.tile.TileSet;
import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.VectorTileLayer.TileLoaderProcessHook;
import org.oscim.map.Map;
import org.oscim.renderer.bucket.RenderBuckets;
import org.oscim.renderer.bucket.SymbolItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.model.Node;
import com.badlogic.gdx.utils.Array;
public class Poi3DLayer extends Layer implements Map.UpdateListener {
static final Logger log = LoggerFactory.getLogger(Poi3DLayer.class);
static class Poi3DTileData extends TileData {
public final List<SymbolItem> symbols = new List<SymbolItem>();
@Override
protected void dispose() {
SymbolItem.pool.releaseAll(symbols.clear());
}
}
final static String POI_DATA = Poi3DLayer.class.getSimpleName();
final static Tag TREE_TAG = new Tag("natural", "tree");
private Poi3DTileData get(MapTile tile) {
Poi3DTileData ld = (Poi3DTileData) tile.getData(POI_DATA);
if (ld == null) {
ld = new Poi3DTileData();
tile.addData(POI_DATA, ld);
}
return ld;
}
GdxRenderer3D g3d;
VectorTileLayer mTileLayer;
public Poi3DLayer(Map map, VectorTileLayer tileLayer) {
super(map);
tileLayer.addHook(new TileLoaderProcessHook() {
@Override
public boolean process(MapTile tile, RenderBuckets buckets, MapElement element) {
if (!element.tags.contains(TREE_TAG))
return false;
Poi3DTileData td = get(tile);
PointF p = element.getPoint(0);
SymbolItem s = SymbolItem.pool.get();
s.x = p.x;
s.y = p.y;
td.symbols.push(s);
return true;
}
@Override
public void complete(MapTile tile, boolean success) {
}
});
mTileLayer = tileLayer;
mRenderer = g3d = new GdxRenderer3D(mMap);
// Material mat = new
// Material(ColorAttribute.createDiffuse(Color.BLUE));
// ModelBuilder modelBuilder = new ModelBuilder();
// long attributes = Usage.Position | Usage.Normal |
// Usage.TextureCoordinates;
// mModel = modelBuilder.createSphere(10f, 10f, 10f, 12, 12,
// mat, attributes);
assets = new AssetManager();
assets.load("data/g3d/treeA.g3dj", Model.class);
loading = true;
}
TileSet mTileSet = new TileSet();
TileSet mPrevTiles = new TileSet();
LinkedHashMap<Tile, Array<SharedModel>> mTileMap =
new LinkedHashMap<Tile, Array<SharedModel>>();
boolean loading;
Model mModel;
AssetManager assets;
private void doneLoading() {
Model model = assets.get("data/g3d/treeA.g3dj", Model.class);
for (int i = 0; i < model.nodes.size; i++) {
Node node = model.nodes.get(i);
if (node.id.equals("treeA_root")) {
node.rotation.setFromAxis(1, 0, 0, 90);
mModel = model;
}
}
loading = false;
}
@Override
public void onMapEvent(Event ev, MapPosition pos) {
if (ev == Map.CLEAR_EVENT) {
mTileSet = new TileSet();
mPrevTiles = new TileSet();
mTileMap = new LinkedHashMap<Tile, Array<SharedModel>>();
synchronized (g3d) {
g3d.instances.clear();
}
}
if (loading && assets.update()) {
doneLoading();
// Renderable renderable = new Renderable();
// new SharedModel(mModel).getRenderable(renderable);
// Shader shader = new DefaultShader(renderable, true, false,
// false, false, 1, 0, 0, 0);
}
if (loading)
return;
// log.debug("update");
mTileLayer.tileRenderer().getVisibleTiles(mTileSet);
if (mTileSet.cnt == 0) {
mTileSet.releaseTiles();
return;
}
boolean changed = false;
Array<SharedModel> added = new Array<SharedModel>();
Array<SharedModel> removed = new Array<SharedModel>();
for (int i = 0; i < mTileSet.cnt; i++) {
MapTile t = mTileSet.tiles[i];
if (mPrevTiles.contains(t))
continue;
Array<SharedModel> instances = new Array<SharedModel>();
Poi3DTileData ld = (Poi3DTileData) t.getData(POI_DATA);
if (ld == null)
continue;
for (SymbolItem it : ld.symbols) {
SharedModel inst = new SharedModel(mModel);
inst.userData = it;
// float r = 0.5f + 0.5f * (float) Math.random();
// float g = 0.5f + 0.5f * (float) Math.random();
// float b = 0.5f + 0.5f * (float) Math.random();
// inst.transform.setTranslation(new Vector3(it.x, it.y,
// 10));
// inst.materials.get(0).set(ColorAttribute.createDiffuse(r,
// g, b, 0.8f));
instances.add(inst);
added.add(inst);
}
if (instances.size == 0)
continue;
log.debug("add " + t + " " + instances.size);
changed = true;
mTileMap.put(t, instances);
}
for (int i = 0; i < mPrevTiles.cnt; i++) {
MapTile t = mPrevTiles.tiles[i];
if (mTileSet.contains(t))
continue;
Array<SharedModel> instances = mTileMap.get(t);
if (instances == null)
continue;
changed = true;
removed.addAll(instances);
mTileMap.remove(t);
log.debug("remove " + t);
}
mPrevTiles.releaseTiles();
int zoom = mTileSet.tiles[0].zoomLevel;
TileSet tmp = mPrevTiles;
mPrevTiles = mTileSet;
mTileSet = tmp;
if (!changed)
return;
// scale aka tree height
float scale = (float) (1f / (1 << (17 - zoom))) * 8;
double tileX = (pos.x * (Tile.SIZE << zoom));
double tileY = (pos.y * (Tile.SIZE << zoom));
synchronized (g3d) {
for (Entry<Tile, Array<SharedModel>> e : mTileMap.entrySet()) {
Tile t = e.getKey();
float dx = (float) (t.tileX * Tile.SIZE - tileX);
float dy = (float) (t.tileY * Tile.SIZE - tileY);
for (SharedModel inst : e.getValue()) {
SymbolItem it = (SymbolItem) inst.userData;
// variable height
float s = scale + (it.x * it.y) % 3;
float r = (it.x * it.y) % 360;
inst.transform.idt();
inst.transform.scale(s, s, s);
inst.transform.translate((dx + it.x) / s, (dy + it.y) / s, 0);
inst.transform.rotate(0, 0, 1, r);
// inst.transform.setToTranslationAndScaling((dx +
// it.x), (dy + it.y),
// 0, s, s, s);
}
}
g3d.instances.removeAll(removed, true);
g3d.instances.addAll(added);
g3d.cam.setMapPosition(pos.x, pos.y, 1 << zoom);
}
}
}