org.oscim.gdx.poi3d.GdxModelLayer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vtm-gdx-poi3d Show documentation
Show all versions of vtm-gdx-poi3d Show documentation
OpenGL vector map library - running on Android, iOS, Desktop and browser.
/*
* Copyright 2014 Hannes Janetzek
* Copyright 2018-2019 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 .
*/
package org.oscim.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 mAdded = new Array<>();
private AssetManager mAssets;
private GdxRenderer3D2 mG3d;
private boolean mLoading;
private java.util.Map 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.scale.set(1, 1, -1);
node.rotation.setFromAxis(1, 0, 0, 90);
}
model.calculateTransforms();
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 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();
}
}