- added tilt view gesture

- use simple line shader when rotation is disabled
This commit is contained in:
Hannes Janetzek 2012-09-23 11:08:18 +02:00
parent 7d7cf10d89
commit 8ec405cf5c
8 changed files with 145 additions and 127 deletions

View File

@ -65,7 +65,8 @@ public class MapDatabase implements IMapDatabase {
private static final String CACHE_FILE = "%d-%d-%d.tile"; private static final String CACHE_FILE = "%d-%d-%d.tile";
private static final String SERVER_ADDR = "city.informatik.uni-bremen.de"; private static final String SERVER_ADDR = "city.informatik.uni-bremen.de";
private static final String URL = "/osci/map-live/"; // private static final String URL = "/osci/map-live/";
private static final String URL = "/osci/oscim/";
private final static float REF_TILE_SIZE = 4096.0f; private final static float REF_TILE_SIZE = 4096.0f;
@ -83,21 +84,6 @@ public class MapDatabase implements IMapDatabase {
private final boolean debug = false; private final boolean debug = false;
// private static final int MAX_TAGS_CACHE = 100;
// private static Map<String, Tag> tagHash = Collections
// .synchronizedMap(new LinkedHashMap<String, Tag>(
// MAX_TAGS_CACHE, 0.75f, true) {
//
// private static final long serialVersionUID = 1L;
//
// @Override
// protected boolean removeEldestEntry(Entry<String, Tag> e) {
// if (size() < MAX_TAGS_CACHE)
// return false;
// return true;
// }
// });
@Override @Override
public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) { public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
QueryResult result = QueryResult.SUCCESS; QueryResult result = QueryResult.SUCCESS;
@ -234,7 +220,7 @@ public class MapDatabase implements IMapDatabase {
return file; return file;
} }
// /////////////// hand sewed tile protocol buffers decoder /////////////////// // /////////////// hand sewed tile protocol buffers decoder ///////////////
// TODO write an own serialization format for structs and packed strings.. // TODO write an own serialization format for structs and packed strings..
private static final int BUFFER_SIZE = 65536; private static final int BUFFER_SIZE = 65536;
@ -763,7 +749,7 @@ public class MapDatabase implements IMapDatabase {
| (buffer[offset + 3] & 0xff); | (buffer[offset + 3] & 0xff);
} }
// ///////////////////////// Lightweight HttpClient /////////////////////////////////////// // ///////////////////////// Lightweight HttpClient ///////////////////////
// should have written simple tcp server/client for this... // should have written simple tcp server/client for this...
private int mMaxReq = 0; private int mMaxReq = 0;
@ -788,9 +774,7 @@ public class MapDatabase implements IMapDatabase {
InputStream is = mResponseStream; InputStream is = mResponseStream;
byte[] buf = mReadBuffer; byte[] buf = mReadBuffer;
boolean first = true; boolean first = true;
int read = 0; int read = 0;
int pos = 0; int pos = 0;
int end = 0; int end = 0;
@ -806,8 +790,9 @@ public class MapDatabase implements IMapDatabase {
if (first) { if (first) {
// check only for OK // check only for OK
first = false; first = false;
int i = 0;
for (int i = 0; i < 15 && pos + i < end; i++) for (; i < 15 && pos + i < end; i++)
if (buf[pos + i] != RESPONSE_HTTP_OK[i]) if (buf[pos + i] != RESPONSE_HTTP_OK[i])
return -1; return -1;
@ -854,7 +839,6 @@ public class MapDatabase implements IMapDatabase {
if (mSocket != null && ((mMaxReq-- <= 0) if (mSocket != null && ((mMaxReq-- <= 0)
|| (SystemClock.elapsedRealtime() - mLastRequest || (SystemClock.elapsedRealtime() - mLastRequest
> RESPONSE_EXPECTED_TIMEOUT))) { > RESPONSE_EXPECTED_TIMEOUT))) {
try { try {
mSocket.close(); mSocket.close();
} catch (IOException e) { } catch (IOException e) {
@ -893,7 +877,8 @@ public class MapDatabase implements IMapDatabase {
len += pos; len += pos;
// this does the same but with a few more allocations: // this does the same but with a few more allocations:
// byte[] request = String.format(REQUEST, Integer.valueOf(tile.zoomLevel), // byte[] request = String.format(REQUEST,
// Integer.valueOf(tile.zoomLevel),
// Integer.valueOf(tile.tileX), Integer.valueOf(tile.tileY)).getBytes(); // Integer.valueOf(tile.tileX), Integer.valueOf(tile.tileY)).getBytes();
try { try {
@ -950,7 +935,8 @@ public class MapDatabase implements IMapDatabase {
return pos + i; return pos + i;
} }
// //////////////////////////// Tile cache //////////////////////////////////// // //////////////////////////// Tile cache
// ////////////////////////////////////
private boolean cacheRead(Tile tile, File f) { private boolean cacheRead(Tile tile, File f) {
if (f.exists() && f.length() > 0) { if (f.exists() && f.length() > 0) {

View File

@ -188,7 +188,7 @@ public class MapView extends FrameLayout {
mMapZoomControls = new MapZoomControls(mapActivity, this); mMapZoomControls = new MapZoomControls(mapActivity, this);
mMapZoomControls.setShowMapZoomControls(true); mMapZoomControls.setShowMapZoomControls(true);
enableRotation = true; // enableRotation = true;
for (MapWorker worker : mMapWorkers) for (MapWorker worker : mMapWorkers)
worker.start(); worker.start();

View File

@ -38,7 +38,7 @@ public class MapViewPosition {
private byte mZoomLevel; private byte mZoomLevel;
private float mScale; private float mScale;
private float mRotation; private float mRotation;
private float mTilt; public float mTilt;
// 2^mZoomLevel * mScale; // 2^mZoomLevel * mScale;
private float mMapScale; private float mMapScale;
@ -278,4 +278,17 @@ public class MapViewPosition {
mScale = newScale / (1 << z); mScale = newScale / (1 << z);
mMapScale = newScale; mMapScale = newScale;
} }
public boolean tilt(float moveX) {
float tilt = mTilt + moveX;
if (tilt > 25)
tilt = 25;
else if (tilt < 0)
tilt = 0;
if (mTilt == tilt)
return false;
mTilt = tilt;
return true;
}
} }

View File

@ -95,16 +95,21 @@ public class TouchHandler {
private boolean mScaling = false; private boolean mScaling = false;
private boolean onActionMove(MotionEvent event) { private boolean onActionMove(MotionEvent event) {
int pointerIndex = event.findPointerIndex(mActivePointerId); int id = event.findPointerIndex(mActivePointerId);
// calculate the distance between previous and current position // calculate the distance between previous and current position
float moveX = event.getX(pointerIndex) - mPosX; float moveX = event.getX(id) - mPosX;
float moveY = event.getY(pointerIndex) - mPosY; float moveY = event.getY(id) - mPosY;
// save the position of the event
// Log.d("...", "mx " + moveX + " my " + moveY);
boolean scaling = mScaleGestureDetector.isInProgress(); boolean scaling = mScaleGestureDetector.isInProgress();
if (!mScaling) { if (!mScaling) {
mScaling = scaling; mScaling = scaling;
} }
if (!scaling && !mMoveStart) { if (!scaling && !mMoveStart) {
if (Math.abs(moveX) > 3 * mMapMoveDelta if (Math.abs(moveX) > 3 * mMapMoveDelta
@ -112,11 +117,17 @@ public class TouchHandler {
// the map movement threshold has been reached // the map movement threshold has been reached
// longPressDetector.pressStop(); // longPressDetector.pressStop();
mMoveStart = true; mMoveStart = true;
// save the position of the event
mPosX = event.getX(pointerIndex);
mPosY = event.getY(pointerIndex);
} }
return true;
}
mPosX = event.getX(id);
mPosY = event.getY(id);
if (!scaling) {
mMapPosition.moveMap(moveX, moveY);
mMapView.redrawMap();
return true; return true;
} }
@ -133,7 +144,12 @@ public class TouchHandler {
double rad = Math.atan2(dy, dx); double rad = Math.atan2(dy, dx);
double r = rad - mAngle; double r = rad - mAngle;
// Log.d("...", "move " + x + " " + y + " " + cx + " " + cy); if (!mBeginRotate && Math.abs(dy) < 80) {
if (mMapPosition.tilt(moveY / 4)) {
mMapView.redrawMap();
return true;
}
}
if (!mBeginRotate && !mBeginScale) { if (!mBeginRotate && !mBeginScale) {
if (r > 0.02 || r < -0.02) if (r > 0.02 || r < -0.02)
@ -153,18 +169,9 @@ public class TouchHandler {
mAngle = rad; mAngle = rad;
mMapView.redrawMap(); mMapView.redrawMap();
} }
}
}
// save the position of the event
mPosX = event.getX(pointerIndex);
mPosY = event.getY(pointerIndex);
if (scaling) {
return true;
} }
}
mMapPosition.moveMap(moveX, moveY);
mMapView.redrawMap();
return true; return true;
} }

View File

@ -523,7 +523,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
Matrix.setRotateM(mRotateMatrix, 0, mapPosition.angle, 0, 0, 1); Matrix.setRotateM(mRotateMatrix, 0, mapPosition.angle, 0, 0, 1);
// tilt map // tilt map
float angle = 15f / (mHeight / 2); // mMapView.getMapViewPosition().mTilt;
float angle = mMapView.getMapViewPosition().mTilt / (mHeight / 2);
Matrix.setRotateM(mTmpMatrix, 0, -angle, 1, 0, 0); Matrix.setRotateM(mTmpMatrix, 0, -angle, 1, 0, 0);
// move camera center back to map center // move camera center back to map center
@ -698,6 +700,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
PolygonLayer pl = tile.polygonLayers; PolygonLayer pl = tile.polygonLayers;
boolean clipped = false; boolean clipped = false;
int simpleShader = mRotate ? 0 : 1;
for (; pl != null || ll != null;) { for (; pl != null || ll != null;) {
int lnext = Integer.MAX_VALUE; int lnext = Integer.MAX_VALUE;
@ -724,7 +727,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
} }
GLES20.glEnable(GL_BLEND); GLES20.glEnable(GL_BLEND);
ll = LineRenderer.drawLines(tile, ll, pnext, mvp, div, z, s); ll = LineRenderer.drawLines(tile, ll, pnext, mvp, div, z, s,
simpleShader);
} }
} }
} }
@ -755,8 +759,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// TODO could use tile.proxies here // TODO could use tile.proxies here
private static void drawProxyTile(MapPosition mapPosition, MapTile tile) { private static void drawProxyTile(MapPosition mapPosition, MapTile tile) {
int diff = mapPosition.zoomLevel - tile.zoomLevel;
boolean drawn = false; boolean drawn = false;
if (mapPosition.scale > 1.5f) { if (mapPosition.scale > 1.5f || diff < 0) {
// prefer drawing children // prefer drawing children
if (!drawProxyChild(mapPosition, tile)) { if (!drawProxyChild(mapPosition, tile)) {
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {

View File

@ -21,73 +21,91 @@ import org.oscim.utils.GlUtils;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.util.FloatMath; import android.util.FloatMath;
import android.util.Log;
class LineRenderer { class LineRenderer {
private final static String TAG = "LineRenderer";
private static int NUM_VERTEX_SHORTS = 4; private static int NUM_VERTEX_SHORTS = 4;
private static final int LINE_VERTICES_DATA_POS_OFFSET = 0; private static final int LINE_VERTICES_DATA_POS_OFFSET = 0;
private static final int LINE_VERTICES_DATA_TEX_OFFSET = 4; private static final int LINE_VERTICES_DATA_TEX_OFFSET = 4;
// shader handles // shader handles
private static int lineProgram; private static int[] lineProgram = new int[2];
private static int hLineVertexPosition; private static int[] hLineVertexPosition = new int[2];
private static int hLineTexturePosition; private static int[] hLineTexturePosition = new int[2];
private static int hLineColor; private static int[] hLineColor = new int[2];
private static int hLineMatrix; private static int[] hLineMatrix = new int[2];
private static int hLineScale; private static int[] hLineScale = new int[2];
private static int hLineWidth; private static int[] hLineWidth = new int[2];
private static int hLineOffset;
static boolean init() { static boolean init() {
lineProgram = GlUtils.createProgram(Shaders.lineVertexShader, lineProgram[0] = GlUtils.createProgram(Shaders.lineVertexShader,
Shaders.lineFragmentShader); Shaders.lineFragmentShader);
if (lineProgram == 0) { if (lineProgram[0] == 0) {
// Log.e(TAG, "Could not create line program."); Log.e(TAG, "Could not create line program.");
return false; return false;
} }
hLineMatrix = GLES20.glGetUniformLocation(lineProgram, "u_mvp"); hLineMatrix[0] = GLES20.glGetUniformLocation(lineProgram[0], "u_mvp");
hLineScale = GLES20.glGetUniformLocation(lineProgram, "u_wscale"); hLineScale[0] = GLES20.glGetUniformLocation(lineProgram[0], "u_wscale");
hLineWidth = GLES20.glGetUniformLocation(lineProgram, "u_width"); hLineWidth[0] = GLES20.glGetUniformLocation(lineProgram[0], "u_width");
hLineColor = GLES20.glGetUniformLocation(lineProgram, "u_color"); hLineColor[0] = GLES20.glGetUniformLocation(lineProgram[0], "u_color");
hLineVertexPosition = GLES20.glGetAttribLocation(lineProgram, "a_position"); hLineVertexPosition[0] = GLES20.glGetAttribLocation(lineProgram[0], "a_position");
hLineTexturePosition = GLES20.glGetAttribLocation(lineProgram, "a_st"); hLineTexturePosition[0] = GLES20.glGetAttribLocation(lineProgram[0], "a_st");
lineProgram[1] = GlUtils.createProgram(Shaders.lineVertexShader,
Shaders.lineSimpleFragmentShader);
if (lineProgram[1] == 0) {
Log.e(TAG, "Could not create simple line program.");
return false;
}
hLineMatrix[1] = GLES20.glGetUniformLocation(lineProgram[1], "u_mvp");
hLineScale[1] = GLES20.glGetUniformLocation(lineProgram[1], "u_wscale");
hLineWidth[1] = GLES20.glGetUniformLocation(lineProgram[1], "u_width");
hLineColor[1] = GLES20.glGetUniformLocation(lineProgram[1], "u_color");
hLineVertexPosition[1] = GLES20.glGetAttribLocation(lineProgram[1], "a_position");
hLineTexturePosition[1] = GLES20.glGetAttribLocation(lineProgram[1], "a_st");
return true; return true;
} }
static final boolean mFast = false; // static int mSimple = 1;
static LineLayer drawLines(MapTile tile, LineLayer layer, int next, float[] matrix, static LineLayer drawLines(MapTile tile, LineLayer layer, int next, float[] matrix,
float div, double zoom, float scale) { float div, double zoom, float scale, int mode) {
// int mode = mSimple;
if (layer == null) if (layer == null)
return null; return null;
// TODO should use fast line program when view is not tilted // TODO should use fast line program when view is not tilted
GLES20.glUseProgram(lineProgram); GLES20.glUseProgram(lineProgram[mode]);
GLES20.glEnableVertexAttribArray(hLineVertexPosition); GLES20.glEnableVertexAttribArray(hLineVertexPosition[mode]);
GLES20.glEnableVertexAttribArray(hLineTexturePosition); GLES20.glEnableVertexAttribArray(hLineTexturePosition[mode]);
GLES20.glVertexAttribPointer(hLineVertexPosition, 2, GLES20.GL_SHORT, GLES20.glVertexAttribPointer(hLineVertexPosition[mode], 2, GLES20.GL_SHORT,
false, 8, tile.lineOffset + LINE_VERTICES_DATA_POS_OFFSET); false, 8, tile.lineOffset + LINE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(hLineTexturePosition, 2, GLES20.GL_SHORT, GLES20.glVertexAttribPointer(hLineTexturePosition[mode], 2, GLES20.GL_SHORT,
false, 8, tile.lineOffset + LINE_VERTICES_DATA_TEX_OFFSET); false, 8, tile.lineOffset + LINE_VERTICES_DATA_TEX_OFFSET);
GLES20.glUniformMatrix4fv(hLineMatrix, 1, false, matrix, 0); GLES20.glUniformMatrix4fv(hLineMatrix[mode], 1, false, matrix, 0);
// scale factor to map one pixel on tile to one pixel on screen: // scale factor to map one pixel on tile to one pixel on screen:
// only works with orthographic projection // only works with orthographic projection
float s = scale / div; float s = scale / div;
float pixel = 2.0f / s; float pixel = 2.0f / s;
if (mFast) if (mode == 0)
GLES20.glUniform1f(hLineScale, pixel); pixel = 0;
else
GLES20.glUniform1f(hLineScale, 0); GLES20.glUniform1f(hLineScale[mode], pixel);
// line scale factor (for non fixed lines) // line scale factor (for non fixed lines)
float lineScale = FloatMath.sqrt(s); float lineScale = FloatMath.sqrt(s);
@ -104,13 +122,10 @@ class LineRenderer {
if (line.fade >= zoom) if (line.fade >= zoom)
alpha = (scale > 1.2f ? scale : 1.2f) - alpha; alpha = (scale > 1.2f ? scale : 1.2f) - alpha;
GlUtils.setColor(hLineColor, line.color, alpha); GlUtils.setColor(hLineColor[mode], line.color, alpha);
if (blur) { if (blur) {
if (mFast) GLES20.glUniform1f(hLineScale[mode], pixel);
GLES20.glUniform1f(hLineScale, pixel);
else
GLES20.glUniform1f(hLineScale, 0);
blur = false; blur = false;
} }
@ -118,39 +133,41 @@ class LineRenderer {
for (LineLayer o = l.outlines; o != null; o = o.outlines) { for (LineLayer o = l.outlines; o != null; o = o.outlines) {
if (line.blur != 0) { if (line.blur != 0) {
GLES20.glUniform1f(hLineScale, (l.width + o.width) / s GLES20.glUniform1f(hLineScale[mode], (l.width + o.width) / s
- (line.blur / s)); - (line.blur / s));
blur = true; blur = true;
} }
if (zoom > TileGenerator.STROKE_MAX_ZOOM_LEVEL) if (zoom > TileGenerator.STROKE_MAX_ZOOM_LEVEL)
GLES20.glUniform1f(hLineWidth, (l.width + o.width) / s); GLES20.glUniform1f(hLineWidth[mode], (l.width + o.width) / s);
else else
GLES20.glUniform1f(hLineWidth, l.width / s + o.width / lineScale); GLES20.glUniform1f(hLineWidth[mode], l.width / s + o.width
/ lineScale);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, o.offset, o.verticesCnt); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, o.offset, o.verticesCnt);
} }
} }
else { else {
if (line.blur != 0) { if (line.blur != 0) {
GLES20.glUniform1f(hLineScale, (l.width / lineScale) * line.blur); GLES20.glUniform1f(hLineScale[mode], (l.width / lineScale)
* line.blur);
blur = true; blur = true;
} }
if (line.fixed || zoom > TileGenerator.STROKE_MAX_ZOOM_LEVEL) { if (line.fixed || zoom > TileGenerator.STROKE_MAX_ZOOM_LEVEL) {
// invert scaling of extrusion vectors so that line width // invert scaling of extrusion vectors so that line width
// stays the same. // stays the same.
GLES20.glUniform1f(hLineWidth, l.width / s); GLES20.glUniform1f(hLineWidth[mode], l.width / s);
} else { } else {
GLES20.glUniform1f(hLineWidth, l.width / lineScale); GLES20.glUniform1f(hLineWidth[mode], l.width / lineScale);
} }
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, l.offset, l.verticesCnt); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
} }
} }
GLES20.glDisableVertexAttribArray(hLineVertexPosition); GLES20.glDisableVertexAttribArray(hLineVertexPosition[mode]);
GLES20.glDisableVertexAttribArray(hLineTexturePosition); GLES20.glDisableVertexAttribArray(hLineTexturePosition[mode]);
return l; return l;
} }

View File

@ -78,18 +78,6 @@ class MapTile extends JobTile {
return isActive || refs > 0; return isActive || refs > 0;
} }
// void unref() {
// if (refs == 0) {
// Log.d("MapTile", "XXX already unrefd " + this);
// return;
// }
// refs--;
// }
//
// void ref() {
// refs++;
// }
void lock() { void lock() {
isActive = true; isActive = true;
@ -102,13 +90,14 @@ class MapTile extends JobTile {
if (p != null && (p.isReady || p.newData || p.isLoading)) { if (p != null && (p.isReady || p.newData || p.isLoading)) {
proxies |= PROXY_PARENT; proxies |= PROXY_PARENT;
p.refs++; p.refs++;
} else { }
p = rel.parent.parent.tile; p = rel.parent.parent.tile;
if (p != null && (p.isReady || p.newData || p.isLoading)) { if (p != null && (p.isReady || p.newData || p.isLoading)) {
proxies |= PROXY_GRAMPA; proxies |= PROXY_GRAMPA;
p.refs++; p.refs++;
} }
}
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
if (rel.child[j] != null) { if (rel.child[j] != null) {
p = rel.child[j].tile; p = rel.child[j].tile;
@ -129,7 +118,8 @@ class MapTile extends JobTile {
if ((proxies & (1 << 4)) != 0) { if ((proxies & (1 << 4)) != 0) {
MapTile p = rel.parent.tile; MapTile p = rel.parent.tile;
p.refs--; p.refs--;
} else if ((proxies & (1 << 5)) != 0) { }
if ((proxies & (1 << 5)) != 0) {
MapTile p = rel.parent.parent.tile; MapTile p = rel.parent.parent.tile;
p.refs--; p.refs--;
} }

View File

@ -51,25 +51,24 @@ class Shaders {
// + " v_st = u_width * a_st;" // + " v_st = u_width * a_st;"
// + "}"; // + "}";
// final static String lineFragmentShader = "" final static String lineSimpleFragmentShader = ""
// + "precision mediump float;" + "precision mediump float;"
// + "uniform float u_wscale;" + "uniform float u_wscale;"
// + "uniform float u_width;" + "uniform float u_width;"
// + "uniform vec4 u_color;" + "uniform vec4 u_color;"
// + "varying vec2 v_st;" + "varying vec2 v_st;"
// + "const float zero = 0.0;" + "const float zero = 0.0;"
// + "void main() {" + "void main() {"
// + " float len;" + " float len;"
// + " if (v_st.t == zero)" + " if (v_st.t == zero)"
// + " len = abs(v_st.s);" + " len = abs(v_st.s);"
// + " else " + " else "
// + " len = length(v_st);" + " len = length(v_st);"
// // fade to alpha. u_wscale is the width in pixel which should be faded, // fade to alpha. u_wscale is the width in pixel which should be
// // u_width - len the position of this fragment on the perpendicular to // faded, u_width - len the position of this fragment on the
// // this line segment // perpendicular to this line segment
// + " gl_FragColor = smoothstep(zero, u_wscale, u_width - len) * u_color;" + " gl_FragColor = smoothstep(zero, u_wscale, u_width - len) * u_color;"
// // + " gl_FragColor = u_color;" + "}";
// + "}";
final static String lineFragmentShader = "" final static String lineFragmentShader = ""
+ "#extension GL_OES_standard_derivatives : enable\n" + "#extension GL_OES_standard_derivatives : enable\n"