org.oscim.renderer.LocationTextureRenderer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vtm Show documentation
Show all versions of vtm Show documentation
OpenGL vector map library written in Java - running on Android, iOS, Desktop and within the browser.
/*
* Copyright 2013 Ahmad Saleem
* Copyright 2013 Hannes Janetzek
* Copyright 2016-2019 devemux86
* Copyright 2016 ocsike
* Copyright 2017 Mathieu De Brito
* Copyright 2017-2018 Longri
*
* 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.renderer;
import org.oscim.backend.CanvasAdapter;
import org.oscim.backend.GL;
import org.oscim.backend.canvas.Bitmap;
import org.oscim.core.Box;
import org.oscim.core.Point;
import org.oscim.core.Tile;
import org.oscim.layers.Layer;
import org.oscim.map.Map;
import org.oscim.renderer.bucket.SymbolBucket;
import org.oscim.renderer.bucket.SymbolItem;
import org.oscim.utils.FastMath;
import org.oscim.utils.math.Interpolation;
import static org.oscim.backend.GLAdapter.gl;
public class LocationTextureRenderer extends BucketRenderer {
private static final long ANIM_RATE = 50;
private static final long INTERVAL = 2000;
public static float CIRCLE_SIZE = /*30*/0;
private static final int COLOR = 0xff3333cc;
private static final int SHOW_ACCURACY_ZOOM = 16;
private final Map mMap;
private final Layer mLayer;
protected final float mScale;
private final SymbolBucket mSymbolLayer;
private String mShaderFile;
protected int mShaderProgram;
private int hVertexPosition;
private int hMatrixPosition;
private int hScale;
private int hPhase;
private int uColor;
private int uMode;
private final Point mIndicatorPosition = new Point();
private final Point mScreenPoint = new Point();
private final Box mBBox = new Box();
private boolean mLocationIsVisible;
private boolean mRunAnim;
private boolean mAnimate = true;
private long mAnimStart;
private boolean mCenter;
private boolean mBillboard;
private Bitmap mBitmapArrow, mBitmapMarker;
private LocationCallback mCallback;
private int mColor = COLOR;
private final Point mLocation = new Point(Double.NaN, Double.NaN);
private double mRadius;
private int mShowAccuracyZoom = SHOW_ACCURACY_ZOOM;
public LocationTextureRenderer(Map map, Layer layer) {
this(map, layer, CanvasAdapter.getScale());
}
public LocationTextureRenderer(Map map, Layer layer, float scale) {
mMap = map;
mLayer = layer;
mScale = scale;
mSymbolLayer = new SymbolBucket();
}
public void setAnimate(boolean animate) {
mAnimate = animate;
}
public void setBillboard(boolean billboard) {
mBillboard = billboard;
}
public void setBitmapArrow(Bitmap bitmap) {
mBitmapArrow = bitmap;
}
public void setBitmapMarker(Bitmap bitmap) {
mBitmapMarker = bitmap;
}
public void setCallback(LocationCallback callback) {
mCallback = callback;
}
public void setCenter(boolean center) {
mCenter = center;
}
public void setColor(int color) {
mColor = color;
}
public void setLocation(double x, double y, double radius) {
mLocation.x = x;
mLocation.y = y;
mRadius = radius;
}
public void setShader(String shaderFile) {
mShaderFile = shaderFile;
mInitialized = false;
}
public void setShowAccuracyZoom(int showAccuracyZoom) {
mShowAccuracyZoom = showAccuracyZoom;
}
public void animate(boolean enable) {
if (mRunAnim == enable)
return;
mRunAnim = enable;
if (!enable)
return;
if (!mAnimate)
return;
final Runnable action = new Runnable() {
private long lastRun;
@Override
public void run() {
if (!mRunAnim)
return;
if (!mAnimate)
return;
long diff = System.currentTimeMillis() - lastRun;
mMap.postDelayed(this, Math.min(ANIM_RATE, diff));
mMap.render();
lastRun = System.currentTimeMillis();
}
};
mAnimStart = System.currentTimeMillis();
mMap.postDelayed(action, ANIM_RATE);
}
private float animPhase() {
return (float) ((MapRenderer.frametime - mAnimStart) % INTERVAL) / INTERVAL;
}
@Override
public synchronized void update(GLViewport v) {
if (!mInitialized) {
init();
mInitialized = true;
}
if (!mLayer.isEnabled()) {
setReady(false);
return;
}
/*if (!v.changed() && isReady())
return;*/
setReady(true);
int width = mMap.getWidth();
int height = mMap.getHeight();
double x, y;
if (mCenter) {
x = (width >> 1) + width * mMap.viewport().getMapViewCenterX();
y = (height >> 1) + height * mMap.viewport().getMapViewCenterY();
} else {
// clamp location to a position that can be
// safely translated to screen coordinates
v.getBBox(mBBox, 0);
x = mLocation.x;
y = mLocation.y;
if (!mBBox.contains(mLocation)) {
x = FastMath.clamp(x, mBBox.xmin, mBBox.xmax);
y = FastMath.clamp(y, mBBox.ymin, mBBox.ymax);
}
// get position of Location in pixel relative to
// screen center
v.toScreenPoint(x, y, mScreenPoint);
x = mScreenPoint.x + (width >> 1);
y = mScreenPoint.y + (height >> 1);
}
// clip position to screen boundaries
int visible = 0;
if (x > width - 5)
x = width;
else if (x < 5)
x = 0;
else
visible++;
if (y > height - 5)
y = height;
else if (y < 5)
y = 0;
else
visible++;
mLocationIsVisible = (visible == 2);
// set location indicator position
v.fromScreenPoint(x, y, mIndicatorPosition);
/* Texture */
buckets.clear();
if (mBitmapArrow == null || mBitmapMarker == null)
return;
if (!mLocationIsVisible)
return;
float itx, ity;
if (mCenter) {
itx = 0;
ity = 0;
} else {
double mx = v.pos.x;
double my = v.pos.y;
double scale = Tile.SIZE * v.pos.scale;
long flip = (long) (Tile.SIZE * v.pos.scale) >> 1;
itx = (float) ((mLocation.x - mx) * scale);
ity = (float) ((mLocation.y - my) * scale);
if (itx > flip)
itx -= (flip << 1);
else if (itx < -flip)
itx += (flip << 1);
}
mMapPosition.copy(v.pos);
mMapPosition.bearing = -mMapPosition.bearing;
SymbolItem s = SymbolItem.pool.get();
if (mCallback != null && mCallback.hasRotation())
s.set(itx, ity, mBitmapArrow, mCallback.getRotation(), mBillboard);
else
s.set(itx, ity, mBitmapMarker, mBillboard);
mSymbolLayer.pushSymbol(s);
buckets.set(mSymbolLayer);
buckets.prepare();
compile();
}
@Override
public synchronized void render(GLViewport v) {
GLState.useProgram(mShaderProgram);
GLState.blend(true);
GLState.test(false, false);
GLState.enableVertexArrays(hVertexPosition, GLState.DISABLED);
MapRenderer.bindQuadVertexVBO(hVertexPosition/*, true*/);
float radius = CIRCLE_SIZE * mScale;
boolean viewShed = false;
if (!mLocationIsVisible /* || pos.zoomLevel < SHOW_ACCURACY_ZOOM */) {
animate(true);
} else {
if (v.pos.zoomLevel >= mShowAccuracyZoom)
radius = (float) (mRadius * v.pos.scale);
radius = Math.max(CIRCLE_SIZE * mScale, radius);
viewShed = true;
animate(false);
}
gl.uniform1f(hScale, radius);
double x = mIndicatorPosition.x - v.pos.x;
double y = mIndicatorPosition.y - v.pos.y;
double tileScale = Tile.SIZE * v.pos.scale;
v.mvp.setTransScale((float) (x * tileScale), (float) (y * tileScale), 1);
v.mvp.multiplyMM(v.viewproj, v.mvp);
v.mvp.setAsUniform(hMatrixPosition);
if (!viewShed && mAnimate) {
float phase = Math.abs(animPhase() - 0.5f) * 2;
//phase = Interpolation.fade.apply(phase);
phase = Interpolation.swing.apply(phase);
gl.uniform1f(hPhase, 0.8f + phase * 0.2f);
} else {
gl.uniform1f(hPhase, 1);
}
if (viewShed && mLocationIsVisible) {
if (mCallback != null && mCallback.hasRotation())
gl.uniform1i(uMode, 1); // With bearing
else
gl.uniform1i(uMode, 0); // Without bearing
} else
gl.uniform1i(uMode, -1); // Outside screen
GLUtils.setColor(uColor, mColor);
gl.drawArrays(GL.TRIANGLE_STRIP, 0, 4);
/* Texture */
super.render(v);
}
protected boolean init() {
int program = GLShader.loadShader(mShaderFile != null ? mShaderFile : "accuracy_1");
if (program == 0)
return false;
mShaderProgram = program;
hVertexPosition = gl.getAttribLocation(program, "a_pos");
hMatrixPosition = gl.getUniformLocation(program, "u_mvp");
hPhase = gl.getUniformLocation(program, "u_phase");
hScale = gl.getUniformLocation(program, "u_scale");
uColor = gl.getUniformLocation(program, "u_color");
uMode = gl.getUniformLocation(program, "u_mode");
return true;
}
}