api: no more sync'ed Viewport methods

- remove synchronized viewport methods: viewport MUST only be changed on main-thread
- when calling Map.setPosition() from another thread the position will be applied
  on the next main-loop iteration
This commit is contained in:
Hannes Janetzek
2014-10-24 22:20:11 +02:00
parent 381907526e
commit 8626aa2f53
10 changed files with 328 additions and 165 deletions

View File

@@ -18,16 +18,20 @@ package org.oscim.android;
import org.oscim.android.gl.GLView; import org.oscim.android.gl.GLView;
import org.oscim.map.Map; import org.oscim.map.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.widget.RelativeLayout.LayoutParams; import android.widget.RelativeLayout.LayoutParams;
public class AndroidMap extends Map { public class AndroidMap extends Map {
static final Logger log = LoggerFactory.getLogger(AndroidMap.class);
private final MapView mMapView; private final MapView mMapView;
final GLView mGLView; final GLView mGLView;
private volatile boolean mWaitRedraw; private boolean mRenderRequest;
private volatile boolean mPausing; private boolean mRenderWait;
private boolean mPausing;
public AndroidMap(MapView mapView) { public AndroidMap(MapView mapView) {
super(); super();
@@ -52,14 +56,24 @@ public class AndroidMap extends Map {
return mMapView.getHeight(); return mMapView.getHeight();
} }
private final Runnable mRedrawCb = new Runnable() {
@Override
public void run() {
prepareFrame();
mGLView.requestRender();
}
};
@Override @Override
public void updateMap(boolean redraw) { public void updateMap(boolean redraw) {
//if (redraw && !mClearMap && !mPausing) if (mPausing)
// mGLView.requestRender(); return;
if (!mWaitRedraw) { if (!mRenderRequest) {
mWaitRedraw = true; mRenderRequest = true;
mMapView.post(mRedrawRequest); mMapView.post(mRedrawCb);
} else {
mRenderWait = true;
} }
} }
@@ -68,25 +82,24 @@ public class AndroidMap extends Map {
if (mPausing) if (mPausing)
return; return;
if (mClearMap) updateMap(true);
updateMap(false);
else
mGLView.requestRender();
} }
private final Runnable mRedrawRequest = new Runnable() { @Override
@Override public void beginFrame() {
public void run() { }
redrawMapInternal();
@Override
public void doneFrame() {
mRenderRequest = false;
if (mRenderWait) {
//log.debug("redraw");
mRenderWait = false;
updateMap(true);
//prepareFrame();
//mGLView.requestRender();
} }
};
void redrawMapInternal() {
mWaitRedraw = false;
updateLayers();
mGLView.requestRender();
} }
@Override @Override
@@ -100,6 +113,7 @@ public class AndroidMap extends Map {
} }
public void pause(boolean pause) { public void pause(boolean pause) {
log.debug("pause... {}", pause);
mPausing = pause; mPausing = pause;
} }
} }

View File

@@ -38,15 +38,12 @@ import com.badlogic.gdx.utils.Timer.Task;
public abstract class GdxMap implements ApplicationListener { public abstract class GdxMap implements ApplicationListener {
final static Logger log = LoggerFactory.getLogger(GdxMap.class); final static Logger log = LoggerFactory.getLogger(GdxMap.class);
protected final Map mMap; protected Map mMap;
private final MapAdapter mMapAdapter;
VectorTileLayer mMapLayer; VectorTileLayer mMapLayer;
private final MapRenderer mMapRenderer; private MapRenderer mMapRenderer;
public GdxMap() { public GdxMap() {
mMap = mMapAdapter = new MapAdapter();
mMapRenderer = new MapRenderer(mMap);
} }
protected void initDefaultLayers(TileSource tileSource, boolean tileGrid, boolean labels, protected void initDefaultLayers(TileSource tileSource, boolean tileGrid, boolean labels,
@@ -70,6 +67,8 @@ public abstract class GdxMap implements ApplicationListener {
@Override @Override
public void create() { public void create() {
mMap = new MapAdapter();
mMapRenderer = new MapRenderer(mMap);
Gdx.graphics.setContinuousRendering(false); Gdx.graphics.setContinuousRendering(false);
Gdx.app.setLogLevel(Application.LOG_DEBUG); Gdx.app.setLogLevel(Application.LOG_DEBUG);
@@ -101,9 +100,13 @@ public abstract class GdxMap implements ApplicationListener {
} }
/* private */boolean mRenderWait;
/* private */boolean mRenderRequest;
/* private */boolean mUpdateRequest;
@Override @Override
public void render() { public void render() {
if (!mMapAdapter.needsRedraw()) if (!mRenderRequest)
return; return;
mMapRenderer.onDrawFrame(); mMapRenderer.onDrawFrame();
@@ -132,8 +135,7 @@ public abstract class GdxMap implements ApplicationListener {
return mMap; return mMap;
} }
static class MapAdapter extends Map { class MapAdapter extends Map {
boolean mRenderRequest;
@Override @Override
public int getWidth() { public int getWidth() {
@@ -145,21 +147,35 @@ public abstract class GdxMap implements ApplicationListener {
return Gdx.graphics.getHeight(); return Gdx.graphics.getHeight();
} }
private final Runnable mRedrawCb = new Runnable() {
@Override
public void run() {
prepareFrame();
Gdx.graphics.requestRendering();
}
};
@Override @Override
public void updateMap(boolean forceRender) { public void updateMap(boolean forceRender) {
if (!mWaitRedraw) {
mWaitRedraw = true; if (!mRenderRequest) {
Gdx.app.postRunnable(mRedrawRequest); mRenderRequest = true;
Gdx.app.postRunnable(mRedrawCb);
} else {
mRenderWait = true;
} }
} }
@Override @Override
public void render() { public void render() {
//updateMap(true);
mRenderRequest = true; mRenderRequest = true;
if (mClearMap) if (mClearMap)
updateMap(false); updateMap(false);
else else {
Gdx.graphics.requestRendering(); Gdx.graphics.requestRendering();
}
} }
@Override @Override
@@ -179,35 +195,22 @@ public abstract class GdxMap implements ApplicationListener {
return true; return true;
} }
/** @Override
* Update all Layers on Main thread. public void beginFrame() {
*
* @param forceRedraw
* also render frame FIXME (does nothing atm)
*/
private void redrawMapInternal(boolean forceRedraw) {
updateLayers();
mRenderRequest = true;
Gdx.graphics.requestRendering();
} }
/* private */boolean mWaitRedraw; @Override
private final Runnable mRedrawRequest = new Runnable() { public void doneFrame() {
@Override
public void run() {
mWaitRedraw = false;
redrawMapInternal(false);
}
};
public boolean needsRedraw() {
if (!mRenderRequest)
return false;
mRenderRequest = false; mRenderRequest = false;
return true;
}
if (mRenderWait) {
mRenderWait = false;
mRenderRequest = true;
prepareFrame();
Gdx.graphics.requestRendering();
}
}
} }
} }

View File

@@ -0,0 +1,16 @@
package org.oscim.utils;
public class ThreadUtils {
public static void assertMainThread() {
}
public static boolean isMainThread() {
return true;
}
public static void init() {
}
}

View File

@@ -27,14 +27,14 @@ import org.oscim.core.MapPosition;
import org.oscim.core.Point; import org.oscim.core.Point;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.renderer.MapRenderer; import org.oscim.renderer.MapRenderer;
import org.oscim.utils.ThreadUtils;
import org.oscim.utils.async.Task;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class Animator { public class Animator {
static final Logger log = LoggerFactory.getLogger(Animator.class); static final Logger log = LoggerFactory.getLogger(Animator.class);
//static final Logger log = LoggerFactory.getLogger(MapAnimator.class);
private final static int ANIM_NONE = 0; private final static int ANIM_NONE = 0;
private final static int ANIM_MOVE = 1 << 0; private final static int ANIM_MOVE = 1 << 0;
private final static int ANIM_SCALE = 1 << 1; private final static int ANIM_SCALE = 1 << 1;
@@ -62,6 +62,8 @@ public class Animator {
} }
public synchronized void animateTo(long duration, BoundingBox bbox) { public synchronized void animateTo(long duration, BoundingBox bbox) {
ThreadUtils.assertMainThread();
mMap.getMapPosition(mStartPos); mMap.getMapPosition(mStartPos);
/* TODO for large distance first scale out, then in /* TODO for large distance first scale out, then in
* calculate the maximum scale at which the BoundingBox * calculate the maximum scale at which the BoundingBox
@@ -89,12 +91,22 @@ public class Animator {
animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT); animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT);
} }
public synchronized void animateTo(BoundingBox bbox) { public void animateTo(BoundingBox bbox) {
animateTo(1000, bbox); animateTo(1000, bbox);
} }
public synchronized void animateTo(long duration, GeoPoint geoPoint, /**
* Animate to GeoPoint
*
* @param duration in ms
* @param geoPoint
* @param scale
* @param relative alter scale relative to current scale
*/
public void animateTo(long duration, GeoPoint geoPoint,
double scale, boolean relative) { double scale, boolean relative) {
ThreadUtils.assertMainThread();
mMap.getMapPosition(mStartPos); mMap.getMapPosition(mStartPos);
if (relative) if (relative)
@@ -110,11 +122,13 @@ public class Animator {
animStart(duration, ANIM_MOVE | ANIM_SCALE); animStart(duration, ANIM_MOVE | ANIM_SCALE);
} }
public synchronized void animateTo(GeoPoint p) { public void animateTo(GeoPoint p) {
animateTo(500, p, 1, true); animateTo(500, p, 1, true);
} }
public synchronized void animateTo(long duration, MapPosition pos) { public void animateTo(long duration, MapPosition pos) {
ThreadUtils.assertMainThread();
mMap.getMapPosition(mStartPos); mMap.getMapPosition(mStartPos);
pos.scale = clamp(pos.scale, pos.scale = clamp(pos.scale,
@@ -130,8 +144,10 @@ public class Animator {
animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT); animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT);
} }
public synchronized void animateZoom(long duration, double scaleBy, public void animateZoom(long duration, double scaleBy,
float pivotX, float pivotY) { float pivotX, float pivotY) {
ThreadUtils.assertMainThread();
mMap.getMapPosition(mCurPos); mMap.getMapPosition(mCurPos);
if (mState == ANIM_SCALE) if (mState == ANIM_SCALE)
@@ -150,9 +166,11 @@ public class Animator {
animStart(duration, ANIM_SCALE); animStart(duration, ANIM_SCALE);
} }
public synchronized void animateFling(float velocityX, float velocityY, public void animateFling(float velocityX, float velocityY,
int xmin, int xmax, int ymin, int ymax) { int xmin, int xmax, int ymin, int ymax) {
ThreadUtils.assertMainThread();
if (velocityX * velocityX + velocityY * velocityY < 2048) if (velocityX * velocityX + velocityY * velocityY < 2048)
return; return;
@@ -177,87 +195,90 @@ public class Animator {
} }
private void animStart(float duration, int state) { private void animStart(float duration, int state) {
mState = state;
mCurPos.copy(mStartPos); mCurPos.copy(mStartPos);
mState = state;
mDuration = duration; mDuration = duration;
mAnimEnd = System.currentTimeMillis() + (long) duration; mAnimEnd = System.currentTimeMillis() + (long) duration;
mMap.render(); mMap.render();
} }
private void animCancel() {
mState = ANIM_NONE;
mPivot.x = 0;
mPivot.y = 0;
}
/** /**
* called by MapRenderer at begin of each frame. * called by MapRenderer at begin of each frame.
*/ */
public synchronized void updateAnimation() { void updateAnimation() {
if (mState == ANIM_NONE) if (mState == ANIM_NONE)
return; return;
long millisLeft = mAnimEnd - MapRenderer.frametime; long millisLeft = mAnimEnd - MapRenderer.frametime;
boolean changed = false; //boolean changed = false;
ViewController v = mMap.viewport(); ViewController v = mMap.viewport();
synchronized (v) { //synchronized (v) {
/* cancel animation when position was changed since last /* cancel animation when position was changed since last
* update, i.e. when it was modified outside the animator. */ * update, i.e. when it was modified outside the animator. */
if (v.getMapPosition(mCurPos)) { if (v.getMapPosition(mCurPos)) {
animCancel(); log.debug("cancel anim - changed");
return; cancel();
} return;
float adv = clamp(1.0f - millisLeft / mDuration, 0, 1);
double scaleAdv = 1;
if ((mState & ANIM_SCALE) != 0) {
scaleAdv = doScale(v, adv);
}
if ((mState & ANIM_MOVE) != 0) {
v.moveTo(mStartPos.x + mDeltaPos.x * (adv / scaleAdv),
mStartPos.y + mDeltaPos.y * (adv / scaleAdv));
}
if ((mState & ANIM_FLING) != 0) {
adv = (float) Math.sqrt(adv);
double dx = mVelocity.x * adv;
double dy = mVelocity.y * adv;
if ((dx - mScroll.x) != 0 || (dy - mScroll.y) != 0) {
v.moveMap((float) (dx - mScroll.x),
(float) (dy - mScroll.y));
mScroll.x = dx;
mScroll.y = dy;
}
}
if ((mState & ANIM_ROTATE) != 0) {
v.setRotation(mStartPos.bearing + mDeltaPos.bearing * adv);
}
if ((mState & ANIM_TILT) != 0) {
v.setTilt(mStartPos.tilt + mDeltaPos.tilt * adv);
}
if (millisLeft <= 0)
animCancel();
/* remember current map position */
changed = v.getMapPosition(mCurPos);
} }
float adv = clamp(1.0f - millisLeft / mDuration, 0, 1);
double scaleAdv = 1;
if ((mState & ANIM_SCALE) != 0) {
scaleAdv = doScale(v, adv);
}
if ((mState & ANIM_MOVE) != 0) {
v.moveTo(mStartPos.x + mDeltaPos.x * (adv / scaleAdv),
mStartPos.y + mDeltaPos.y * (adv / scaleAdv));
}
if ((mState & ANIM_FLING) != 0) {
adv = (float) Math.sqrt(adv);
double dx = mVelocity.x * adv;
double dy = mVelocity.y * adv;
if ((dx - mScroll.x) != 0 || (dy - mScroll.y) != 0) {
v.moveMap((float) (dx - mScroll.x),
(float) (dy - mScroll.y));
mScroll.x = dx;
mScroll.y = dy;
}
}
if ((mState & ANIM_ROTATE) != 0) {
v.setRotation(mStartPos.bearing + mDeltaPos.bearing * adv);
}
if ((mState & ANIM_TILT) != 0) {
v.setTilt(mStartPos.tilt + mDeltaPos.tilt * adv);
}
if (millisLeft <= 0) {
//log.debug("animate END");
cancel();
}
/* remember current map position */
final boolean changed = v.getMapPosition(mCurPos);
if (changed) { if (changed) {
/* render and inform layers that position has changed */
mMap.updateMap(true); mMap.updateMap(true);
} else { } else {
/* just render next frame */ mMap.postDelayed(updateTask, 10);
mMap.render();
} }
} }
private Task updateTask = new Task() {
@Override
public int go(boolean canceled) {
if (!canceled)
updateAnimation();
return Task.DONE;
}
};
private double doScale(ViewController v, float adv) { private double doScale(ViewController v, float adv) {
double newScale = mStartPos.scale + mDeltaPos.scale * Math.sqrt(adv); double newScale = mStartPos.scale + mDeltaPos.scale * Math.sqrt(adv);
@@ -267,7 +288,10 @@ public class Animator {
return newScale / (mStartPos.scale + mDeltaPos.scale); return newScale / (mStartPos.scale + mDeltaPos.scale);
} }
public synchronized void cancel() { public void cancel() {
//ThreadUtils.assertMainThread();
mState = ANIM_NONE; mState = ANIM_NONE;
mPivot.x = 0;
mPivot.y = 0;
} }
} }

View File

@@ -32,6 +32,7 @@ import org.oscim.theme.IRenderTheme;
import org.oscim.theme.ThemeFile; import org.oscim.theme.ThemeFile;
import org.oscim.theme.ThemeLoader; import org.oscim.theme.ThemeLoader;
import org.oscim.tiling.TileSource; import org.oscim.tiling.TileSource;
import org.oscim.utils.ThreadUtils;
import org.oscim.utils.async.AsyncExecutor; import org.oscim.utils.async.AsyncExecutor;
import org.oscim.utils.async.TaskQueue; import org.oscim.utils.async.TaskQueue;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -85,7 +86,7 @@ public abstract class Map implements TaskQueue {
private final Layers mLayers; private final Layers mLayers;
private final ViewController mViewport; private final ViewController mViewport;
private final Animator mAnimator; protected final Animator mAnimator;
private final MapPosition mMapPosition; private final MapPosition mMapPosition;
private final AsyncExecutor mAsyncExecutor; private final AsyncExecutor mAsyncExecutor;
@@ -97,6 +98,8 @@ public abstract class Map implements TaskQueue {
protected boolean mClearMap = true; protected boolean mClearMap = true;
public Map() { public Map() {
ThreadUtils.init();
mViewport = new ViewController(); mViewport = new ViewController();
mAnimator = new Animator(this); mAnimator = new Animator(this);
mLayers = new Layers(this); mLayers = new Layers(this);
@@ -237,9 +240,19 @@ public abstract class Map implements TaskQueue {
/** /**
* Set {@link MapPosition} of {@link Viewport} and trigger a redraw. * Set {@link MapPosition} of {@link Viewport} and trigger a redraw.
*/ */
public void setMapPosition(MapPosition mapPosition) { public void setMapPosition(final MapPosition mapPosition) {
mViewport.setMapPosition(mapPosition); if (!ThreadUtils.isMainThread())
updateMap(true); post(new Runnable() {
@Override
public void run() {
mViewport.setMapPosition(mapPosition);
updateMap(true);
}
});
else {
mViewport.setMapPosition(mapPosition);
updateMap(true);
}
} }
public void setMapPosition(double latitude, double longitude, double scale) { public void setMapPosition(double latitude, double longitude, double scale) {
@@ -253,6 +266,10 @@ public abstract class Map implements TaskQueue {
* @return true when MapPosition was updated (has changed) * @return true when MapPosition was updated (has changed)
*/ */
public boolean getMapPosition(MapPosition mapPosition) { public boolean getMapPosition(MapPosition mapPosition) {
if (!ThreadUtils.isMainThread()) {
return mViewport.getSyncMapPosition(mapPosition);
}
return mViewport.getMapPosition(mapPosition); return mViewport.getMapPosition(mapPosition);
} }
@@ -289,14 +306,18 @@ public abstract class Map implements TaskQueue {
} }
/** /**
* This function is run on main-loop before rendering a frame. * This function is run on main-thread before rendering a frame.
* Caution: Do not call directly! *
* For internal use only. Do not call!
*/ */
protected void updateLayers() { protected void prepareFrame() {
boolean changed = false; ThreadUtils.assertMainThread();
MapPosition pos = mMapPosition; MapPosition pos = mMapPosition;
changed |= mViewport.getMapPosition(pos); mAnimator.updateAnimation();
boolean changed = mViewport.getMapPosition(pos);
if (mClearMap) if (mClearMap)
events.fire(CLEAR_EVENT, pos); events.fire(CLEAR_EVENT, pos);
@@ -306,9 +327,17 @@ public abstract class Map implements TaskQueue {
events.fire(UPDATE_EVENT, pos); events.fire(UPDATE_EVENT, pos);
mClearMap = false; mClearMap = false;
mAnimator.updateAnimation();
mViewport.syncViewport();
} }
public boolean handleGesture(Gesture g, MotionEvent e) { public boolean handleGesture(Gesture g, MotionEvent e) {
return mLayers.handleGesture(g, e); return mLayers.handleGesture(g, e);
} }
public abstract void beginFrame();
public abstract void doneFrame();
} }

View File

@@ -5,10 +5,13 @@ import org.oscim.core.Point;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.renderer.GLMatrix; import org.oscim.renderer.GLMatrix;
import org.oscim.utils.FastMath; import org.oscim.utils.FastMath;
import org.oscim.utils.ThreadUtils;
public class ViewController extends Viewport { public class ViewController extends Viewport {
public synchronized void setScreenSize(int width, int height) { public void setScreenSize(int width, int height) {
ThreadUtils.assertMainThread();
mHeight = height; mHeight = height;
mWidth = width; mWidth = width;
@@ -50,7 +53,9 @@ public class ViewController extends Viewport {
* @param mx the amount of pixels to move the map horizontally. * @param mx the amount of pixels to move the map horizontally.
* @param my the amount of pixels to move the map vertically. * @param my the amount of pixels to move the map vertically.
*/ */
public synchronized void moveMap(float mx, float my) { public void moveMap(float mx, float my) {
ThreadUtils.assertMainThread();
Point p = applyRotation(mx, my); Point p = applyRotation(mx, my);
double tileScale = mPos.scale * Tile.SIZE; double tileScale = mPos.scale * Tile.SIZE;
moveTo(mPos.x - p.x / tileScale, mPos.y - p.y / tileScale); moveTo(mPos.x - p.x / tileScale, mPos.y - p.y / tileScale);
@@ -94,7 +99,9 @@ public class ViewController extends Viewport {
* @param pivotY * @param pivotY
* @return true if scale was changed * @return true if scale was changed
*/ */
public synchronized boolean scaleMap(float scale, float pivotX, float pivotY) { public boolean scaleMap(float scale, float pivotX, float pivotY) {
ThreadUtils.assertMainThread();
// just sanitize input // just sanitize input
//scale = FastMath.clamp(scale, 0.5f, 2); //scale = FastMath.clamp(scale, 0.5f, 2);
if (scale < 0.000001) if (scale < 0.000001)
@@ -126,7 +133,8 @@ public class ViewController extends Viewport {
* @param pivotX * @param pivotX
* @param pivotY * @param pivotY
*/ */
public synchronized void rotateMap(double radians, float pivotX, float pivotY) { public void rotateMap(double radians, float pivotX, float pivotY) {
ThreadUtils.assertMainThread();
double rsin = Math.sin(radians); double rsin = Math.sin(radians);
double rcos = Math.cos(radians); double rcos = Math.cos(radians);
@@ -139,7 +147,9 @@ public class ViewController extends Viewport {
setRotation(mPos.bearing + Math.toDegrees(radians)); setRotation(mPos.bearing + Math.toDegrees(radians));
} }
public synchronized void setRotation(double degree) { public void setRotation(double degree) {
ThreadUtils.assertMainThread();
while (degree > 180) while (degree > 180)
degree -= 360; degree -= 360;
while (degree < -180) while (degree < -180)
@@ -149,11 +159,15 @@ public class ViewController extends Viewport {
updateMatrices(); updateMatrices();
} }
public synchronized boolean tiltMap(float move) { public boolean tiltMap(float move) {
ThreadUtils.assertMainThread();
return setTilt(mPos.tilt + move); return setTilt(mPos.tilt + move);
} }
public synchronized boolean setTilt(float tilt) { public boolean setTilt(float tilt) {
ThreadUtils.assertMainThread();
tilt = FastMath.clamp(tilt, 0, MAX_TILT); tilt = FastMath.clamp(tilt, 0, MAX_TILT);
if (tilt == mPos.tilt) if (tilt == mPos.tilt)
return false; return false;
@@ -162,7 +176,9 @@ public class ViewController extends Viewport {
return true; return true;
} }
public synchronized void setMapPosition(MapPosition mapPosition) { public void setMapPosition(MapPosition mapPosition) {
ThreadUtils.assertMainThread();
mPos.scale = FastMath.clamp(mapPosition.scale, MIN_SCALE, MAX_SCALE); mPos.scale = FastMath.clamp(mapPosition.scale, MIN_SCALE, MAX_SCALE);
mPos.x = mapPosition.x; mPos.x = mapPosition.x;
mPos.y = mapPosition.y; mPos.y = mapPosition.y;
@@ -199,4 +215,30 @@ public class ViewController extends Viewport {
/* (AB)^-1 = B^-1*A^-1, invert projection */ /* (AB)^-1 = B^-1*A^-1, invert projection */
mUnprojMatrix.multiplyMM(mTmpMatrix, mProjMatrixInverse); mUnprojMatrix.multiplyMM(mTmpMatrix, mProjMatrixInverse);
} }
public final Viewport mNextFrame = new Viewport();
/** synchronize on this object when doing multiple calls on it */
public final Viewport getSyncViewport() {
return mNextFrame;
}
void syncViewport() {
synchronized (mNextFrame) {
mNextFrame.copy(this);
}
}
public boolean getSyncViewport(Viewport v) {
synchronized (mNextFrame) {
return v.copy(mNextFrame);
}
}
public boolean getSyncMapPosition(MapPosition mapPosition) {
synchronized (mNextFrame) {
return mNextFrame.getMapPosition(mapPosition);
}
}
} }

View File

@@ -87,7 +87,7 @@ public class Viewport {
* @return true iff current position is different from * @return true iff current position is different from
* passed position. * passed position.
*/ */
public synchronized boolean getMapPosition(MapPosition pos) { public boolean getMapPosition(MapPosition pos) {
boolean changed = (pos.scale != mPos.scale boolean changed = (pos.scale != mPos.scale
|| pos.x != mPos.x || pos.x != mPos.x
@@ -114,7 +114,7 @@ public class Viewport {
* @param box float[8] will be set. * @param box float[8] will be set.
* @param add increase extents of box * @param add increase extents of box
*/ */
public synchronized void getMapExtents(float[] box, float add) { public void getMapExtents(float[] box, float add) {
float t = getDepth(1); float t = getDepth(1);
float t2 = getDepth(-1); float t2 = getDepth(-1);
@@ -143,6 +143,8 @@ public class Viewport {
* Get Z-value of the map-plane for a point on screen - * Get Z-value of the map-plane for a point on screen -
* calculate the intersection of a ray from camera origin * calculate the intersection of a ray from camera origin
* and the map plane * and the map plane
* TODO use
* www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf
*/ */
protected float getDepth(float y) { protected float getDepth(float y) {
// origin is moved by VIEW_DISTANCE // origin is moved by VIEW_DISTANCE
@@ -244,7 +246,7 @@ public class Viewport {
* @param y screen coordinate * @param y screen coordinate
* @return the corresponding GeoPoint * @return the corresponding GeoPoint
*/ */
public synchronized GeoPoint fromScreenPoint(float x, float y) { public GeoPoint fromScreenPoint(float x, float y) {
fromScreenPoint(x, y, mMovePoint); fromScreenPoint(x, y, mMovePoint);
return new GeoPoint( return new GeoPoint(
MercatorProjection.toLatitude(mMovePoint.y), MercatorProjection.toLatitude(mMovePoint.y),
@@ -257,7 +259,7 @@ public class Viewport {
* @param x screen coordinate * @param x screen coordinate
* @param y screen coordinate * @param y screen coordinate
*/ */
public synchronized void fromScreenPoint(double x, double y, Point out) { public void fromScreenPoint(double x, double y, Point out) {
// scale to -1..1 // scale to -1..1
float mx = (float) (1 - (x / mWidth * 2)); float mx = (float) (1 - (x / mWidth * 2));
float my = (float) (1 - (y / mHeight * 2)); float my = (float) (1 - (y / mHeight * 2));
@@ -294,7 +296,7 @@ public class Viewport {
* @param geoPoint the GeoPoint * @param geoPoint the GeoPoint
* @param out Point projected to screen pixel relative to center * @param out Point projected to screen pixel relative to center
*/ */
public synchronized void toScreenPoint(GeoPoint geoPoint, Point out) { public void toScreenPoint(GeoPoint geoPoint, Point out) {
MercatorProjection.project(geoPoint, out); MercatorProjection.project(geoPoint, out);
toScreenPoint(out.x, out.y, out); toScreenPoint(out.x, out.y, out);
} }
@@ -304,7 +306,7 @@ public class Viewport {
* *
* @param out Point projected to screen coordinate * @param out Point projected to screen coordinate
*/ */
public synchronized void toScreenPoint(double x, double y, Point out) { public void toScreenPoint(double x, double y, Point out) {
double cs = mPos.scale * Tile.SIZE; double cs = mPos.scale * Tile.SIZE;
double cx = mPos.x * cs; double cx = mPos.x * cs;
@@ -322,20 +324,17 @@ public class Viewport {
out.y = -(mv[1] * (mHeight / 2)); out.y = -(mv[1] * (mHeight / 2));
} }
public synchronized boolean copy(Viewport viewport) { protected boolean copy(Viewport viewport) {
mHeight = viewport.mHeight;
mWidth = viewport.mWidth;
mProjMatrix.copy(viewport.mProjMatrix);
mProjMatrixUnscaled.copy(viewport.mProjMatrixUnscaled);
mProjMatrixInverse.copy(viewport.mProjMatrixInverse);
mUnprojMatrix.copy(viewport.mUnprojMatrix); mUnprojMatrix.copy(viewport.mUnprojMatrix);
mRotationMatrix.copy(viewport.mRotationMatrix); mRotationMatrix.copy(viewport.mRotationMatrix);
mViewMatrix.copy(viewport.mViewMatrix); mViewMatrix.copy(viewport.mViewMatrix);
mViewProjMatrix.copy(viewport.mViewProjMatrix); mViewProjMatrix.copy(viewport.mViewProjMatrix);
return viewport.getMapPosition(mPos); return viewport.getMapPosition(mPos);
} }
public synchronized void initFrom(Viewport viewport) {
mProjMatrix.copy(viewport.mProjMatrix);
mProjMatrixUnscaled.copy(viewport.mProjMatrixUnscaled);
mProjMatrixInverse.copy(viewport.mProjMatrixInverse);
mHeight = viewport.mHeight;
mWidth = viewport.mWidth;
}
} }

View File

@@ -1,6 +1,7 @@
package org.oscim.renderer; package org.oscim.renderer;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.map.Map;
import org.oscim.map.Viewport; import org.oscim.map.Viewport;
public class GLViewport extends Viewport { public class GLViewport extends Viewport {
@@ -40,8 +41,8 @@ public class GLViewport extends Viewport {
return changed; return changed;
} }
void setFrom(Viewport viewport) { void setFrom(Map map) {
changed = super.copy(viewport); changed = map.viewport().getSyncViewport(this);
getMapExtents(plane, 0); getMapExtents(plane, 0);
} }

View File

@@ -70,10 +70,28 @@ public class MapRenderer {
mClearColor = GLUtils.colorToFloat(color); mClearColor = GLUtils.colorToFloat(color);
} }
private final Runnable renderBegin = new Runnable() {
@Override
public void run() {
mMap.beginFrame();
}
};
private final Runnable renderDone = new Runnable() {
@Override
public void run() {
mMap.doneFrame();
}
};
public void onDrawFrame() { public void onDrawFrame() {
frametime = System.currentTimeMillis(); frametime = System.currentTimeMillis();
mMap.post(renderBegin);
draw(); draw();
mMap.post(renderDone);
mBufferPool.releaseBuffers(); mBufferPool.releaseBuffers();
TextureItem.disposeTextures(); TextureItem.disposeTextures();
} }
@@ -98,8 +116,7 @@ public class MapRenderer {
GLState.bindElementBuffer(-1); GLState.bindElementBuffer(-1);
GLState.bindVertexBuffer(-1); GLState.bindVertexBuffer(-1);
mMap.animator().updateAnimation(); mViewport.setFrom(mMap);
mViewport.setFrom(mMap.viewport());
if (GLAdapter.debugView) { if (GLAdapter.debugView) {
/* modify this to scale only the view, to see /* modify this to scale only the view, to see
@@ -145,8 +162,6 @@ public class MapRenderer {
if (width <= 0 || height <= 0) if (width <= 0 || height <= 0)
return; return;
//mMap.viewport().getMatrix(null, mMatrices.proj, null);
mViewport.initFrom(mMap.viewport());
gl.viewport(0, 0, width, height); gl.viewport(0, 0, width, height);
//GL.scissor(0, 0, width, height); //GL.scissor(0, 0, width, height);

View File

@@ -0,0 +1,20 @@
package org.oscim.utils;
public class ThreadUtils {
private static Thread MAIN_THREAD;
public static void assertMainThread() {
if (MAIN_THREAD != Thread.currentThread())
throw new RuntimeException("Access from non-main thread!");
}
public static boolean isMainThread() {
return MAIN_THREAD == Thread.currentThread();
}
public static void init() {
MAIN_THREAD = Thread.currentThread();
}
}