vtm-gdx-poi3d module (#600)
This commit is contained in:
@@ -19,6 +19,7 @@ package org.oscim.test.gdx.poi3d;
|
||||
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.gdx.GdxMapApp;
|
||||
import org.oscim.gdx.poi3d.Poi3DLayer;
|
||||
import org.oscim.layers.tile.buildings.BuildingLayer;
|
||||
import org.oscim.layers.tile.vector.VectorTileLayer;
|
||||
import org.oscim.layers.tile.vector.labeling.LabelLayer;
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Hannes Janetzek
|
||||
* Copyright 2018 Gustl22
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.test.gdx.poi3d;
|
||||
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.graphics.g3d.Model;
|
||||
import com.badlogic.gdx.graphics.g3d.ModelInstance;
|
||||
import com.badlogic.gdx.graphics.g3d.model.Node;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.core.MercatorProjection;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.event.Event;
|
||||
import org.oscim.gdx.GdxAssets;
|
||||
import org.oscim.layers.Layer;
|
||||
import org.oscim.layers.tile.buildings.BuildingLayer;
|
||||
import org.oscim.map.Map;
|
||||
import org.oscim.model.VtmModels;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Experimental layer to display 3d models.
|
||||
*/
|
||||
public class GdxModelLayer extends Layer implements Map.UpdateListener {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GdxModelLayer.class);
|
||||
|
||||
private static final int MIN_ZOOM = BuildingLayer.MIN_ZOOM;
|
||||
|
||||
private Array<ModelInstance> mAdded = new Array<>();
|
||||
private AssetManager mAssets;
|
||||
private GdxRenderer3D2 mG3d;
|
||||
private boolean mLoading;
|
||||
private java.util.Map<ModelPosition, ModelHolder> mScenes = new HashMap<>();
|
||||
|
||||
public GdxModelLayer(Map map) {
|
||||
super(map);
|
||||
|
||||
mRenderer = mG3d = new GdxRenderer3D2(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);
|
||||
|
||||
mAssets = new AssetManager();
|
||||
}
|
||||
|
||||
public ModelPosition addModel(VtmModels model, double lat, double lon, float rotation) {
|
||||
return addModel(GdxAssets.getAssetPath(model.getPath()), lat, lon, rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add model with specified path and position.
|
||||
*
|
||||
* @return the models position, can be modified during rendering e.g. to make animations.
|
||||
* Don't forget to trigger map events (as it usually does if something changes).
|
||||
*/
|
||||
public ModelPosition addModel(String path, double lat, double lon, float rotation) {
|
||||
ModelPosition pos = new ModelPosition(lat, lon, rotation);
|
||||
|
||||
mScenes.put(pos, new ModelHolder(path));
|
||||
|
||||
mAssets.load(path, Model.class);
|
||||
if (!mLoading)
|
||||
mLoading = true;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
private void doneLoading() {
|
||||
for (ModelHolder poiModel : mScenes.values()) {
|
||||
Model model = mAssets.get(poiModel.getPath());
|
||||
for (Node node : model.nodes) {
|
||||
log.debug("loader node " + node.id);
|
||||
|
||||
/* Use with {@link GdxRenderer3D} */
|
||||
if (node.hasChildren() && ((Object) mG3d) instanceof GdxRenderer3D) {
|
||||
if (model.nodes.size != 1) {
|
||||
throw new RuntimeException("Model has more than one node with GdxRenderer: " + model.toString());
|
||||
}
|
||||
node = node.getChild(0);
|
||||
log.debug("loader node " + node.id);
|
||||
|
||||
model.nodes.removeIndex(0);
|
||||
model.nodes.add(node);
|
||||
}
|
||||
node.rotation.setFromAxis(1, 0, 0, 90);
|
||||
}
|
||||
poiModel.setModel(model);
|
||||
}
|
||||
|
||||
mLoading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapEvent(Event ev, MapPosition pos) {
|
||||
|
||||
// if (ev == Map.CLEAR_EVENT) {
|
||||
// synchronized (g3d) {
|
||||
// g3d.instances.clear();
|
||||
// }
|
||||
// }
|
||||
|
||||
if (mLoading && mAssets.update()) {
|
||||
doneLoading();
|
||||
refreshModelInstances();
|
||||
}
|
||||
|
||||
if (mLoading)
|
||||
return;
|
||||
|
||||
double lat = MercatorProjection.toLatitude(pos.y);
|
||||
float groundscale = (float) MercatorProjection
|
||||
.groundResolutionWithScale(lat, 1 << pos.zoomLevel);
|
||||
|
||||
|
||||
float scale = 1f / groundscale;
|
||||
|
||||
synchronized (mG3d) {
|
||||
// remove if out of visible zoom range
|
||||
mG3d.instances.removeAll(mAdded, true);
|
||||
if (pos.getZoomLevel() >= MIN_ZOOM) {
|
||||
mG3d.instances.addAll(mAdded);
|
||||
}
|
||||
|
||||
for (ModelInstance inst : mAdded) {
|
||||
ModelPosition p = (ModelPosition) inst.userData;
|
||||
|
||||
float dx = (float) ((p.x - pos.x) * (Tile.SIZE << pos.zoomLevel));
|
||||
float dy = (float) ((p.y - pos.y) * (Tile.SIZE << pos.zoomLevel));
|
||||
|
||||
inst.transform.idt();
|
||||
inst.transform.scale(scale, scale, scale);
|
||||
inst.transform.translate(dx / scale, dy / scale, 0);
|
||||
inst.transform.rotate(0, 0, 1, p.getRotation());
|
||||
}
|
||||
}
|
||||
|
||||
mG3d.cam.setMapPosition(pos.x, pos.y, 1 << pos.getZoomLevel());
|
||||
}
|
||||
|
||||
public void refreshModelInstances() {
|
||||
for (java.util.Map.Entry<ModelPosition, ModelHolder> scene : mScenes.entrySet()) {
|
||||
mAdded.clear();
|
||||
mG3d.instances.clear();
|
||||
|
||||
ModelInstance inst = new ModelInstance(scene.getValue().getModel());
|
||||
inst.userData = scene.getKey();
|
||||
mAdded.add(inst); // Local stored
|
||||
mG3d.instances.add(inst); // g3d stored
|
||||
}
|
||||
}
|
||||
|
||||
public void removeModel(ModelPosition position) {
|
||||
mScenes.remove(position);
|
||||
if (!mLoading)
|
||||
refreshModelInstances();
|
||||
}
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
package org.oscim.test.gdx.poi3d;
|
||||
|
||||
import com.badlogic.gdx.graphics.g3d.Environment;
|
||||
import com.badlogic.gdx.graphics.g3d.Model;
|
||||
import com.badlogic.gdx.graphics.g3d.ModelBatch;
|
||||
import com.badlogic.gdx.graphics.g3d.ModelInstance;
|
||||
import com.badlogic.gdx.graphics.g3d.Renderable;
|
||||
import com.badlogic.gdx.graphics.g3d.Shader;
|
||||
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
|
||||
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
|
||||
import com.badlogic.gdx.graphics.g3d.utils.DefaultShaderProvider;
|
||||
import com.badlogic.gdx.graphics.g3d.utils.DefaultTextureBinder;
|
||||
import com.badlogic.gdx.graphics.g3d.utils.RenderContext;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import org.oscim.backend.GL;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.map.Map;
|
||||
import org.oscim.map.Viewport;
|
||||
import org.oscim.renderer.GLState;
|
||||
import org.oscim.renderer.GLViewport;
|
||||
import org.oscim.renderer.LayerRenderer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.oscim.backend.GLAdapter.gl;
|
||||
|
||||
public class GdxModelRenderer extends LayerRenderer {
|
||||
static final Logger log = LoggerFactory.getLogger(GdxModelRenderer.class);
|
||||
|
||||
ModelBatch modelBatch;
|
||||
public MapCamera cam;
|
||||
Map mMap;
|
||||
|
||||
boolean loading;
|
||||
|
||||
public Environment lights;
|
||||
|
||||
public Array<ModelInstance> instances = new Array<>();
|
||||
|
||||
public Shader shader;
|
||||
public RenderContext renderContext;
|
||||
public Model model;
|
||||
private ModelBatch mBatch = new ModelBatch();
|
||||
|
||||
public GdxModelRenderer(Map map) {
|
||||
mMap = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setup() {
|
||||
|
||||
modelBatch = new ModelBatch(new DefaultShaderProvider());
|
||||
|
||||
lights = new Environment();
|
||||
lights.set(new ColorAttribute(ColorAttribute.AmbientLight, 1.0f, 1.0f, 1.0f, 1.f));
|
||||
lights.add(new DirectionalLight().set(0.3f, 0.3f, 0.3f, 0, 1, -0.2f));
|
||||
|
||||
cam = new MapCamera(mMap);
|
||||
|
||||
renderContext =
|
||||
new RenderContext(new DefaultTextureBinder(DefaultTextureBinder.WEIGHTED, 1));
|
||||
|
||||
// shader = new DefaultShader(renderable.material,
|
||||
// renderable.mesh.getVertexAttributes(), true, false, 1, 0, 0, 0);
|
||||
// shader.init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void update(GLViewport v) {
|
||||
// if (loading && assets.update())
|
||||
// doneLoading();
|
||||
|
||||
if (!isReady()) {
|
||||
cam.setPosition(v.pos);
|
||||
setReady(true);
|
||||
}
|
||||
|
||||
// if (changed) {
|
||||
// cam.update(position, matrices);
|
||||
// }
|
||||
}
|
||||
|
||||
Vector3 tempVector = new Vector3();
|
||||
float[] mBox = new float[8];
|
||||
|
||||
Renderable r = new Renderable();
|
||||
|
||||
@Override
|
||||
public void render(GLViewport v) {
|
||||
if (instances.size == 0)
|
||||
return;
|
||||
|
||||
// GLUtils.checkGlError(">" + TAG);
|
||||
|
||||
gl.depthMask(true);
|
||||
|
||||
if (v.pos.zoomLevel < 16)
|
||||
gl.clear(GL.DEPTH_BUFFER_BIT);
|
||||
|
||||
// Unbind via GLState to ensure no buffer is replaced by accident
|
||||
GLState.bindElementBuffer(GLState.UNBIND);
|
||||
GLState.bindBuffer(GL.ARRAY_BUFFER, GLState.UNBIND);
|
||||
|
||||
// set state that is expected after modelBatch.end();
|
||||
// modelBatch keeps track of its own state
|
||||
GLState.enableVertexArrays(GLState.DISABLED, GLState.DISABLED);
|
||||
GLState.bindTex2D(GLState.DISABLED);
|
||||
GLState.useProgram(GLState.DISABLED);
|
||||
GLState.test(false, false);
|
||||
GLState.blend(false);
|
||||
|
||||
cam.update(v);
|
||||
|
||||
Viewport p = mMap.viewport();
|
||||
p.getMapExtents(mBox, 10);
|
||||
float scale = (float) (cam.mMapPosition.scale / v.pos.scale);
|
||||
|
||||
float dx = (float) (cam.mMapPosition.x - v.pos.x)
|
||||
* (Tile.SIZE << cam.mMapPosition.zoomLevel);
|
||||
float dy = (float) (cam.mMapPosition.y - v.pos.y)
|
||||
* (Tile.SIZE << cam.mMapPosition.zoomLevel);
|
||||
|
||||
for (int i = 0; i < 8; i += 2) {
|
||||
mBox[i] *= scale;
|
||||
mBox[i] -= dx;
|
||||
mBox[i + 1] *= scale;
|
||||
mBox[i + 1] -= dy;
|
||||
}
|
||||
|
||||
//int w = mMap.getWidth() / 2;
|
||||
//int h = mMap.getHeight() / 2;
|
||||
//float sqRadius = (w * w + h * h) / scale;
|
||||
|
||||
synchronized (this) {
|
||||
if (instances.size == 0)
|
||||
return;
|
||||
|
||||
//renderContext.begin();
|
||||
|
||||
// if (shader == null) {
|
||||
// r = instances.get(0).getRenderable(r);
|
||||
// DefaultShader.Config c = new DefaultShader.Config();
|
||||
// c.numBones = 0;
|
||||
// c.numDirectionalLights = 1;
|
||||
// r.environment = lights;
|
||||
//
|
||||
// shader = new DefaultShader(r, c);
|
||||
// shader.init();
|
||||
// }
|
||||
mBatch.begin(cam);
|
||||
//shader.begin(cam, renderContext);
|
||||
|
||||
for (ModelInstance instance : instances) {
|
||||
instance.transform.getTranslation(tempVector);
|
||||
//instance.getRenderables(renderables, pool);
|
||||
// if (tempVector.x * tempVector.x + tempVector.y * tempVector.y > sqRadius)
|
||||
// continue;
|
||||
// tempVector.scl(0.8f, 0.8f, 1);
|
||||
// if (!GeometryUtils.pointInPoly(tempVector.x, tempVector.y, mBox, 8, 0))
|
||||
// continue;
|
||||
|
||||
mBatch.render(instance);
|
||||
|
||||
//shader.render(r);
|
||||
}
|
||||
mBatch.end();
|
||||
|
||||
//shader.end();
|
||||
//renderContext.end();
|
||||
}
|
||||
|
||||
gl.depthMask(false);
|
||||
GLState.bindElementBuffer(GLState.UNBIND);
|
||||
GLState.bindBuffer(GL.ARRAY_BUFFER, GLState.UNBIND);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void dispose () {
|
||||
// modelBatch.dispose();
|
||||
// assets.dispose();
|
||||
// assets = null;
|
||||
// axesModel.dispose();
|
||||
// axesModel = null;
|
||||
// }
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
package org.oscim.test.gdx.poi3d;
|
||||
|
||||
import com.badlogic.gdx.graphics.g3d.Environment;
|
||||
import com.badlogic.gdx.graphics.g3d.Model;
|
||||
import com.badlogic.gdx.graphics.g3d.ModelBatch;
|
||||
import com.badlogic.gdx.graphics.g3d.ModelInstance;
|
||||
import com.badlogic.gdx.graphics.g3d.Renderable;
|
||||
import com.badlogic.gdx.graphics.g3d.Shader;
|
||||
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
|
||||
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
|
||||
import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader;
|
||||
import com.badlogic.gdx.graphics.g3d.utils.DefaultShaderProvider;
|
||||
import com.badlogic.gdx.graphics.g3d.utils.DefaultTextureBinder;
|
||||
import com.badlogic.gdx.graphics.g3d.utils.RenderContext;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import org.oscim.backend.GL;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.map.Map;
|
||||
import org.oscim.map.Viewport;
|
||||
import org.oscim.renderer.GLState;
|
||||
import org.oscim.renderer.GLViewport;
|
||||
import org.oscim.renderer.LayerRenderer;
|
||||
import org.oscim.utils.geom.GeometryUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.oscim.backend.GLAdapter.gl;
|
||||
|
||||
public class GdxRenderer3D extends LayerRenderer {
|
||||
static final Logger log = LoggerFactory.getLogger(GdxRenderer3D.class);
|
||||
|
||||
ModelBatch modelBatch;
|
||||
public MapCamera cam;
|
||||
Map mMap;
|
||||
|
||||
boolean loading;
|
||||
|
||||
public Environment lights;
|
||||
|
||||
public Array<ModelInstance> instances = new Array<>();
|
||||
|
||||
public Shader shader;
|
||||
public RenderContext renderContext;
|
||||
public Model model;
|
||||
|
||||
public GdxRenderer3D(Map map) {
|
||||
mMap = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setup() {
|
||||
|
||||
modelBatch = new ModelBatch(new DefaultShaderProvider());
|
||||
|
||||
lights = new Environment();
|
||||
lights.set(new ColorAttribute(ColorAttribute.AmbientLight, 1.0f, 1.0f, 1.0f, 1.f));
|
||||
lights.add(new DirectionalLight().set(0.3f, 0.3f, 0.3f, 0, 1, -0.2f));
|
||||
|
||||
cam = new MapCamera(mMap);
|
||||
|
||||
renderContext =
|
||||
new RenderContext(new DefaultTextureBinder(DefaultTextureBinder.WEIGHTED, 1));
|
||||
|
||||
// shader = new DefaultShader(renderable.material,
|
||||
// renderable.mesh.getVertexAttributes(), true, false, 1, 0, 0, 0);
|
||||
// shader.init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void update(GLViewport v) {
|
||||
// if (loading && assets.update())
|
||||
// doneLoading();
|
||||
|
||||
if (!isReady()) {
|
||||
cam.setPosition(v.pos);
|
||||
setReady(true);
|
||||
}
|
||||
|
||||
// if (changed) {
|
||||
// cam.update(position, matrices);
|
||||
// }
|
||||
}
|
||||
|
||||
Vector3 tempVector = new Vector3();
|
||||
float[] mBox = new float[8];
|
||||
|
||||
Renderable r = new Renderable();
|
||||
|
||||
@Override
|
||||
public void render(GLViewport v) {
|
||||
if (instances.size == 0)
|
||||
return;
|
||||
|
||||
// GLUtils.checkGlError(">" + TAG);
|
||||
|
||||
gl.depthMask(true);
|
||||
|
||||
// if (position.zoomLevel < 17)
|
||||
// GL.clear(GL20.DEPTH_BUFFER_BIT);
|
||||
|
||||
// Unbind via GLState to ensure no buffer is replaced by accident
|
||||
GLState.bindElementBuffer(GLState.UNBIND);
|
||||
GLState.bindBuffer(GL.ARRAY_BUFFER, GLState.UNBIND);
|
||||
|
||||
// set state that is expected after modelBatch.end();
|
||||
// modelBatch keeps track of its own state
|
||||
GLState.enableVertexArrays(GLState.DISABLED, GLState.DISABLED);
|
||||
GLState.bindTex2D(GLState.DISABLED);
|
||||
GLState.useProgram(GLState.DISABLED);
|
||||
GLState.test(false, false);
|
||||
GLState.blend(false);
|
||||
|
||||
cam.update(v);
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
int cnt = 0;
|
||||
int rnd = 0;
|
||||
|
||||
Viewport p = mMap.viewport();
|
||||
p.getMapExtents(mBox, 10);
|
||||
float scale = (float) (cam.mMapPosition.scale / v.pos.scale);
|
||||
|
||||
float dx = (float) (cam.mMapPosition.x - v.pos.x)
|
||||
* (Tile.SIZE << cam.mMapPosition.zoomLevel);
|
||||
float dy = (float) (cam.mMapPosition.y - v.pos.y)
|
||||
* (Tile.SIZE << cam.mMapPosition.zoomLevel);
|
||||
|
||||
for (int i = 0; i < 8; i += 2) {
|
||||
mBox[i] *= scale;
|
||||
mBox[i] -= dx;
|
||||
mBox[i + 1] *= scale;
|
||||
mBox[i + 1] -= dy;
|
||||
}
|
||||
|
||||
int w = mMap.getWidth() / 2;
|
||||
int h = mMap.getHeight() / 2;
|
||||
|
||||
float sqRadius = (w * w + h * h) / scale;
|
||||
|
||||
synchronized (this) {
|
||||
if (instances.size == 0)
|
||||
return;
|
||||
|
||||
cnt = instances.size;
|
||||
|
||||
renderContext.begin();
|
||||
|
||||
if (shader == null) {
|
||||
r = instances.get(0).getRenderable(r);
|
||||
DefaultShader.Config c = new DefaultShader.Config();
|
||||
c.numBones = 0;
|
||||
c.numDirectionalLights = 1;
|
||||
r.environment = lights;
|
||||
// shader = new DefaultShader(r, true, false, false, false, 1,
|
||||
// 0, 0, 0);
|
||||
shader = new DefaultShader(r, c);
|
||||
shader.init();
|
||||
}
|
||||
|
||||
shader.begin(cam, renderContext);
|
||||
|
||||
for (ModelInstance instance : instances) {
|
||||
instance.transform.getTranslation(tempVector);
|
||||
|
||||
if (tempVector.x * tempVector.x + tempVector.y * tempVector.y > sqRadius)
|
||||
continue;
|
||||
|
||||
tempVector.scl(0.8f, 0.8f, 1);
|
||||
|
||||
if (!GeometryUtils.pointInPoly(tempVector.x, tempVector.y, mBox, 8, 0))
|
||||
continue;
|
||||
|
||||
instance.getRenderable(r);
|
||||
// r.lights = lights;
|
||||
// r.environment = lights;
|
||||
shader.render(r);
|
||||
|
||||
rnd++;
|
||||
}
|
||||
|
||||
shader.end();
|
||||
renderContext.end();
|
||||
}
|
||||
log.debug(">>> " + (System.currentTimeMillis() - time) + " " + cnt + "/" + rnd);
|
||||
|
||||
gl.depthMask(false);
|
||||
GLState.bindElementBuffer(GLState.UNBIND);
|
||||
GLState.bindBuffer(GL.ARRAY_BUFFER, GLState.UNBIND);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void dispose () {
|
||||
// modelBatch.dispose();
|
||||
// assets.dispose();
|
||||
// assets = null;
|
||||
// axesModel.dispose();
|
||||
// axesModel = null;
|
||||
// }
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Hannes Janetzek
|
||||
* Copyright 2018 Gustl22
|
||||
*
|
||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.test.gdx.poi3d;
|
||||
|
||||
import com.badlogic.gdx.graphics.g3d.Environment;
|
||||
import com.badlogic.gdx.graphics.g3d.ModelBatch;
|
||||
import com.badlogic.gdx.graphics.g3d.ModelInstance;
|
||||
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
|
||||
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
|
||||
import com.badlogic.gdx.graphics.g3d.utils.DefaultShaderProvider;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import org.oscim.backend.GL;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.map.Map;
|
||||
import org.oscim.map.Viewport;
|
||||
import org.oscim.renderer.GLState;
|
||||
import org.oscim.renderer.GLViewport;
|
||||
import org.oscim.renderer.LayerRenderer;
|
||||
import org.oscim.utils.geom.GeometryUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.oscim.backend.GLAdapter.gl;
|
||||
|
||||
/**
|
||||
* Gdx renderer for more complex 3D models.
|
||||
*/
|
||||
public class GdxRenderer3D2 extends LayerRenderer {
|
||||
static final Logger log = LoggerFactory.getLogger(GdxRenderer3D2.class);
|
||||
|
||||
ModelBatch modelBatch;
|
||||
public MapCamera cam;
|
||||
Map mMap;
|
||||
|
||||
boolean loading;
|
||||
|
||||
public Environment lights;
|
||||
|
||||
public Array<ModelInstance> instances = new Array<>();
|
||||
|
||||
public GdxRenderer3D2(Map map) {
|
||||
mMap = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setup() {
|
||||
|
||||
modelBatch = new ModelBatch(new DefaultShaderProvider());
|
||||
|
||||
lights = new Environment();
|
||||
|
||||
lights.add(new DirectionalLight().set(0.7f, 0.7f, 0.7f, 0, 1, -0.2f));
|
||||
lights.set(new ColorAttribute(ColorAttribute.AmbientLight, 1f, 1f, 1f, 1f));
|
||||
|
||||
cam = new MapCamera(mMap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void update(GLViewport v) {
|
||||
// if (loading && assets.update())
|
||||
// doneLoading();
|
||||
|
||||
if (!isReady()) {
|
||||
cam.setPosition(v.pos);
|
||||
setReady(true);
|
||||
}
|
||||
|
||||
// if (changed) {
|
||||
// cam.update(position, matrices);
|
||||
// }
|
||||
}
|
||||
|
||||
Vector3 tempVector = new Vector3();
|
||||
float[] mBox = new float[8];
|
||||
|
||||
@Override
|
||||
public void render(GLViewport v) {
|
||||
if (instances.size == 0)
|
||||
return;
|
||||
|
||||
// GLUtils.checkGlError(">" + TAG);
|
||||
|
||||
gl.depthMask(true);
|
||||
|
||||
if (v.pos.zoomLevel < 17)
|
||||
gl.clear(GL.DEPTH_BUFFER_BIT);
|
||||
|
||||
// Unbind via GLState to ensure no buffer is replaced by accident
|
||||
GLState.bindElementBuffer(GLState.UNBIND);
|
||||
GLState.bindBuffer(GL.ARRAY_BUFFER, GLState.UNBIND);
|
||||
|
||||
// set state that is expected after modelBatch.end();
|
||||
// modelBatch keeps track of its own state
|
||||
GLState.enableVertexArrays(GLState.DISABLED, GLState.DISABLED);
|
||||
GLState.bindTex2D(GLState.DISABLED);
|
||||
GLState.useProgram(GLState.DISABLED);
|
||||
GLState.test(false, false);
|
||||
GLState.blend(false);
|
||||
|
||||
// GL.cullFace(GL20.BACK);
|
||||
// GL.frontFace(GL20.CW);
|
||||
|
||||
cam.update(v);
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
int cnt = 0;
|
||||
int rnd = 0;
|
||||
|
||||
Viewport p = mMap.viewport();
|
||||
p.getMapExtents(mBox, 10);
|
||||
float scale = (float) (cam.mMapPosition.scale / v.pos.scale);
|
||||
|
||||
float dx = (float) (cam.mMapPosition.x - v.pos.x)
|
||||
* (Tile.SIZE << cam.mMapPosition.zoomLevel);
|
||||
float dy = (float) (cam.mMapPosition.y - v.pos.y)
|
||||
* (Tile.SIZE << cam.mMapPosition.zoomLevel);
|
||||
|
||||
for (int i = 0; i < 8; i += 2) {
|
||||
mBox[i] *= scale;
|
||||
mBox[i] -= dx;
|
||||
mBox[i + 1] *= scale;
|
||||
mBox[i + 1] -= dy;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
modelBatch.begin(cam);
|
||||
cnt = instances.size;
|
||||
|
||||
for (ModelInstance instance : instances) {
|
||||
instance.transform.getTranslation(tempVector);
|
||||
tempVector.scl(0.9f, 0.9f, 1);
|
||||
if (!GeometryUtils.pointInPoly(tempVector.x, tempVector.y, mBox, 8, 0))
|
||||
continue;
|
||||
|
||||
modelBatch.render(instance, lights);
|
||||
rnd++;
|
||||
}
|
||||
modelBatch.end();
|
||||
}
|
||||
log.debug(">>> " + (System.currentTimeMillis() - time) + " " + cnt + "/" + rnd);
|
||||
|
||||
// GLUtils.checkGlError("<" + TAG);
|
||||
|
||||
gl.depthMask(false);
|
||||
GLState.bindElementBuffer(GLState.UNBIND);
|
||||
GLState.bindBuffer(GL.ARRAY_BUFFER, GLState.UNBIND);
|
||||
|
||||
// GLState.bindTex2D(-1);
|
||||
// GLState.useProgram(-1);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void dispose () {
|
||||
// modelBatch.dispose();
|
||||
// assets.dispose();
|
||||
// assets = null;
|
||||
// axesModel.dispose();
|
||||
// axesModel = null;
|
||||
// }
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package org.oscim.test.gdx.poi3d;
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera;
|
||||
import com.badlogic.gdx.math.Matrix4;
|
||||
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.map.Map;
|
||||
import org.oscim.renderer.GLViewport;
|
||||
|
||||
public class MapCamera extends Camera {
|
||||
|
||||
private final Map mMap;
|
||||
|
||||
public MapCamera(Map map) {
|
||||
mMap = map;
|
||||
|
||||
this.near = 1;
|
||||
this.far = 8;
|
||||
}
|
||||
|
||||
MapPosition mMapPosition = new MapPosition();
|
||||
|
||||
public void setPosition(MapPosition pos) {
|
||||
mMapPosition.copy(pos);
|
||||
|
||||
this.viewportWidth = mMap.getWidth();
|
||||
this.viewportHeight = mMap.getHeight();
|
||||
}
|
||||
|
||||
public void setMapPosition(double x, double y, double scale) {
|
||||
mMapPosition.setScale(scale);
|
||||
mMapPosition.x = x;
|
||||
mMapPosition.y = y;
|
||||
}
|
||||
|
||||
public void update(GLViewport v) {
|
||||
double scale = (v.pos.scale * Tile.SIZE);
|
||||
|
||||
float x = (float) ((mMapPosition.x - v.pos.x) * scale);
|
||||
float y = (float) ((mMapPosition.y - v.pos.y) * scale);
|
||||
float z = (float) (v.pos.scale / mMapPosition.scale);
|
||||
|
||||
v.proj.get(projection.getValues());
|
||||
v.mvp.setTransScale(x, y, z);
|
||||
v.mvp.setValue(10, z);
|
||||
v.mvp.multiplyLhs(v.view);
|
||||
v.mvp.get(view.getValues());
|
||||
|
||||
combined.set(projection);
|
||||
|
||||
Matrix4.mul(combined.val, view.val);
|
||||
|
||||
//if (updateFrustum) {
|
||||
invProjectionView.set(combined);
|
||||
Matrix4.inv(invProjectionView.val);
|
||||
frustum.update(invProjectionView);
|
||||
//}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(boolean updateFrustum) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Gustl22
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.test.gdx.poi3d;
|
||||
|
||||
import com.badlogic.gdx.graphics.g3d.Model;
|
||||
|
||||
class ModelHolder {
|
||||
Model mModel;
|
||||
String mPath;
|
||||
|
||||
ModelHolder(String path) {
|
||||
mPath = path;
|
||||
}
|
||||
|
||||
public Model getModel() {
|
||||
return mModel;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return mPath;
|
||||
}
|
||||
|
||||
public void setModel(Model model) {
|
||||
mModel = model;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Gustl22
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.test.gdx.poi3d;
|
||||
|
||||
import org.oscim.core.MercatorProjection;
|
||||
|
||||
public class ModelPosition {
|
||||
public double x;
|
||||
public double y;
|
||||
public float rotation;
|
||||
|
||||
public ModelPosition(double lat, double lon, float rotation) {
|
||||
setPosition(lat, lon, rotation);
|
||||
}
|
||||
|
||||
public double getLat() {
|
||||
return MercatorProjection.toLatitude(y);
|
||||
}
|
||||
|
||||
public double getLon() {
|
||||
return MercatorProjection.toLongitude(x);
|
||||
}
|
||||
|
||||
public float getRotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public void setPosition(double lat, double lon, float rotation) {
|
||||
this.y = MercatorProjection.latitudeToY(lat);
|
||||
this.x = MercatorProjection.longitudeToX(lon);
|
||||
this.rotation = rotation;
|
||||
}
|
||||
}
|
||||
@@ -1,400 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Hannes Janetzek
|
||||
* Copyright 2018 Gustl22
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oscim.test.gdx.poi3d;
|
||||
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.graphics.g3d.Model;
|
||||
import com.badlogic.gdx.graphics.g3d.ModelInstance;
|
||||
import com.badlogic.gdx.graphics.g3d.model.Node;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
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.gdx.GdxAssets;
|
||||
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.buildings.BuildingLayer;
|
||||
import org.oscim.layers.tile.vector.VectorTileLayer;
|
||||
import org.oscim.layers.tile.vector.VectorTileLayer.TileLoaderProcessHook;
|
||||
import org.oscim.map.Map;
|
||||
import org.oscim.model.VtmModels;
|
||||
import org.oscim.renderer.bucket.RenderBuckets;
|
||||
import org.oscim.renderer.bucket.SymbolItem;
|
||||
import org.oscim.utils.pool.Inlist;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Experimental Layer to display POIs with 3D models.
|
||||
*/
|
||||
public class Poi3DLayer extends Layer implements Map.UpdateListener {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(Poi3DLayer.class);
|
||||
|
||||
static class Poi3DTileData extends TileData {
|
||||
public final HashMap<ModelHolder, List<SymbolItem>> symbols = new HashMap<>();
|
||||
|
||||
@Override
|
||||
protected void dispose() {
|
||||
for (List<SymbolItem> symbolItems : symbols.values()) {
|
||||
SymbolItem.pool.releaseAll(symbolItems.clear());
|
||||
}
|
||||
symbols.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public final static int MIN_ZOOM = BuildingLayer.MIN_ZOOM;
|
||||
static final String POI_DATA = Poi3DLayer.class.getSimpleName();
|
||||
public final static boolean RANDOM_TRANSFORM = true; // TODO customizable for each tag
|
||||
|
||||
public final static Tag TAG_TREE = new Tag("natural", "tree");
|
||||
public final static Tag TAG_MEMORIAL = new Tag("historic", "memorial");
|
||||
public final static Tag TAG_FOREST = new Tag("landuse", "forest");
|
||||
public final static Tag TAG_WOOD = new Tag("natural", "wood");
|
||||
// Not supported by Oscim Tiles
|
||||
public final static Tag TAG_ARTWORK = new Tag("tourism", "artwork");
|
||||
public final static Tag TAG_TREE_BROADLEAVED = new Tag("leaf_type", "broadleaved");
|
||||
public final static Tag TAG_TREE_NEEDLELEAVED = new Tag("leaf_type", "needleleaved");
|
||||
public final static Tag TAG_STREETLAMP = new Tag("highway", "street_lamp");
|
||||
|
||||
AssetManager mAssets;
|
||||
GdxRenderer3D2 mG3d;
|
||||
boolean mLoading;
|
||||
LinkedHashMap<Tag, List<ModelHolder>> mScenes = new LinkedHashMap<>();
|
||||
VectorTileLayer mTileLayer;
|
||||
LinkedHashMap<Tile, Array<ModelInstance>> mTileMap = new LinkedHashMap<>();
|
||||
TileSet mTileSet = new TileSet();
|
||||
TileSet mPrevTiles = new TileSet();
|
||||
|
||||
public Poi3DLayer(Map map, VectorTileLayer tileLayer) {
|
||||
this(map, tileLayer, true);
|
||||
}
|
||||
|
||||
public Poi3DLayer(Map map, VectorTileLayer tileLayer, boolean useDefaults) {
|
||||
super(map);
|
||||
tileLayer.addHook(new TileLoaderProcessHook() {
|
||||
|
||||
@Override
|
||||
public boolean process(MapTile tile, RenderBuckets buckets, MapElement element) {
|
||||
|
||||
if (tile.zoomLevel < MIN_ZOOM) return false;
|
||||
|
||||
Poi3DTileData td = get(tile);
|
||||
|
||||
for (Entry<Tag, List<ModelHolder>> scene : mScenes.entrySet()) {
|
||||
if (!element.tags.contains(scene.getKey()))
|
||||
continue;
|
||||
List<ModelHolder> holders = scene.getValue();
|
||||
|
||||
PointF p;
|
||||
SymbolItem s;
|
||||
// TODO fill poly area with items
|
||||
for (int i = 0; i < element.getNumPoints(); i++) {
|
||||
p = element.getPoint(i);
|
||||
s = SymbolItem.pool.get();
|
||||
s.x = p.x;
|
||||
s.y = p.y;
|
||||
|
||||
ModelHolder holder;
|
||||
if (holders.size() > 1) {
|
||||
// Use random for tags with multiple models.
|
||||
int random = getPosHash(tile, s) % holders.size();
|
||||
holder = holders.get(random);
|
||||
} else
|
||||
holder = holders.get(0);
|
||||
|
||||
Inlist.List<SymbolItem> symbolItems = td.symbols.get(holder);
|
||||
if (symbolItems == null) {
|
||||
symbolItems = new Inlist.List<>();
|
||||
td.symbols.put(holder, symbolItems);
|
||||
}
|
||||
|
||||
symbolItems.push(s);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete(MapTile tile, boolean success) {
|
||||
}
|
||||
});
|
||||
mTileLayer = tileLayer;
|
||||
|
||||
mRenderer = mG3d = new GdxRenderer3D2(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);
|
||||
|
||||
mAssets = new AssetManager();
|
||||
|
||||
if (useDefaults)
|
||||
useDefaults();
|
||||
}
|
||||
|
||||
public void addModel(VtmModels model, Tag tag) {
|
||||
addModel(GdxAssets.getAssetPath(model.getPath()), tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign model with specified path to an OSM tag. You can assign multiple models to one tag, too.
|
||||
*/
|
||||
public void addModel(String path, Tag tag) {
|
||||
List<ModelHolder> scene = mScenes.get(tag);
|
||||
if (scene == null) {
|
||||
scene = new ArrayList<>();
|
||||
mScenes.put(tag, scene);
|
||||
}
|
||||
scene.add(new ModelHolder(path));
|
||||
mAssets.load(path, Model.class);
|
||||
if (!mLoading)
|
||||
mLoading = true;
|
||||
}
|
||||
|
||||
private void doneLoading() {
|
||||
for (List<ModelHolder> holders : mScenes.values()) {
|
||||
for (ModelHolder holder : holders) {
|
||||
Model model = mAssets.get(holder.getPath());
|
||||
for (Node node : model.nodes) {
|
||||
log.debug("loader node " + node.id);
|
||||
|
||||
/* Use with {@link GdxRenderer3D} */
|
||||
if (node.hasChildren() && ((Object) mG3d) instanceof GdxRenderer3D) {
|
||||
if (model.nodes.size != 1) {
|
||||
throw new RuntimeException("Model has more than one node with GdxRenderer: " + model.toString());
|
||||
}
|
||||
node = node.getChild(0);
|
||||
log.debug("loader node " + node.id);
|
||||
|
||||
model.nodes.removeIndex(0);
|
||||
model.nodes.add(node);
|
||||
}
|
||||
node.rotation.setFromAxis(1, 0, 0, 90);
|
||||
}
|
||||
holder.setModel(model);
|
||||
}
|
||||
}
|
||||
|
||||
mLoading = false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an int which is equal in all zoom levels
|
||||
*/
|
||||
private int getPosHash(Tile tile, SymbolItem item) {
|
||||
int a = (int) (((tile.tileX + ((double) item.x / Tile.SIZE)) * 1000000000) / (1 << tile.zoomLevel));
|
||||
int b = (int) (((tile.tileY + ((double) item.y / Tile.SIZE)) * 1000000000) / (1 << tile.zoomLevel));
|
||||
return Math.abs(a * b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapEvent(Event ev, MapPosition pos) {
|
||||
|
||||
if (ev == Map.CLEAR_EVENT) {
|
||||
mTileSet = new TileSet();
|
||||
mPrevTiles = new TileSet();
|
||||
mTileMap = new LinkedHashMap<>();
|
||||
synchronized (mG3d) {
|
||||
mG3d.instances.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (mLoading && mAssets.update()) {
|
||||
doneLoading();
|
||||
// Renderable renderable = new Renderable();
|
||||
// new ModelInstance(mModel).getRenderable(renderable);
|
||||
// Shader shader = new DefaultShader(renderable, true, false,
|
||||
// false, false, 1, 0, 0, 0);
|
||||
}
|
||||
if (mLoading)
|
||||
return;
|
||||
|
||||
// log.debug("update");
|
||||
|
||||
mTileLayer.tileRenderer().getVisibleTiles(mTileSet);
|
||||
|
||||
if (mTileSet.cnt == 0) {
|
||||
mTileSet.releaseTiles();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
Array<ModelInstance> added = new Array<>();
|
||||
Array<ModelInstance> removed = new Array<>();
|
||||
|
||||
for (int i = 0; i < mTileSet.cnt; i++) {
|
||||
MapTile t = mTileSet.tiles[i];
|
||||
if (mPrevTiles.contains(t))
|
||||
continue;
|
||||
|
||||
Array<ModelInstance> instances = new Array<>();
|
||||
|
||||
Poi3DTileData ld = (Poi3DTileData) t.getData(POI_DATA);
|
||||
if (ld == null)
|
||||
continue;
|
||||
|
||||
for (Entry<ModelHolder, Inlist.List<SymbolItem>> entry : ld.symbols.entrySet()) {
|
||||
for (SymbolItem it : entry.getValue()) {
|
||||
|
||||
ModelInstance inst = new ModelInstance(entry.getKey().getModel());
|
||||
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<ModelInstance> 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;
|
||||
float groundScale = mTileSet.tiles[0].getGroundScale();
|
||||
|
||||
TileSet tmp = mPrevTiles;
|
||||
mPrevTiles = mTileSet;
|
||||
mTileSet = tmp;
|
||||
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
// scale relative to latitude
|
||||
float scale = 1f / groundScale;
|
||||
|
||||
double tileX = (pos.x * (Tile.SIZE << zoom));
|
||||
double tileY = (pos.y * (Tile.SIZE << zoom));
|
||||
|
||||
synchronized (mG3d) {
|
||||
|
||||
for (Entry<Tile, Array<ModelInstance>> e : mTileMap.entrySet()) {
|
||||
Tile t = e.getKey();
|
||||
|
||||
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
||||
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
||||
|
||||
for (ModelInstance inst : e.getValue()) {
|
||||
SymbolItem it = (SymbolItem) inst.userData;
|
||||
|
||||
float s = scale;
|
||||
float r = 0f;
|
||||
|
||||
// random/variable height and rotation
|
||||
if (RANDOM_TRANSFORM) {
|
||||
float deviationStep = s * 0.1f;
|
||||
int hash = getPosHash(t, it); // Use absolute coordinates
|
||||
s += ((hash % 4) - 2) * deviationStep;
|
||||
r = hash % 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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
mG3d.instances.removeAll(removed, true);
|
||||
mG3d.instances.addAll(added);
|
||||
mG3d.cam.setMapPosition(pos.x, pos.y, 1 << zoom);
|
||||
}
|
||||
}
|
||||
|
||||
public void useDefaults() {
|
||||
/* Keep order (the upper tags have higher priority)
|
||||
* Example: needle leaved woods only get fir model although it has the wood tag.
|
||||
*/
|
||||
addModel(VtmModels.MEMORIAL, TAG_ARTWORK);
|
||||
addModel(VtmModels.MEMORIAL, TAG_MEMORIAL);
|
||||
addModel(VtmModels.STREETLAMP, TAG_STREETLAMP);
|
||||
addModel(VtmModels.TREE_FIR, TAG_TREE_NEEDLELEAVED);
|
||||
addModel(VtmModels.TREE_OAK, TAG_TREE_BROADLEAVED);
|
||||
addModel(VtmModels.TREE_ASH, TAG_TREE);
|
||||
addModel(VtmModels.TREE_FIR, TAG_WOOD);
|
||||
addModel(VtmModels.TREE_OAK, TAG_WOOD);
|
||||
addModel(VtmModels.TREE_ASH, TAG_WOOD);
|
||||
addModel(VtmModels.TREE_OAK, TAG_FOREST);
|
||||
addModel(VtmModels.TREE_ASH, TAG_FOREST);
|
||||
addModel(VtmModels.TREE_FIR, TAG_FOREST);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user